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
@@ -4,12 +4,38 @@ import type { ReactiveTraceArtifact } from "../reactive/diagnostics.js";
4
4
  export interface AIContextPacket {
5
5
  schemaVersion: string;
6
6
  generatedAt: string;
7
+ app?: {
8
+ mode: "frontend" | "fullstack" | "server";
9
+ runtimeTopology: "single-instance" | "multi-instance";
10
+ };
7
11
  summary: {
8
12
  headline: string;
9
13
  events: number;
10
14
  errors: number;
11
15
  warnings: number;
12
16
  };
17
+ readiness: {
18
+ deploy: {
19
+ status: "ready" | "caution" | "blocked";
20
+ reasons: string[];
21
+ };
22
+ scaling: {
23
+ status: "ready" | "caution" | "blocked" | "not-applicable";
24
+ reasons: string[];
25
+ };
26
+ };
27
+ release?: {
28
+ appMode: "frontend" | "fullstack" | "server";
29
+ runtimeKind: "frontend-static" | "fullstack-runtime" | "server-runtime";
30
+ processEntrypoints: string[];
31
+ handlerEntrypoints: string[];
32
+ workerEntrypoint?: string;
33
+ routeCount: number;
34
+ clientAssetCount: number;
35
+ prerenderedCount: number;
36
+ serverEntryCount: number;
37
+ generatedAt: string;
38
+ };
13
39
  latestDiagnostic?: Partial<AIDiagnostic>;
14
40
  recentIncidents: Array<{
15
41
  ts: string;
@@ -53,5 +79,67 @@ export interface AIContextPacket {
53
79
  };
54
80
  recommendations: string[];
55
81
  }
82
+ export interface AIReleaseBrief {
83
+ schemaVersion: string;
84
+ generatedAt: string;
85
+ app?: AIContextPacket["app"];
86
+ release?: AIContextPacket["release"];
87
+ readiness: AIContextPacket["readiness"];
88
+ verdict: "ship" | "review" | "hold";
89
+ headline: string;
90
+ blockers: string[];
91
+ cautions: string[];
92
+ recommendations: string[];
93
+ }
94
+ export interface AIIncidentBrief {
95
+ schemaVersion: string;
96
+ generatedAt: string;
97
+ app?: AIContextPacket["app"];
98
+ release?: AIContextPacket["release"];
99
+ readiness: AIContextPacket["readiness"];
100
+ severity: "critical" | "high" | "medium" | "low";
101
+ headline: string;
102
+ incidents: AIContextPacket["recentIncidents"];
103
+ clusters: AIContextPacket["incidentClusters"];
104
+ artifactRegressions: AIContextPacket["artifactRegressions"];
105
+ recommendations: string[];
106
+ }
107
+ export interface AIDeploySummary {
108
+ schemaVersion: string;
109
+ generatedAt: string;
110
+ app?: AIContextPacket["app"];
111
+ release?: AIContextPacket["release"];
112
+ readiness: AIContextPacket["readiness"];
113
+ status: "ready" | "review" | "blocked";
114
+ headline: string;
115
+ processEntrypoints: string[];
116
+ handlerEntrypoints: string[];
117
+ workerEntrypoint?: string;
118
+ artifactRegressions: AIContextPacket["artifactRegressions"];
119
+ recommendations: string[];
120
+ }
121
+ export interface AIIncidentSnapshot {
122
+ schemaVersion: string;
123
+ generatedAt: string;
124
+ app?: AIContextPacket["app"];
125
+ release?: AIContextPacket["release"];
126
+ readiness: AIContextPacket["readiness"];
127
+ severity: "critical" | "high" | "medium" | "low";
128
+ headline: string;
129
+ latestIncident?: AIContextPacket["recentIncidents"][number];
130
+ incidentCount: number;
131
+ clusterCount: number;
132
+ clusters: AIContextPacket["incidentClusters"];
133
+ hotspots: AIContextPacket["hotspots"];
134
+ recommendations: string[];
135
+ }
56
136
  export declare function createAIContextPacket(report: AIHealthReport, events: AIEvent[], latestDiagnostic?: Partial<AIDiagnostic>, reactiveTrace?: ReactiveTraceArtifact | null): AIContextPacket;
57
137
  export declare function renderAIContextMarkdown(packet: AIContextPacket): string;
138
+ export declare function createAIReleaseBrief(packet: AIContextPacket): AIReleaseBrief;
139
+ export declare function renderAIReleaseBriefMarkdown(brief: AIReleaseBrief): string;
140
+ export declare function createAIIncidentBrief(packet: AIContextPacket): AIIncidentBrief;
141
+ export declare function renderAIIncidentBriefMarkdown(brief: AIIncidentBrief): string;
142
+ export declare function createAIDeploySummary(packet: AIContextPacket): AIDeploySummary;
143
+ export declare function renderAIDeploySummaryMarkdown(summary: AIDeploySummary): string;
144
+ export declare function createAIIncidentSnapshot(packet: AIContextPacket): AIIncidentSnapshot;
145
+ export declare function renderAIIncidentSnapshotMarkdown(snapshot: AIIncidentSnapshot): string;
@@ -1,14 +1,32 @@
1
1
  import { GORSEE_AI_CONTEXT_SCHEMA_VERSION } from "./contracts.js";
2
2
  export function createAIContextPacket(report, events, latestDiagnostic, reactiveTrace) {
3
+ const readiness = report.readiness ?? {
4
+ deploy: { status: "ready", reasons: [] },
5
+ scaling: { status: "not-applicable", reasons: [] }
6
+ };
3
7
  return {
4
8
  schemaVersion: GORSEE_AI_CONTEXT_SCHEMA_VERSION,
5
9
  generatedAt: new Date().toISOString(),
10
+ app: report.app,
6
11
  summary: {
7
12
  headline: buildHeadline(report),
8
13
  events: report.events.total,
9
14
  errors: report.diagnostics.errors,
10
15
  warnings: report.diagnostics.warnings
11
16
  },
17
+ readiness,
18
+ release: report.release ? {
19
+ appMode: report.release.appMode,
20
+ runtimeKind: report.release.runtimeKind,
21
+ processEntrypoints: report.release.processEntrypoints,
22
+ handlerEntrypoints: report.release.handlerEntrypoints,
23
+ workerEntrypoint: report.release.workerEntrypoint,
24
+ routeCount: report.release.summary.routeCount,
25
+ clientAssetCount: report.release.summary.clientAssetCount,
26
+ prerenderedCount: report.release.summary.prerenderedCount,
27
+ serverEntryCount: report.release.summary.serverEntryCount,
28
+ generatedAt: report.release.generatedAt
29
+ } : void 0,
12
30
  latestDiagnostic,
13
31
  recentIncidents: report.incidents,
14
32
  incidentClusters: report.incidentClusters.map((cluster) => ({
@@ -49,6 +67,13 @@ export function renderAIContextMarkdown(packet) {
49
67
  "",
50
68
  `Generated: ${packet.generatedAt}`,
51
69
  "",
70
+ ...packet.app ? [
71
+ "## App Context",
72
+ "",
73
+ `- Mode: ${packet.app.mode}`,
74
+ `- Runtime topology: ${packet.app.runtimeTopology}`,
75
+ ""
76
+ ] : [],
52
77
  "## Summary",
53
78
  "",
54
79
  `- ${packet.summary.headline}`,
@@ -58,6 +83,28 @@ export function renderAIContextMarkdown(packet) {
58
83
  ];
59
84
  if (packet.latestDiagnostic?.code)
60
85
  lines.push("", "## Latest Diagnostic", "", `- ${packet.latestDiagnostic.code}: ${packet.latestDiagnostic.message ?? ""}`.trim());
86
+ if (packet.release) {
87
+ lines.push("", "## Release Artifact", "");
88
+ lines.push(`- Mode: ${packet.release.appMode}`);
89
+ lines.push(`- Runtime: ${packet.release.runtimeKind}`);
90
+ lines.push(`- Routes: ${packet.release.routeCount}`);
91
+ lines.push(`- Client assets: ${packet.release.clientAssetCount}`);
92
+ lines.push(`- Prerendered pages: ${packet.release.prerenderedCount}`);
93
+ lines.push(`- Server entries: ${packet.release.serverEntryCount}`);
94
+ if (packet.release.processEntrypoints.length > 0)
95
+ lines.push(`- Process entrypoints: ${packet.release.processEntrypoints.join(", ")}`);
96
+ if (packet.release.handlerEntrypoints.length > 0)
97
+ lines.push(`- Handler entrypoints: ${packet.release.handlerEntrypoints.join(", ")}`);
98
+ if (packet.release.workerEntrypoint)
99
+ lines.push(`- Worker entrypoint: ${packet.release.workerEntrypoint}`);
100
+ }
101
+ lines.push("", "## Readiness", "");
102
+ lines.push(`- Deploy: ${packet.readiness.deploy.status}`);
103
+ for (const reason of packet.readiness.deploy.reasons.slice(0, 3))
104
+ lines.push(` - ${reason}`);
105
+ lines.push(`- Scaling: ${packet.readiness.scaling.status}`);
106
+ for (const reason of packet.readiness.scaling.reasons.slice(0, 3))
107
+ lines.push(` - ${reason}`);
61
108
  if (packet.recentIncidents.length > 0) {
62
109
  lines.push("", "## Recent Incidents", "");
63
110
  for (const incident of packet.recentIncidents.slice(0, 10)) {
@@ -101,11 +148,264 @@ export function renderAIContextMarkdown(packet) {
101
148
  return lines.join(`
102
149
  `);
103
150
  }
151
+ export function createAIReleaseBrief(packet) {
152
+ const blockers = [
153
+ ...packet.readiness.deploy.status === "blocked" ? packet.readiness.deploy.reasons : [],
154
+ ...packet.readiness.scaling.status === "blocked" ? packet.readiness.scaling.reasons : []
155
+ ], cautions = [
156
+ ...packet.readiness.deploy.status === "caution" ? packet.readiness.deploy.reasons : [],
157
+ ...packet.readiness.scaling.status === "caution" ? packet.readiness.scaling.reasons : []
158
+ ], verdict = blockers.length > 0 ? "hold" : cautions.length > 0 ? "review" : "ship";
159
+ return {
160
+ schemaVersion: GORSEE_AI_CONTEXT_SCHEMA_VERSION,
161
+ generatedAt: new Date().toISOString(),
162
+ app: packet.app,
163
+ release: packet.release,
164
+ readiness: packet.readiness,
165
+ verdict,
166
+ headline: verdict === "hold" ? "Release should not be promoted yet." : verdict === "review" ? "Release is close, but needs operator review." : "Release looks ready for promotion.",
167
+ blockers,
168
+ cautions,
169
+ recommendations: packet.recommendations
170
+ };
171
+ }
172
+ export function renderAIReleaseBriefMarkdown(brief) {
173
+ const lines = [
174
+ "# Gorsee AI Release Brief",
175
+ "",
176
+ `Schema: ${brief.schemaVersion}`,
177
+ "",
178
+ `Generated: ${brief.generatedAt}`,
179
+ "",
180
+ `Verdict: ${brief.verdict}`,
181
+ "",
182
+ brief.headline
183
+ ];
184
+ if (brief.release) {
185
+ lines.push("", "## Release", "");
186
+ lines.push(`- Mode: ${brief.release.appMode}`);
187
+ lines.push(`- Runtime: ${brief.release.runtimeKind}`);
188
+ lines.push(`- Routes: ${brief.release.routeCount}`);
189
+ lines.push(`- Client assets: ${brief.release.clientAssetCount}`);
190
+ lines.push(`- Server entries: ${brief.release.serverEntryCount}`);
191
+ }
192
+ lines.push("", "## Readiness", "");
193
+ lines.push(`- Deploy: ${brief.readiness.deploy.status}`);
194
+ lines.push(`- Scaling: ${brief.readiness.scaling.status}`);
195
+ if (brief.blockers.length > 0) {
196
+ lines.push("", "## Blockers", "");
197
+ for (const blocker of brief.blockers)
198
+ lines.push(`- ${blocker}`);
199
+ }
200
+ if (brief.cautions.length > 0) {
201
+ lines.push("", "## Cautions", "");
202
+ for (const caution of brief.cautions)
203
+ lines.push(`- ${caution}`);
204
+ }
205
+ if (brief.recommendations.length > 0) {
206
+ lines.push("", "## Recommendations", "");
207
+ for (const recommendation of brief.recommendations.slice(0, 5))
208
+ lines.push(`- ${recommendation}`);
209
+ }
210
+ return lines.join(`
211
+ `);
212
+ }
213
+ export function createAIIncidentBrief(packet) {
214
+ const severity = packet.summary.errors > 0 ? packet.incidentClusters.length > 0 && packet.incidentClusters[0].count > 1 ? "critical" : "high" : packet.summary.warnings > 0 ? "medium" : "low";
215
+ return {
216
+ schemaVersion: GORSEE_AI_CONTEXT_SCHEMA_VERSION,
217
+ generatedAt: new Date().toISOString(),
218
+ app: packet.app,
219
+ release: packet.release,
220
+ readiness: packet.readiness,
221
+ severity,
222
+ headline: packet.recentIncidents[0]?.message ?? packet.summary.headline,
223
+ incidents: packet.recentIncidents,
224
+ clusters: packet.incidentClusters,
225
+ artifactRegressions: packet.artifactRegressions,
226
+ recommendations: packet.recommendations
227
+ };
228
+ }
229
+ export function renderAIIncidentBriefMarkdown(brief) {
230
+ const lines = [
231
+ "# Gorsee AI Incident Brief",
232
+ "",
233
+ `Schema: ${brief.schemaVersion}`,
234
+ "",
235
+ `Generated: ${brief.generatedAt}`,
236
+ "",
237
+ `Severity: ${brief.severity}`,
238
+ "",
239
+ brief.headline
240
+ ];
241
+ if (brief.release) {
242
+ lines.push("", "## Release Context", "");
243
+ lines.push(`- Mode: ${brief.release.appMode}`);
244
+ lines.push(`- Runtime: ${brief.release.runtimeKind}`);
245
+ }
246
+ if (brief.incidents.length > 0) {
247
+ lines.push("", "## Incidents", "");
248
+ for (const incident of brief.incidents.slice(0, 5)) {
249
+ const loc = incident.file ? ` (${incident.file}${incident.line ? `:${incident.line}` : ""})` : incident.route ? ` (${incident.route})` : "";
250
+ lines.push(`- [${incident.kind}] ${incident.message}${loc}`);
251
+ }
252
+ }
253
+ if (brief.clusters.length > 0) {
254
+ lines.push("", "## Clusters", "");
255
+ for (const cluster of brief.clusters.slice(0, 5))
256
+ lines.push(`- ${cluster.kind} \xD7 ${cluster.count}`);
257
+ }
258
+ if (brief.recommendations.length > 0) {
259
+ lines.push("", "## Recommendations", "");
260
+ for (const recommendation of brief.recommendations.slice(0, 5))
261
+ lines.push(`- ${recommendation}`);
262
+ }
263
+ return lines.join(`
264
+ `);
265
+ }
266
+ export function createAIDeploySummary(packet) {
267
+ const status = packet.readiness.deploy.status === "blocked" ? "blocked" : packet.readiness.deploy.status === "caution" || packet.readiness.scaling.status === "caution" || packet.readiness.scaling.status === "blocked" ? "review" : "ready";
268
+ return {
269
+ schemaVersion: GORSEE_AI_CONTEXT_SCHEMA_VERSION,
270
+ generatedAt: new Date().toISOString(),
271
+ app: packet.app,
272
+ release: packet.release,
273
+ readiness: packet.readiness,
274
+ status,
275
+ headline: status === "blocked" ? "Deploy promotion is currently blocked by release or diagnostics signals." : status === "review" ? "Deploy promotion needs operator review before rollout." : "Deploy promotion looks ready from the current local artifact surface.",
276
+ processEntrypoints: packet.release?.processEntrypoints ?? [],
277
+ handlerEntrypoints: packet.release?.handlerEntrypoints ?? [],
278
+ workerEntrypoint: packet.release?.workerEntrypoint,
279
+ artifactRegressions: packet.artifactRegressions,
280
+ recommendations: packet.recommendations
281
+ };
282
+ }
283
+ export function renderAIDeploySummaryMarkdown(summary) {
284
+ const lines = [
285
+ "# Gorsee AI Deploy Summary",
286
+ "",
287
+ `Schema: ${summary.schemaVersion}`,
288
+ "",
289
+ `Generated: ${summary.generatedAt}`,
290
+ "",
291
+ `Status: ${summary.status}`,
292
+ "",
293
+ summary.headline
294
+ ];
295
+ if (summary.app) {
296
+ lines.push("", "## App Context", "");
297
+ lines.push(`- Mode: ${summary.app.mode}`);
298
+ lines.push(`- Runtime topology: ${summary.app.runtimeTopology}`);
299
+ }
300
+ if (summary.release) {
301
+ lines.push("", "## Release Context", "");
302
+ lines.push(`- Mode: ${summary.release.appMode}`);
303
+ lines.push(`- Runtime: ${summary.release.runtimeKind}`);
304
+ lines.push(`- Routes: ${summary.release.routeCount}`);
305
+ lines.push(`- Client assets: ${summary.release.clientAssetCount}`);
306
+ lines.push(`- Prerendered pages: ${summary.release.prerenderedCount}`);
307
+ lines.push(`- Server entries: ${summary.release.serverEntryCount}`);
308
+ }
309
+ lines.push("", "## Entrypoints", "");
310
+ lines.push(`- Process: ${summary.processEntrypoints.length > 0 ? summary.processEntrypoints.join(", ") : "none"}`);
311
+ lines.push(`- Handlers: ${summary.handlerEntrypoints.length > 0 ? summary.handlerEntrypoints.join(", ") : "none"}`);
312
+ lines.push(`- Worker: ${summary.workerEntrypoint ?? "none"}`);
313
+ lines.push("", "## Readiness", "");
314
+ lines.push(`- Deploy: ${summary.readiness.deploy.status}`);
315
+ lines.push(`- Scaling: ${summary.readiness.scaling.status}`);
316
+ if (summary.artifactRegressions.length > 0) {
317
+ lines.push("", "## Artifact Regressions", "");
318
+ for (const regression of summary.artifactRegressions.slice(0, 5)) {
319
+ const path = regression.path ? ` (${regression.path})` : "";
320
+ lines.push(`- ${regression.phase} ${regression.latestStatus}${path}`);
321
+ }
322
+ }
323
+ if (summary.recommendations.length > 0) {
324
+ lines.push("", "## Recommendations", "");
325
+ for (const recommendation of summary.recommendations.slice(0, 5))
326
+ lines.push(`- ${recommendation}`);
327
+ }
328
+ return lines.join(`
329
+ `);
330
+ }
331
+ export function createAIIncidentSnapshot(packet) {
332
+ const brief = createAIIncidentBrief(packet);
333
+ return {
334
+ schemaVersion: GORSEE_AI_CONTEXT_SCHEMA_VERSION,
335
+ generatedAt: new Date().toISOString(),
336
+ app: packet.app,
337
+ release: packet.release,
338
+ readiness: packet.readiness,
339
+ severity: brief.severity,
340
+ headline: brief.headline,
341
+ latestIncident: packet.recentIncidents[0],
342
+ incidentCount: packet.recentIncidents.length,
343
+ clusterCount: packet.incidentClusters.length,
344
+ clusters: packet.incidentClusters,
345
+ hotspots: packet.hotspots,
346
+ recommendations: packet.recommendations
347
+ };
348
+ }
349
+ export function renderAIIncidentSnapshotMarkdown(snapshot) {
350
+ const lines = [
351
+ "# Gorsee AI Incident Snapshot",
352
+ "",
353
+ `Schema: ${snapshot.schemaVersion}`,
354
+ "",
355
+ `Generated: ${snapshot.generatedAt}`,
356
+ "",
357
+ `Severity: ${snapshot.severity}`,
358
+ "",
359
+ snapshot.headline
360
+ ];
361
+ if (snapshot.app) {
362
+ lines.push("", "## App Context", "");
363
+ lines.push(`- Mode: ${snapshot.app.mode}`);
364
+ lines.push(`- Runtime topology: ${snapshot.app.runtimeTopology}`);
365
+ }
366
+ if (snapshot.release) {
367
+ lines.push("", "## Release Context", "");
368
+ lines.push(`- Mode: ${snapshot.release.appMode}`);
369
+ lines.push(`- Runtime: ${snapshot.release.runtimeKind}`);
370
+ }
371
+ lines.push("", "## Incident Overview", "");
372
+ lines.push(`- Incidents: ${snapshot.incidentCount}`);
373
+ lines.push(`- Clusters: ${snapshot.clusterCount}`);
374
+ if (snapshot.latestIncident)
375
+ lines.push(`- Latest: [${snapshot.latestIncident.kind}] ${snapshot.latestIncident.message}`);
376
+ if (snapshot.clusters.length > 0) {
377
+ lines.push("", "## Clusters", "");
378
+ for (const cluster of snapshot.clusters.slice(0, 5))
379
+ lines.push(`- ${cluster.kind} \xD7 ${cluster.count}`);
380
+ }
381
+ if (snapshot.hotspots.length > 0) {
382
+ lines.push("", "## Hotspots", "");
383
+ for (const hotspot of snapshot.hotspots.slice(0, 5))
384
+ lines.push(`- ${hotspot.kind}: ${hotspot.key} \xD7 ${hotspot.count}`);
385
+ }
386
+ if (snapshot.recommendations.length > 0) {
387
+ lines.push("", "## Recommendations", "");
388
+ for (const recommendation of snapshot.recommendations.slice(0, 5))
389
+ lines.push(`- ${recommendation}`);
390
+ }
391
+ return lines.join(`
392
+ `);
393
+ }
104
394
  function buildHeadline(report) {
395
+ const readiness = report.readiness ?? {
396
+ deploy: { status: "ready", reasons: [] },
397
+ scaling: { status: "not-applicable", reasons: [] }
398
+ };
105
399
  if (report.diagnostics.errors > 0)
106
400
  return "Project currently has AI-observed errors that need attention.";
401
+ if (readiness.deploy.status === "blocked")
402
+ return "Deploy readiness is currently blocked by release, diagnostic, or artifact signals.";
403
+ if (readiness.scaling.status === "blocked")
404
+ return "Scaling readiness is currently blocked by multi-instance or distributed-state signals.";
107
405
  if (report.diagnostics.warnings > 0)
108
406
  return "Project is stable but has warnings worth reviewing.";
407
+ if (report.release)
408
+ return `Release artifact is present for ${report.release.appMode} (${report.release.runtimeKind}).`;
109
409
  if (report.events.total === 0)
110
410
  return "AI observability is enabled but no events were collected yet.";
111
411
  return "Project looks healthy from the current AI event stream.";
@@ -129,7 +429,10 @@ function topEntries(source, kind) {
129
429
  return [...source.entries()].sort((a, b) => b[1] - a[1]).slice(0, 3).map(([key, count]) => ({ key, count, kind }));
130
430
  }
131
431
  function buildRecommendations(report, latestDiagnostic, events, reactiveTrace) {
132
- const recommendations = [], errorEvents = events.filter((event) => event.severity === "error"), requestErrors = events.filter((event) => event.kind === "request.error");
432
+ const recommendations = [], readiness = report.readiness ?? {
433
+ deploy: { status: "ready", reasons: [] },
434
+ scaling: { status: "not-applicable", reasons: [] }
435
+ }, errorEvents = events.filter((event) => event.severity === "error"), requestErrors = events.filter((event) => event.kind === "request.error");
133
436
  if (latestDiagnostic?.code)
134
437
  recommendations.push(`Investigate the latest diagnostic ${latestDiagnostic.code} before relying on this context in automation.`);
135
438
  if (requestErrors.length > 0)
@@ -140,6 +443,12 @@ function buildRecommendations(report, latestDiagnostic, events, reactiveTrace) {
140
443
  recommendations.push("Run `gorsee ai doctor` after the next build to verify whether build-phase errors persist.");
141
444
  if (report.artifactRegressions.length > 0)
142
445
  recommendations.push("Review artifact regressions before shipping; release/deploy/build artifacts have recorded failures or warnings.");
446
+ if (report.release)
447
+ recommendations.push(`Validate dist/release.json before promotion; current runtime kind is ${report.release.runtimeKind}.`);
448
+ if (readiness.deploy.status !== "ready")
449
+ recommendations.push(`Deploy readiness is ${readiness.deploy.status}; resolve the reported release/artifact issues before promotion.`);
450
+ if (readiness.scaling.status === "blocked" || readiness.scaling.status === "caution")
451
+ recommendations.push(`Scaling readiness is ${readiness.scaling.status}; review runtime.topology and distributed-state signals before horizontal rollout.`);
143
452
  if (reactiveTrace && reactiveTrace.events.length > 0)
144
453
  recommendations.push("Reactive trace data is available; inspect dependency edges and invalidation events before changing resource or mutation behavior.");
145
454
  if (recommendations.length === 0)
@@ -1,3 +1,5 @@
1
1
  import type { Route } from "../router/scanner.js";
2
- import { type BuildManifest } from "../server/manifest.js";
3
- export declare function createBuildManifest(routes: Route[], entryMap: Map<string, string>, hashMap: Map<string, string>, prerenderedPaths?: Iterable<string>): Promise<BuildManifest>;
2
+ import { type BuildManifest, type ReleaseArtifact } from "../server/manifest.js";
3
+ import type { AppMode } from "../runtime/app-config.js";
4
+ export declare function createBuildManifest(routes: Route[], entryMap: Map<string, string>, hashMap: Map<string, string>, prerenderedPaths?: Iterable<string>, appMode?: AppMode): Promise<BuildManifest>;
5
+ export declare function createReleaseArtifact(manifest: BuildManifest, clientAssets: Iterable<string>, serverEntries: Iterable<string>): ReleaseArtifact;
@@ -1,8 +1,12 @@
1
1
  import { inspectRouteBuildMetadata } from "./route-metadata.js";
2
- import { BUILD_MANIFEST_SCHEMA_VERSION } from "../server/manifest.js";
3
- export async function createBuildManifest(routes, entryMap, hashMap, prerenderedPaths = []) {
2
+ import {
3
+ BUILD_MANIFEST_SCHEMA_VERSION,
4
+ RELEASE_ARTIFACT_SCHEMA_VERSION
5
+ } from "../server/manifest.js";
6
+ export async function createBuildManifest(routes, entryMap, hashMap, prerenderedPaths = [], appMode = "fullstack") {
4
7
  const prerendered = new Set(prerenderedPaths), manifest = {
5
8
  schemaVersion: BUILD_MANIFEST_SCHEMA_VERSION,
9
+ appMode,
6
10
  routes: {},
7
11
  chunks: [],
8
12
  prerendered: [...prerendered],
@@ -21,3 +25,29 @@ export async function createBuildManifest(routes, entryMap, hashMap, prerendered
21
25
  manifest.chunks.push(hashed);
22
26
  return manifest;
23
27
  }
28
+ export function createReleaseArtifact(manifest, clientAssets, serverEntries) {
29
+ const clientAssetList = [...clientAssets].sort(), serverEntryList = [...serverEntries].sort(), prerenderedHtml = manifest.prerendered.map((pathname) => pathname === "/" ? "static/index.html" : `static/${pathname.slice(1)}/index.html`).sort(), processEntrypoints = serverEntryList.filter((entry) => entry === "prod.js" || entry === "prod-node.js"), handlerEntrypoints = serverEntryList.filter((entry) => entry === "server-handler.js" || entry === "server-handler-node.js"), workerEntrypoint = serverEntryList.includes("worker.js") ? "worker.js" : void 0;
30
+ return {
31
+ schemaVersion: RELEASE_ARTIFACT_SCHEMA_VERSION,
32
+ appMode: manifest.appMode ?? "fullstack",
33
+ generatedAt: manifest.buildTime,
34
+ summary: {
35
+ routeCount: Object.keys(manifest.routes).length,
36
+ clientAssetCount: clientAssetList.length,
37
+ prerenderedCount: manifest.prerendered.length,
38
+ serverEntryCount: serverEntryList.length
39
+ },
40
+ runtime: {
41
+ kind: manifest.appMode === "frontend" ? "frontend-static" : manifest.appMode === "server" ? "server-runtime" : "fullstack-runtime",
42
+ processEntrypoints,
43
+ handlerEntrypoints,
44
+ workerEntrypoint
45
+ },
46
+ artifacts: {
47
+ buildManifest: "manifest.json",
48
+ clientAssets: clientAssetList,
49
+ serverEntries: serverEntryList,
50
+ prerenderedHtml
51
+ }
52
+ };
53
+ }
@@ -7,14 +7,18 @@ import {
7
7
  createIDEProjectionWatcher,
8
8
  createAIBridgeServer,
9
9
  createAIContextPacket,
10
+ createAIIncidentBrief,
11
+ createAIReleaseBrief,
10
12
  createAIMCPServer,
11
13
  createLineReader,
12
14
  readAIDiagnosticsSnapshot,
13
15
  readAIEvents,
14
16
  readReactiveTraceArtifact,
17
+ renderAIIncidentBriefMarkdown,
15
18
  renderAIContextMarkdown,
16
19
  renderAIContextBundleMarkdown,
17
20
  renderAIFrameworkMarkdown,
21
+ renderAIReleaseBriefMarkdown,
18
22
  resolveAIStorePaths,
19
23
  resolveAISessionPackPaths,
20
24
  resolveIDEProjectionPaths,
@@ -97,8 +101,22 @@ async function runAIDoctor(paths, flags) {
97
101
  console.log(` Diagnostics: ${report.diagnostics.total}`);
98
102
  console.log(` Errors: ${report.diagnostics.errors}`);
99
103
  console.log(` Warnings: ${report.diagnostics.warnings}`);
104
+ console.log(` Deploy readiness: ${report.readiness.deploy.status}`);
105
+ console.log(` Scaling readiness: ${report.readiness.scaling.status}`);
100
106
  if (report.events.latest)
101
107
  console.log(` Latest event: ${report.events.latest.kind} @ ${report.events.latest.ts}`);
108
+ if (report.release) {
109
+ console.log(`
110
+ Release artifact:`);
111
+ console.log(` - mode=${report.release.appMode} runtime=${report.release.runtimeKind}`);
112
+ console.log(` - routes=${report.release.summary.routeCount} clientAssets=${report.release.summary.clientAssetCount} prerendered=${report.release.summary.prerenderedCount} serverEntries=${report.release.summary.serverEntryCount}`);
113
+ if (report.release.processEntrypoints.length > 0)
114
+ console.log(` - process=${report.release.processEntrypoints.join(", ")}`);
115
+ if (report.release.handlerEntrypoints.length > 0)
116
+ console.log(` - handlers=${report.release.handlerEntrypoints.join(", ")}`);
117
+ if (report.release.workerEntrypoint)
118
+ console.log(` - worker=${report.release.workerEntrypoint}`);
119
+ }
102
120
  if (report.diagnostics.latest?.code)
103
121
  console.log(` Latest diagnostic: ${report.diagnostics.latest.code} ${report.diagnostics.latest.message ?? ""}`.trim());
104
122
  if (report.incidents.length > 0) {
@@ -125,6 +143,14 @@ async function runAIDoctor(paths, flags) {
125
143
  console.log(` - [${artifact.phase}] errors=${artifact.errors} warnings=${artifact.warnings} successes=${artifact.successes}${details ? ` (${details})` : ""}`);
126
144
  }
127
145
  }
146
+ if (report.readiness.deploy.reasons.length > 0 || report.readiness.scaling.reasons.length > 0) {
147
+ console.log(`
148
+ Readiness reasons:`);
149
+ for (const reason of report.readiness.deploy.reasons.slice(0, 3))
150
+ console.log(` - deploy: ${reason}`);
151
+ for (const reason of report.readiness.scaling.reasons.slice(0, 3))
152
+ console.log(` - scaling: ${reason}`);
153
+ }
128
154
  if (reactiveTrace) {
129
155
  console.log(`
130
156
  Reactive trace:`);
@@ -169,6 +195,24 @@ async function runAIExport(cwd, paths, flags) {
169
195
  return;
170
196
  }
171
197
  const events = await readAIEvents(paths.eventsPath, { limit: flags.limit ?? 200 }), diagnostics = await readAIDiagnosticsSnapshot(paths.diagnosticsPath), reactiveTrace = await readReactiveTraceArtifact(paths.reactiveTracePath), report = await buildAIHealthReport(paths, { limit: flags.limit ?? 200 }), packet = createAIContextPacket(report, events, diagnostics?.latest, reactiveTrace);
198
+ if (flags.brief === "release") {
199
+ const brief = createAIReleaseBrief(packet);
200
+ if ((flags.format ?? "json") === "markdown") {
201
+ console.log(renderAIReleaseBriefMarkdown(brief));
202
+ return;
203
+ }
204
+ console.log(JSON.stringify(brief, null, 2));
205
+ return;
206
+ }
207
+ if (flags.brief === "incident") {
208
+ const brief = createAIIncidentBrief(packet);
209
+ if ((flags.format ?? "json") === "markdown") {
210
+ console.log(renderAIIncidentBriefMarkdown(brief));
211
+ return;
212
+ }
213
+ console.log(JSON.stringify(brief, null, 2));
214
+ return;
215
+ }
172
216
  if ((flags.format ?? "json") === "markdown") {
173
217
  console.log(renderAIContextMarkdown(packet));
174
218
  return;
@@ -186,6 +230,14 @@ async function runAIPack(cwd, paths, flags) {
186
230
  generatedAt: result.bundle.generatedAt,
187
231
  latestJsonPath: result.paths.latestJsonPath,
188
232
  latestMarkdownPath: result.paths.latestMarkdownPath,
233
+ latestDeploySummaryJsonPath: result.paths.latestDeploySummaryJsonPath,
234
+ latestDeploySummaryMarkdownPath: result.paths.latestDeploySummaryMarkdownPath,
235
+ latestReleaseBriefJsonPath: result.paths.latestReleaseBriefJsonPath,
236
+ latestReleaseBriefMarkdownPath: result.paths.latestReleaseBriefMarkdownPath,
237
+ latestIncidentBriefJsonPath: result.paths.latestIncidentBriefJsonPath,
238
+ latestIncidentBriefMarkdownPath: result.paths.latestIncidentBriefMarkdownPath,
239
+ latestIncidentSnapshotJsonPath: result.paths.latestIncidentSnapshotJsonPath,
240
+ latestIncidentSnapshotMarkdownPath: result.paths.latestIncidentSnapshotMarkdownPath,
189
241
  historyDir: result.paths.historyDir,
190
242
  snippets: result.bundle.snippets.length
191
243
  }, null, 2));
@@ -196,6 +248,14 @@ async function runAIPack(cwd, paths, flags) {
196
248
  `);
197
249
  console.log(` latest json -> ${result.paths.latestJsonPath}`);
198
250
  console.log(` latest md -> ${result.paths.latestMarkdownPath}`);
251
+ console.log(` deploy -> ${result.paths.latestDeploySummaryJsonPath}`);
252
+ console.log(` deploy md -> ${result.paths.latestDeploySummaryMarkdownPath}`);
253
+ console.log(` release -> ${result.paths.latestReleaseBriefJsonPath}`);
254
+ console.log(` release md -> ${result.paths.latestReleaseBriefMarkdownPath}`);
255
+ console.log(` incident -> ${result.paths.latestIncidentBriefJsonPath}`);
256
+ console.log(` incident md -> ${result.paths.latestIncidentBriefMarkdownPath}`);
257
+ console.log(` snapshot -> ${result.paths.latestIncidentSnapshotJsonPath}`);
258
+ console.log(` snapshot md -> ${result.paths.latestIncidentSnapshotMarkdownPath}`);
199
259
  console.log(` history -> ${result.paths.historyDir}`);
200
260
  console.log(` snippets -> ${result.bundle.snippets.length}`);
201
261
  console.log();
@@ -274,6 +334,11 @@ function parseAIFlags(args) {
274
334
  if (format === "json" || format === "markdown")
275
335
  flags.format = format;
276
336
  }
337
+ if (arg === "--brief") {
338
+ const brief = args[i + 1];
339
+ if (brief === "release" || brief === "incident")
340
+ flags.brief = brief;
341
+ }
277
342
  }
278
343
  return flags;
279
344
  }
@@ -287,6 +352,7 @@ function printAIHelp() {
287
352
  console.log(" doctor Summarize diagnostics and recent incidents");
288
353
  console.log(" replay Replay correlated AI events in timeline order");
289
354
  console.log(" export Export a compact AI context packet or bundle");
355
+ console.log(" Use --brief release|incident for verdict-oriented summaries");
290
356
  console.log(" pack Write the latest agent-ready session pack to disk");
291
357
  console.log(" ide-sync Write IDE-friendly diagnostics/events/context files");
292
358
  console.log(" bridge Start local HTTP bridge for IDE/agent ingestion");