gsd-pi 2.79.0 → 2.80.0
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 +94 -47
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/gsd/auto/contracts.js +1 -0
- package/dist/resources/extensions/gsd/auto/orchestrator.js +146 -0
- package/dist/resources/extensions/gsd/auto/phases.js +61 -7
- package/dist/resources/extensions/gsd/auto/session.js +8 -0
- package/dist/resources/extensions/gsd/auto-artifact-paths.js +2 -2
- package/dist/resources/extensions/gsd/auto-dispatch.js +2 -0
- package/dist/resources/extensions/gsd/auto-prompts.js +52 -29
- package/dist/resources/extensions/gsd/auto-recovery.js +63 -55
- package/dist/resources/extensions/gsd/auto-runtime-state.js +4 -0
- package/dist/resources/extensions/gsd/auto-start.js +3 -2
- package/dist/resources/extensions/gsd/auto.js +159 -2
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +9 -1
- package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +2 -2
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +41 -45
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +8 -8
- package/dist/resources/extensions/gsd/commands/context.js +1 -1
- package/dist/resources/extensions/gsd/gsd-db.js +34 -1
- package/dist/resources/extensions/gsd/guided-flow.js +40 -0
- package/dist/resources/extensions/gsd/paths.js +5 -1
- package/dist/resources/extensions/gsd/post-execution-checks.js +25 -6
- package/dist/resources/extensions/gsd/preferences-types.js +20 -2
- package/dist/resources/extensions/gsd/preferences-validation.js +3 -3
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +82 -2
- package/dist/resources/extensions/gsd/unit-context-composer.js +32 -0
- package/dist/resources/extensions/gsd/unit-context-manifest.js +21 -0
- package/dist/resources/extensions/gsd/uok/audit.js +23 -9
- package/dist/resources/extensions/gsd/uok/contracts.js +69 -1
- package/dist/resources/extensions/gsd/uok/dispatch-envelope.js +3 -0
- package/dist/resources/extensions/gsd/uok/loop-adapter.js +48 -33
- package/dist/resources/extensions/gsd/uok/timeline.js +125 -0
- package/dist/resources/extensions/shared/gsd-phase-state.js +45 -3
- package/dist/resources/extensions/shared/interview-ui.js +15 -4
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +9 -9
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +9 -9
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/package.json +1 -1
- package/packages/daemon/package.json +2 -2
- package/packages/mcp-server/dist/workflow-tools.d.ts +1 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +53 -0
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +2 -2
- package/packages/mcp-server/src/workflow-tools.test.ts +129 -2
- package/packages/mcp-server/src/workflow-tools.ts +81 -0
- package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-tui/package.json +1 -1
- package/packages/rpc-client/package.json +1 -1
- package/pkg/package.json +1 -1
- package/src/resources/extensions/gsd/auto/contracts.ts +87 -0
- package/src/resources/extensions/gsd/auto/loop-deps.ts +10 -3
- package/src/resources/extensions/gsd/auto/orchestrator.ts +161 -0
- package/src/resources/extensions/gsd/auto/phases.ts +88 -9
- package/src/resources/extensions/gsd/auto/session.ts +11 -0
- package/src/resources/extensions/gsd/auto-artifact-paths.ts +2 -2
- package/src/resources/extensions/gsd/auto-dispatch.ts +1 -0
- package/src/resources/extensions/gsd/auto-prompts.ts +106 -28
- package/src/resources/extensions/gsd/auto-recovery.ts +59 -53
- package/src/resources/extensions/gsd/auto-runtime-state.ts +7 -0
- package/src/resources/extensions/gsd/auto-start.ts +3 -2
- package/src/resources/extensions/gsd/auto.ts +167 -1
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +14 -1
- package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +2 -2
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +49 -46
- package/src/resources/extensions/gsd/bootstrap/tests/write-gate-shouldblock-basepath.test.ts +97 -0
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +8 -4
- package/src/resources/extensions/gsd/commands/context.ts +1 -1
- package/src/resources/extensions/gsd/gsd-db.ts +35 -1
- package/src/resources/extensions/gsd/guided-flow.ts +47 -0
- package/src/resources/extensions/gsd/interrupted-session.ts +1 -0
- package/src/resources/extensions/gsd/paths.ts +6 -1
- package/src/resources/extensions/gsd/post-execution-checks.ts +31 -6
- package/src/resources/extensions/gsd/preferences-types.ts +23 -4
- package/src/resources/extensions/gsd/preferences-validation.ts +3 -3
- package/src/resources/extensions/gsd/tests/auto-abort-pause-regression.test.ts +32 -0
- package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +353 -0
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +108 -1
- package/src/resources/extensions/gsd/tests/auto-runtime-state.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/auto-session-encapsulation.test.ts +3 -0
- package/src/resources/extensions/gsd/tests/bootstrap-derive-state-db-open.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/check-auto-start-pending-gate.test.ts +203 -0
- package/src/resources/extensions/gsd/tests/check-auto-start-ready-guard.test.ts +148 -0
- package/src/resources/extensions/gsd/tests/current-directory-root-homedir-fallback.test.ts +63 -0
- package/src/resources/extensions/gsd/tests/deep-planning-mode-dispatch.test.ts +42 -0
- package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +63 -2
- package/src/resources/extensions/gsd/tests/execute-summary-save-empty-project.test.ts +109 -0
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +95 -0
- package/src/resources/extensions/gsd/tests/guided-flow-prompt-consolidation.test.ts +14 -0
- package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +79 -0
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +134 -0
- package/src/resources/extensions/gsd/tests/parallel-skill-prompt-integration.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/paused-session-via-db.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/plan-slice.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/post-execution-checks.test.ts +46 -0
- package/src/resources/extensions/gsd/tests/pre-exec-gate-loop.test.ts +3 -0
- package/src/resources/extensions/gsd/tests/register-hooks-compaction-checkpoint.test.ts +85 -0
- package/src/resources/extensions/gsd/tests/run-uat-composer.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/subagent-model-dispatch.test.ts +59 -0
- package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +32 -0
- package/src/resources/extensions/gsd/tests/uok-contracts.test.ts +109 -1
- package/src/resources/extensions/gsd/tests/uok-loop-adapter-writer.test.ts +98 -0
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +132 -3
- package/src/resources/extensions/gsd/tests/worktree-path-injection.test.ts +3 -0
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +84 -1
- package/src/resources/extensions/gsd/unit-context-composer.ts +49 -0
- package/src/resources/extensions/gsd/unit-context-manifest.ts +34 -0
- package/src/resources/extensions/gsd/uok/audit.ts +25 -9
- package/src/resources/extensions/gsd/uok/contracts.ts +105 -0
- package/src/resources/extensions/gsd/uok/dispatch-envelope.ts +4 -0
- package/src/resources/extensions/gsd/uok/loop-adapter.ts +60 -45
- package/src/resources/extensions/gsd/uok/timeline.ts +158 -0
- package/src/resources/extensions/shared/gsd-phase-state.ts +56 -3
- package/src/resources/extensions/shared/interview-ui.ts +18 -5
- package/src/resources/extensions/shared/tests/gsd-phase-state.test.ts +43 -1
- package/src/resources/extensions/shared/tests/interview-notes-loop.test.ts +41 -0
- /package/dist/web/standalone/.next/static/{J-CU-p_sp45CJHT3R9TJS → V-3Ehy4B24f9FCGiLPWIM}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{J-CU-p_sp45CJHT3R9TJS → V-3Ehy4B24f9FCGiLPWIM}/_ssgManifest.js +0 -0
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// GSD2 UOK Turn Observer and DB-Backed Lifecycle Emission
|
|
2
|
+
import { CURRENT_UOK_CONTRACT_VERSION, validateTurnResult } from "./contracts.js";
|
|
1
3
|
import { buildAuditEnvelope, emitUokAuditEvent } from "./audit.js";
|
|
2
4
|
import { writeTurnCloseoutGitRecord, writeTurnGitTransaction } from "./gitops.js";
|
|
3
5
|
import { acquireWriterToken, nextWriteRecord, releaseWriterToken } from "./writer.js";
|
|
@@ -115,46 +117,59 @@ export function createTurnObserver(options) {
|
|
|
115
117
|
}
|
|
116
118
|
},
|
|
117
119
|
onTurnResult(result) {
|
|
118
|
-
const
|
|
119
|
-
|
|
120
|
-
|
|
120
|
+
const cleanup = () => {
|
|
121
|
+
if (writerToken) {
|
|
122
|
+
releaseWriterToken(options.basePath, writerToken);
|
|
123
|
+
}
|
|
124
|
+
writerToken = null;
|
|
125
|
+
current = null;
|
|
126
|
+
phaseResults.length = 0;
|
|
121
127
|
};
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
128
|
+
try {
|
|
129
|
+
const merged = {
|
|
130
|
+
...result,
|
|
131
|
+
version: CURRENT_UOK_CONTRACT_VERSION,
|
|
132
|
+
phaseResults: Array.isArray(result.phaseResults) && result.phaseResults.length > 0 ? result.phaseResults : [...phaseResults],
|
|
133
|
+
};
|
|
134
|
+
const validation = validateTurnResult(merged);
|
|
135
|
+
if (!validation.ok) {
|
|
136
|
+
throw new Error(`Invalid UOK turn result: ${validation.issues.map((issue) => `${issue.path}: ${issue.message}`).join("; ")}`);
|
|
137
|
+
}
|
|
138
|
+
if (options.enableAudit) {
|
|
139
|
+
emitUokAuditEvent(options.basePath, buildAuditEnvelope({
|
|
140
|
+
traceId: validation.value.traceId,
|
|
141
|
+
turnId: validation.value.turnId,
|
|
142
|
+
category: "orchestration",
|
|
143
|
+
type: "turn-result",
|
|
144
|
+
payload: nextSequenceMetadata("audit", "append", {
|
|
145
|
+
contractVersion: validation.value.version,
|
|
146
|
+
unitType: validation.value.unitType,
|
|
147
|
+
unitId: validation.value.unitId,
|
|
148
|
+
status: validation.value.status,
|
|
149
|
+
failureClass: validation.value.failureClass,
|
|
150
|
+
error: validation.value.error,
|
|
151
|
+
phaseCount: validation.value.phaseResults.length,
|
|
152
|
+
}),
|
|
153
|
+
}));
|
|
154
|
+
}
|
|
155
|
+
if (options.enableGitops) {
|
|
156
|
+
const closeout = merged.closeout ?? {
|
|
157
|
+
traceId: merged.traceId,
|
|
158
|
+
turnId: merged.turnId,
|
|
129
159
|
unitType: merged.unitType,
|
|
130
160
|
unitId: merged.unitId,
|
|
131
161
|
status: merged.status,
|
|
132
162
|
failureClass: merged.failureClass,
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
163
|
+
gitAction: options.gitAction,
|
|
164
|
+
gitPushed: options.gitPush,
|
|
165
|
+
finishedAt: merged.finishedAt,
|
|
166
|
+
};
|
|
167
|
+
writeTurnCloseoutGitRecord(options.basePath, closeout, nextSequenceMetadata("gitops", "update", { action: "record" }));
|
|
168
|
+
}
|
|
137
169
|
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
traceId: merged.traceId,
|
|
141
|
-
turnId: merged.turnId,
|
|
142
|
-
unitType: merged.unitType,
|
|
143
|
-
unitId: merged.unitId,
|
|
144
|
-
status: merged.status,
|
|
145
|
-
failureClass: merged.failureClass,
|
|
146
|
-
gitAction: options.gitAction,
|
|
147
|
-
gitPushed: options.gitPush,
|
|
148
|
-
finishedAt: merged.finishedAt,
|
|
149
|
-
};
|
|
150
|
-
writeTurnCloseoutGitRecord(options.basePath, closeout, nextSequenceMetadata("gitops", "update", { action: "record" }));
|
|
170
|
+
finally {
|
|
171
|
+
cleanup();
|
|
151
172
|
}
|
|
152
|
-
if (writerToken) {
|
|
153
|
-
releaseWriterToken(options.basePath, writerToken);
|
|
154
|
-
}
|
|
155
|
-
writerToken = null;
|
|
156
|
-
current = null;
|
|
157
|
-
phaseResults.length = 0;
|
|
158
173
|
},
|
|
159
174
|
};
|
|
160
175
|
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
// GSD2 UOK Timeline Reconstruction from Authoritative DB Records
|
|
2
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { _getAdapter, isDbAvailable } from "../gsd-db.js";
|
|
5
|
+
import { gsdRoot } from "../paths.js";
|
|
6
|
+
function parseJsonRecord(value) {
|
|
7
|
+
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
|
8
|
+
return value;
|
|
9
|
+
}
|
|
10
|
+
if (typeof value !== "string" || value.trim() === "")
|
|
11
|
+
return {};
|
|
12
|
+
try {
|
|
13
|
+
const parsed = JSON.parse(value);
|
|
14
|
+
return typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)
|
|
15
|
+
? parsed
|
|
16
|
+
: {};
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
return {};
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function matchesFilter(entry, filter) {
|
|
23
|
+
if (filter.traceId && entry.traceId !== filter.traceId)
|
|
24
|
+
return false;
|
|
25
|
+
if (filter.turnId && entry.turnId !== filter.turnId)
|
|
26
|
+
return false;
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
function byTimestamp(a, b) {
|
|
30
|
+
return a.ts.localeCompare(b.ts);
|
|
31
|
+
}
|
|
32
|
+
function readDbTimeline(filter) {
|
|
33
|
+
const db = _getAdapter();
|
|
34
|
+
if (!db)
|
|
35
|
+
return [];
|
|
36
|
+
const entries = [];
|
|
37
|
+
const where = [];
|
|
38
|
+
const params = {};
|
|
39
|
+
if (filter.traceId) {
|
|
40
|
+
where.push("trace_id = :trace_id");
|
|
41
|
+
params[":trace_id"] = filter.traceId;
|
|
42
|
+
}
|
|
43
|
+
if (filter.turnId) {
|
|
44
|
+
where.push("turn_id = :turn_id");
|
|
45
|
+
params[":turn_id"] = filter.turnId;
|
|
46
|
+
}
|
|
47
|
+
const suffix = where.length > 0 ? ` WHERE ${where.join(" AND ")}` : "";
|
|
48
|
+
const auditRows = db.prepare(`SELECT trace_id, turn_id, type, ts, payload_json FROM audit_events${suffix}`).all(params);
|
|
49
|
+
for (const row of auditRows) {
|
|
50
|
+
entries.push({
|
|
51
|
+
source: "audit_events",
|
|
52
|
+
ts: row.ts,
|
|
53
|
+
traceId: row.trace_id,
|
|
54
|
+
turnId: row.turn_id,
|
|
55
|
+
type: row.type,
|
|
56
|
+
payload: parseJsonRecord(row.payload_json),
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
const dispatchRows = db.prepare(`SELECT trace_id, turn_id, unit_type, unit_id, status, started_at, ended_at, exit_reason,
|
|
60
|
+
error_summary, retry_after_ms, attempt_n, max_attempts
|
|
61
|
+
FROM unit_dispatches${suffix}`).all(params);
|
|
62
|
+
for (const row of dispatchRows) {
|
|
63
|
+
entries.push({
|
|
64
|
+
source: "unit_dispatches",
|
|
65
|
+
ts: String(row.ended_at ?? row.started_at ?? ""),
|
|
66
|
+
traceId: String(row.trace_id ?? ""),
|
|
67
|
+
turnId: typeof row.turn_id === "string" ? row.turn_id : null,
|
|
68
|
+
type: `dispatch-${String(row.status ?? "unknown")}`,
|
|
69
|
+
payload: { ...row },
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
const gitRows = db.prepare(`SELECT trace_id, turn_id, unit_type, unit_id, stage, action, push, status, error,
|
|
73
|
+
metadata_json, updated_at
|
|
74
|
+
FROM turn_git_transactions${suffix}`).all(params);
|
|
75
|
+
for (const row of gitRows) {
|
|
76
|
+
entries.push({
|
|
77
|
+
source: "turn_git_transactions",
|
|
78
|
+
ts: String(row.updated_at ?? ""),
|
|
79
|
+
traceId: String(row.trace_id ?? ""),
|
|
80
|
+
turnId: typeof row.turn_id === "string" ? row.turn_id : null,
|
|
81
|
+
type: `gitops-${String(row.stage ?? "unknown")}`,
|
|
82
|
+
payload: {
|
|
83
|
+
...row,
|
|
84
|
+
metadata: parseJsonRecord(row.metadata_json),
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
return entries.filter((entry) => entry.ts !== "").sort(byTimestamp);
|
|
89
|
+
}
|
|
90
|
+
function readJsonlTimeline(basePath, filter) {
|
|
91
|
+
const path = join(gsdRoot(basePath), "audit", "events.jsonl");
|
|
92
|
+
if (!existsSync(path))
|
|
93
|
+
return [];
|
|
94
|
+
return readFileSync(path, "utf-8")
|
|
95
|
+
.split("\n")
|
|
96
|
+
.filter(Boolean)
|
|
97
|
+
.map((line) => {
|
|
98
|
+
const event = parseJsonRecord(line);
|
|
99
|
+
const entry = {
|
|
100
|
+
source: "audit_jsonl",
|
|
101
|
+
ts: String(event.ts ?? ""),
|
|
102
|
+
traceId: typeof event.traceId === "string" ? event.traceId : undefined,
|
|
103
|
+
turnId: typeof event.turnId === "string" ? event.turnId : null,
|
|
104
|
+
type: String(event.type ?? "audit"),
|
|
105
|
+
payload: parseJsonRecord(event.payload),
|
|
106
|
+
};
|
|
107
|
+
return entry.ts && matchesFilter(entry, filter) ? entry : null;
|
|
108
|
+
})
|
|
109
|
+
.filter((entry) => entry !== null)
|
|
110
|
+
.sort(byTimestamp);
|
|
111
|
+
}
|
|
112
|
+
export function buildTurnTimeline(basePath, filter = {}) {
|
|
113
|
+
if (isDbAvailable()) {
|
|
114
|
+
return {
|
|
115
|
+
authoritative: "db",
|
|
116
|
+
degraded: false,
|
|
117
|
+
entries: readDbTimeline(filter),
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
return {
|
|
121
|
+
authoritative: "degraded-fallback",
|
|
122
|
+
degraded: true,
|
|
123
|
+
entries: readJsonlTimeline(basePath, filter),
|
|
124
|
+
};
|
|
125
|
+
}
|
|
@@ -1,29 +1,71 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* GSD2 Phase State — cross-extension coordination
|
|
3
3
|
* Copyright (c) 2026 Jeremy McSpadden <jeremy@fluxlabs.net>
|
|
4
4
|
*
|
|
5
5
|
* Lightweight module-level state that GSD auto-mode writes to and the
|
|
6
6
|
* subagent tool reads from. Both extensions run in the same process so
|
|
7
7
|
* a module variable is sufficient — no file I/O needed.
|
|
8
8
|
*/
|
|
9
|
+
import { buildAuditEnvelope, emitUokAuditEvent } from "../gsd/uok/audit.js";
|
|
9
10
|
let _active = false;
|
|
10
11
|
let _currentPhase = null;
|
|
12
|
+
let _auditContext = null;
|
|
13
|
+
function emitPhaseChange(action, previousPhase, nextPhase) {
|
|
14
|
+
if (!_auditContext)
|
|
15
|
+
return;
|
|
16
|
+
emitUokAuditEvent(_auditContext.basePath, buildAuditEnvelope({
|
|
17
|
+
traceId: _auditContext.traceId,
|
|
18
|
+
turnId: _auditContext.turnId,
|
|
19
|
+
causedBy: _auditContext.causedBy,
|
|
20
|
+
category: "orchestration",
|
|
21
|
+
type: "phase_changed",
|
|
22
|
+
payload: {
|
|
23
|
+
action,
|
|
24
|
+
active: _active,
|
|
25
|
+
previousPhase,
|
|
26
|
+
nextPhase,
|
|
27
|
+
},
|
|
28
|
+
}));
|
|
29
|
+
}
|
|
30
|
+
export function configureGSDPhaseAudit(context) {
|
|
31
|
+
_auditContext = context;
|
|
32
|
+
}
|
|
11
33
|
/** Mark GSD auto-mode as active. */
|
|
12
|
-
export function activateGSD() {
|
|
34
|
+
export function activateGSD(context) {
|
|
35
|
+
if (context)
|
|
36
|
+
_auditContext = context;
|
|
37
|
+
const previousPhase = _currentPhase;
|
|
13
38
|
_active = true;
|
|
39
|
+
emitPhaseChange("activate", previousPhase, _currentPhase);
|
|
14
40
|
}
|
|
15
41
|
/** Mark GSD auto-mode as inactive and clear the current phase. */
|
|
16
42
|
export function deactivateGSD() {
|
|
43
|
+
const previousPhase = _currentPhase;
|
|
17
44
|
_active = false;
|
|
18
45
|
_currentPhase = null;
|
|
46
|
+
emitPhaseChange("deactivate", previousPhase, _currentPhase);
|
|
47
|
+
_auditContext = null;
|
|
19
48
|
}
|
|
20
49
|
/** Set the currently dispatched GSD phase (e.g. "plan-milestone"). */
|
|
21
|
-
export function setCurrentPhase(phase) {
|
|
50
|
+
export function setCurrentPhase(phase, context) {
|
|
51
|
+
if (context)
|
|
52
|
+
_auditContext = context;
|
|
53
|
+
if (!_active) {
|
|
54
|
+
process.emitWarning(`Ignoring GSD phase "${phase}" while GSD auto-mode is inactive`, {
|
|
55
|
+
code: "GSD_PHASE_INACTIVE",
|
|
56
|
+
});
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
const previousPhase = _currentPhase;
|
|
22
60
|
_currentPhase = phase;
|
|
61
|
+
emitPhaseChange("set", previousPhase, _currentPhase);
|
|
62
|
+
return true;
|
|
23
63
|
}
|
|
24
64
|
/** Clear the current phase (unit completed or aborted). */
|
|
25
65
|
export function clearCurrentPhase() {
|
|
66
|
+
const previousPhase = _currentPhase;
|
|
26
67
|
_currentPhase = null;
|
|
68
|
+
emitPhaseChange("clear", previousPhase, _currentPhase);
|
|
27
69
|
}
|
|
28
70
|
/** Returns true if GSD auto-mode is currently active. */
|
|
29
71
|
export function isGSDActive() {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// GSD2 — Shared interview round UI widget
|
|
1
2
|
/**
|
|
2
3
|
* Shared interview round UI widget.
|
|
3
4
|
*
|
|
@@ -128,14 +129,24 @@ export async function showInterviewRound(questions, opts, ctx) {
|
|
|
128
129
|
let showingExitConfirm = false;
|
|
129
130
|
let exitCursor = 0; // 0 = keep going (default), 1 = end interview
|
|
130
131
|
let cachedLines;
|
|
132
|
+
let completed = false;
|
|
133
|
+
let removeAbortListener;
|
|
134
|
+
function finish(result) {
|
|
135
|
+
if (completed)
|
|
136
|
+
return;
|
|
137
|
+
completed = true;
|
|
138
|
+
removeAbortListener?.();
|
|
139
|
+
done(result);
|
|
140
|
+
}
|
|
131
141
|
// External cancellation (e.g. remote channel won the race)
|
|
132
142
|
if (opts.signal) {
|
|
133
|
-
const onAbort = () =>
|
|
143
|
+
const onAbort = () => finish({ endInterview: false, answers: {} });
|
|
134
144
|
if (opts.signal.aborted) {
|
|
135
145
|
onAbort();
|
|
136
146
|
}
|
|
137
147
|
else {
|
|
138
148
|
opts.signal.addEventListener("abort", onAbort, { once: true });
|
|
149
|
+
removeAbortListener = () => opts.signal?.removeEventListener("abort", onAbort);
|
|
139
150
|
}
|
|
140
151
|
}
|
|
141
152
|
// Editor is created once; editorTheme comes from the design system
|
|
@@ -212,7 +223,7 @@ export async function showInterviewRound(questions, opts, ctx) {
|
|
|
212
223
|
}
|
|
213
224
|
function submit() {
|
|
214
225
|
saveEditorToState();
|
|
215
|
-
|
|
226
|
+
finish(buildResult());
|
|
216
227
|
}
|
|
217
228
|
function goNextOrSubmit() {
|
|
218
229
|
if (!isMultiSelect(currentIdx)) {
|
|
@@ -267,7 +278,7 @@ export async function showInterviewRound(questions, opts, ctx) {
|
|
|
267
278
|
return;
|
|
268
279
|
}
|
|
269
280
|
if (data === "2") {
|
|
270
|
-
|
|
281
|
+
finish({ endInterview: false, answers: {} });
|
|
271
282
|
return;
|
|
272
283
|
}
|
|
273
284
|
if (matchesKey(data, Key.enter) || matchesKey(data, Key.space)) {
|
|
@@ -276,7 +287,7 @@ export async function showInterviewRound(questions, opts, ctx) {
|
|
|
276
287
|
refresh();
|
|
277
288
|
}
|
|
278
289
|
else {
|
|
279
|
-
|
|
290
|
+
finish({ endInterview: false, answers: {} });
|
|
280
291
|
}
|
|
281
292
|
return;
|
|
282
293
|
}
|