gorsee 0.2.11 → 0.2.12
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/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 +1 -1
package/README.md
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
# Gorsee.js
|
|
2
2
|
|
|
3
|
-
AI-first reactive full-stack TypeScript framework for deterministic collaboration between humans and coding agents.
|
|
3
|
+
AI-first reactive full-stack TypeScript framework and application platform for deterministic collaboration between humans and coding agents across frontend, fullstack, and server systems.
|
|
4
4
|
|
|
5
|
-
Gorsee is not a pet project, not a research toy, and not a bundle of optional recipes. It is a product-grade
|
|
5
|
+
Gorsee is not a pet project, not a research toy, and not a bundle of optional recipes. It is a product-grade platform with strict runtime contracts, built-in security boundaries, fine-grained reactivity, and AI-native developer tooling.
|
|
6
6
|
|
|
7
7
|
## Product Direction
|
|
8
8
|
|
|
9
9
|
Gorsee is built around four non-negotiable product goals:
|
|
10
10
|
|
|
11
|
-
- AI-first development: the
|
|
11
|
+
- AI-first development: the platform must be predictable for coding agents, not only ergonomic for humans.
|
|
12
12
|
- Deterministic architecture: one clear way beats many inconsistent ways.
|
|
13
13
|
- Reactive execution: fine-grained reactivity, islands, and minimal client JavaScript over VDOM-heavy legacy models.
|
|
14
14
|
- Built-in guarantees: auth, request policy, cache boundaries, diagnostics, and deploy contracts are framework properties, not scattered ecosystem recipes.
|
|
@@ -17,6 +17,7 @@ Read the strategic docs:
|
|
|
17
17
|
|
|
18
18
|
- [Product Vision](./docs/PRODUCT_VISION.md)
|
|
19
19
|
- [Framework Doctrine](./docs/FRAMEWORK_DOCTRINE.md)
|
|
20
|
+
- [Application Modes](./docs/APPLICATION_MODES.md)
|
|
20
21
|
- [Security Model](./docs/SECURITY_MODEL.md)
|
|
21
22
|
- [Top-Tier Roadmap](./docs/TOP_TIER_ROADMAP.md)
|
|
22
23
|
- [Canonical Language Plan](./docs/CANONICAL_LANGUAGE_PLAN.md)
|
|
@@ -77,6 +78,33 @@ Read the strategic docs:
|
|
|
77
78
|
- [Evidence Policy](./docs/EVIDENCE_POLICY.md)
|
|
78
79
|
- [Roadmap Completion Policy](./docs/ROADMAP_COMPLETION_POLICY.md)
|
|
79
80
|
|
|
81
|
+
## Canonical Modes
|
|
82
|
+
|
|
83
|
+
Gorsee ships one product with three canonical application modes:
|
|
84
|
+
|
|
85
|
+
- `frontend` for browser-first prerendered apps deployed to static-capable targets
|
|
86
|
+
- `fullstack` for the canonical Gorsee route/runtime model across UI + server execution
|
|
87
|
+
- `server` for API-first and service-oriented systems without mandatory browser surfaces
|
|
88
|
+
|
|
89
|
+
Set the mode explicitly in `app.config.ts`:
|
|
90
|
+
|
|
91
|
+
```ts
|
|
92
|
+
export default {
|
|
93
|
+
app: {
|
|
94
|
+
mode: "fullstack",
|
|
95
|
+
},
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
`fullstack` remains the default when `app.mode` is omitted.
|
|
100
|
+
|
|
101
|
+
High-level mode guidance:
|
|
102
|
+
|
|
103
|
+
- `frontend` builds browser-first prerendered output and should prefer static-capable deploy targets.
|
|
104
|
+
- `fullstack` keeps the canonical Gorsee route/runtime model and can target Bun, Node, or worker-style deploy adapters.
|
|
105
|
+
- `server` focuses on API-first and service-oriented systems with process/runtime ownership kept explicit.
|
|
106
|
+
- `server` mode should prefer `gorsee worker` for canonical long-running worker and service entry execution.
|
|
107
|
+
|
|
80
108
|
## Quick Start
|
|
81
109
|
|
|
82
110
|
```bash
|
|
@@ -86,6 +114,22 @@ bun install
|
|
|
86
114
|
bun run dev
|
|
87
115
|
```
|
|
88
116
|
|
|
117
|
+
Worker-first server path:
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
bunx gorsee create my-service --template worker-service
|
|
121
|
+
cd my-service
|
|
122
|
+
bun install
|
|
123
|
+
bun run worker
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Canonical worker CLI path for server-mode apps:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
gorsee worker
|
|
130
|
+
gorsee worker --entry workers/custom.ts
|
|
131
|
+
```
|
|
132
|
+
|
|
89
133
|
Alternative bootstrap paths:
|
|
90
134
|
|
|
91
135
|
```bash
|
|
@@ -238,21 +282,25 @@ const userRoute = createTypedRoute("/users/[id]")
|
|
|
238
282
|
|
|
239
283
|
## Starter Templates
|
|
240
284
|
|
|
241
|
-
`gorsee create` ships with
|
|
285
|
+
`gorsee create` ships with canonical starters for each official mode:
|
|
242
286
|
|
|
287
|
+
- `frontend` for browser-first prerendered apps
|
|
243
288
|
- `basic` for the minimal canonical scaffold
|
|
244
289
|
- `secure-saas` for authenticated SaaS apps with protected route groups
|
|
245
290
|
- `content-site` for public content and marketing sites
|
|
246
291
|
- `agent-aware-ops` for internal tools with AI-first workflows enabled
|
|
247
292
|
- `workspace-monorepo` for workspace layouts with one app package and one shared package
|
|
293
|
+
- `server-api` for API-first and service-oriented server apps
|
|
248
294
|
|
|
249
295
|
Examples:
|
|
250
296
|
|
|
251
297
|
```bash
|
|
298
|
+
bunx gorsee create my-frontend --template frontend
|
|
252
299
|
bunx gorsee create my-saas --template secure-saas
|
|
253
300
|
bunx gorsee create my-site --template content-site
|
|
254
301
|
bunx gorsee create my-ops --template agent-aware-ops
|
|
255
302
|
bunx gorsee create my-workspace --template workspace-monorepo
|
|
303
|
+
bunx gorsee create my-service --template server-api
|
|
256
304
|
npx create-gorsee my-app
|
|
257
305
|
npm create gorsee@latest my-app
|
|
258
306
|
```
|
package/dist-pkg/ai/bundle.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type AppMode } from "../runtime/app-config.js";
|
|
1
2
|
export interface AIFrameworkDocRef {
|
|
2
3
|
path: string;
|
|
3
4
|
purpose: string;
|
|
@@ -8,6 +9,7 @@ export interface AIFrameworkPacket {
|
|
|
8
9
|
generatedAt: string;
|
|
9
10
|
cwd: string;
|
|
10
11
|
projectName: string;
|
|
12
|
+
appMode: AppMode;
|
|
11
13
|
product: {
|
|
12
14
|
name: "Gorsee";
|
|
13
15
|
version?: string;
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { access, readFile } from "node:fs/promises";
|
|
2
2
|
import { basename, join, relative } from "node:path";
|
|
3
3
|
import { generateFrameworkMD } from "../cli/framework-md.js";
|
|
4
|
+
import { loadAppConfig, resolveAppMode } from "../runtime/app-config.js";
|
|
4
5
|
const LOCAL_DOCS = [
|
|
5
6
|
{ 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
7
|
{ 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
8
|
{ 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
9
|
], CANONICAL_DOCS = [
|
|
9
10
|
{ 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" },
|
|
11
|
+
{ path: "docs/APPLICATION_MODES.md", purpose: "\u041A\u0430\u043D\u043E\u043D\u0438\u0447\u0435\u0441\u043A\u0438\u0435 \u0440\u0435\u0436\u0438\u043C\u044B frontend/fullstack/server \u0438 \u0433\u0440\u0430\u043D\u0438\u0446\u044B \u043C\u0435\u0436\u0434\u0443 \u043D\u0438\u043C\u0438" },
|
|
10
12
|
{ 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
13
|
{ path: "docs/SECURITY_MODEL.md", purpose: "Runtime/security guarantees \u0438 fail-closed \u043C\u043E\u0434\u0435\u043B\u044C" },
|
|
12
14
|
{ path: "docs/AI_WORKFLOWS.md", purpose: "\u041A\u0430\u043D\u043E\u043D\u0438\u0447\u0435\u0441\u043A\u0438\u0439 human+agent workflow" },
|
|
@@ -68,13 +70,14 @@ function renderDocLines(docs) {
|
|
|
68
70
|
return docs.map((doc) => `- \`${doc.path}\` -- ${doc.purpose}`);
|
|
69
71
|
}
|
|
70
72
|
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);
|
|
73
|
+
const projectName = await resolveProjectName(cwd), appMode = resolveAppMode(await loadAppConfig(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
74
|
return {
|
|
73
75
|
kind: "gorsee.framework",
|
|
74
76
|
schemaVersion: 1,
|
|
75
77
|
generatedAt: new Date().toISOString(),
|
|
76
78
|
cwd,
|
|
77
79
|
projectName,
|
|
80
|
+
appMode,
|
|
78
81
|
product: {
|
|
79
82
|
name: "Gorsee",
|
|
80
83
|
version: await resolveFrameworkVersion(),
|
|
@@ -108,6 +111,7 @@ export async function buildAIFrameworkPacket(cwd) {
|
|
|
108
111
|
recommendedStart: [
|
|
109
112
|
"Read AGENTS.md first when it exists.",
|
|
110
113
|
"Read FRAMEWORK.md for the current app shape and syntax.",
|
|
114
|
+
`Respect the current app.mode contract: ${appMode}.`,
|
|
111
115
|
"Use gorsee/client for browser-safe code and gorsee/server for runtime/server boundaries.",
|
|
112
116
|
"Prefer scoped stable subpaths when auth, db, security, forms, routes, ai, or log is the primary concern.",
|
|
113
117
|
"Use gorsee ai export --bundle for incident/debug context, not for framework cold-start context."
|
|
@@ -122,6 +126,7 @@ export function renderAIFrameworkMarkdown(packet) {
|
|
|
122
126
|
"",
|
|
123
127
|
`Generated: ${packet.generatedAt}`,
|
|
124
128
|
`Project: ${packet.projectName}`,
|
|
129
|
+
`App Mode: ${packet.appMode}`,
|
|
125
130
|
packet.product.version ? `Framework Version: ${packet.product.version}` : void 0,
|
|
126
131
|
"",
|
|
127
132
|
"## Product",
|
package/dist-pkg/ai/ide.d.ts
CHANGED
package/dist-pkg/ai/ide.js
CHANGED
|
@@ -16,6 +16,7 @@ export async function buildIDEProjection(storePaths, options = {}) {
|
|
|
16
16
|
return {
|
|
17
17
|
schemaVersion: GORSEE_AI_CONTEXT_SCHEMA_VERSION,
|
|
18
18
|
updatedAt: new Date().toISOString(),
|
|
19
|
+
app: context.app,
|
|
19
20
|
diagnostics: diagnosticsSnapshot?.latest ? [{
|
|
20
21
|
code: diagnosticsSnapshot.latest.code,
|
|
21
22
|
message: diagnosticsSnapshot.latest.message ?? "",
|
|
@@ -44,11 +45,13 @@ export async function writeIDEProjection(projectionPaths, projection) {
|
|
|
44
45
|
await writeFile(projectionPaths.diagnosticsPath, JSON.stringify({
|
|
45
46
|
schemaVersion: projection.schemaVersion,
|
|
46
47
|
updatedAt: projection.updatedAt,
|
|
48
|
+
app: projection.app,
|
|
47
49
|
diagnostics: projection.diagnostics
|
|
48
50
|
}, null, 2), "utf-8");
|
|
49
51
|
await writeFile(projectionPaths.eventsPath, JSON.stringify({
|
|
50
52
|
schemaVersion: projection.schemaVersion,
|
|
51
53
|
updatedAt: projection.updatedAt,
|
|
54
|
+
app: projection.app,
|
|
52
55
|
events: projection.recentEvents,
|
|
53
56
|
artifactRegressions: projection.artifactRegressions
|
|
54
57
|
}, null, 2), "utf-8");
|
package/dist-pkg/ai/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ export { writeArtifactFailurePack, writeArtifactLifecycleEvent, writeArtifactSuc
|
|
|
4
4
|
export { createAIBridgeHandler, createAIBridgeServer, type AIBridgeHandler, type AIBridgeServer, type AIBridgeServerOptions, type AIBridgeSnapshot, } from "./bridge.js";
|
|
5
5
|
export { buildAIHealthReport, readAIDiagnosticsSnapshot, readReactiveTraceArtifact, readAIEvents, resolveAIStorePaths, type AIHealthReport, type AIStorePaths, } from "./store.js";
|
|
6
6
|
export { createAIMCPServer, createLineReader, type AIMCPServerOptions, } from "./mcp.js";
|
|
7
|
-
export { createAIContextPacket, renderAIContextMarkdown, type AIContextPacket, } from "./summary.js";
|
|
7
|
+
export { createAIContextPacket, createAIDeploySummary, createAIIncidentBrief, createAIIncidentSnapshot, createAIReleaseBrief, renderAIDeploySummaryMarkdown, renderAIIncidentBriefMarkdown, renderAIIncidentSnapshotMarkdown, renderAIContextMarkdown, renderAIReleaseBriefMarkdown, type AIContextPacket, type AIDeploySummary, type AIIncidentBrief, type AIIncidentSnapshot, type AIReleaseBrief, } from "./summary.js";
|
|
8
8
|
export { buildAIContextBundle, renderAIContextBundleMarkdown, type AIContextBundle, type AIContextSnippet, } from "./bundle.js";
|
|
9
9
|
export { buildAIFrameworkPacket, renderAIFrameworkMarkdown, type AIFrameworkDocRef, type AIFrameworkPacket, } from "./framework-context.js";
|
|
10
10
|
export { buildIDEProjection, resolveIDEProjectionPaths, writeIDEProjection, type IDEProjection, type IDEProjectionPaths, } from "./ide.js";
|
|
@@ -12,6 +12,12 @@ export { createIDEProjectionWatcher, type IDEProjectionWatcher, type IDEProjecti
|
|
|
12
12
|
export { resolveAISessionPackConfig, resolveAISessionPackPaths, shouldGenerateAISessionPack, writeAISessionPack, type AISessionPackConfig, type AISessionPackPaths, } from "./session-pack.js";
|
|
13
13
|
export type AIEventSeverity = "debug" | "info" | "warn" | "error";
|
|
14
14
|
export type AIEventSource = "runtime" | "build" | "cli" | "check" | "deploy" | "dev" | "log";
|
|
15
|
+
export type AIAppMode = "frontend" | "fullstack" | "server";
|
|
16
|
+
export type AIRuntimeTopology = "single-instance" | "multi-instance";
|
|
17
|
+
export interface AIAppContext {
|
|
18
|
+
mode: AIAppMode;
|
|
19
|
+
runtimeTopology: AIRuntimeTopology;
|
|
20
|
+
}
|
|
15
21
|
export interface AITraceContext {
|
|
16
22
|
requestId?: string;
|
|
17
23
|
traceId: string;
|
|
@@ -28,6 +34,7 @@ export interface AIDiagnostic {
|
|
|
28
34
|
route?: string;
|
|
29
35
|
fix?: string;
|
|
30
36
|
ts: string;
|
|
37
|
+
app?: AIAppContext;
|
|
31
38
|
}
|
|
32
39
|
export interface AIEvent {
|
|
33
40
|
id: string;
|
|
@@ -48,6 +55,7 @@ export interface AIEvent {
|
|
|
48
55
|
line?: number;
|
|
49
56
|
tags?: string[];
|
|
50
57
|
data?: Record<string, unknown>;
|
|
58
|
+
app?: AIAppContext;
|
|
51
59
|
}
|
|
52
60
|
export interface AIBridgeConfig {
|
|
53
61
|
url: string;
|
|
@@ -63,6 +71,7 @@ export interface AIObservabilityConfig {
|
|
|
63
71
|
sessionId?: string;
|
|
64
72
|
bridge?: AIBridgeConfig;
|
|
65
73
|
sessionPack?: AISessionPackConfig;
|
|
74
|
+
app?: AIAppContext;
|
|
66
75
|
}
|
|
67
76
|
export declare function configureAIObservability(config?: AIObservabilityConfig): void;
|
|
68
77
|
export declare function getAIObservabilityConfig(): AIObservabilityConfig;
|
package/dist-pkg/ai/index.js
CHANGED
|
@@ -31,7 +31,15 @@ export {
|
|
|
31
31
|
} from "./mcp.js";
|
|
32
32
|
export {
|
|
33
33
|
createAIContextPacket,
|
|
34
|
-
|
|
34
|
+
createAIDeploySummary,
|
|
35
|
+
createAIIncidentBrief,
|
|
36
|
+
createAIIncidentSnapshot,
|
|
37
|
+
createAIReleaseBrief,
|
|
38
|
+
renderAIDeploySummaryMarkdown,
|
|
39
|
+
renderAIIncidentBriefMarkdown,
|
|
40
|
+
renderAIIncidentSnapshotMarkdown,
|
|
41
|
+
renderAIContextMarkdown,
|
|
42
|
+
renderAIReleaseBriefMarkdown
|
|
35
43
|
} from "./summary.js";
|
|
36
44
|
export {
|
|
37
45
|
buildAIContextBundle,
|
|
@@ -88,6 +96,7 @@ export async function emitAIEvent(input) {
|
|
|
88
96
|
id: input.id ?? crypto.randomUUID(),
|
|
89
97
|
ts: input.ts ?? new Date().toISOString(),
|
|
90
98
|
...input,
|
|
99
|
+
app: input.app ?? currentConfig.app,
|
|
91
100
|
data: redactValue(input.data, currentConfig.redactKeys ?? DEFAULT_REDACT_KEYS)
|
|
92
101
|
}, writes = [];
|
|
93
102
|
if (currentConfig.jsonlPath)
|
|
@@ -194,6 +203,7 @@ async function writeDiagnosticsSnapshot(path, event) {
|
|
|
194
203
|
const snapshot = {
|
|
195
204
|
updatedAt: event.ts,
|
|
196
205
|
sessionId: currentConfig.sessionId,
|
|
206
|
+
app: event.app,
|
|
197
207
|
latest: {
|
|
198
208
|
code: event.code,
|
|
199
209
|
message: event.message,
|
|
@@ -204,7 +214,8 @@ async function writeDiagnosticsSnapshot(path, event) {
|
|
|
204
214
|
route: event.route,
|
|
205
215
|
requestId: event.requestId,
|
|
206
216
|
traceId: event.traceId,
|
|
207
|
-
spanId: event.spanId
|
|
217
|
+
spanId: event.spanId,
|
|
218
|
+
app: event.app
|
|
208
219
|
}
|
|
209
220
|
};
|
|
210
221
|
await mkdir(dirname(path), { recursive: !0 });
|
package/dist-pkg/ai/mcp.js
CHANGED
|
@@ -131,6 +131,10 @@ export function createLineReader(input) {
|
|
|
131
131
|
}
|
|
132
132
|
function renderDoctorText(report) {
|
|
133
133
|
const lines = [
|
|
134
|
+
...report.app ? [
|
|
135
|
+
`App mode: ${report.app.mode}`,
|
|
136
|
+
`Runtime topology: ${report.app.runtimeTopology}`
|
|
137
|
+
] : [],
|
|
134
138
|
`Events: ${report.events.total}`,
|
|
135
139
|
`Diagnostics: ${report.diagnostics.total}`,
|
|
136
140
|
`Errors: ${report.diagnostics.errors}`,
|
|
@@ -13,6 +13,14 @@ export interface AISessionPackPaths {
|
|
|
13
13
|
outDir: string;
|
|
14
14
|
latestJsonPath: string;
|
|
15
15
|
latestMarkdownPath: string;
|
|
16
|
+
latestReleaseBriefJsonPath: string;
|
|
17
|
+
latestReleaseBriefMarkdownPath: string;
|
|
18
|
+
latestIncidentBriefJsonPath: string;
|
|
19
|
+
latestIncidentBriefMarkdownPath: string;
|
|
20
|
+
latestDeploySummaryJsonPath: string;
|
|
21
|
+
latestDeploySummaryMarkdownPath: string;
|
|
22
|
+
latestIncidentSnapshotJsonPath: string;
|
|
23
|
+
latestIncidentSnapshotMarkdownPath: string;
|
|
16
24
|
historyDir: string;
|
|
17
25
|
}
|
|
18
26
|
export declare function resolveAISessionPackConfig(cwd: string, config?: AISessionPackConfig): AISessionPackConfig | undefined;
|
|
@@ -2,6 +2,16 @@ import { mkdir, writeFile } from "node:fs/promises";
|
|
|
2
2
|
import { isAbsolute, join } from "node:path";
|
|
3
3
|
import { buildAIContextBundle, renderAIContextBundleMarkdown } from "./bundle.js";
|
|
4
4
|
import { GORSEE_AI_CONTEXT_SCHEMA_VERSION } from "./contracts.js";
|
|
5
|
+
import {
|
|
6
|
+
createAIDeploySummary,
|
|
7
|
+
createAIIncidentBrief,
|
|
8
|
+
createAIIncidentSnapshot,
|
|
9
|
+
createAIReleaseBrief,
|
|
10
|
+
renderAIDeploySummaryMarkdown,
|
|
11
|
+
renderAIIncidentBriefMarkdown,
|
|
12
|
+
renderAIIncidentSnapshotMarkdown,
|
|
13
|
+
renderAIReleaseBriefMarkdown
|
|
14
|
+
} from "./summary.js";
|
|
5
15
|
export function resolveAISessionPackConfig(cwd, config) {
|
|
6
16
|
if (!config?.enabled)
|
|
7
17
|
return config;
|
|
@@ -21,6 +31,14 @@ export function resolveAISessionPackPaths(cwd, config) {
|
|
|
21
31
|
outDir,
|
|
22
32
|
latestJsonPath: join(outDir, "latest.json"),
|
|
23
33
|
latestMarkdownPath: join(outDir, "latest.md"),
|
|
34
|
+
latestReleaseBriefJsonPath: join(outDir, "release-brief.json"),
|
|
35
|
+
latestReleaseBriefMarkdownPath: join(outDir, "release-brief.md"),
|
|
36
|
+
latestIncidentBriefJsonPath: join(outDir, "incident-brief.json"),
|
|
37
|
+
latestIncidentBriefMarkdownPath: join(outDir, "incident-brief.md"),
|
|
38
|
+
latestDeploySummaryJsonPath: join(outDir, "deploy-summary.json"),
|
|
39
|
+
latestDeploySummaryMarkdownPath: join(outDir, "deploy-summary.md"),
|
|
40
|
+
latestIncidentSnapshotJsonPath: join(outDir, "incident-snapshot.json"),
|
|
41
|
+
latestIncidentSnapshotMarkdownPath: join(outDir, "incident-snapshot.md"),
|
|
24
42
|
historyDir: join(outDir, "history")
|
|
25
43
|
};
|
|
26
44
|
}
|
|
@@ -30,18 +48,50 @@ export async function writeAISessionPack(cwd, storePaths, config) {
|
|
|
30
48
|
maxSnippets: resolved.maxSnippets
|
|
31
49
|
});
|
|
32
50
|
await mkdir(paths.historyDir, { recursive: !0 });
|
|
33
|
-
const stamp = bundle.generatedAt.replace(/[:.]/g, "-"), json = JSON.stringify(bundle, null, 2), markdown = [
|
|
51
|
+
const stamp = bundle.generatedAt.replace(/[:.]/g, "-"), deploySummary = createAIDeploySummary(bundle.packet), releaseBrief = createAIReleaseBrief(bundle.packet), incidentBrief = createAIIncidentBrief(bundle.packet), incidentSnapshot = createAIIncidentSnapshot(bundle.packet), json = JSON.stringify(bundle, null, 2), markdown = [
|
|
34
52
|
`<!-- gorsee-ai-schema: ${GORSEE_AI_CONTEXT_SCHEMA_VERSION} -->`,
|
|
35
53
|
renderAIContextBundleMarkdown(bundle)
|
|
36
54
|
].join(`
|
|
55
|
+
`), releaseBriefJson = JSON.stringify(releaseBrief, null, 2), deploySummaryJson = JSON.stringify(deploySummary, null, 2), deploySummaryMarkdown = [
|
|
56
|
+
`<!-- gorsee-ai-schema: ${GORSEE_AI_CONTEXT_SCHEMA_VERSION} -->`,
|
|
57
|
+
renderAIDeploySummaryMarkdown(deploySummary)
|
|
58
|
+
].join(`
|
|
59
|
+
`), releaseBriefMarkdown = [
|
|
60
|
+
`<!-- gorsee-ai-schema: ${GORSEE_AI_CONTEXT_SCHEMA_VERSION} -->`,
|
|
61
|
+
renderAIReleaseBriefMarkdown(releaseBrief)
|
|
62
|
+
].join(`
|
|
63
|
+
`), incidentBriefJson = JSON.stringify(incidentBrief, null, 2), incidentBriefMarkdown = [
|
|
64
|
+
`<!-- gorsee-ai-schema: ${GORSEE_AI_CONTEXT_SCHEMA_VERSION} -->`,
|
|
65
|
+
renderAIIncidentBriefMarkdown(incidentBrief)
|
|
66
|
+
].join(`
|
|
67
|
+
`), incidentSnapshotJson = JSON.stringify(incidentSnapshot, null, 2), incidentSnapshotMarkdown = [
|
|
68
|
+
`<!-- gorsee-ai-schema: ${GORSEE_AI_CONTEXT_SCHEMA_VERSION} -->`,
|
|
69
|
+
renderAIIncidentSnapshotMarkdown(incidentSnapshot)
|
|
70
|
+
].join(`
|
|
37
71
|
`);
|
|
38
72
|
if ((resolved.formats ?? ["json", "markdown"]).includes("json")) {
|
|
39
73
|
await writeFile(paths.latestJsonPath, json, "utf-8");
|
|
40
74
|
await writeFile(join(paths.historyDir, `${stamp}.json`), json, "utf-8");
|
|
75
|
+
await writeFile(paths.latestDeploySummaryJsonPath, deploySummaryJson, "utf-8");
|
|
76
|
+
await writeFile(join(paths.historyDir, `${stamp}.deploy-summary.json`), deploySummaryJson, "utf-8");
|
|
77
|
+
await writeFile(paths.latestReleaseBriefJsonPath, releaseBriefJson, "utf-8");
|
|
78
|
+
await writeFile(join(paths.historyDir, `${stamp}.release-brief.json`), releaseBriefJson, "utf-8");
|
|
79
|
+
await writeFile(paths.latestIncidentBriefJsonPath, incidentBriefJson, "utf-8");
|
|
80
|
+
await writeFile(join(paths.historyDir, `${stamp}.incident-brief.json`), incidentBriefJson, "utf-8");
|
|
81
|
+
await writeFile(paths.latestIncidentSnapshotJsonPath, incidentSnapshotJson, "utf-8");
|
|
82
|
+
await writeFile(join(paths.historyDir, `${stamp}.incident-snapshot.json`), incidentSnapshotJson, "utf-8");
|
|
41
83
|
}
|
|
42
84
|
if ((resolved.formats ?? ["json", "markdown"]).includes("markdown")) {
|
|
43
85
|
await writeFile(paths.latestMarkdownPath, markdown, "utf-8");
|
|
44
86
|
await writeFile(join(paths.historyDir, `${stamp}.md`), markdown, "utf-8");
|
|
87
|
+
await writeFile(paths.latestDeploySummaryMarkdownPath, deploySummaryMarkdown, "utf-8");
|
|
88
|
+
await writeFile(join(paths.historyDir, `${stamp}.deploy-summary.md`), deploySummaryMarkdown, "utf-8");
|
|
89
|
+
await writeFile(paths.latestReleaseBriefMarkdownPath, releaseBriefMarkdown, "utf-8");
|
|
90
|
+
await writeFile(join(paths.historyDir, `${stamp}.release-brief.md`), releaseBriefMarkdown, "utf-8");
|
|
91
|
+
await writeFile(paths.latestIncidentBriefMarkdownPath, incidentBriefMarkdown, "utf-8");
|
|
92
|
+
await writeFile(join(paths.historyDir, `${stamp}.incident-brief.md`), incidentBriefMarkdown, "utf-8");
|
|
93
|
+
await writeFile(paths.latestIncidentSnapshotMarkdownPath, incidentSnapshotMarkdown, "utf-8");
|
|
94
|
+
await writeFile(join(paths.historyDir, `${stamp}.incident-snapshot.md`), incidentSnapshotMarkdown, "utf-8");
|
|
45
95
|
}
|
|
46
96
|
return { bundle, paths, stamp };
|
|
47
97
|
}
|
package/dist-pkg/ai/store.d.ts
CHANGED
|
@@ -1,11 +1,33 @@
|
|
|
1
|
-
import type { AIDiagnostic, AIEvent } from "./index.js";
|
|
1
|
+
import type { AIAppContext, AIDiagnostic, AIEvent } from "./index.js";
|
|
2
2
|
import type { ReactiveTraceArtifact } from "../reactive/diagnostics.js";
|
|
3
|
+
import type { ReleaseArtifact } from "../server/manifest.js";
|
|
3
4
|
export interface AIStorePaths {
|
|
4
5
|
eventsPath: string;
|
|
5
6
|
diagnosticsPath: string;
|
|
6
7
|
reactiveTracePath: string;
|
|
8
|
+
releaseArtifactPath?: string;
|
|
7
9
|
}
|
|
8
10
|
export interface AIHealthReport {
|
|
11
|
+
app?: AIAppContext;
|
|
12
|
+
release?: {
|
|
13
|
+
appMode: ReleaseArtifact["appMode"];
|
|
14
|
+
runtimeKind: ReleaseArtifact["runtime"]["kind"];
|
|
15
|
+
processEntrypoints: string[];
|
|
16
|
+
handlerEntrypoints: string[];
|
|
17
|
+
workerEntrypoint?: string;
|
|
18
|
+
summary: ReleaseArtifact["summary"];
|
|
19
|
+
generatedAt: string;
|
|
20
|
+
};
|
|
21
|
+
readiness: {
|
|
22
|
+
deploy: {
|
|
23
|
+
status: "ready" | "caution" | "blocked";
|
|
24
|
+
reasons: string[];
|
|
25
|
+
};
|
|
26
|
+
scaling: {
|
|
27
|
+
status: "ready" | "caution" | "blocked" | "not-applicable";
|
|
28
|
+
reasons: string[];
|
|
29
|
+
};
|
|
30
|
+
};
|
|
9
31
|
events: {
|
|
10
32
|
total: number;
|
|
11
33
|
bySeverity: Record<string, number>;
|
|
@@ -59,9 +81,11 @@ export declare function readAIEvents(path: string, options?: {
|
|
|
59
81
|
export declare function readAIDiagnosticsSnapshot(path: string): Promise<{
|
|
60
82
|
updatedAt?: string;
|
|
61
83
|
sessionId?: string;
|
|
84
|
+
app?: AIAppContext;
|
|
62
85
|
latest?: Partial<AIDiagnostic>;
|
|
63
86
|
} | null>;
|
|
64
87
|
export declare function readReactiveTraceArtifact(path: string): Promise<ReactiveTraceArtifact | null>;
|
|
88
|
+
export declare function readReleaseArtifact(path: string): Promise<ReleaseArtifact | null>;
|
|
65
89
|
export declare function buildAIHealthReport(paths: AIStorePaths, options?: {
|
|
66
90
|
limit?: number;
|
|
67
91
|
}): Promise<AIHealthReport>;
|
package/dist-pkg/ai/store.js
CHANGED
|
@@ -5,7 +5,8 @@ export function resolveAIStorePaths(cwd) {
|
|
|
5
5
|
return {
|
|
6
6
|
eventsPath: join(cwd, ".gorsee", "ai-events.jsonl"),
|
|
7
7
|
diagnosticsPath: join(cwd, ".gorsee", "ai-diagnostics.json"),
|
|
8
|
-
reactiveTracePath: join(cwd, ".gorsee", "reactive-trace.json")
|
|
8
|
+
reactiveTracePath: join(cwd, ".gorsee", "reactive-trace.json"),
|
|
9
|
+
releaseArtifactPath: join(cwd, "dist", "release.json")
|
|
9
10
|
};
|
|
10
11
|
}
|
|
11
12
|
export async function readAIEvents(path, options = {}) {
|
|
@@ -32,8 +33,14 @@ export async function readReactiveTraceArtifact(path) {
|
|
|
32
33
|
return null;
|
|
33
34
|
return safeJSONParse(content);
|
|
34
35
|
}
|
|
36
|
+
export async function readReleaseArtifact(path) {
|
|
37
|
+
const content = await safeReadFile(path);
|
|
38
|
+
if (!content)
|
|
39
|
+
return null;
|
|
40
|
+
return safeJSONParse(content);
|
|
41
|
+
}
|
|
35
42
|
export async function buildAIHealthReport(paths, options = {}) {
|
|
36
|
-
const events = await readAIEvents(paths.eventsPath, options), snapshot = await readAIDiagnosticsSnapshot(paths.diagnosticsPath), bySeverity = {}, byKind = {};
|
|
43
|
+
const events = await readAIEvents(paths.eventsPath, options), snapshot = await readAIDiagnosticsSnapshot(paths.diagnosticsPath), releaseArtifact = paths.releaseArtifactPath ? await readReleaseArtifact(paths.releaseArtifactPath) : null, bySeverity = {}, byKind = {};
|
|
37
44
|
let errors = 0, warnings = 0;
|
|
38
45
|
for (const event of events) {
|
|
39
46
|
bySeverity[event.severity] = (bySeverity[event.severity] ?? 0) + 1;
|
|
@@ -51,8 +58,33 @@ export async function buildAIHealthReport(paths, options = {}) {
|
|
|
51
58
|
file: event.file,
|
|
52
59
|
line: event.line,
|
|
53
60
|
code: event.code
|
|
54
|
-
})), incidentClusters = buildIncidentClusters(events), artifactRegressions = buildArtifactRegressions(events)
|
|
61
|
+
})), incidentClusters = buildIncidentClusters(events), artifactRegressions = buildArtifactRegressions(events), appContext = snapshot?.app ?? [...events].reverse().find((event) => event.app)?.app, releaseContext = releaseArtifact ? {
|
|
62
|
+
appMode: releaseArtifact.appMode,
|
|
63
|
+
runtimeKind: releaseArtifact.runtime.kind,
|
|
64
|
+
processEntrypoints: releaseArtifact.runtime.processEntrypoints,
|
|
65
|
+
handlerEntrypoints: releaseArtifact.runtime.handlerEntrypoints,
|
|
66
|
+
workerEntrypoint: releaseArtifact.runtime.workerEntrypoint,
|
|
67
|
+
summary: releaseArtifact.summary,
|
|
68
|
+
generatedAt: releaseArtifact.generatedAt
|
|
69
|
+
} : void 0;
|
|
55
70
|
return {
|
|
71
|
+
app: appContext,
|
|
72
|
+
release: releaseContext,
|
|
73
|
+
readiness: {
|
|
74
|
+
deploy: buildDeployReadiness({
|
|
75
|
+
app: appContext,
|
|
76
|
+
release: releaseContext,
|
|
77
|
+
diagnosticsErrors: errors,
|
|
78
|
+
diagnosticsWarnings: warnings,
|
|
79
|
+
incidents,
|
|
80
|
+
artifactRegressions
|
|
81
|
+
}),
|
|
82
|
+
scaling: buildScalingReadiness({
|
|
83
|
+
app: appContext,
|
|
84
|
+
release: releaseContext,
|
|
85
|
+
events
|
|
86
|
+
})
|
|
87
|
+
},
|
|
56
88
|
events: {
|
|
57
89
|
total: events.length,
|
|
58
90
|
bySeverity,
|
|
@@ -70,6 +102,60 @@ export async function buildAIHealthReport(paths, options = {}) {
|
|
|
70
102
|
artifactRegressions
|
|
71
103
|
};
|
|
72
104
|
}
|
|
105
|
+
function buildDeployReadiness(input) {
|
|
106
|
+
const reasons = [];
|
|
107
|
+
if (!input.release)
|
|
108
|
+
reasons.push("dist/release.json is missing; release-level runtime context is not available.");
|
|
109
|
+
if (input.app && input.release && input.app.mode !== input.release.appMode)
|
|
110
|
+
reasons.push(`app.mode (${input.app.mode}) does not match release artifact mode (${input.release.appMode}).`);
|
|
111
|
+
if (input.diagnosticsErrors > 0)
|
|
112
|
+
reasons.push(`AI diagnostics currently report ${input.diagnosticsErrors} error event(s).`);
|
|
113
|
+
if (input.artifactRegressions.some((entry) => entry.errors > 0))
|
|
114
|
+
reasons.push("artifact regressions contain error-level failures.");
|
|
115
|
+
if (reasons.length > 0)
|
|
116
|
+
return { status: "blocked", reasons };
|
|
117
|
+
if (input.diagnosticsWarnings > 0)
|
|
118
|
+
reasons.push(`AI diagnostics currently report ${input.diagnosticsWarnings} warning event(s).`);
|
|
119
|
+
if (input.incidents.length > 0)
|
|
120
|
+
reasons.push(`recent incident history is non-empty (${input.incidents.length}).`);
|
|
121
|
+
if (input.artifactRegressions.some((entry) => entry.warnings > 0))
|
|
122
|
+
reasons.push("artifact regressions contain warning-level drift.");
|
|
123
|
+
if (reasons.length > 0)
|
|
124
|
+
return { status: "caution", reasons };
|
|
125
|
+
reasons.push(input.release ? `release artifact is aligned for ${input.release.appMode} (${input.release.runtimeKind}).` : "no blocking deploy signals were found.");
|
|
126
|
+
return { status: "ready", reasons };
|
|
127
|
+
}
|
|
128
|
+
function buildScalingReadiness(input) {
|
|
129
|
+
const reasons = [], eventCodes = new Set(input.events.map((event) => event.code).filter((code) => Boolean(code)));
|
|
130
|
+
if (input.release?.appMode === "frontend")
|
|
131
|
+
return {
|
|
132
|
+
status: "not-applicable",
|
|
133
|
+
reasons: ["frontend-static release artifacts do not own a multi-instance server runtime."]
|
|
134
|
+
};
|
|
135
|
+
if (input.app?.runtimeTopology !== "multi-instance")
|
|
136
|
+
return {
|
|
137
|
+
status: "not-applicable",
|
|
138
|
+
reasons: ["runtime.topology is not declared as multi-instance."]
|
|
139
|
+
};
|
|
140
|
+
if (!input.release)
|
|
141
|
+
reasons.push("dist/release.json is missing; scaling cannot be assessed against the built runtime.");
|
|
142
|
+
if (input.release && input.release.runtimeKind === "frontend-static")
|
|
143
|
+
reasons.push("release runtime kind is frontend-static, which cannot satisfy multi-instance server scaling.");
|
|
144
|
+
for (const code of ["W917", "W918", "W919", "W920"])
|
|
145
|
+
if (eventCodes.has(code))
|
|
146
|
+
reasons.push(`check/runtime events still report ${code}, which blocks distributed scaling readiness.`);
|
|
147
|
+
if (reasons.length > 0)
|
|
148
|
+
return { status: "blocked", reasons };
|
|
149
|
+
if (eventCodes.has("W921"))
|
|
150
|
+
return {
|
|
151
|
+
status: "caution",
|
|
152
|
+
reasons: ["multi-instance runtime is configured, but AI observability does not yet forward to a bridge/aggregator (W921)."]
|
|
153
|
+
};
|
|
154
|
+
return {
|
|
155
|
+
status: "ready",
|
|
156
|
+
reasons: ["multi-instance topology is declared and no distributed-state blocker signals are present."]
|
|
157
|
+
};
|
|
158
|
+
}
|
|
73
159
|
function buildIncidentClusters(events) {
|
|
74
160
|
const clusters = new Map;
|
|
75
161
|
for (const event of events) {
|