gorsee 0.2.7 → 0.2.8

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 CHANGED
@@ -95,6 +95,12 @@ npm create gorsee@latest my-app
95
95
 
96
96
  Open [http://localhost:3000](http://localhost:3000).
97
97
 
98
+ For agent cold-start context:
99
+
100
+ ```bash
101
+ bunx gorsee ai framework --format markdown
102
+ ```
103
+
98
104
  ## Why Gorsee
99
105
 
100
106
  Most modern frameworks optimize for flexibility, historical compatibility, or ecosystem breadth.
@@ -115,6 +121,7 @@ What that means in practice:
115
121
  - content collections with nested frontmatter parsing, schema validation, excerpts, block-scalar support, and locale-aware querying
116
122
  - deterministic plugin platform with capabilities, dependency ordering, config validation, and conformance testing
117
123
  - AI diagnostics, saved reactive-trace ingestion, context bundles, IDE projections, and MCP integration built into the framework lifecycle
124
+ - canonical cold-start framework packets via `gorsee ai framework`
118
125
  - CLI enforcement through `gorsee check`, release gates, deploy contracts, and policy docs
119
126
  - machine-readable public API stability enforcement through `bun run api:policy`
120
127
  - machine-readable adoption and market-ready proof enforcement through `bun run adoption:policy`
@@ -255,7 +262,7 @@ npm create gorsee@latest my-app
255
262
  | `gorsee routes` | Show route table |
256
263
  | `gorsee generate <entity>` | Generate CRUD scaffold with typed routes, validated forms, and inferred `memory|sqlite|postgres` data mode |
257
264
  | `gorsee docs --format json --contracts` | Emit machine-readable route/docs contract artifact |
258
- | `gorsee upgrade --rewrite-imports --check --report docs/upgrade-report.json` | Audit migration drift, rewrite obvious import/loader aliases, and write a structured upgrade report |
265
+ | `gorsee upgrade` | Upgrade to the latest published Gorsee version, rewrite obvious migration drift, write `docs/upgrade-report.json`, and run verification |
259
266
  | `gorsee typegen` | Generate typed routes |
260
267
  | `gorsee migrate` | Run database migrations |
261
268
  | `gorsee deploy` | Generate deploy config for supported targets, with `--runtime bun|node` on process-based adapters |
@@ -269,7 +276,8 @@ Runtime debugging surface:
269
276
  Migration ergonomics:
270
277
 
271
278
  - `gorsee check --rewrite-imports --rewrite-loaders` can normalize obvious scoped-import and `loader -> load` drift before the audit runs.
272
- - `gorsee upgrade --rewrite-imports --check --report docs/upgrade-report.json` is the canonical migration cleanup flow.
279
+ - `gorsee upgrade` is the canonical end-to-end upgrade flow for installed apps.
280
+ - `gorsee upgrade --check --report docs/upgrade-report.json` is the dry-run migration audit flow when you want review before installation.
273
281
 
274
282
  ## Product Standards
275
283
 
@@ -0,0 +1,42 @@
1
+ export interface AIFrameworkDocRef {
2
+ path: string;
3
+ purpose: string;
4
+ }
5
+ export interface AIFrameworkPacket {
6
+ kind: "gorsee.framework";
7
+ schemaVersion: 1;
8
+ generatedAt: string;
9
+ cwd: string;
10
+ projectName: string;
11
+ product: {
12
+ name: "Gorsee";
13
+ version?: string;
14
+ identity: string;
15
+ maturity: string;
16
+ };
17
+ entrypoints: {
18
+ browser: string;
19
+ server: string;
20
+ compatibility: string;
21
+ scoped: string[];
22
+ };
23
+ routeGrammar: string[];
24
+ syntax: {
25
+ browserImports: string;
26
+ serverImports: string;
27
+ routeExample: string;
28
+ };
29
+ aiCommands: Array<{
30
+ command: string;
31
+ purpose: string;
32
+ }>;
33
+ docs: {
34
+ local: AIFrameworkDocRef[];
35
+ canonical: AIFrameworkDocRef[];
36
+ };
37
+ recommendedStart: string[];
38
+ frameworkReferencePath?: string;
39
+ frameworkReferenceMarkdown: string;
40
+ }
41
+ export declare function buildAIFrameworkPacket(cwd: string): Promise<AIFrameworkPacket>;
42
+ export declare function renderAIFrameworkMarkdown(packet: AIFrameworkPacket): string;
@@ -0,0 +1,172 @@
1
+ import { access, readFile } from "node:fs/promises";
2
+ import { basename, join, relative } from "node:path";
3
+ import { generateFrameworkMD } from "../cli/framework-md.js";
4
+ const LOCAL_DOCS = [
5
+ { path: "AGENTS.md", purpose: "\u041F\u0440\u043E\u0435\u043A\u0442\u043D\u044B\u0439 operating contract \u0434\u043B\u044F \u0430\u0433\u0435\u043D\u0442\u043E\u0432" },
6
+ { path: "FRAMEWORK.md", purpose: "AI-friendly reference \u0434\u043B\u044F \u0442\u0435\u043A\u0443\u0449\u0435\u0433\u043E \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u044F" },
7
+ { path: "README.md", purpose: "\u0411\u044B\u0441\u0442\u0440\u044B\u0439 \u0432\u0445\u043E\u0434 \u0438 \u043F\u0443\u0431\u043B\u0438\u0447\u043D\u0430\u044F \u043F\u043E\u0432\u0435\u0440\u0445\u043D\u043E\u0441\u0442\u044C" }
8
+ ], CANONICAL_DOCS = [
9
+ { path: "docs/FRAMEWORK_DOCTRINE.md", purpose: "\u0410\u0440\u0445\u0438\u0442\u0435\u043A\u0442\u0443\u0440\u043D\u0430\u044F \u0434\u043E\u043A\u0442\u0440\u0438\u043D\u0430 \u0438 \u0438\u043D\u0432\u0430\u0440\u0438\u0430\u043D\u0442\u044B" },
10
+ { path: "docs/API_STABILITY.md", purpose: "\u0421\u0442\u0430\u0431\u0438\u043B\u044C\u043D\u044B\u0435 \u043F\u0443\u0431\u043B\u0438\u0447\u043D\u044B\u0435 entrypoints \u0438 migration semantics" },
11
+ { path: "docs/SECURITY_MODEL.md", purpose: "Runtime/security guarantees \u0438 fail-closed \u043C\u043E\u0434\u0435\u043B\u044C" },
12
+ { path: "docs/AI_WORKFLOWS.md", purpose: "\u041A\u0430\u043D\u043E\u043D\u0438\u0447\u0435\u0441\u043A\u0438\u0439 human+agent workflow" },
13
+ { path: "docs/AI_SURFACE_STABILITY.md", purpose: "\u0421\u0442\u0430\u0431\u0438\u043B\u044C\u043D\u043E\u0441\u0442\u044C AI-facing surface" },
14
+ { path: "docs/AI_SESSION_PACKS.md", purpose: "Cross-session handoff \u0434\u043B\u044F \u0430\u0433\u0435\u043D\u0442\u043E\u0432" },
15
+ { path: "docs/STARTER_ONBOARDING.md", purpose: "\u0421\u0442\u0430\u0440\u0442\u043E\u0432\u044B\u0435 app-\u043A\u043B\u0430\u0441\u0441\u044B \u0438 onboarding path" },
16
+ { path: "docs/MIGRATION_GUIDE.md", purpose: "\u041F\u0435\u0440\u0435\u0445\u043E\u0434 \u0441 compatibility imports \u043D\u0430 canonical surfaces" },
17
+ { path: "docs/RUNTIME_TRIAGE.md", purpose: "\u0422\u0440\u0438\u0430\u0436 runtime/regression \u043F\u0440\u043E\u0431\u043B\u0435\u043C" },
18
+ { path: "docs/STARTER_FAILURES.md", purpose: "\u0427\u0430\u0441\u0442\u044B\u0435 \u043E\u0448\u0438\u0431\u043A\u0438 \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0438 \u0438 scaffold" }
19
+ ], AI_COMMANDS = [
20
+ { command: "gorsee ai framework --format markdown", purpose: "\u041A\u0430\u043D\u043E\u043D\u0438\u0447\u0435\u0441\u043A\u0438\u0439 cold-start packet \u043F\u043E \u0444\u0440\u0435\u0439\u043C\u0432\u043E\u0440\u043A\u0443" },
21
+ { command: "gorsee ai export --format markdown", purpose: "\u041A\u043E\u043C\u043F\u0430\u043A\u0442\u043D\u044B\u0439 packet \u043F\u043E \u0442\u0435\u043A\u0443\u0449\u0435\u043C\u0443 AI/runtime \u0441\u043E\u0441\u0442\u043E\u044F\u043D\u0438\u044E" },
22
+ { command: "gorsee ai export --bundle --format markdown", purpose: "Runtime packet \u0441 \u0440\u0430\u043D\u0436\u0438\u0440\u043E\u0432\u0430\u043D\u043D\u044B\u043C\u0438 code snippets" },
23
+ { command: "gorsee ai doctor", purpose: "\u0421\u0432\u043E\u0434\u043A\u0430 diagnostics/incidents/artifact regressions" },
24
+ { command: "gorsee ai pack", purpose: "\u0417\u0430\u043F\u0438\u0441\u044C session pack \u0432 .gorsee/agent" },
25
+ { command: "gorsee ai ide-sync", purpose: "IDE-friendly projection \u0444\u0430\u0439\u043B\u043E\u0432" },
26
+ { command: "gorsee ai mcp", purpose: "stdio MCP \u0441\u0435\u0440\u0432\u0435\u0440 \u043F\u043E\u0432\u0435\u0440\u0445 \u043B\u043E\u043A\u0430\u043B\u044C\u043D\u043E\u0433\u043E AI state" }
27
+ ];
28
+ async function pathExists(path) {
29
+ try {
30
+ await access(path);
31
+ return !0;
32
+ } catch {
33
+ return !1;
34
+ }
35
+ }
36
+ async function readJSON(path) {
37
+ try {
38
+ return JSON.parse(await readFile(path, "utf-8"));
39
+ } catch {
40
+ return;
41
+ }
42
+ }
43
+ async function resolveFrameworkVersion() {
44
+ for (const candidate of [
45
+ join(import.meta.dir, "..", "..", "package.json"),
46
+ join(import.meta.dir, "..", "package.json")
47
+ ]) {
48
+ const pkg = await readJSON(candidate);
49
+ if (typeof pkg?.version === "string")
50
+ return pkg.version;
51
+ }
52
+ return;
53
+ }
54
+ async function resolveProjectName(cwd) {
55
+ const pkg = await readJSON(join(cwd, "package.json"));
56
+ if (typeof pkg?.name === "string" && pkg.name.trim().length > 0)
57
+ return pkg.name;
58
+ return basename(cwd);
59
+ }
60
+ async function collectDocRefs(cwd, refs) {
61
+ const result = [];
62
+ for (const ref of refs)
63
+ if (await pathExists(join(cwd, ref.path)))
64
+ result.push(ref);
65
+ return result;
66
+ }
67
+ function renderDocLines(docs) {
68
+ return docs.map((doc) => `- \`${doc.path}\` -- ${doc.purpose}`);
69
+ }
70
+ export async function buildAIFrameworkPacket(cwd) {
71
+ const projectName = await resolveProjectName(cwd), localDocs = await collectDocRefs(cwd, LOCAL_DOCS), canonicalDocs = await collectDocRefs(cwd, CANONICAL_DOCS), frameworkReferencePath = await pathExists(join(cwd, "FRAMEWORK.md")) ? relative(cwd, join(cwd, "FRAMEWORK.md")) || "FRAMEWORK.md" : void 0, frameworkReferenceMarkdown = frameworkReferencePath ? await readFile(join(cwd, frameworkReferencePath), "utf-8") : generateFrameworkMD(projectName);
72
+ return {
73
+ kind: "gorsee.framework",
74
+ schemaVersion: 1,
75
+ generatedAt: new Date().toISOString(),
76
+ cwd,
77
+ projectName,
78
+ product: {
79
+ name: "Gorsee",
80
+ version: await resolveFrameworkVersion(),
81
+ identity: "AI-first reactive full-stack framework for deterministic human and agent collaboration",
82
+ maturity: "Mature product framework with strict runtime, security, release, and AI workflow contracts"
83
+ },
84
+ entrypoints: {
85
+ browser: "gorsee/client",
86
+ server: "gorsee/server",
87
+ compatibility: "gorsee and gorsee/compat are compatibility-only for new code",
88
+ scoped: ["gorsee/auth", "gorsee/db", "gorsee/security", "gorsee/log", "gorsee/forms", "gorsee/routes", "gorsee/ai"]
89
+ },
90
+ routeGrammar: [
91
+ "default export -> page UI",
92
+ "load -> route data reads",
93
+ "action -> page-bound mutations",
94
+ "cache -> declarative cache policy",
95
+ "middleware -> request policy and cross-cutting guards",
96
+ "GET/POST/etc -> raw HTTP endpoints"
97
+ ],
98
+ syntax: {
99
+ browserImports: 'import { createSignal, Head, Link } from "gorsee/client"',
100
+ serverImports: 'import { middleware, type Context } from "gorsee/server"',
101
+ routeExample: "routes/users/[id].tsx -> /users/:id"
102
+ },
103
+ aiCommands: AI_COMMANDS,
104
+ docs: {
105
+ local: localDocs,
106
+ canonical: canonicalDocs
107
+ },
108
+ recommendedStart: [
109
+ "Read AGENTS.md first when it exists.",
110
+ "Read FRAMEWORK.md for the current app shape and syntax.",
111
+ "Use gorsee/client for browser-safe code and gorsee/server for runtime/server boundaries.",
112
+ "Prefer scoped stable subpaths when auth, db, security, forms, routes, ai, or log is the primary concern.",
113
+ "Use gorsee ai export --bundle for incident/debug context, not for framework cold-start context."
114
+ ],
115
+ frameworkReferencePath,
116
+ frameworkReferenceMarkdown
117
+ };
118
+ }
119
+ export function renderAIFrameworkMarkdown(packet) {
120
+ return [
121
+ "# Gorsee AI Framework Packet",
122
+ "",
123
+ `Generated: ${packet.generatedAt}`,
124
+ `Project: ${packet.projectName}`,
125
+ packet.product.version ? `Framework Version: ${packet.product.version}` : void 0,
126
+ "",
127
+ "## Product",
128
+ "",
129
+ `- ${packet.product.identity}`,
130
+ `- ${packet.product.maturity}`,
131
+ "",
132
+ "## Canonical Entrypoints",
133
+ "",
134
+ `- browser: \`${packet.entrypoints.browser}\``,
135
+ `- server: \`${packet.entrypoints.server}\``,
136
+ `- compatibility: ${packet.entrypoints.compatibility}`,
137
+ `- scoped: ${packet.entrypoints.scoped.map((entry) => `\`${entry}\``).join(", ")}`,
138
+ "",
139
+ "## Route Grammar",
140
+ "",
141
+ ...packet.routeGrammar.map((entry) => `- ${entry}`),
142
+ "",
143
+ "## Syntax",
144
+ "",
145
+ `- ${packet.syntax.browserImports}`,
146
+ `- ${packet.syntax.serverImports}`,
147
+ `- ${packet.syntax.routeExample}`,
148
+ "",
149
+ "## Recommended Start",
150
+ "",
151
+ ...packet.recommendedStart.map((entry) => `- ${entry}`),
152
+ "",
153
+ "## AI Commands",
154
+ "",
155
+ ...packet.aiCommands.map((entry) => `- \`${entry.command}\` -- ${entry.purpose}`),
156
+ "",
157
+ "## Local Docs",
158
+ "",
159
+ ...packet.docs.local.length > 0 ? renderDocLines(packet.docs.local) : ["- No local AI/context docs detected in the current cwd."],
160
+ "",
161
+ "## Canonical Docs",
162
+ "",
163
+ ...packet.docs.canonical.length > 0 ? renderDocLines(packet.docs.canonical) : ["- Canonical repo docs are not present in the current cwd."],
164
+ "",
165
+ "## Framework Reference",
166
+ "",
167
+ packet.frameworkReferencePath ? `Source: \`${packet.frameworkReferencePath}\`` : "Source: generated built-in framework reference",
168
+ "",
169
+ packet.frameworkReferenceMarkdown
170
+ ].filter((line) => line !== void 0).join(`
171
+ `);
172
+ }
@@ -6,6 +6,7 @@ export { buildAIHealthReport, readAIDiagnosticsSnapshot, readReactiveTraceArtifa
6
6
  export { createAIMCPServer, createLineReader, type AIMCPServerOptions, } from "./mcp.js";
7
7
  export { createAIContextPacket, renderAIContextMarkdown, type AIContextPacket, } from "./summary.js";
8
8
  export { buildAIContextBundle, renderAIContextBundleMarkdown, type AIContextBundle, type AIContextSnippet, } from "./bundle.js";
9
+ export { buildAIFrameworkPacket, renderAIFrameworkMarkdown, type AIFrameworkDocRef, type AIFrameworkPacket, } from "./framework-context.js";
9
10
  export { buildIDEProjection, resolveIDEProjectionPaths, writeIDEProjection, type IDEProjection, type IDEProjectionPaths, } from "./ide.js";
10
11
  export { createIDEProjectionWatcher, type IDEProjectionWatcher, type IDEProjectionWatcherOptions, } from "./watch.js";
11
12
  export { resolveAISessionPackConfig, resolveAISessionPackPaths, shouldGenerateAISessionPack, writeAISessionPack, type AISessionPackConfig, type AISessionPackPaths, } from "./session-pack.js";
@@ -37,6 +37,10 @@ export {
37
37
  buildAIContextBundle,
38
38
  renderAIContextBundleMarkdown
39
39
  } from "./bundle.js";
40
+ export {
41
+ buildAIFrameworkPacket,
42
+ renderAIFrameworkMarkdown
43
+ } from "./framework-context.js";
40
44
  export {
41
45
  buildIDEProjection,
42
46
  resolveIDEProjectionPaths,
@@ -2,6 +2,7 @@ import { createProjectContext } from "../runtime/project.js";
2
2
  import {
3
3
  buildAIHealthReport,
4
4
  buildAIContextBundle,
5
+ buildAIFrameworkPacket,
5
6
  buildIDEProjection,
6
7
  createIDEProjectionWatcher,
7
8
  createAIBridgeServer,
@@ -13,6 +14,7 @@ import {
13
14
  readReactiveTraceArtifact,
14
15
  renderAIContextMarkdown,
15
16
  renderAIContextBundleMarkdown,
17
+ renderAIFrameworkMarkdown,
16
18
  resolveAIStorePaths,
17
19
  resolveAISessionPackPaths,
18
20
  resolveIDEProjectionPaths,
@@ -22,6 +24,8 @@ import {
22
24
  export async function runAI(args, options = {}) {
23
25
  const subcommand = args[0] ?? "help", flags = parseAIFlags(args.slice(1)), { cwd } = createProjectContext(options), paths = resolveAIStorePaths(cwd);
24
26
  switch (subcommand) {
27
+ case "framework":
28
+ return runAIFramework(cwd, flags);
25
29
  case "tail":
26
30
  return runAITail(paths.eventsPath, flags);
27
31
  case "doctor":
@@ -43,6 +47,14 @@ export async function runAI(args, options = {}) {
43
47
  printAIHelp();
44
48
  }
45
49
  }
50
+ async function runAIFramework(cwd, flags) {
51
+ const packet = await buildAIFrameworkPacket(cwd);
52
+ if ((flags.format ?? "json") === "markdown") {
53
+ console.log(renderAIFrameworkMarkdown(packet));
54
+ return;
55
+ }
56
+ console.log(JSON.stringify(packet, null, 2));
57
+ }
46
58
  async function runAITail(eventsPath, flags) {
47
59
  const events = await readAIEvents(eventsPath, { limit: flags.limit ?? 20 });
48
60
  if (flags.json) {
@@ -270,6 +282,7 @@ function printAIHelp() {
270
282
  gorsee ai <subcommand>
271
283
  `);
272
284
  console.log(" Subcommands:");
285
+ console.log(" framework Export canonical framework context for cold-start agents");
273
286
  console.log(" tail Read recent structured AI events");
274
287
  console.log(" doctor Summarize diagnostics and recent incidents");
275
288
  console.log(" replay Replay correlated AI events in timeline order");
@@ -190,7 +190,7 @@ function checkImportContracts(cwd, astFacts) {
190
190
  code: "W916",
191
191
  file: rel,
192
192
  message: 'Route module still exports "loader" instead of canonical "load"',
193
- fix: 'Rename exported "loader" to "load", or run `gorsee check --rewrite-loaders` / `gorsee upgrade --rewrite-imports` to rewrite obvious cases automatically'
193
+ fix: 'Rename exported "loader" to "load", or run `gorsee check --rewrite-loaders` / `gorsee upgrade` to rewrite obvious cases automatically'
194
194
  });
195
195
  for (const drift of collectCanonicalImportDrift(facts.imports)) {
196
196
  const entries = [...drift.replacements.entries()].map(([name, target]) => `${name} -> ${target}`).join(", "), targets = [...new Set(drift.replacements.values())].join(", ");
@@ -472,6 +472,7 @@ Use the Gorsee docs to pick one clear path before expanding architecture.
472
472
  | \`bun run build\` | Production build |
473
473
  | \`bun run start\` | Start production server |
474
474
  | \`bun run check\` | Type check + safety audit |
475
+ | \`bunx gorsee ai framework --format markdown\` | Export canonical framework context for a new agent session |
475
476
  | \`bunx gorsee ai doctor\` | Summarize AI diagnostics and incidents |
476
477
  | \`bunx gorsee ai tail --limit 20\` | Inspect recent structured AI events |
477
478
  | \`bunx gorsee ai export --format markdown\` | Generate a compact AI context packet |
@@ -5,6 +5,10 @@ interface UpgradeFlags {
5
5
  report: string | null;
6
6
  rewriteImports: boolean;
7
7
  }
8
+ export interface UpgradeStepResult {
9
+ command: string[];
10
+ exitCode: number;
11
+ }
8
12
  export interface UpgradeIssue {
9
13
  code: string;
10
14
  file: string;
@@ -20,6 +24,14 @@ export interface UpgradeReport {
20
24
  upgradeAvailable: boolean;
21
25
  issues: UpgradeIssue[];
22
26
  }
27
+ export interface UpgradeExecutionResult {
28
+ report: UpgradeReport;
29
+ installed: boolean;
30
+ installResult?: UpgradeStepResult;
31
+ checkResult?: UpgradeStepResult;
32
+ changedFiles: string[];
33
+ reportPath: string;
34
+ }
23
35
  export declare function parseUpgradeFlags(args: string[]): UpgradeFlags;
24
36
  /** Compare semver strings: -1 (a < b), 0 (equal), 1 (a > b) */
25
37
  export declare function compareVersions(a: string, b: string): number;
@@ -32,6 +44,12 @@ export declare function collectUpgradeReport(cwd: string, versions: {
32
44
  export declare function writeUpgradeReport(cwd: string, reportPath: string, report: UpgradeReport): Promise<void>;
33
45
  export interface UpgradeCommandOptions extends RuntimeOptions {
34
46
  }
47
+ export declare function performUpgrade(cwd: string, flags: UpgradeFlags, hooks?: {
48
+ fetchLatestVersion?: () => Promise<string | null>;
49
+ getCurrentVersion?: (cwd: string) => Promise<string | null>;
50
+ runInstallStep?: (cwd: string) => Promise<UpgradeStepResult>;
51
+ runCheckStep?: (cwd: string) => Promise<UpgradeStepResult>;
52
+ }): Promise<UpgradeExecutionResult | null>;
35
53
  export declare function upgradeFramework(args: string[], options?: UpgradeCommandOptions): Promise<void>;
36
54
  /** @deprecated Use upgradeFramework() for programmatic access. */
37
55
  export declare function runUpgrade(args: string[], options?: UpgradeCommandOptions): Promise<void>;
@@ -39,6 +39,7 @@ async function getCurrentVersion(cwd) {
39
39
  }
40
40
  }
41
41
  export const NPM_REGISTRY_URL = "https://registry.npmjs.org/gorsee/latest";
42
+ const DEFAULT_UPGRADE_REPORT_PATH = "docs/upgrade-report.json";
42
43
  async function fetchLatestVersion() {
43
44
  try {
44
45
  const res = await fetch(NPM_REGISTRY_URL);
@@ -124,7 +125,7 @@ export async function collectUpgradeIssues(cwd) {
124
125
  issues.push(issue(drift.source === "gorsee/server" ? "UG009" : "UG010", relative(cwd, file), `Domain APIs still come from "${drift.source}" instead of scoped stable subpaths: ${entries}`, drift.source === "gorsee/server" ? `Keep runtime primitives on "gorsee/server" and move domain imports to ${targets}` : `Keep browser runtime primitives on "gorsee/client" and move domain imports to ${targets}`, "info"));
125
126
  }
126
127
  if (facts.exportedNames.has("loader"))
127
- issues.push(issue("UG011", relative(cwd, file), 'Route module still exports "loader" instead of canonical "load"', 'Rename exported "loader" to "load", or run `gorsee upgrade --rewrite-imports` to rewrite obvious cases automatically', "info"));
128
+ issues.push(issue("UG011", relative(cwd, file), 'Route module still exports "loader" instead of canonical "load"', 'Rename exported "loader" to "load", or run `gorsee upgrade` to rewrite obvious cases automatically', "info"));
128
129
  }
129
130
  return issues;
130
131
  }
@@ -145,87 +146,149 @@ export async function writeUpgradeReport(cwd, reportPath, report) {
145
146
  await writeFile(outputPath, JSON.stringify(report, null, 2) + `
146
147
  `, "utf-8");
147
148
  }
148
- export async function upgradeFramework(args, options = {}) {
149
- const { cwd } = createProjectContext(options), flags = parseUpgradeFlags(args);
150
- if (flags.rewriteImports) {
151
- const importRewrite = await rewriteCanonicalImportsInProject(cwd), loaderRewrite = await rewriteLegacyLoadersInProject(cwd), changedFiles = [...new Set([...importRewrite.changedFiles, ...loaderRewrite.changedFiles])].sort();
152
- if (changedFiles.length > 0) {
153
- console.log(`
149
+ async function runProcess(command, cwd) {
150
+ const exitCode = await Bun.spawn(command, {
151
+ cwd,
152
+ stdout: "inherit",
153
+ stderr: "inherit"
154
+ }).exited;
155
+ return { command, exitCode };
156
+ }
157
+ async function runInstallStep(cwd) {
158
+ return runProcess(["bun", "add", "gorsee@latest"], cwd);
159
+ }
160
+ async function runCheckStep(cwd) {
161
+ return runProcess(["bun", "run", "check"], cwd);
162
+ }
163
+ async function rewriteUpgradeDrift(cwd) {
164
+ const importRewrite = await rewriteCanonicalImportsInProject(cwd), loaderRewrite = await rewriteLegacyLoadersInProject(cwd);
165
+ return [...new Set([...importRewrite.changedFiles, ...loaderRewrite.changedFiles])].sort();
166
+ }
167
+ function printChangedFiles(changedFiles) {
168
+ if (changedFiles.length > 0) {
169
+ console.log(`
154
170
  Rewrote canonical imports and loader aliases:`);
155
- for (const file of changedFiles)
156
- console.log(` - ${file}`);
157
- } else
158
- console.log(`
159
- Canonical import and loader rewrite found no changes.`);
171
+ for (const file of changedFiles)
172
+ console.log(` - ${file}`);
173
+ return;
160
174
  }
161
- const current = await getCurrentVersion(cwd);
175
+ console.log(`
176
+ Canonical import and loader rewrite found no changes.`);
177
+ }
178
+ export async function performUpgrade(cwd, flags, hooks = {}) {
179
+ const getCurrentVersionImpl = hooks.getCurrentVersion ?? getCurrentVersion, fetchLatestVersionImpl = hooks.fetchLatestVersion ?? fetchLatestVersion, runInstallStepImpl = hooks.runInstallStep ?? runInstallStep, runCheckStepImpl = hooks.runCheckStep ?? runCheckStep, reportPath = flags.report ?? DEFAULT_UPGRADE_REPORT_PATH, current = await getCurrentVersionImpl(cwd);
162
180
  if (!current) {
163
181
  console.log(`
164
182
  Gorsee.js not found in node_modules. Run: bun add gorsee
165
183
  `);
166
- return;
184
+ return null;
167
185
  }
168
186
  console.log(`
169
187
  Current version: v${current}`);
170
- const latest = await fetchLatestVersion();
188
+ const latest = await fetchLatestVersionImpl();
171
189
  if (!latest) {
172
190
  console.log(` Could not fetch latest version from npm registry.
173
191
  `);
174
- return;
192
+ return null;
175
193
  }
176
- const report = await collectUpgradeReport(cwd, {
194
+ console.log(` Latest version: v${latest}`);
195
+ const preflightReport = await collectUpgradeReport(cwd, {
177
196
  currentVersion: current,
178
197
  latestVersion: latest
179
198
  });
180
- if (flags.report) {
181
- await writeUpgradeReport(cwd, flags.report, report);
182
- console.log(` Upgrade report: ${flags.report}`);
199
+ await writeUpgradeReport(cwd, reportPath, preflightReport);
200
+ console.log(` Upgrade report: ${reportPath}`);
201
+ if (preflightReport.issues.length > 0) {
202
+ console.log(`
203
+ Migration audit:`);
204
+ for (const entry of preflightReport.issues)
205
+ console.log(` - [${entry.code}] ${entry.file}: ${entry.message}`);
183
206
  }
184
207
  if (compareVersions(current, latest) >= 0) {
185
208
  console.log(` Already up to date (v${current})`);
186
- if (report.issues.length > 0) {
209
+ if (flags.check) {
210
+ console.log();
211
+ return {
212
+ report: preflightReport,
213
+ installed: !1,
214
+ changedFiles: [],
215
+ reportPath
216
+ };
217
+ }
218
+ const changedFiles = await rewriteUpgradeDrift(cwd);
219
+ printChangedFiles(changedFiles);
220
+ console.log(`
221
+ Running upgrade verification (bun run check)...`);
222
+ const checkResult = await runCheckStepImpl(cwd);
223
+ if (checkResult.exitCode !== 0) {
187
224
  console.log(`
188
- Migration audit:`);
189
- for (const entry of report.issues)
190
- console.log(` - [${entry.code}] ${entry.file}: ${entry.message}`);
225
+ Post-upgrade verification failed (exit code ${checkResult.exitCode})
226
+ `);
227
+ process.exit(checkResult.exitCode);
191
228
  }
192
- console.log();
193
- return;
194
- }
195
- console.log(` Latest version: v${latest}`);
196
- console.log(` Upgrade: v${current} -> v${latest}`);
197
- if (report.issues.length > 0) {
198
229
  console.log(`
199
- Migration audit:`);
200
- for (const entry of report.issues)
201
- console.log(` - [${entry.code}] ${entry.file}: ${entry.message}`);
230
+ Upgrade verification passed.
231
+ `);
232
+ return {
233
+ report: preflightReport,
234
+ installed: !1,
235
+ checkResult,
236
+ changedFiles,
237
+ reportPath
238
+ };
202
239
  }
240
+ console.log(` Upgrade: v${current} -> v${latest}`);
203
241
  if (flags.check) {
204
242
  console.log();
205
- return;
243
+ return {
244
+ report: preflightReport,
245
+ installed: !1,
246
+ changedFiles: [],
247
+ reportPath
248
+ };
206
249
  }
207
- if (!flags.force) {
250
+ console.log(`
251
+ Installing gorsee@latest...`);
252
+ const installResult = await runInstallStepImpl(cwd);
253
+ if (installResult.exitCode !== 0) {
208
254
  console.log(`
209
- Run with --force to install after reviewing the migration audit.
255
+ Install failed (exit code ${installResult.exitCode})
210
256
  `);
211
- return;
257
+ process.exit(installResult.exitCode);
212
258
  }
259
+ const changedFiles = await rewriteUpgradeDrift(cwd);
260
+ printChangedFiles(changedFiles);
213
261
  console.log(`
214
- Installing gorsee@latest...`);
215
- const exitCode = await Bun.spawn(["bun", "add", "gorsee@latest"], {
216
- cwd,
217
- stdout: "inherit",
218
- stderr: "inherit"
219
- }).exited;
220
- if (exitCode !== 0) {
262
+ Running upgrade verification (bun run check)...`);
263
+ const checkResult = await runCheckStepImpl(cwd);
264
+ if (checkResult.exitCode !== 0) {
221
265
  console.log(`
222
- Install failed (exit code ${exitCode})
266
+ Upgrade verification failed (exit code ${checkResult.exitCode})
223
267
  `);
224
- process.exit(exitCode);
268
+ process.exit(checkResult.exitCode);
225
269
  }
270
+ const installedVersion = await getCurrentVersionImpl(cwd), finalReport = await collectUpgradeReport(cwd, {
271
+ currentVersion: installedVersion,
272
+ latestVersion: latest
273
+ });
274
+ await writeUpgradeReport(cwd, reportPath, finalReport);
226
275
  console.log(`
227
- Upgraded successfully to v${latest}
276
+ Upgraded successfully to v${installedVersion ?? latest}
228
277
  `);
278
+ return {
279
+ report: finalReport,
280
+ installed: !0,
281
+ installResult,
282
+ checkResult,
283
+ changedFiles,
284
+ reportPath
285
+ };
286
+ }
287
+ export async function upgradeFramework(args, options = {}) {
288
+ const { cwd } = createProjectContext(options), flags = parseUpgradeFlags(args);
289
+ if (flags.force)
290
+ console.log("\n Note: --force is no longer required. `gorsee upgrade` installs by default unless --check is used.");
291
+ await performUpgrade(cwd, flags);
229
292
  }
230
293
  export async function runUpgrade(args, options = {}) {
231
294
  return upgradeFramework(args, options);
@@ -357,6 +357,7 @@ gorsee build Production build
357
357
  gorsee check Type + safety + structure check
358
358
  gorsee check --rewrite-imports --rewrite-loaders
359
359
  Normalize canonical imports and loader aliases before auditing
360
+ gorsee ai framework Export canonical framework context for cold-start agents
360
361
  gorsee ai doctor Summarize AI diagnostics and incidents
361
362
  gorsee ai replay Reconstruct recent correlated AI event timeline
362
363
  gorsee ai export Export a compact agent-ready context packet
@@ -367,7 +368,8 @@ gorsee migrate Run database migrations
367
368
  gorsee generate X Generate CRUD for entity X
368
369
  \`\`\`
369
370
 
370
- - For migration cleanup, prefer \`gorsee upgrade --rewrite-imports --check --report docs/upgrade-report.json\`.
371
+ - For installed apps, prefer \`gorsee upgrade\` for the full version bump + rewrite + verification flow.
372
+ - Use \`gorsee upgrade --check --report docs/upgrade-report.json\` for a dry-run audit without installation.
371
373
 
372
374
  ## Error Codes
373
375
 
@@ -11,7 +11,7 @@ const args = process.argv.slice(2), command = args[0], COMMANDS = {
11
11
  deploy: "Generate deploy config (vercel/fly/cloudflare/netlify/docker)",
12
12
  test: "Run tests (unit/integration/e2e)",
13
13
  docs: "Generate API documentation from routes",
14
- ai: "AI-first tooling: tail, doctor, bridge, mcp",
14
+ ai: "AI-first tooling: framework, tail, doctor, bridge, mcp",
15
15
  upgrade: "Upgrade Gorsee.js with migration audit and canonical rewrites",
16
16
  help: "Show this help message"
17
17
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gorsee",
3
- "version": "0.2.7",
3
+ "version": "0.2.8",
4
4
  "description": "AI-first reactive full-stack TypeScript framework for deterministic human and agent collaboration",
5
5
  "type": "module",
6
6
  "packageManager": "bun@1.3.9",