gorsee 0.2.11 → 0.2.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/README.md +52 -4
  2. package/dist-pkg/ai/bundle.d.ts +1 -0
  3. package/dist-pkg/ai/framework-context.d.ts +2 -0
  4. package/dist-pkg/ai/framework-context.js +6 -1
  5. package/dist-pkg/ai/ide.d.ts +1 -0
  6. package/dist-pkg/ai/ide.js +3 -0
  7. package/dist-pkg/ai/index.d.ts +10 -1
  8. package/dist-pkg/ai/index.js +13 -2
  9. package/dist-pkg/ai/mcp.js +4 -0
  10. package/dist-pkg/ai/session-pack.d.ts +8 -0
  11. package/dist-pkg/ai/session-pack.js +51 -1
  12. package/dist-pkg/ai/store.d.ts +25 -1
  13. package/dist-pkg/ai/store.js +89 -3
  14. package/dist-pkg/ai/summary.d.ts +88 -0
  15. package/dist-pkg/ai/summary.js +310 -1
  16. package/dist-pkg/build/manifest.d.ts +4 -2
  17. package/dist-pkg/build/manifest.js +32 -2
  18. package/dist-pkg/cli/cmd-ai.js +66 -0
  19. package/dist-pkg/cli/cmd-build.js +72 -26
  20. package/dist-pkg/cli/cmd-check.js +104 -11
  21. package/dist-pkg/cli/cmd-create.js +333 -7
  22. package/dist-pkg/cli/cmd-deploy.js +17 -3
  23. package/dist-pkg/cli/cmd-docs.d.ts +3 -1
  24. package/dist-pkg/cli/cmd-docs.js +5 -3
  25. package/dist-pkg/cli/cmd-start.js +8 -1
  26. package/dist-pkg/cli/cmd-upgrade.d.ts +3 -0
  27. package/dist-pkg/cli/cmd-upgrade.js +14 -2
  28. package/dist-pkg/cli/cmd-worker.d.ts +9 -0
  29. package/dist-pkg/cli/cmd-worker.js +78 -0
  30. package/dist-pkg/cli/framework-md.js +16 -4
  31. package/dist-pkg/cli/index.js +5 -0
  32. package/dist-pkg/runtime/app-config.d.ts +5 -0
  33. package/dist-pkg/runtime/app-config.js +26 -5
  34. package/dist-pkg/runtime/typed-routes.js +3 -4
  35. package/dist-pkg/server/index.d.ts +2 -1
  36. package/dist-pkg/server/index.js +1 -0
  37. package/dist-pkg/server/jobs.d.ts +35 -1
  38. package/dist-pkg/server/jobs.js +226 -3
  39. package/dist-pkg/server/manifest.d.ts +30 -0
  40. package/dist-pkg/server/manifest.js +30 -1
  41. package/dist-pkg/server/redis-client.d.ts +9 -0
  42. package/dist-pkg/server/redis-client.js +4 -1
  43. package/dist-pkg/server/redis-job-queue.d.ts +2 -0
  44. package/dist-pkg/server/redis-job-queue.js +434 -16
  45. package/dist-pkg/server/worker-service.d.ts +33 -0
  46. package/dist-pkg/server/worker-service.js +135 -0
  47. package/dist-pkg/server-entry.d.ts +2 -1
  48. package/dist-pkg/server-entry.js +4 -0
  49. package/package.json +3 -3
@@ -113,6 +113,10 @@ DATABASE_URL=./data.sqlite
113
113
  # Public vars (exposed to client)
114
114
  PUBLIC_APP_NAME=My Gorsee App
