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.
- package/README.md +52 -4
- package/dist-pkg/ai/bundle.d.ts +1 -0
- package/dist-pkg/ai/framework-context.d.ts +2 -0
- package/dist-pkg/ai/framework-context.js +6 -1
- package/dist-pkg/ai/ide.d.ts +1 -0
- package/dist-pkg/ai/ide.js +3 -0
- package/dist-pkg/ai/index.d.ts +10 -1
- package/dist-pkg/ai/index.js +13 -2
- package/dist-pkg/ai/mcp.js +4 -0
- package/dist-pkg/ai/session-pack.d.ts +8 -0
- package/dist-pkg/ai/session-pack.js +51 -1
- package/dist-pkg/ai/store.d.ts +25 -1
- package/dist-pkg/ai/store.js +89 -3
- package/dist-pkg/ai/summary.d.ts +88 -0
- package/dist-pkg/ai/summary.js +310 -1
- package/dist-pkg/build/manifest.d.ts +4 -2
- package/dist-pkg/build/manifest.js +32 -2
- package/dist-pkg/cli/cmd-ai.js +66 -0
- package/dist-pkg/cli/cmd-build.js +72 -26
- package/dist-pkg/cli/cmd-check.js +104 -11
- package/dist-pkg/cli/cmd-create.js +333 -7
- package/dist-pkg/cli/cmd-deploy.js +17 -3
- package/dist-pkg/cli/cmd-docs.d.ts +3 -1
- package/dist-pkg/cli/cmd-docs.js +5 -3
- package/dist-pkg/cli/cmd-start.js +8 -1
- package/dist-pkg/cli/cmd-upgrade.d.ts +3 -0
- package/dist-pkg/cli/cmd-upgrade.js +14 -2
- package/dist-pkg/cli/cmd-worker.d.ts +9 -0
- package/dist-pkg/cli/cmd-worker.js +78 -0
- package/dist-pkg/cli/framework-md.js +16 -4
- package/dist-pkg/cli/index.js +5 -0
- package/dist-pkg/runtime/app-config.d.ts +5 -0
- package/dist-pkg/runtime/app-config.js +26 -5
- package/dist-pkg/runtime/typed-routes.js +3 -4
- package/dist-pkg/server/index.d.ts +2 -1
- package/dist-pkg/server/index.js +1 -0
- package/dist-pkg/server/jobs.d.ts +35 -1
- package/dist-pkg/server/jobs.js +226 -3
- package/dist-pkg/server/manifest.d.ts +30 -0
- package/dist-pkg/server/manifest.js +30 -1
- package/dist-pkg/server/redis-client.d.ts +9 -0
- package/dist-pkg/server/redis-client.js +4 -1
- package/dist-pkg/server/redis-job-queue.d.ts +2 -0
- package/dist-pkg/server/redis-job-queue.js +434 -16
- package/dist-pkg/server/worker-service.d.ts +33 -0
- package/dist-pkg/server/worker-service.js +135 -0
- package/dist-pkg/server-entry.d.ts +2 -1
- package/dist-pkg/server-entry.js +4 -0
- 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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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 {
|
package/dist-pkg/cli/cmd-docs.js
CHANGED
|
@@ -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
|
-
|
|
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 {};
|