AppView in a box as a Vite plugin thing hatk.dev

feat: remove hatk new, use vp create template instead

- Remove hatk new scaffolding command (~600 lines) from CLI
- Point users to vp create github:hatk-dev/hatk-template-starter
- Update quickstart with vp prerequisites and new create flow
- Update CLI docs, scaffold docs, project structure docs
- Add pronunciation to site hero
- Disable memory diagnostics logging

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

+39 -630
+1 -7
docs/site/cli/index.md
··· 3 3 description: All available Hatk CLI commands. 4 4 --- 5 5 6 - The `hatk` CLI manages your entire development workflow — from scaffolding a new project to building for production. 7 - 8 - ## Getting Started 9 - 10 - | Command | Description | 11 - | ----------------- | ------------------------- | 12 - | `hatk new <name>` | Create a new hatk project | 6 + The `hatk` CLI manages your development workflow — generators, dev server, and builds. To create a new project, use `vp create github:hatk-dev/hatk-template-starter` (see [Quickstart](/getting-started/quickstart)). 13 7 14 8 ## Generators 15 9
+6 -9
docs/site/cli/scaffold.md
··· 1 1 --- 2 2 title: Scaffolding 3 - description: Create projects and generate code with the Hatk CLI. 3 + description: Generate code with the Hatk CLI. 4 4 --- 5 5 6 - ## `hatk new` 6 + ## Creating a project 7 7 8 - Create a new Hatk project with the standard directory structure. 8 + Create a new hatk project using the Vite+ template: 9 9 10 10 ```bash 11 - hatk new <name> [--svelte] 11 + vp create github:hatk-dev/hatk-template-starter 12 12 ``` 13 13 14 - | Option | Description | 15 - | ---------- | --------------------------------------------------------- | 16 - | `<name>` | Project directory name (required) | 17 - | `--svelte` | Include a SvelteKit frontend with `app/routes` and `app/lib` | 14 + You'll be prompted for the target directory name. 18 15 19 - The command creates the project directory with `hatk.config.ts`, `lexicons/`, `server/`, `seeds/`, `test/`, and the core framework lexicons under `lexicons/dev/hatk/`. With `--svelte`, it also creates `app/`, `vite.config.ts`, and `svelte.config.js`. 16 + See the [Quickstart](/getting-started/quickstart) for prerequisites and setup. 20 17 21 18 ## `hatk generate` 22 19
+2 -2
docs/site/getting-started/project-structure.md
··· 3 3 description: Understand the files and directories in a hatk project. 4 4 --- 5 5 6 - After running `npx hatk new`, your project looks like this: 6 + After creating a project with `vp create github:hatk-dev/hatk-template-starter`, your project looks like this: 7 7 8 8 ``` 9 9 my-app/ ··· 138 138 139 139 ## `db/schema.sql` 140 140 141 - Optional custom SQL that runs after hatk creates its auto-generated tables. Use this for custom indexes, views, or tables that go beyond what lexicons define. 141 + Auto-generated database reference schema. This file is written by hatk on startup and shows the current table structure. 142 142 143 143 ## `docker-compose.yml` / `Dockerfile` 144 144
+22 -14
docs/site/getting-started/quickstart.md
··· 5 5 6 6 ## Prerequisites 7 7 8 - - **Node.js 22+** — check with `node --version` 8 + - **Vite+** — install with `curl -fsSL https://vite.plus | bash` (or `irm https://vite.plus/ps1 | iex` on Windows) 9 9 - **Docker** — needed to run the local PDS (Personal Data Server) during development 10 10 11 + Vite+ manages Node.js and your package manager automatically. Run `vp help` to verify it's installed. 12 + 11 13 ## Create a new project 12 14 13 15 ```bash 14 - npx hatk new my-app 16 + vp create github:hatk-dev/hatk-template-starter 15 17 ``` 16 18 17 - This scaffolds a full-stack project with a SvelteKit frontend, example feed, seed data, and everything wired together. The generated project includes: 19 + This scaffolds a full-stack project with a SvelteKit frontend, OAuth login, seed data, and everything wired together. The generated project includes: 18 20 19 21 ``` 20 - my-app/ 21 - ├── app/ # SvelteKit frontend (routes, components, styles) 22 - ├── server/ # Backend logic (feeds, XRPC handlers, hooks) 23 - ├── lexicons/ # AT Protocol schemas for your data types 24 - ├── seeds/ # Test fixture data for local development 25 - ├── hatk.config.ts # Project configuration 26 - ├── hatk.generated.ts # Auto-generated types from your lexicons 27 - ├── vite.config.ts # Vite + SvelteKit config 28 - └── docker-compose.yml # Local PDS for development 22 + my-appview/ 23 + ├── app/ # SvelteKit frontend (routes, components, styles) 24 + ├── server/ # Backend logic (hooks, feeds, XRPC handlers) 25 + ├── lexicons/ # AT Protocol schemas for your data types 26 + ├── seeds/ # Test fixture data for local development 27 + ├── db/ # Database reference schemas 28 + ├── hatk.config.ts # Project configuration 29 + ├── hatk.generated.ts # Auto-generated types (server) 30 + ├── hatk.generated.client.ts # Auto-generated types (client) 31 + ├── vite.config.ts # Vite+ / SvelteKit config 32 + ├── svelte.config.js # SvelteKit adapter config 33 + ├── tsconfig.json # TypeScript config (app) 34 + ├── tsconfig.server.json # TypeScript config (server) 35 + └── docker-compose.yml # Local PLC directory and PDS for development 29 36 ``` 30 37 31 38 ## Start the dev server 32 39 33 40 ```bash 34 - cd my-app 35 - npm run dev 41 + cd my-appview 42 + npx svelte-kit sync 43 + vp dev 36 44 ``` 37 45 38 46 This does three things automatically:
+1
docs/site/index.md
··· 3 3 4 4 hero: 5 5 name: "hat://k" 6 + text: pronounced "hack" 6 7 tagline: Extends your Vite application with an AT Protocol server. Add feeds, labels, and XRPC endpoints to your app, all typed from your lexicons. 7 8 actions: 8 9 - theme: brand
+7 -598
packages/hatk/src/cli.ts
··· 1 1 #!/usr/bin/env node 2 - import { mkdirSync, writeFileSync, existsSync, unlinkSync, readdirSync, readFileSync, cpSync } from 'node:fs' 2 + import { mkdirSync, writeFileSync, existsSync, unlinkSync, readdirSync, readFileSync } from 'node:fs' 3 3 import { resolve, join, dirname } from 'node:path' 4 4 import { execSync, spawn } from 'node:child_process' 5 5 import { loadLexicons, discoverCollections, buildSchemas } from './database/schema.ts' ··· 65 65 function usage() { 66 66 console.log(` 67 67 Usage: hatk <command> [options] 68 - 69 - Getting Started 70 - new <name> [--svelte] [--duckdb] [--template <t>] Create a new hatk project 71 68 72 69 Running 73 70 start Start the hatk server ··· 203 200 // --- Commands --- 204 201 205 202 if (command === 'new') { 206 - const name = args[1] 207 - if (!name) { 208 - console.error('Usage: hatk new <name> [--svelte] [--duckdb] [--template <template-name>]') 209 - process.exit(1) 210 - } 211 - 212 - const templateIdx = args.indexOf('--template') 213 - const templateName = templateIdx !== -1 ? args[templateIdx + 1] : null 214 - if (templateIdx !== -1 && !templateName) { 215 - console.error('Usage: hatk new <name> --template <template-name>') 216 - process.exit(1) 217 - } 218 - 219 - const dir = resolve(name) 220 - if (existsSync(dir)) { 221 - console.error(`Directory ${name} already exists`) 222 - process.exit(1) 223 - } 224 - 225 - if (templateName) { 226 - const repo = `https://github.com/hatk-dev/hatk-template-${templateName}.git` 227 - console.log(`Cloning template ${templateName}...`) 228 - try { 229 - execSync(`git clone --depth 1 ${repo} ${dir}`, { stdio: 'inherit' }) 230 - } catch { 231 - console.error(`Failed to clone template: ${repo}`) 232 - process.exit(1) 233 - } 234 - execSync(`rm -rf ${join(dir, '.git')}`) 235 - const pkgPath = join(dir, 'package.json') 236 - if (existsSync(pkgPath)) { 237 - const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8')) 238 - pkg.name = name 239 - writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n') 240 - } 241 - console.log(`\nCreated ${name}/ from template ${templateName}`) 242 - console.log(`\n cd ${name}`) 243 - console.log(` npm install`) 244 - console.log(` hatk dev`) 245 - process.exit(0) 246 - } 247 - 248 - const withSvelte = args.includes('--svelte') 249 - const withDuckdb = args.includes('--duckdb') 250 - const dbEngine = withDuckdb ? 'duckdb' : 'sqlite' 251 - mkdirSync(dir) 252 - const subs = [ 253 - 'lexicons', 254 - 'server', 255 - 'seeds', 256 - 'public', 257 - 'test', 258 - 'test/server', 259 - 'test/integration', 260 - 'test/browser', 261 - 'test/fixtures', 262 - ] 263 - if (withSvelte) subs.push('src', 'src/routes', 'src/lib') 264 - for (const sub of subs) { 265 - mkdirSync(join(dir, sub)) 266 - } 267 - 268 - writeFileSync( 269 - join(dir, 'hatk.config.ts'), 270 - `import { defineConfig } from '@hatk/hatk/config' 271 - 272 - export default defineConfig({ 273 - relay: 'ws://localhost:2583', 274 - plc: 'http://localhost:2582', 275 - port: 3000, 276 - databaseEngine: '${dbEngine}', 277 - database: 'data/hatk.db', 278 - admins: [], 279 - backfill: { 280 - parallelism: 10, 281 - }, 282 - }) 283 - `, 284 - ) 285 - 286 - writeFileSync( 287 - join(dir, 'public', 'index.html'), 288 - `<!DOCTYPE html> 289 - <html><head><title>${name}</title></head> 290 - <body><h1>${name}</h1></body></html> 291 - `, 292 - ) 293 - 294 - // Copy core framework lexicons (dev.hatk.* and dependencies like com.atproto.repo.strongRef) 295 - const builtinLexDir = join(import.meta.dirname!, 'lexicons') 296 - cpSync(builtinLexDir, join(dir, 'lexicons'), { recursive: true }) 297 - 298 - writeFileSync( 299 - join(dir, 'seeds', 'seed.ts'), 300 - loadTemplate('seed.tpl', ''), 301 - ) 302 - 303 - writeFileSync( 304 - join(dir, 'docker-compose.yml'), 305 - `services: 306 - plc: 307 - build: 308 - context: https://github.com/did-method-plc/did-method-plc.git 309 - dockerfile: packages/server/Dockerfile 310 - ports: 311 - - '2582:2582' 312 - environment: 313 - - DATABASE_URL=postgres://plc:plc@postgres:5432/plc 314 - - PORT=2582 315 - command: ['dumb-init', 'node', '--enable-source-maps', '../dist/bin.js'] 316 - depends_on: 317 - postgres: 318 - condition: service_healthy 319 - healthcheck: 320 - test: ['CMD-SHELL', 'wget -q --spider http://localhost:2582/_health || exit 1'] 321 - interval: 2s 322 - timeout: 5s 323 - retries: 15 324 - 325 - pds: 326 - image: ghcr.io/bluesky-social/pds:latest 327 - ports: 328 - - '2583:2583' 329 - environment: 330 - - PDS_HOSTNAME=localhost 331 - - PDS_PORT=2583 332 - - PDS_DID_PLC_URL=http://plc:2582 333 - - PDS_DATA_DIRECTORY=/pds 334 - - PDS_BLOBSTORE_DISK_LOCATION=/pds/blobs 335 - - PDS_JWT_SECRET=dev-jwt-secret 336 - - PDS_ADMIN_PASSWORD=dev-admin 337 - - PDS_PLC_ROTATION_KEY_K256_PRIVATE_KEY_HEX=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef 338 - - PDS_INVITE_REQUIRED=false 339 - - PDS_DEV_MODE=true 340 - - LOG_ENABLED=true 341 - volumes: 342 - - pds_data:/pds 343 - depends_on: 344 - plc: 345 - condition: service_healthy 346 - healthcheck: 347 - test: ['CMD-SHELL', 'wget -q --spider http://localhost:2583/xrpc/_health || exit 1'] 348 - interval: 2s 349 - timeout: 5s 350 - retries: 15 351 - 352 - postgres: 353 - image: postgres:16-alpine 354 - environment: 355 - - POSTGRES_USER=plc 356 - - POSTGRES_PASSWORD=plc 357 - - POSTGRES_DB=plc 358 - volumes: 359 - - plc_data:/var/lib/postgresql/data 360 - healthcheck: 361 - test: ['CMD-SHELL', 'pg_isready -U plc'] 362 - interval: 2s 363 - timeout: 5s 364 - retries: 10 365 - 366 - volumes: 367 - pds_data: 368 - plc_data: 369 - `, 370 - ) 371 - 372 - writeFileSync( 373 - join(dir, '.dockerignore'), 374 - `node_modules 375 - data 376 - .svelte-kit 377 - public 378 - `, 379 - ) 380 - 381 - writeFileSync( 382 - join(dir, 'Dockerfile'), 383 - `FROM node:25-slim 384 - WORKDIR /app 385 - COPY package.json package-lock.json ./ 386 - RUN npm ci 387 - COPY . . 388 - RUN node_modules/.bin/hatk build 389 - RUN npm prune --omit=dev 390 - EXPOSE 3000 391 - CMD ["node", "--experimental-strip-types", "--max-old-space-size=512", "node_modules/@hatk/hatk/dist/main.js", "hatk.config.ts"] 392 - `, 393 - ) 394 - 395 - const pkgDeps: Record<string, string> = { '@hatk/oauth-client': '*', hatk: '*' } 396 - if (!withDuckdb) { 397 - pkgDeps['better-sqlite3'] = '^11' 398 - } 399 - const pkgDevDeps: Record<string, string> = { 400 - '@playwright/test': '^1', 401 - oxfmt: '^0.35.0', 402 - oxlint: '^1', 403 - typescript: '^5', 404 - vite: '^6', 405 - vitest: '^4', 406 - '@types/node': '^22', 407 - } 408 - if (withSvelte) { 409 - pkgDevDeps['@sveltejs/adapter-static'] = '^3' 410 - pkgDevDeps['@sveltejs/kit'] = '^2' 411 - pkgDevDeps['@sveltejs/vite-plugin-svelte'] = '^5' 412 - pkgDevDeps['svelte'] = '^5' 413 - pkgDevDeps['svelte-check'] = '^4' 414 - } 415 - writeFileSync( 416 - join(dir, 'package.json'), 417 - JSON.stringify( 418 - { 419 - name, 420 - private: true, 421 - type: 'module', 422 - scripts: { 423 - start: 'hatk start', 424 - dev: 'hatk dev', 425 - build: 'hatk build', 426 - check: 'hatk check', 427 - format: 'hatk format', 428 - }, 429 - dependencies: pkgDeps, 430 - devDependencies: pkgDevDeps, 431 - }, 432 - null, 433 - 2, 434 - ) + '\n', 435 - ) 436 - 437 - writeFileSync( 438 - join(dir, 'tsconfig.server.json'), 439 - JSON.stringify( 440 - { 441 - compilerOptions: { 442 - target: 'ES2022', 443 - module: 'Node16', 444 - moduleResolution: 'Node16', 445 - strict: true, 446 - esModuleInterop: true, 447 - skipLibCheck: true, 448 - noEmit: true, 449 - allowImportingTsExtensions: true, 450 - resolveJsonModule: true, 451 - }, 452 - include: ['server', 'seeds', 'hatk.generated.ts', 'hatk.config.ts'], 453 - }, 454 - null, 455 - 2, 456 - ) + '\n', 457 - ) 458 - 459 - writeFileSync( 460 - join(dir, 'playwright.config.ts'), 461 - `import { defineConfig } from '@playwright/test' 462 - 463 - export default defineConfig({ 464 - testDir: 'test/browser', 465 - use: { baseURL: 'http://127.0.0.1:3000' }, 466 - globalSetup: './test/browser/global-setup.ts', 467 - }) 468 - `, 469 - ) 470 - 471 - writeFileSync( 472 - join(dir, 'test/browser/global-setup.ts'), 473 - `import { execSync } from 'node:child_process' 474 - import { existsSync } from 'node:fs' 475 - 476 - export default function globalSetup() { 477 - if (existsSync('src/app.html')) { 478 - execSync('npx vite build', { stdio: 'inherit' }) 479 - } 480 - } 481 - `, 482 - ) 483 - 484 - writeFileSync( 485 - join(dir, '.gitignore'), 486 - `node_modules/ 487 - *.db 488 - data/ 489 - test-results/ 490 - .svelte-kit/ 491 - .DS_Store 492 - public/ 493 - `, 494 - ) 495 - 496 - writeFileSync( 497 - join(dir, '.oxlintrc.json'), 498 - `{ 499 - "ignorePatterns": ["public", "data", ".svelte-kit", "hatk.generated.ts"] 500 - } 501 - `, 502 - ) 503 - 504 - writeFileSync( 505 - join(dir, '.oxfmtrc.json'), 506 - `{ 507 - "semi": false, 508 - "singleQuote": true, 509 - "trailingComma": "all", 510 - "printWidth": 120, 511 - "tabWidth": 2, 512 - "ignorePatterns": ["public", "data", ".svelte-kit", "hatk.generated.ts"] 513 - } 514 - `, 515 - ) 516 - 517 - if (withSvelte) { 518 - writeFileSync( 519 - join(dir, 'svelte.config.js'), 520 - `import adapter from '@sveltejs/adapter-static' 521 - 522 - export default { 523 - kit: { 524 - adapter: adapter({ 525 - pages: 'public', 526 - assets: 'public', 527 - fallback: 'index.html', 528 - }), 529 - paths: { base: '' }, 530 - alias: { 531 - $hatk: './hatk.generated.ts', 532 - }, 533 - }, 534 - } 535 - `, 536 - ) 537 - 538 - writeFileSync( 539 - join(dir, 'vite.config.ts'), 540 - `import { sveltekit } from '@sveltejs/kit/vite' 541 - import { hatk } from '@hatk/hatk/vite-plugin' 542 - import { defineConfig } from 'vite' 543 - 544 - export default defineConfig({ 545 - plugins: [sveltekit(), hatk()], 546 - }) 547 - `, 548 - ) 549 - 550 - writeFileSync( 551 - join(dir, 'tsconfig.json'), 552 - JSON.stringify( 553 - { 554 - extends: './.svelte-kit/tsconfig.json', 555 - compilerOptions: { 556 - allowJs: true, 557 - checkJs: false, 558 - esModuleInterop: true, 559 - forceConsistentCasingInFileNames: true, 560 - resolveJsonModule: true, 561 - skipLibCheck: true, 562 - sourceMap: true, 563 - strict: true, 564 - moduleResolution: 'bundler', 565 - allowImportingTsExtensions: true, 566 - }, 567 - }, 568 - null, 569 - 2, 570 - ) + '\n', 571 - ) 572 - 573 - writeFileSync( 574 - join(dir, 'src/app.html'), 575 - `<!doctype html> 576 - <html lang="en"> 577 - <head> 578 - <meta charset="utf-8" /> 579 - <meta name="viewport" content="width=device-width, initial-scale=1" /> 580 - <meta name="description" content="${name}" /> 581 - <title>${name}</title> 582 - %sveltekit.head% 583 - </head> 584 - <body data-sveltekit-preload-data="hover"> 585 - <div style="display: contents">%sveltekit.body%</div> 586 - </body> 587 - </html> 588 - `, 589 - ) 590 - 591 - writeFileSync( 592 - join(dir, 'src/app.css'), 593 - `*, 594 - *::before, 595 - *::after { 596 - box-sizing: border-box; 597 - margin: 0; 598 - padding: 0; 599 - } 600 - 601 - :root { 602 - --bg-root: #080b12; 603 - --bg-surface: #0f1419; 604 - --bg-elevated: #161d27; 605 - --bg-hover: #1c2633; 606 - --border: #1e293b; 607 - --teal: #14b8a6; 608 - --text-primary: #e2e8f0; 609 - --text-secondary: #94a3b8; 610 - --text-muted: #64748b; 611 - } 612 - 613 - html { 614 - background: var(--bg-root); 615 - color: var(--text-primary); 616 - } 617 - 618 - body { 619 - font-family: -apple-system, system-ui, sans-serif; 620 - font-size: 15px; 621 - line-height: 1.5; 622 - min-height: 100vh; 623 - } 624 - 625 - a { 626 - color: inherit; 627 - text-decoration: none; 628 - } 629 - `, 630 - ) 631 - 632 - writeFileSync( 633 - join(dir, 'src/routes/+layout.svelte'), 634 - `<script lang="ts"> 635 - import type { Snippet } from 'svelte' 636 - import '../app.css' 637 - 638 - let { children }: { children: Snippet } = $props() 639 - </script> 640 - 641 - {@render children()} 642 - `, 643 - ) 644 - 645 - writeFileSync( 646 - join(dir, 'src/routes/+page.svelte'), 647 - `<h1>${name}</h1> 648 - <p>Your hatk server is running.</p> 649 - `, 650 - ) 651 - 652 - writeFileSync( 653 - join(dir, 'src/error.html'), 654 - `<!doctype html> 655 - <html lang="en"> 656 - <head> 657 - <meta charset="utf-8" /> 658 - <meta name="viewport" content="width=device-width, initial-scale=1" /> 659 - <title>%sveltekit.error.message% — ${name}</title> 660 - <style> 661 - * { box-sizing: border-box; margin: 0; padding: 0; } 662 - body { 663 - font-family: -apple-system, system-ui, sans-serif; 664 - background: #080b12; color: #e2e8f0; 665 - min-height: 100vh; display: flex; align-items: center; justify-content: center; 666 - } 667 - .error-page { display: flex; flex-direction: column; align-items: center; text-align: center; gap: 8px; padding: 24px; } 668 - .error-code { font-size: 72px; font-weight: 800; color: #14b8a6; line-height: 1; } 669 - .error-title { font-size: 24px; font-weight: 800; } 670 - .error-link { 671 - margin-top: 16px; padding: 10px 24px; background: #14b8a6; color: #000; 672 - border-radius: 20px; font-weight: 600; font-size: 14px; text-decoration: none; 673 - } 674 - </style> 675 - </head> 676 - <body> 677 - <div class="error-page"> 678 - <span class="error-code">%sveltekit.status%</span> 679 - <h1 class="error-title">%sveltekit.error.message%</h1> 680 - <a href="/" class="error-link">Back to home</a> 681 - </div> 682 - </body> 683 - </html> 684 - `, 685 - ) 686 - 687 - writeFileSync( 688 - join(dir, 'src/routes/+error.svelte'), 689 - `<script lang="ts"> 690 - import { page } from '$app/state' 691 - </script> 692 - 693 - <div style="display: flex; flex-direction: column; align-items: center; justify-content: center; min-height: 80vh; gap: 8px;"> 694 - <span style="font-size: 72px; font-weight: 800; color: var(--teal);">{page.status}</span> 695 - <h1 style="font-size: 24px; font-weight: 800;">{page.error?.message}</h1> 696 - <a href="/" style="margin-top: 16px; padding: 10px 24px; background: var(--teal); color: #000; border-radius: 20px; font-weight: 600; font-size: 14px;">Back to home</a> 697 - </div> 698 - `, 699 - ) 700 - } 701 - 702 - let agentsMd = `# hatk project 703 - 704 - This is an AT Protocol application built with [hatk](https://github.com/hatk-dev/hatk). 705 - Read the project's lexicons in \`lexicons/\` to understand the data model. 706 - Types are generated from lexicons into \`hatk.generated.ts\` — never edit this file directly. 707 - 708 - ## Project structure 709 - 710 - | Directory | Purpose | 711 - |-------------|------------------------------------------------------| 712 - | \`lexicons/\` | AT Protocol lexicon schemas (JSON). Defines collections and XRPC methods | 713 - | \`server/\` | All server-side code: feeds, XRPC handlers, hooks, labels, OG routes, setup scripts | 714 - | \`seeds/\` | Test data seeding scripts for local development | 715 - | \`test/\` | Test files (vitest). Run with \`vp test\` | 716 - | \`public/\` | Static files served at the root | 717 - ` 718 - if (withSvelte) { 719 - agentsMd += `| \`src/\` | SvelteKit frontend (routes, components, styles) | 720 - 721 - ` 722 - } else { 723 - agentsMd += ` 724 - ` 725 - } 726 - 727 - agentsMd += `## Key files 728 - 729 - - \`hatk.config.ts\` — project configuration (see \`defineConfig\` for type info) 730 - - \`hatk.generated.ts\` — auto-generated server types and helpers. Regenerate with \`hatk generate types\` 731 - - \`hatk.generated.client.ts\` — auto-generated client-safe types and \`callXrpc\`. Never import \`hatk.generated.ts\` from frontend code 732 - 733 - ## The \`$hatk\` alias 734 - 735 - Server files in \`server/\` import from \`$hatk\`: 736 - \`\`\`ts 737 - import { defineFeed, views, type Status } from "$hatk" 738 - \`\`\` 739 - ` 740 - if (withSvelte) { 741 - agentsMd += ` 742 - SvelteKit routes and components import from \`$hatk/client\`: 743 - \`\`\`ts 744 - import { callXrpc, getViewer } from "$hatk/client" 745 - \`\`\` 746 - 747 - \`$hatk\` resolves to \`hatk.generated.ts\` and \`$hatk/client\` to \`hatk.generated.client.ts\`. 748 - The Vite plugin handles this in dev/build. In tests and production, a Node.js module resolve hook handles it. 749 - ` 750 - } else { 751 - agentsMd += ` 752 - \`$hatk\` resolves to \`hatk.generated.ts\`. The Vite plugin handles this in dev/build. 753 - In tests and production, a Node.js module resolve hook handles it. 754 - ` 755 - } 756 - 757 - agentsMd += ` 758 - ## Commands 759 - 760 - Run \`npx hatk --help\` for the full list of commands. 761 - 762 - Use \`npx hatk generate\` to scaffold new feeds, xrpc handlers, labels, and lexicons 763 - rather than creating files manually. These generate files with the correct imports. 764 - 765 - After modifying lexicons, always run \`npx hatk generate types\` to update the generated types. 766 - ` 767 - if (withSvelte) { 768 - agentsMd += ` 769 - ## Running 770 - 771 - - \`vp dev\` — start dev server (hatk + SvelteKit + PDS) 772 - - \`vp build\` — build for production (SvelteKit outputs to \`build/\`) 773 - - \`hatk start\` — start production server (hatk + SvelteKit via \`build/handler.js\`) 774 - - \`vp test\` — run tests 775 - ` 776 - } 777 - 778 - writeFileSync(join(dir, 'AGENTS.md'), agentsMd) 779 - 780 - console.log(`Created ${name}/`) 781 - console.log(` hatk.config.ts`) 782 - console.log(` lexicons/ — lexicon JSON files (core + your own)`) 783 - console.log(` server/ — feeds, XRPC handlers, hooks, labels, OG routes, setup`) 784 - console.log(` seeds/ — seed fixture data (hatk seed)`) 785 - console.log(` test/ — test files (hatk test)`) 786 - console.log(` public/ — static files`) 787 - console.log(` docker-compose.yml — local PDS for development`) 788 - console.log(` Dockerfile — production container`) 789 - if (withSvelte) { 790 - console.log(` src/ — SvelteKit frontend`) 791 - console.log(` svelte.config.js`) 792 - console.log(` vite.config.ts`) 793 - } 794 - 795 - // Generate types so the project is ready to go 796 - execSync('npx hatk generate types', { stdio: 'inherit', cwd: dir }) 797 - if (withSvelte) { 798 - execSync('npx svelte-kit sync', { stdio: 'inherit', cwd: dir }) 799 - } 203 + console.error('`hatk new` has been removed. Create a new project with:') 204 + console.error('') 205 + console.error(' vp create github:hatk-dev/hatk-template-starter') 206 + console.error('') 207 + console.error('Install vp first: curl -fsSL https://vite.plus | bash') 208 + process.exit(1) 800 209 } else if (command === 'generate') { 801 210 const type = args[1] 802 211