115
115
  `, APP_CONFIG = `export default {
116
+ app: {
117
+ mode: "fullstack" as const,
118
+ },
119
+
116
120
  port: 3000,
117
121
 
118
122
  db: {
@@ -153,7 +157,7 @@ PUBLIC_APP_NAME=My Gorsee App
153
157
  hsts: true,
154
158
  csrf: true,
155
159
  rateLimit: {
156
- requests: 100,
160
+ maxRequests: 100,
157
161
  window: "1m",
158
162
  },
159
163
  rpc: {
@@ -168,6 +172,125 @@ PUBLIC_APP_NAME=My Gorsee App
168
172
  target: "bun" as const,
169
173
  },
170
174
  }
175
+ `, FRONTEND_INDEX_ROUTE = `import { createSignal, Head, Link } from "gorsee/client"
176
+
177
+ export const prerender = true
178
+
179
+ export default function HomePage() {
180
+ const [count, setCount] = createSignal(0)
181
+
182
+ return (
183
+ <section>
184
+ <Head>
185
+ <title>My Gorsee Frontend</title>
186
+ <meta name="description" content="Browser-first frontend app built with Gorsee.js" />
187
+ </Head>
188
+ <h1>My Gorsee Frontend</h1>
189
+ <p>Static, browser-first, and ready for CDN-style deployment.</p>
190
+ <nav>
191
+ <Link href="/">Home</Link> | <Link href="/about">About</Link>
192
+ </nav>
193
+ <button on:click={() => setCount((value: number) => value + 1)}>Clicks: {count}</button>
194
+ </section>
195
+ )
196
+ }
197
+ `, FRONTEND_ABOUT_ROUTE = `import { Head, Link } from "gorsee/client"
198
+
199
+ export const prerender = true
200
+
201
+ export default function AboutPage() {
202
+ return (
203
+ <section>
204
+ <Head><title>About - Gorsee Frontend</title></Head>
205
+ <h1>About This Frontend App</h1>
206
+ <p>This starter stays browser-safe: no server routes, no RPC boundary, no process runtime.</p>
207
+ <Link href="/">Back home</Link>
208
+ </section>
209
+ )
210
+ }
211
+ `, FRONTEND_APP_CONFIG = `export default {
212
+ app: {
213
+ mode: "frontend" as const,
214
+ },
215
+
216
+ ai: {
217
+ enabled: false,
218
+ },
219
+ }
220
+ `, SERVER_API_ROUTE = `import { createMemoryJobQueue, defineJob, type Context } from "gorsee/server"
221
+
222
+ const jobs = createMemoryJobQueue()
223
+
224
+ const pingJob = defineJob<{ source: string }>("ping-audit", async (_payload) => {
225
+ return
226
+ })
227
+
228
+ export async function GET(_ctx: Context): Promise<Response> {
229
+ return Response.json({
230
+ service: "gorsee-server-api",
231
+ status: "ok",
232
+ })
233
+ }
234
+
235
+ export async function POST(_ctx: Context): Promise<Response> {
236
+ await jobs.enqueue(pingJob, { source: "manual" })
237
+ return Response.json({ accepted: true }, { status: 202 })
238
+ }
239
+ `, SERVER_HEALTH_ROUTE = `import type { Context } from "gorsee/server"
240
+
241
+ export function GET(_ctx: Context): Response {
242
+ return Response.json({
243
+ status: "ok",
244
+ ts: new Date().toISOString(),
245
+ })
246
+ }
247
+ `, SERVER_APP_CONFIG = `export default {
248
+ app: {
249
+ mode: "server" as const,
250
+ },
251
+
252
+ runtime: {
253
+ topology: "single-instance" as const,
254
+ },
255
+
256
+ security: {
257
+ origin: process.env.APP_ORIGIN ?? "http://localhost:3000",
258
+ rateLimit: {
259
+ maxRequests: 100,
260
+ window: "1m",
261
+ },
262
+ },
263
+ }
264
+ `, WORKER_SERVICE_MAIN = `import {
265
+ createMemoryJobQueue,
266
+ defineJob,
267
+ defineWorkerService,
268
+ runWorkerService,
269
+ } from "gorsee/server"
270
+
271
+ const jobs = createMemoryJobQueue()
272
+
273
+ const auditJob = defineJob<{ source: string }>("audit-worker-tick", async (_payload) => {
274
+ return
275
+ })
276
+
277
+ const service = defineWorkerService("audit-worker", async (context) => {
278
+ await jobs.enqueue(auditJob, { source: "startup" })
279
+ const timer = setInterval(async () => {
280
+ await context.emitHeartbeat("worker polling queue", {
281
+ pending: await jobs.size(),
282
+ })
283
+ await jobs.runNext()
284
+ }, 250)
285
+
286
+ await context.emitReady()
287
+ await context.waitForShutdown()
288
+ clearInterval(timer)
289
+ })
290
+
291
+ const running = await runWorkerService(service)
292
+ await running.ready
293
+ await new Promise<void>(() => {})
171
294
  `, TSCONFIG = `{
172
295
  "compilerOptions": {
173
296
  "target": "ESNext",
@@ -181,7 +304,7 @@ PUBLIC_APP_NAME=My Gorsee App
181
304
  "noEmit": true,
182
305
  "types": ["bun"]
183
306
  },
184
- "include": ["routes/**/*.ts", "routes/**/*.tsx", "shared/**/*.ts", "middleware/**/*.ts"]
307
+ "include": ["routes/**/*.ts", "routes/**/*.tsx", "shared/**/*.ts", "middleware/**/*.ts", "workers/**/*.ts"]
185
308
  }
186
309
  `, GITIGNORE = `node_modules/
187
310
  dist/
@@ -191,7 +314,7 @@ dist/
191
314
  *.sqlite
192
315
  *.db
193
316
  .DS_Store
194
- `, PACKAGE_MANAGER = "bun@1.3.9", REPO_ROOT = fileURLToPath(new URL("../../", import.meta.url)), FRAMEWORK_VERSION = JSON.parse(await readFile(join(REPO_ROOT, "package.json"), "utf-8")), FRAMEWORK_PACKAGE_VERSION = FRAMEWORK_VERSION.version, CREATE_TEMPLATES = ["basic", "secure-saas", "content-site", "agent-aware-ops", "workspace-monorepo"], TEMPLATE_DEFINITIONS = {
317
+ `, PACKAGE_MANAGER = "bun@1.3.9", REPO_ROOT = fileURLToPath(new URL("../../", import.meta.url)), FRAMEWORK_VERSION = JSON.parse(await readFile(join(REPO_ROOT, "package.json"), "utf-8")), FRAMEWORK_PACKAGE_VERSION = FRAMEWORK_VERSION.version, CREATE_TEMPLATES = ["frontend", "basic", "secure-saas", "content-site", "agent-aware-ops", "workspace-monorepo", "server-api", "worker-service"], TEMPLATE_DEFINITIONS = {
195
318
  "secure-saas": {
196
319
  sourceDir: join(REPO_ROOT, "examples/secure-saas"),
197
320
  readmeDescription: "Authenticated SaaS starter with protected route groups, explicit auth middleware, and private cache semantics.",
@@ -258,15 +381,17 @@ dist/
258
381
  `);
259
382
  const routePath = join(dir, "apps/web/routes/index.tsx"), routeSource = await readFile(routePath, "utf-8");
260
383
  await writeFile(routePath, routeSource.replaceAll("@example/shared", "@workspace/shared"));
384
+ await ensureAppModeConfig(join(dir, "apps/web/app.config.ts"), "fullstack");
261
385
  }
262
386
  }
263
387
  };
264
- function createPackageScripts() {
388
+ function createPackageScripts(extraScripts = {}) {
265
389
  return {
266
390
  dev: "bun run ./node_modules/gorsee/dist-pkg/bin/gorsee.js dev",
267
391
  build: "bun run ./node_modules/gorsee/dist-pkg/bin/gorsee.js build",
268
392
  start: "bun run ./node_modules/gorsee/dist-pkg/bin/gorsee.js start",
269
- check: "bun run ./node_modules/gorsee/dist-pkg/bin/gorsee.js check"
393
+ check: "bun run ./node_modules/gorsee/dist-pkg/bin/gorsee.js check",
394
+ ...extraScripts
270
395
  };
271
396
  }
272
397
  function normalizePackageName(name) {
@@ -343,6 +468,37 @@ async function normalizeSinglePackageManifest(packageJsonPath, packageName) {
343
468
  `);
344
469
  }
345
470
  function generateTemplateReadme(name, template) {
471
+ if (template === "frontend")
472
+ return generateModeReadme(name, "frontend", [
473
+ "- browser-safe `gorsee/client` entrypoints only",
474
+ "- prerendered routes ready for static/CDN deployment",
475
+ "- no process runtime or server/RPC assumptions"
476
+ ], [
477
+ "`bun run dev`",
478
+ "`bun run build`",
479
+ "`bun run check`"
480
+ ], "bun run dev");
481
+ if (template === "server-api")
482
+ return generateModeReadme(name, "server", [
483
+ "- API-first route tree with `gorsee/server` primitives",
484
+ "- explicit runtime topology and security baseline",
485
+ "- ready for process/service deployment instead of browser bundles"
486
+ ], [
487
+ "`bun run dev`",
488
+ "`bun run build`",
489
+ "`bun run start`",
490
+ "`bun run check`"
491
+ ], "bun run dev");
492
+ if (template === "worker-service")
493
+ return generateModeReadme(name, "server", [
494
+ "- worker-first service entry in `workers/main.ts`",
495
+ "- canonical `defineWorkerService()` + `runWorkerService()` lifecycle contract",
496
+ "- background queue and heartbeat telemetry wired into the AI observability surface"
497
+ ], [
498
+ "`bun run worker`",
499
+ "`bun run build`",
500
+ "`bun run check`"
501
+ ], "bun run worker");
346
502
  const definition = TEMPLATE_DEFINITIONS[template], highlightLines = definition.readmeHighlights.map((item) => `- ${item}`).join(`
347
503
  `), workspaceHint = template === "workspace-monorepo" ? `
348
504
  ## Workspace Commands
@@ -416,22 +572,164 @@ async function createBasicProject(dir, name) {
416
572
  }, null, 2) + `
417
573
  `);
418
574
  }
575
+ async function createFrontendProject(dir, name) {
576
+ await mkdir(join(dir, "routes"), { recursive: !0 });
577
+ await mkdir(join(dir, "shared"), { recursive: !0 });
578
+ await mkdir(join(dir, "public"), { recursive: !0 });
579
+ await writeFile(join(dir, "routes/index.tsx"), FRONTEND_INDEX_ROUTE);
580
+ await writeFile(join(dir, "routes/about.tsx"), FRONTEND_ABOUT_ROUTE);
581
+ await writeFile(join(dir, "public/styles.css"), DEFAULT_CSS);
582
+ await writeFile(join(dir, "app.config.ts"), FRONTEND_APP_CONFIG);
583
+ await writeFile(join(dir, "tsconfig.json"), TSCONFIG);
584
+ await writeFile(join(dir, ".gitignore"), GITIGNORE);
585
+ await writeFile(join(dir, ".env.example"), `PUBLIC_APP_NAME=My Gorsee Frontend
586
+ `);
587
+ await writeFile(join(dir, ".env"), `PUBLIC_APP_NAME=My Gorsee Frontend
588
+ `);
589
+ await writeFile(join(dir, "README.md"), generateTemplateReadme(name, "frontend"));
590
+ await writeFile(join(dir, "package.json"), JSON.stringify({
591
+ name: normalizePackageName(name),
592
+ version: "0.1.0",
593
+ type: "module",
594
+ packageManager: PACKAGE_MANAGER,
595
+ scripts: createPackageScripts(),
596
+ dependencies: {
597
+ gorsee: FRAMEWORK_PACKAGE_VERSION
598
+ },
599
+ devDependencies: {
600
+ "@types/bun": "1.3.10"
601
+ }
602
+ }, null, 2) + `
603
+ `);
604
+ }
605
+ async function createServerAPIProject(dir, name) {
606
+ await mkdir(join(dir, "routes/api"), { recursive: !0 });
607
+ await mkdir(join(dir, "shared"), { recursive: !0 });
608
+ await mkdir(join(dir, "migrations"), { recursive: !0 });
609
+ await writeFile(join(dir, "routes/api/index.ts"), SERVER_API_ROUTE);
610
+ await writeFile(join(dir, "routes/api/health.ts"), SERVER_HEALTH_ROUTE);
611
+ await writeFile(join(dir, "app.config.ts"), SERVER_APP_CONFIG);
612
+ await writeFile(join(dir, "tsconfig.json"), TSCONFIG);
613
+ await writeFile(join(dir, ".gitignore"), GITIGNORE);
614
+ await writeFile(join(dir, ".env.example"), ENV_EXAMPLE);
615
+ await writeFile(join(dir, ".env"), ENV_EXAMPLE);
616
+ await writeFile(join(dir, "README.md"), generateTemplateReadme(name, "server-api"));
617
+ await writeFile(join(dir, "package.json"), JSON.stringify({
618
+ name: normalizePackageName(name),
619
+ version: "0.1.0",
620
+ type: "module",
621
+ packageManager: PACKAGE_MANAGER,
622
+ scripts: createPackageScripts(),
623
+ dependencies: {
624
+ gorsee: FRAMEWORK_PACKAGE_VERSION
625
+ },
626
+ devDependencies: {
627
+ "@types/bun": "1.3.10"
628
+ }
629
+ }, null, 2) + `
630
+ `);
631
+ }
632
+ async function createWorkerServiceProject(dir, name) {
633
+ await mkdir(join(dir, "routes/api"), { recursive: !0 });
634
+ await mkdir(join(dir, "workers"), { recursive: !0 });
635
+ await mkdir(join(dir, "shared"), { recursive: !0 });
636
+ await writeFile(join(dir, "routes/api/health.ts"), SERVER_HEALTH_ROUTE);
637
+ await writeFile(join(dir, "workers/main.ts"), WORKER_SERVICE_MAIN);
638
+ await writeFile(join(dir, "app.config.ts"), SERVER_APP_CONFIG);
639
+ await writeFile(join(dir, "tsconfig.json"), TSCONFIG);
640
+ await writeFile(join(dir, ".gitignore"), GITIGNORE);
641
+ await writeFile(join(dir, ".env.example"), ENV_EXAMPLE);
642
+ await writeFile(join(dir, ".env"), ENV_EXAMPLE);
643
+ await writeFile(join(dir, "README.md"), generateTemplateReadme(name, "worker-service"));
644
+ await writeFile(join(dir, "package.json"), JSON.stringify({
645
+ name: normalizePackageName(name),
646
+ version: "0.1.0",
647
+ type: "module",
648
+ packageManager: PACKAGE_MANAGER,
649
+ scripts: createPackageScripts({
650
+ worker: "bun run ./node_modules/gorsee/dist-pkg/bin/gorsee.js worker"
651
+ }),
652
+ dependencies: {
653
+ gorsee: FRAMEWORK_PACKAGE_VERSION
654
+ },
655
+ devDependencies: {
656
+ "@types/bun": "1.3.10"
657
+ }
658
+ }, null, 2) + `
659
+ `);
660
+ }
419
661
  async function createTemplateProject(dir, name, template) {
662
+ if (template === "frontend") {
663
+ await createFrontendProject(dir, name);
664
+ return;
665
+ }
666
+ if (template === "server-api") {
667
+ await createServerAPIProject(dir, name);
668
+ return;
669
+ }
670
+ if (template === "worker-service") {
671
+ await createWorkerServiceProject(dir, name);
672
+ return;
673
+ }
420
674
  const definition = TEMPLATE_DEFINITIONS[template];
421
675
  await copyTemplateTree(definition.sourceDir, dir);
422
676
  await writeFile(join(dir, "README.md"), generateTemplateReadme(name, template));
423
677
  if (template !== "workspace-monorepo") {
424
678
  await writeFile(join(dir, ".gitignore"), GITIGNORE);
425
679
  await normalizeSinglePackageManifest(join(dir, "package.json"), normalizePackageName(name));
680
+ await ensureAppModeConfig(join(dir, "app.config.ts"), "fullstack");
426
681
  }
427
682
  if (definition.postCreate)
428
683
  await definition.postCreate(dir, name);
429
684
  }
685
+ async function ensureAppModeConfig(appConfigPath, mode) {
686
+ try {
687
+ const source = await readFile(appConfigPath, "utf-8");
688
+ if (source.includes("app:") && source.includes("mode:"))
689
+ return;
690
+ const updated = source.replace(/export\s+default\s+\{/, `export default {
691
+ app: {
692
+ mode: "${mode}" as const,
693
+ },`);
694
+ await writeFile(appConfigPath, updated);
695
+ } catch {}
696
+ }
697
+ function generateModeReadme(name, mode, highlights, commands, startCommand) {
698
+ return `# ${name}
699
+
700
+ Built with Gorsee.js \u2014 AI-first application platform.
701
+
702
+ Mode: \`${mode}\`
703
+
704
+ ## Included Shape
705
+
706
+ ${highlights.join(`
707
+ `)}
708
+
709
+ ## Getting Started
710
+
711
+ \`\`\`bash
712
+ bun install
713
+ ${startCommand}
714
+ \`\`\`
715
+
716
+ ## Commands
717
+
718
+ ${commands.map((command) => `- ${command}`).join(`
719
+ `)}
720
+
721
+ ## Product Rule
722
+
723
+ Keep \`app.mode\` explicit in \`app.config.ts\` and preserve the canonical ${mode} path instead of mixing in another runtime model by accident.
724
+ `;
725
+ }
430
726
  function generateReadme(name) {
431
727
  return `# ${name}
432
728
 
433
729
  Built with Gorsee.js \u2014 AI-first reactive full-stack TypeScript framework.
434
730
 
731
+ Mode: \`fullstack\`
732
+
435
733
  This project inherits Gorsee's product model:
436
734
 
437
735
  - deterministic collaboration between humans and coding agents
@@ -464,6 +762,12 @@ Open [http://localhost:3000](http://localhost:3000).
464
762
 
465
763
  Use the Gorsee docs to pick one clear path before expanding architecture.
466
764
 
765
+ ## Canonical Modes
766
+
767
+ - \`frontend\` for browser-first prerendered apps
768
+ - \`fullstack\` for the canonical Gorsee route/runtime model
769
+ - \`server\` for API-first and service-oriented systems
770
+
467
771
  ## Commands
468
772
 
469
773
  | Command | Description |
@@ -506,7 +810,7 @@ Use the Gorsee docs to pick one clear path before expanding architecture.
506
810
  - \`bunx gorsee ai doctor\` groups repeated failures into incident clusters so you can distinguish one-off errors from systemic regressions.
507
811
  - \`bunx gorsee ai ide-sync\` writes \`.gorsee/ide/diagnostics.json\`, \`.gorsee/ide/events.json\`, and \`.gorsee/ide/context.md\` for editor integrations.
508
812
  - \`bunx gorsee ai ide-sync --watch\` keeps those files fresh for live IDE diagnostics.
509
- - \`bunx gorsee ai pack\` writes the latest agent-ready session pack to \`.gorsee/agent/latest.{json,md}\`.
813
+ - \`bunx gorsee ai pack\` writes the latest agent-ready session pack plus grounded deploy/release/incident artifacts to \`.gorsee/agent/\`.
510
814
  - \`bun run ai:package:vscode\` stages and packages the VS Code/Cursor extension consumer.
511
815
  - \`bun run release:extension\` emits a version-locked VSIX artifact for editor release/distribution.
512
816
 
@@ -566,6 +870,25 @@ export async function createProject(args, options = {}) {
566
870
  console.log(" FRAMEWORK.md AI context file");
567
871
  console.log(" tsconfig.json");
568
872
  console.log(" package.json");
873
+ } else if (template === "frontend") {
874
+ console.log(" routes/index.tsx prerendered browser-first home page");
875
+ console.log(" routes/about.tsx prerendered secondary page");
876
+ console.log(" public/styles.css default styles");
877
+ console.log(" app.config.ts frontend mode contract");
878
+ console.log(" README.md frontend mode guide");
879
+ console.log(" FRAMEWORK.md AI context file");
880
+ } else if (template === "server-api") {
881
+ console.log(" routes/api/index.ts API entry route");
882
+ console.log(" routes/api/health.ts health probe route");
883
+ console.log(" app.config.ts server mode contract");
884
+ console.log(" README.md server mode guide");
885
+ console.log(" FRAMEWORK.md AI context file");
886
+ } else if (template === "worker-service") {
887
+ console.log(" workers/main.ts worker service entry");
888
+ console.log(" routes/api/health.ts health probe route");
889
+ console.log(" app.config.ts server mode contract");
890
+ console.log(" README.md worker mode guide");
891
+ console.log(" FRAMEWORK.md AI context file");
569
892
  } else if (template === "workspace-monorepo") {
570
893
  console.log(" apps/web Gorsee app package");
571
894
  console.log(" packages/shared shared workspace package");
@@ -588,12 +911,15 @@ export async function createProject(args, options = {}) {
588
911
  console.log(" bun install");
589
912
  console.log(" cd apps/web");
590
913
  console.log(" bun run dev");
914
+ } else if (template === "worker-service") {
915
+ console.log(" bun install");
916
+ console.log(" bun run worker");
591
917
  } else {
592
918
  console.log(" bun install");
593
919
  console.log(" bun run dev");
594
920
  }
595
921
  console.log();
596
- console.log(" Then open http://localhost:3000");
922
+ console.log(template === "worker-service" ? " Then watch the worker lifecycle and /api/health probe output" : " Then open http://localhost:3000");
597
923
  console.log();
598
924
  }
599
925
  export async function runCreate(args, options = {}) {
@@ -4,7 +4,8 @@ import { createProjectContext } from "../runtime/project.js";
4
4
  import { runArtifactLifecycleStep, writeArtifactFailurePack } from "../ai/index.js";
5
5
  import { assertDeployArtifactConformance } from "../deploy/conformance.js";
6
6
  import { isProcessDeployRuntime } from "../deploy/runtime.js";
7
- const TARGETS = ["vercel", "fly", "cloudflare", "netlify", "docker"], DETECT_FILES = {
7
+ import { loadAppConfig, resolveAppMode } from "../runtime/app-config.js";
8
+ const TARGETS = ["vercel", "fly", "cloudflare", "netlify", "docker"], FRONTEND_DEPLOY_TARGETS = new Set(["cloudflare", "netlify"]), DETECT_FILES = {
8
9
  "vercel.json": "vercel",
9
10
  "fly.toml": "fly",
10
11
  "wrangler.toml": "cloudflare",
@@ -310,8 +311,14 @@ async function deployDocker(cwd, runtime) {
310
311
  console.log(" 2. Run: docker run -p 3000:3000 gorsee-app");
311
312
  }
312
313
  export async function generateDeployConfig(args, options = {}) {
313
- const { cwd } = createProjectContext(options), initOnly = args.includes("--init"), flags = parseDeployFlags(args);
314
- let target = parseDeployTargetArg(args) ?? null;
314
+ const { cwd } = createProjectContext(options), initOnly = args.includes("--init"), flags = parseDeployFlags(args), targetArg = parseDeployTargetArg(args), appMode = resolveAppMode(await loadAppConfig(cwd));
315
+ if (appMode === "frontend" && flags.runtime) {
316
+ await writeDeployFailurePack(cwd, "DEPLOY_MODE", "Frontend-mode apps do not support process runtime deploy profiles.");
317
+ console.error(" Frontend-mode apps do not support `--runtime bun|node` process profiles.");
318
+ console.error(" Use a static-capable target without a process runtime override.");
319
+ process.exit(1);
320
+ }
321
+ let target = targetArg ?? null;
315
322
  if (!target) {
316
323
  target = await detectTarget(cwd);
317
324
  if (!target) {
@@ -328,6 +335,12 @@ export async function generateDeployConfig(args, options = {}) {
328
335
  console.error(` Available: ${TARGETS.join(", ")}`);
329
336
  process.exit(1);
330
337
  }
338
+ if (appMode === "frontend" && !FRONTEND_DEPLOY_TARGETS.has(target)) {
339
+ await writeDeployFailurePack(cwd, "DEPLOY_MODE", `Frontend-mode apps currently support only ${[...FRONTEND_DEPLOY_TARGETS].join("/")} deploy generation.`);
340
+ console.error(` Frontend-mode apps currently support only ${[...FRONTEND_DEPLOY_TARGETS].join("/")} deploy generation.`);
341
+ console.error(" Process-oriented deploy generators are reserved for fullstack/server runtime output.");
342
+ process.exit(1);
343
+ }
331
344
  const projectName = cwd.split("/").pop() ?? "gorsee-app", runtime = resolveDeployRuntime(target, flags.runtime);
332
345
  console.log(`
333
346
  Generating ${target} deploy config...
@@ -341,6 +354,7 @@ export async function generateDeployConfig(args, options = {}) {
341
354
  startMessage: `generating deploy config for ${target}`,
342
355
  finishMessage: `deploy config generated for ${target}`,
343
356
  data: {
357
+ appMode,
344
358
  target,
345
359
  runtime,
346
360
  initOnly,
@@ -1,6 +1,7 @@
1
1
  import { type Route } from "../router/scanner.js";
2
2
  import { type RuntimeOptions } from "../runtime/project.js";
3
3
  import { type RouteCompilerFacts } from "../compiler/route-facts.js";
4
+ import { type AppMode } from "../runtime/app-config.js";
4
5
  interface DocFlags {
5
6
  output: string;
6
7
  format: "md" | "json" | "html";
@@ -28,6 +29,7 @@ export interface DocsArtifactSummary {
28
29
  export interface DocsArtifact {
29
30
  schemaVersion: typeof DOCS_ARTIFACT_SCHEMA_VERSION;
30
31
  generatedAt: string;
32
+ appMode: AppMode;
31
33
  summary: DocsArtifactSummary;
32
34
  routes: RouteCompilerFacts[];
33
35
  docs: RouteDoc[];
@@ -38,7 +40,7 @@ declare function extractRouteInfoFromFacts(routeFacts: RouteCompilerFacts): Rout
38
40
  declare function generateMarkdown(docs: RouteDoc[]): string;
39
41
  declare function generateJson(docs: RouteDoc[]): string;
40
42
  export declare function summarizeRouteFacts(routeFacts: RouteCompilerFacts[]): DocsArtifactSummary;
41
- export declare function createDocsArtifact(routeFacts: RouteCompilerFacts[]): DocsArtifact;
43
+ export declare function createDocsArtifact(routeFacts: RouteCompilerFacts[], appMode?: AppMode): DocsArtifact;
42
44
  export declare function generateJsonArtifact(artifact: DocsArtifact): string;
43
45
  declare function generateHtml(docs: RouteDoc[]): string;
44
46
  export interface DocsCommandOptions extends RuntimeOptions {
@@ -8,6 +8,7 @@ import {
8
8
  inspectRouteFacts,
9
9
  toRouteDocSurface
10
10
  } from "../compiler/route-facts.js";
11
+ import { loadAppConfig, resolveAppMode } from "../runtime/app-config.js";
11
12
  export const DOCS_ARTIFACT_SCHEMA_VERSION = 1;
12
13
  export function parseDocsFlags(args) {
13
14
  const flags = { output: "docs/api.md", format: "md", routesOnly: !1, contracts: !1 };
@@ -57,10 +58,11 @@ export function summarizeRouteFacts(routeFacts) {
57
58
  prerenderedRoutes: routeFacts.filter((route) => route.declaresPrerender).length
58
59
  };
59
60
  }
60
- export function createDocsArtifact(routeFacts) {
61
+ export function createDocsArtifact(routeFacts, appMode = "fullstack") {
61
62
  return {
62
63
  schemaVersion: DOCS_ARTIFACT_SCHEMA_VERSION,
63
64
  generatedAt: new Date().toISOString(),
65
+ appMode,
64
66
  summary: summarizeRouteFacts(routeFacts),
65
67
  routes: routeFacts,
66
68
  docs: routeFacts.map(extractRouteInfoFromFacts)
@@ -92,7 +94,7 @@ const GENERATORS = {
92
94
  export async function generateDocs(args, options = {}) {
93
95
  const { cwd, paths } = createProjectContext(options);
94
96
  initializeCompilerBackends(options.env ?? process.env);
95
- const flags = parseDocsFlags(args), routes = await createRouter(paths.routesDir);
97
+ const flags = parseDocsFlags(args), appMode = resolveAppMode(await loadAppConfig(cwd)), routes = await createRouter(paths.routesDir);
96
98
  if (routes.length === 0) {
97
99
  console.log(`
98
100
  No routes found in routes/
@@ -108,7 +110,7 @@ export async function generateDocs(args, options = {}) {
108
110
  const generate = GENERATORS[flags.format], filteredRouteFacts = routeFacts.routes.filter((route) => {
109
111
  const info = extractRouteInfoFromFacts(route);
110
112
  return !(flags.routesOnly && info.isApi);
111
- }), content = flags.format === "json" && flags.contracts ? generateJsonArtifact(createDocsArtifact(filteredRouteFacts)) : generate(docs), outputPath = join(cwd, flags.output);
113
+ }), content = flags.format === "json" && flags.contracts ? generateJsonArtifact(createDocsArtifact(filteredRouteFacts, appMode)) : generate(docs), outputPath = join(cwd, flags.output);
112
114
  await mkdir(dirname(outputPath), { recursive: !0 });
113
115
  await writeFile(outputPath, content, "utf-8");
114
116
  console.log(`
@@ -2,6 +2,7 @@ import { join } from "node:path";
2
2
  import { pathToFileURL } from "node:url";
3
3
  import { stat } from "node:fs/promises";
4
4
  import { createProjectContext } from "../runtime/project.js";
5
+ import { loadAppConfig, resolveAppMode } from "../runtime/app-config.js";
5
6
  export function parseStartFlags(args) {
6
7
  const flags = {};
7
8
  for (let index = 0;index < args.length; index++)
@@ -10,7 +11,13 @@ export function parseStartFlags(args) {
10
11
  return flags;
11
12
  }
12
13
  export async function startBuiltProject(options = {}) {
13
- const { paths } = createProjectContext(options), runtime = options.runtime ?? "bun";
14
+ const { cwd, paths } = createProjectContext(options), runtime = options.runtime ?? "bun";
15
+ if (resolveAppMode(await loadAppConfig(cwd)) === "frontend") {
16
+ console.error(`
17
+ Error: Frontend-mode apps do not produce a process runtime entrypoint.`);
18
+ console.error(" Use `gorsee build` and deploy the generated static/client artifacts to a static-capable target.\n");
19
+ process.exit(1);
20
+ }
14
21
  try {
15
22
  await stat(join(paths.distDir, "manifest.json"));
16
23
  } catch {
@@ -1,4 +1,5 @@
1
1
  import { type RuntimeOptions } from "../runtime/project.js";
2
+ import { type AppMode } from "../runtime/app-config.js";
2
3
  interface UpgradeFlags {
3
4
  check: boolean;
4
5
  force: boolean;
@@ -19,9 +20,11 @@ export interface UpgradeIssue {
19
20
  export interface UpgradeReport {
20
21
  schemaVersion: 1;
21
22
  generatedAt: string;
23
+ appMode: AppMode;
22
24
  currentVersion: string | null;
23
25
  latestVersion: string | null;
24
26
  upgradeAvailable: boolean;
27
+ recommendedDocs: string[];
25
28
  issues: UpgradeIssue[];
26
29
  }
27
30
  export interface UpgradeExecutionResult {
@@ -4,6 +4,13 @@ import { createProjectContext } from "../runtime/project.js";
4
4
  import { analyzeModuleSource } from "../compiler/module-analysis.js";
5
5
  import { collectCanonicalImportDrift } from "./canonical-imports.js";
6
6
  import { rewriteCanonicalImportsInProject, rewriteLegacyLoadersInProject } from "./canonical-import-rewrite.js";
7
+ import { loadAppConfig, resolveAppMode } from "../runtime/app-config.js";
8
+ const UPGRADE_RECOMMENDED_DOCS = [
9
+ "docs/APPLICATION_MODES.md",
10
+ "docs/MIGRATION_GUIDE.md",
11
+ "docs/UPGRADE_PLAYBOOK.md",
12
+ "docs/DEPLOY_TARGET_GUIDE.md"
13
+ ];
7
14
  export function parseUpgradeFlags(args) {
8
15
  const flags = { check: !1, force: !1, report: null, rewriteImports: !1 };
9
16
  for (let index = 0;index < args.length; index += 1) {
@@ -90,7 +97,10 @@ export async function collectUpgradeIssues(cwd) {
90
97
  } catch {
91
98
  issues.push(issue("UG003", "tsconfig.json", "Could not parse tsconfig.json for migration checks", "Fix tsconfig.json so upgrade checks can validate the canonical compiler contract"));
92
99
  }
93
- if ((await tryReadFile(join(cwd, "app.config.ts")))?.includes("ssr:"))
100
+ const appConfigSource = await tryReadFile(join(cwd, "app.config.ts"));
101
+ if (appConfigSource && !/app\s*:\s*\{[\s\S]*mode\s*:/.test(appConfigSource))
102
+ issues.push(issue("UG012", "app.config.ts", "Canonical app.mode is not set explicitly", 'Add `app: { mode: "frontend" | "fullstack" | "server" }` so tooling, deploy, and diagnostics stay mode-aware', "info"));
103
+ if (appConfigSource?.includes("ssr:"))
94
104
  issues.push(issue("UG004", "app.config.ts", "Deprecated app.config.ts key 'ssr' is still present", "Replace 'ssr' with the canonical 'rendering' configuration surface"));
95
105
  const packageJsonSource = await tryReadFile(join(cwd, "package.json"));
96
106
  if (packageJsonSource)
@@ -130,13 +140,15 @@ export async function collectUpgradeIssues(cwd) {
130
140
  return issues;
131
141
  }
132
142
  export async function collectUpgradeReport(cwd, versions) {
133
- const issues = await collectUpgradeIssues(cwd), { currentVersion, latestVersion } = versions, upgradeAvailable = currentVersion !== null && latestVersion !== null && compareVersions(currentVersion, latestVersion) < 0;
143
+ const issues = await collectUpgradeIssues(cwd), appMode = resolveAppMode(await loadAppConfig(cwd)), { currentVersion, latestVersion } = versions, upgradeAvailable = currentVersion !== null && latestVersion !== null && compareVersions(currentVersion, latestVersion) < 0;
134
144
  return {
135
145
  schemaVersion: 1,
136
146
  generatedAt: new Date().toISOString(),
147
+ appMode,
137
148
  currentVersion,
138
149
  latestVersion,
139
150
  upgradeAvailable,
151
+ recommendedDocs: UPGRADE_RECOMMENDED_DOCS,
140
152
  issues
141
153
  };
142
154
  }
@@ -0,0 +1,9 @@
1
+ import { type RuntimeOptions } from "../runtime/project.js";
2
+ export interface WorkerCommandOptions extends RuntimeOptions {
3
+ }
4
+ interface WorkerFlags {
5
+ entry: string;
6
+ }
7
+ export declare function parseWorkerFlags(args: string[]): WorkerFlags;
8
+ export declare function runWorker(args: string[], options?: WorkerCommandOptions): Promise<void>;
9
+ export {};