@gajae-code/coding-agent 0.6.4 → 0.7.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/CHANGELOG.md +51 -0
- package/dist/types/async/job-manager.d.ts +3 -1
- package/dist/types/cli/daemon-cli.d.ts +25 -0
- package/dist/types/cli/migrate-cli.d.ts +20 -0
- package/dist/types/cli/notify-cli.d.ts +23 -0
- package/dist/types/cli/setup-cli.d.ts +20 -1
- package/dist/types/commands/daemon.d.ts +41 -0
- package/dist/types/commands/migrate.d.ts +33 -0
- package/dist/types/commands/notify.d.ts +41 -0
- package/dist/types/config/keybindings.d.ts +4 -0
- package/dist/types/config/model-profile-activation.d.ts +12 -0
- package/dist/types/config/model-profiles.d.ts +2 -1
- package/dist/types/config/model-registry.d.ts +3 -3
- package/dist/types/config/models-config-schema.d.ts +5 -0
- package/dist/types/config/settings-schema.d.ts +38 -0
- package/dist/types/coordinator/contract.d.ts +1 -1
- package/dist/types/daemon/builtin.d.ts +20 -0
- package/dist/types/daemon/control-types.d.ts +57 -0
- package/dist/types/daemon/runtime.d.ts +25 -0
- package/dist/types/extensibility/extensions/types.d.ts +8 -0
- package/dist/types/gjc-runtime/deep-interview-recorder.d.ts +2 -0
- package/dist/types/gjc-runtime/deep-interview-runtime.d.ts +2 -2
- package/dist/types/gjc-runtime/goal-mode-request.d.ts +1 -1
- package/dist/types/gjc-runtime/session-layout.d.ts +59 -0
- package/dist/types/gjc-runtime/session-resolution.d.ts +47 -0
- package/dist/types/gjc-runtime/state-graph.d.ts +1 -1
- package/dist/types/gjc-runtime/state-runtime.d.ts +5 -4
- package/dist/types/gjc-runtime/state-schema.d.ts +2 -0
- package/dist/types/gjc-runtime/state-writer.d.ts +38 -7
- package/dist/types/gjc-runtime/ultragoal-guard.d.ts +15 -0
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +21 -4
- package/dist/types/gjc-runtime/workflow-command-ref.d.ts +1 -1
- package/dist/types/gjc-runtime/workflow-manifest.d.ts +1 -1
- package/dist/types/harness-control-plane/storage.d.ts +2 -1
- package/dist/types/hooks/skill-state.d.ts +12 -4
- package/dist/types/migrate/action-planner.d.ts +11 -0
- package/dist/types/migrate/adapters/claude-code.d.ts +2 -0
- package/dist/types/migrate/adapters/codex.d.ts +5 -0
- package/dist/types/migrate/adapters/index.d.ts +45 -0
- package/dist/types/migrate/adapters/opencode.d.ts +2 -0
- package/dist/types/migrate/executor.d.ts +2 -0
- package/dist/types/migrate/mcp-mapper.d.ts +20 -0
- package/dist/types/migrate/report.d.ts +18 -0
- package/dist/types/migrate/skill-normalizer.d.ts +27 -0
- package/dist/types/migrate/types.d.ts +126 -0
- package/dist/types/modes/components/custom-editor.d.ts +1 -1
- package/dist/types/modes/components/oauth-selector.d.ts +2 -0
- package/dist/types/modes/controllers/selector-controller.d.ts +2 -2
- package/dist/types/modes/interactive-mode.d.ts +1 -1
- package/dist/types/modes/shared/agent-wire/unattended-audit.d.ts +1 -1
- package/dist/types/modes/shared/agent-wire/unattended-session.d.ts +10 -0
- package/dist/types/modes/types.d.ts +7 -1
- package/dist/types/notifications/config-commands.d.ts +26 -0
- package/dist/types/notifications/config.d.ts +61 -0
- package/dist/types/notifications/helpers.d.ts +55 -0
- package/dist/types/notifications/html-format.d.ts +62 -0
- package/dist/types/notifications/index.d.ts +28 -0
- package/dist/types/notifications/rate-limit-pool.d.ts +93 -0
- package/dist/types/notifications/telegram-cli.d.ts +19 -0
- package/dist/types/notifications/telegram-daemon-cli.d.ts +11 -0
- package/dist/types/notifications/telegram-daemon-control.d.ts +56 -0
- package/dist/types/notifications/telegram-daemon.d.ts +276 -0
- package/dist/types/notifications/telegram-reference.d.ts +111 -0
- package/dist/types/notifications/threaded-inbound.d.ts +58 -0
- package/dist/types/notifications/threaded-render.d.ts +66 -0
- package/dist/types/notifications/topic-registry.d.ts +67 -0
- package/dist/types/research-plan/index.d.ts +1 -0
- package/dist/types/research-plan/ledger.d.ts +33 -0
- package/dist/types/rlm/artifacts.d.ts +1 -1
- package/dist/types/rlm/index.d.ts +12 -0
- package/dist/types/runtime-mcp/config-writer.d.ts +26 -0
- package/dist/types/session/agent-session.d.ts +39 -2
- package/dist/types/session/auth-storage.d.ts +1 -1
- package/dist/types/setup/credential-auto-import.d.ts +63 -0
- package/dist/types/setup/credential-import.d.ts +3 -0
- package/dist/types/setup/host-plugin-setup.d.ts +39 -0
- package/dist/types/skill-state/active-state.d.ts +6 -11
- package/dist/types/skill-state/canonical-skills.d.ts +3 -0
- package/dist/types/skill-state/workflow-hud.d.ts +2 -0
- package/dist/types/task/spawn-gate.d.ts +1 -10
- package/dist/types/tools/ask-answer-registry.d.ts +13 -0
- package/dist/types/tools/index.d.ts +18 -0
- package/dist/types/tools/subagent.d.ts +3 -0
- package/package.json +7 -7
- package/scripts/build-binary.ts +3 -0
- package/src/async/job-manager.ts +5 -1
- package/src/cli/daemon-cli.ts +122 -0
- package/src/cli/migrate-cli.ts +106 -0
- package/src/cli/notify-cli.ts +274 -0
- package/src/cli/setup-cli.ts +173 -84
- package/src/cli.ts +3 -0
- package/src/commands/daemon.ts +47 -0
- package/src/commands/deep-interview.ts +2 -2
- package/src/commands/migrate.ts +46 -0
- package/src/commands/notify.ts +61 -0
- package/src/commands/setup.ts +11 -1
- package/src/commands/state.ts +2 -1
- package/src/commands/team.ts +7 -3
- package/src/config/model-profile-activation.ts +74 -5
- package/src/config/model-profiles.ts +7 -4
- package/src/config/model-registry.ts +6 -3
- package/src/config/models-config-schema.ts +1 -1
- package/src/config/settings-schema.ts +29 -0
- package/src/coordinator/contract.ts +3 -0
- package/src/coordinator-mcp/policy.ts +10 -2
- package/src/coordinator-mcp/server.ts +270 -1
- package/src/daemon/builtin.ts +46 -0
- package/src/daemon/control-types.ts +65 -0
- package/src/daemon/runtime.ts +51 -0
- package/src/defaults/gjc/extensions/grok-cli-vendor/biome.json +0 -1
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +28 -24
- package/src/defaults/gjc/skills/ralplan/SKILL.md +8 -4
- package/src/defaults/gjc/skills/team/SKILL.md +51 -47
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +33 -13
- package/src/extensibility/custom-commands/loader.ts +0 -7
- package/src/extensibility/extensions/runner.ts +4 -0
- package/src/extensibility/extensions/types.ts +8 -0
- package/src/extensibility/gjc-plugins/injection.ts +23 -4
- package/src/extensibility/gjc-plugins/state.ts +16 -1
- package/src/gjc-runtime/deep-interview-recorder.ts +51 -18
- package/src/gjc-runtime/deep-interview-runtime.ts +49 -23
- package/src/gjc-runtime/goal-mode-request.ts +26 -11
- package/src/gjc-runtime/launch-tmux.ts +6 -1
- package/src/gjc-runtime/ralplan-runtime.ts +79 -50
- package/src/gjc-runtime/session-layout.ts +180 -0
- package/src/gjc-runtime/session-resolution.ts +217 -0
- package/src/gjc-runtime/state-graph.ts +1 -2
- package/src/gjc-runtime/state-migrations.ts +1 -0
- package/src/gjc-runtime/state-runtime.ts +247 -124
- package/src/gjc-runtime/state-schema.ts +2 -0
- package/src/gjc-runtime/state-writer.ts +289 -41
- package/src/gjc-runtime/team-runtime.ts +43 -19
- package/src/gjc-runtime/tmux-sessions.ts +7 -1
- package/src/gjc-runtime/ultragoal-guard.ts +102 -4
- package/src/gjc-runtime/ultragoal-runtime.ts +226 -60
- package/src/gjc-runtime/workflow-command-ref.ts +1 -2
- package/src/gjc-runtime/workflow-manifest.generated.json +27 -2
- package/src/gjc-runtime/workflow-manifest.ts +12 -3
- package/src/goals/tools/goal-tool.ts +11 -2
- package/src/harness-control-plane/storage.ts +14 -4
- package/src/hooks/native-skill-hook.ts +38 -12
- package/src/hooks/skill-state.ts +178 -83
- package/src/internal-urls/docs-index.generated.ts +9 -6
- package/src/main.ts +30 -0
- package/src/migrate/action-planner.ts +318 -0
- package/src/migrate/adapters/claude-code.ts +39 -0
- package/src/migrate/adapters/codex.ts +70 -0
- package/src/migrate/adapters/index.ts +277 -0
- package/src/migrate/adapters/opencode.ts +52 -0
- package/src/migrate/executor.ts +81 -0
- package/src/migrate/mcp-mapper.ts +152 -0
- package/src/migrate/report.ts +104 -0
- package/src/migrate/skill-normalizer.ts +80 -0
- package/src/migrate/types.ts +163 -0
- package/src/modes/acp/acp-event-mapper.ts +1 -0
- package/src/modes/bridge/bridge-mode.ts +2 -2
- package/src/modes/components/custom-editor.ts +30 -20
- package/src/modes/components/hook-editor.ts +7 -2
- package/src/modes/components/oauth-selector.ts +19 -0
- package/src/modes/controllers/event-controller.ts +20 -0
- package/src/modes/controllers/selector-controller.ts +80 -17
- package/src/modes/interactive-mode.ts +6 -2
- package/src/modes/rpc/rpc-mode.ts +2 -2
- package/src/modes/runtime-init.ts +1 -0
- package/src/modes/shared/agent-wire/event-contract.ts +1 -0
- package/src/modes/shared/agent-wire/event-envelope.ts +1 -0
- package/src/modes/shared/agent-wire/event-observation.ts +16 -0
- package/src/modes/shared/agent-wire/unattended-audit.ts +3 -2
- package/src/modes/shared/agent-wire/unattended-session.ts +22 -0
- package/src/modes/types.ts +7 -1
- package/src/modes/utils/ui-helpers.ts +23 -0
- package/src/notifications/config-commands.ts +50 -0
- package/src/notifications/config.ts +107 -0
- package/src/notifications/helpers.ts +135 -0
- package/src/notifications/html-format.ts +389 -0
- package/src/notifications/index.ts +663 -0
- package/src/notifications/rate-limit-pool.ts +179 -0
- package/src/notifications/telegram-cli.ts +194 -0
- package/src/notifications/telegram-daemon-cli.ts +74 -0
- package/src/notifications/telegram-daemon-control.ts +370 -0
- package/src/notifications/telegram-daemon.ts +1370 -0
- package/src/notifications/telegram-reference.ts +335 -0
- package/src/notifications/threaded-inbound.ts +80 -0
- package/src/notifications/threaded-render.ts +155 -0
- package/src/notifications/topic-registry.ts +133 -0
- package/src/prompts/agents/init.md +1 -1
- package/src/prompts/system/plan-mode-active.md +1 -1
- package/src/prompts/tools/ast-grep.md +1 -1
- package/src/prompts/tools/search.md +1 -1
- package/src/prompts/tools/task.md +1 -2
- package/src/research-plan/index.ts +1 -0
- package/src/research-plan/ledger.ts +177 -0
- package/src/rlm/artifacts.ts +12 -3
- package/src/rlm/index.ts +26 -0
- package/src/runtime-mcp/config-writer.ts +46 -0
- package/src/sdk.ts +16 -0
- package/src/session/agent-session.ts +128 -24
- package/src/session/auth-storage.ts +3 -0
- package/src/session/session-dump-format.ts +43 -2
- package/src/session/session-manager.ts +39 -5
- package/src/setup/credential-auto-import.ts +258 -0
- package/src/setup/credential-import.ts +17 -0
- package/src/setup/hermes/templates/operator-instructions.v1.md +10 -0
- package/src/setup/hermes-setup.ts +1 -1
- package/src/setup/host-plugin-setup.ts +142 -0
- package/src/skill-state/active-state.ts +72 -108
- package/src/skill-state/canonical-skills.ts +4 -0
- package/src/skill-state/deep-interview-mutation-guard.ts +28 -109
- package/src/skill-state/workflow-hud.ts +4 -2
- package/src/skill-state/workflow-state-contract.ts +3 -3
- package/src/slash-commands/builtin-registry.ts +4 -1
- package/src/task/agents.ts +1 -22
- package/src/task/executor.ts +5 -1
- package/src/task/index.ts +1 -41
- package/src/task/spawn-gate.ts +1 -38
- package/src/task/types.ts +1 -1
- package/src/tools/ask-answer-registry.ts +25 -0
- package/src/tools/ask.ts +108 -16
- package/src/tools/computer.ts +58 -4
- package/src/tools/image-gen.ts +5 -8
- package/src/tools/index.ts +19 -0
- package/src/tools/inspect-image.ts +16 -11
- package/src/tools/subagent-render.ts +7 -0
- package/src/tools/subagent.ts +38 -7
- package/dist/types/extensibility/custom-commands/bundled/review/index.d.ts +0 -10
- package/src/extensibility/custom-commands/bundled/review/index.ts +0 -456
- package/src/prompts/agents/explore.md +0 -58
- package/src/prompts/agents/plan.md +0 -49
- package/src/prompts/agents/reviewer.md +0 -141
- package/src/prompts/agents/task.md +0 -16
- package/src/prompts/review-request.md +0 -70
|
@@ -6,10 +6,11 @@ import type { WorkflowHudSummary } from "../skill-state/active-state";
|
|
|
6
6
|
import { buildUltragoalHudSummary as buildWorkflowUltragoalHudSummary } from "../skill-state/workflow-hud";
|
|
7
7
|
import { renderCliWriteReceipt } from "./cli-write-receipt";
|
|
8
8
|
import { DEFAULT_ULTRAGOAL_OBJECTIVE } from "./goal-mode-request";
|
|
9
|
-
import {
|
|
9
|
+
import { gjcRoot, sessionUltragoalDir } from "./session-layout";
|
|
10
|
+
import { resolveGjcSessionForRead, resolveGjcSessionForWrite, writeSessionActivityMarker } from "./session-resolution";
|
|
10
11
|
import { renderUltragoalStatusMarkdown } from "./state-renderer";
|
|
11
12
|
import { reconcileWorkflowSkillState } from "./state-runtime";
|
|
12
|
-
import { appendJsonl, writeArtifact,
|
|
13
|
+
import { appendJsonl, persistedStateRevision, writeArtifact, writeGuardedJsonAtomic } from "./state-writer";
|
|
13
14
|
|
|
14
15
|
export type UltragoalGjcGoalMode = "aggregate" | "per-story";
|
|
15
16
|
export type UltragoalGoalStatus =
|
|
@@ -44,6 +45,7 @@ export interface UltragoalPlan {
|
|
|
44
45
|
goals: UltragoalGoal[];
|
|
45
46
|
createdAt: string;
|
|
46
47
|
updatedAt: string;
|
|
48
|
+
[key: string]: unknown;
|
|
47
49
|
}
|
|
48
50
|
|
|
49
51
|
export type UltragoalReceiptKind = "per-goal" | "final-aggregate";
|
|
@@ -107,6 +109,10 @@ interface JsonObject {
|
|
|
107
109
|
[key: string]: unknown;
|
|
108
110
|
}
|
|
109
111
|
|
|
112
|
+
function currentUltragoalSessionId(cwd: string): string {
|
|
113
|
+
return resolveGjcSessionForWrite(cwd, { envSessionId: process.env.GJC_SESSION_ID }).gjcSessionId;
|
|
114
|
+
}
|
|
115
|
+
|
|
110
116
|
const TERMINAL_OR_SKIPPED_STATUSES = new Set<UltragoalGoalStatus>(["complete", "superseded"]);
|
|
111
117
|
const CLEAN_ARCHITECT_STATUS = "CLEAR";
|
|
112
118
|
const APPROVE_RECOMMENDATION = "APPROVE";
|
|
@@ -162,8 +168,9 @@ export function hashStructuredValue(value: unknown): string {
|
|
|
162
168
|
.digest("hex");
|
|
163
169
|
}
|
|
164
170
|
|
|
165
|
-
export function getUltragoalPaths(cwd: string): UltragoalPaths {
|
|
166
|
-
const
|
|
171
|
+
export function getUltragoalPaths(cwd: string, sessionId?: string | null): UltragoalPaths {
|
|
172
|
+
const explicitSessionId = sessionId?.trim() || process.env.GJC_SESSION_ID?.trim();
|
|
173
|
+
const dir = explicitSessionId ? sessionUltragoalDir(cwd, explicitSessionId) : path.join(gjcRoot(cwd), "ultragoal");
|
|
167
174
|
return {
|
|
168
175
|
dir,
|
|
169
176
|
briefPath: path.join(dir, "brief.md"),
|
|
@@ -178,8 +185,10 @@ function isEnoent(error: unknown): boolean {
|
|
|
178
185
|
);
|
|
179
186
|
}
|
|
180
187
|
|
|
181
|
-
async function appendLedger(cwd: string, event: JsonObject): Promise<UltragoalLedgerEvent> {
|
|
182
|
-
const
|
|
188
|
+
async function appendLedger(cwd: string, event: JsonObject, sessionId?: string | null): Promise<UltragoalLedgerEvent> {
|
|
189
|
+
const resolvedSessionId =
|
|
190
|
+
sessionId?.trim() || resolveGjcSessionForWrite(cwd, { envSessionId: process.env.GJC_SESSION_ID }).gjcSessionId;
|
|
191
|
+
const paths = getUltragoalPaths(cwd, resolvedSessionId);
|
|
183
192
|
const entry: UltragoalLedgerEvent = {
|
|
184
193
|
eventId: typeof event.eventId === "string" ? event.eventId : crypto.randomUUID(),
|
|
185
194
|
...event,
|
|
@@ -187,14 +196,18 @@ async function appendLedger(cwd: string, event: JsonObject): Promise<UltragoalLe
|
|
|
187
196
|
};
|
|
188
197
|
await appendJsonl(paths.ledgerPath, entry, {
|
|
189
198
|
cwd,
|
|
190
|
-
audit: { category: "ledger", verb: "append", owner: "gjc-runtime" },
|
|
199
|
+
audit: { category: "ledger", verb: "append", owner: "gjc-runtime", sessionId: resolvedSessionId },
|
|
191
200
|
});
|
|
201
|
+
await writeSessionActivityMarker(cwd, resolvedSessionId, { writer: "ultragoal-runtime", path: paths.ledgerPath });
|
|
192
202
|
return entry;
|
|
193
203
|
}
|
|
194
204
|
|
|
195
|
-
export async function readUltragoalLedger(cwd: string): Promise<UltragoalLedgerEvent[]> {
|
|
205
|
+
export async function readUltragoalLedger(cwd: string, sessionId?: string | null): Promise<UltragoalLedgerEvent[]> {
|
|
206
|
+
const resolvedSessionId =
|
|
207
|
+
sessionId?.trim() ||
|
|
208
|
+
(await resolveGjcSessionForRead(cwd, { envSessionId: process.env.GJC_SESSION_ID })).gjcSessionId;
|
|
196
209
|
try {
|
|
197
|
-
const raw = await Bun.file(getUltragoalPaths(cwd).ledgerPath).text();
|
|
210
|
+
const raw = await Bun.file(getUltragoalPaths(cwd, resolvedSessionId).ledgerPath).text();
|
|
198
211
|
return raw
|
|
199
212
|
.split(/\r?\n/)
|
|
200
213
|
.map(line => line.trim())
|
|
@@ -206,16 +219,21 @@ export async function readUltragoalLedger(cwd: string): Promise<UltragoalLedgerE
|
|
|
206
219
|
}
|
|
207
220
|
}
|
|
208
221
|
|
|
209
|
-
async function writePlan(cwd: string, plan: UltragoalPlan): Promise<void> {
|
|
210
|
-
const
|
|
222
|
+
async function writePlan(cwd: string, plan: UltragoalPlan, sessionId?: string | null): Promise<void> {
|
|
223
|
+
const resolvedSessionId =
|
|
224
|
+
sessionId?.trim() || resolveGjcSessionForWrite(cwd, { envSessionId: process.env.GJC_SESSION_ID }).gjcSessionId;
|
|
225
|
+
const paths = getUltragoalPaths(cwd, resolvedSessionId);
|
|
211
226
|
await writeArtifact(paths.briefPath, `${plan.brief.trim()}\n`, {
|
|
212
227
|
cwd,
|
|
213
|
-
audit: { category: "artifact", verb: "write", owner: "gjc-runtime" },
|
|
228
|
+
audit: { category: "artifact", verb: "write", owner: "gjc-runtime", sessionId: resolvedSessionId },
|
|
214
229
|
});
|
|
215
|
-
await
|
|
230
|
+
await writeGuardedJsonAtomic(paths.goalsPath, plan, {
|
|
216
231
|
cwd,
|
|
217
|
-
|
|
232
|
+
policy: "source",
|
|
233
|
+
expectedRevision: typeof plan.state_revision === "number" ? persistedStateRevision(plan) : undefined,
|
|
234
|
+
audit: { category: "state", verb: "write", owner: "gjc-runtime", sessionId: resolvedSessionId },
|
|
218
235
|
});
|
|
236
|
+
await writeSessionActivityMarker(cwd, resolvedSessionId, { writer: "ultragoal-runtime", path: paths.goalsPath });
|
|
219
237
|
}
|
|
220
238
|
|
|
221
239
|
function requiredUltragoalGoals(plan: UltragoalPlan): UltragoalGoal[] {
|
|
@@ -426,6 +444,7 @@ function normalizePlan(raw: unknown): UltragoalPlan {
|
|
|
426
444
|
const objective = nonEmptyString(goalRecord.objective) ?? title;
|
|
427
445
|
const goalCreatedAt = nonEmptyString(goalRecord.createdAt) ?? createdAt;
|
|
428
446
|
return {
|
|
447
|
+
...goalRecord,
|
|
429
448
|
id,
|
|
430
449
|
title,
|
|
431
450
|
objective,
|
|
@@ -459,12 +478,18 @@ function normalizePlan(raw: unknown): UltragoalPlan {
|
|
|
459
478
|
goals,
|
|
460
479
|
createdAt,
|
|
461
480
|
updatedAt,
|
|
481
|
+
...(typeof record.state_revision === "number" && Number.isFinite(record.state_revision)
|
|
482
|
+
? { state_revision: record.state_revision }
|
|
483
|
+
: {}),
|
|
462
484
|
};
|
|
463
485
|
}
|
|
464
486
|
|
|
465
|
-
export async function readUltragoalPlan(cwd: string): Promise<UltragoalPlan | null> {
|
|
487
|
+
export async function readUltragoalPlan(cwd: string, sessionId?: string | null): Promise<UltragoalPlan | null> {
|
|
488
|
+
const resolvedSessionId =
|
|
489
|
+
sessionId?.trim() ||
|
|
490
|
+
(await resolveGjcSessionForRead(cwd, { envSessionId: process.env.GJC_SESSION_ID })).gjcSessionId;
|
|
466
491
|
try {
|
|
467
|
-
return normalizePlan(await Bun.file(getUltragoalPaths(cwd).goalsPath).json());
|
|
492
|
+
return normalizePlan(await Bun.file(getUltragoalPaths(cwd, resolvedSessionId).goalsPath).json());
|
|
468
493
|
} catch (error) {
|
|
469
494
|
if (isEnoent(error)) return null;
|
|
470
495
|
throw error;
|
|
@@ -483,9 +508,12 @@ function emptyCounts(): Record<UltragoalGoalStatus, number> {
|
|
|
483
508
|
};
|
|
484
509
|
}
|
|
485
510
|
|
|
486
|
-
export async function getUltragoalStatus(cwd: string): Promise<UltragoalStatusSummary> {
|
|
487
|
-
const
|
|
488
|
-
|
|
511
|
+
export async function getUltragoalStatus(cwd: string, sessionId?: string | null): Promise<UltragoalStatusSummary> {
|
|
512
|
+
const resolvedSessionId =
|
|
513
|
+
sessionId?.trim() ||
|
|
514
|
+
(await resolveGjcSessionForRead(cwd, { envSessionId: process.env.GJC_SESSION_ID })).gjcSessionId;
|
|
515
|
+
const paths = getUltragoalPaths(cwd, resolvedSessionId);
|
|
516
|
+
const plan = await readUltragoalPlan(cwd, resolvedSessionId);
|
|
489
517
|
const counts = emptyCounts();
|
|
490
518
|
if (!plan) return { exists: false, status: "missing", paths, counts, goals: [] };
|
|
491
519
|
for (const goal of plan.goals) counts[goal.status] += 1;
|
|
@@ -577,6 +605,7 @@ export async function createUltragoalPlan(input: {
|
|
|
577
605
|
cwd: string;
|
|
578
606
|
brief: string;
|
|
579
607
|
gjcGoalMode?: UltragoalGjcGoalMode;
|
|
608
|
+
sessionId?: string | null;
|
|
580
609
|
}): Promise<UltragoalPlan> {
|
|
581
610
|
const brief = input.brief.trim();
|
|
582
611
|
if (!brief) throw new Error("ultragoal brief is required");
|
|
@@ -601,8 +630,8 @@ export async function createUltragoalPlan(input: {
|
|
|
601
630
|
createdAt: now,
|
|
602
631
|
updatedAt: now,
|
|
603
632
|
};
|
|
604
|
-
await writePlan(input.cwd, plan);
|
|
605
|
-
await appendLedger(input.cwd, { event: "plan_created", goalIds: plan.goals.map(goal => goal.id) });
|
|
633
|
+
await writePlan(input.cwd, plan, input.sessionId);
|
|
634
|
+
await appendLedger(input.cwd, { event: "plan_created", goalIds: plan.goals.map(goal => goal.id) }, input.sessionId);
|
|
606
635
|
return plan;
|
|
607
636
|
}
|
|
608
637
|
|
|
@@ -639,12 +668,16 @@ export function getUltragoalRunCompletionState(
|
|
|
639
668
|
};
|
|
640
669
|
}
|
|
641
670
|
|
|
642
|
-
export async function startNextUltragoalGoal(input: {
|
|
671
|
+
export async function startNextUltragoalGoal(input: {
|
|
672
|
+
cwd: string;
|
|
673
|
+
retryFailed?: boolean;
|
|
674
|
+
sessionId?: string | null;
|
|
675
|
+
}): Promise<{
|
|
643
676
|
plan: UltragoalPlan;
|
|
644
677
|
goal?: UltragoalGoal;
|
|
645
678
|
allComplete: boolean;
|
|
646
679
|
}> {
|
|
647
|
-
const plan = await readUltragoalPlan(input.cwd);
|
|
680
|
+
const plan = await readUltragoalPlan(input.cwd, input.sessionId);
|
|
648
681
|
if (!plan) throw new Error("No ultragoal plan found. Run `gjc ultragoal create-goals --brief ...` first.");
|
|
649
682
|
const goal = chooseNextGoal(plan, input.retryFailed === true);
|
|
650
683
|
if (!goal) return { plan, allComplete: getUltragoalRunCompletionState(plan).allComplete };
|
|
@@ -654,8 +687,8 @@ export async function startNextUltragoalGoal(input: { cwd: string; retryFailed?:
|
|
|
654
687
|
goal.startedAt = goal.startedAt ?? now;
|
|
655
688
|
goal.updatedAt = now;
|
|
656
689
|
plan.updatedAt = now;
|
|
657
|
-
await writePlan(input.cwd, plan);
|
|
658
|
-
await appendLedger(input.cwd, { event: "goal_started", goalId: goal.id });
|
|
690
|
+
await writePlan(input.cwd, plan, input.sessionId);
|
|
691
|
+
await appendLedger(input.cwd, { event: "goal_started", goalId: goal.id }, input.sessionId);
|
|
659
692
|
}
|
|
660
693
|
return { plan, goal, allComplete: false };
|
|
661
694
|
}
|
|
@@ -865,32 +898,29 @@ function categorizeComputerChangePath(value: string): UltragoalChangeCategory {
|
|
|
865
898
|
return "other";
|
|
866
899
|
}
|
|
867
900
|
|
|
868
|
-
function
|
|
901
|
+
function isComputerControlSurfaceCategory(category: UltragoalChangeCategory): boolean {
|
|
869
902
|
return (
|
|
870
|
-
|
|
871
|
-
(row.oldPath ? categorizeComputerChangePath(row.oldPath) !== "other" : false)
|
|
903
|
+
category === "code" || category === "generated-binding" || category === "tool" || category === "settings-registry"
|
|
872
904
|
);
|
|
873
905
|
}
|
|
874
906
|
|
|
875
|
-
function
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
const oldCategory = row.oldPath ? categorizeComputerChangePath(row.oldPath) : category;
|
|
880
|
-
return category === "docs-static" && oldCategory === "docs-static";
|
|
881
|
-
});
|
|
907
|
+
function isComputerControlSurfaceChangePath(row: UltragoalChangeSetPath): boolean {
|
|
908
|
+
const category = row.category ?? categorizeComputerChangePath(row.path);
|
|
909
|
+
const oldCategory = row.oldPath ? categorizeComputerChangePath(row.oldPath) : category;
|
|
910
|
+
return isComputerControlSurfaceCategory(category) || isComputerControlSurfaceCategory(oldCategory);
|
|
882
911
|
}
|
|
883
912
|
|
|
884
913
|
function trustedChangeSetRequiresComputerSuite(changeSet: UltragoalChangeSet | undefined): boolean {
|
|
885
914
|
if (!changeSet?.trusted) return false;
|
|
886
|
-
|
|
887
|
-
return changeSet.paths.some(isComputerChangePath);
|
|
915
|
+
return changeSet.paths.some(isComputerControlSurfaceChangePath);
|
|
888
916
|
}
|
|
889
917
|
|
|
890
918
|
function requiresComputerRedTeamSuite(executorQa: JsonObject, changeSet: UltragoalChangeSet | undefined): boolean {
|
|
891
919
|
if (trustedChangeSetRequiresComputerSuite(changeSet)) return true;
|
|
892
920
|
const declaredPaths = Array.isArray(executorQa.changedPaths) ? executorQa.changedPaths : [];
|
|
893
|
-
return declaredPaths.some(
|
|
921
|
+
return declaredPaths.some(
|
|
922
|
+
value => typeof value === "string" && isComputerControlSurfaceCategory(categorizeComputerChangePath(value)),
|
|
923
|
+
);
|
|
894
924
|
}
|
|
895
925
|
|
|
896
926
|
function normalizeAdversarialCaseId(value: string): string {
|
|
@@ -2350,6 +2380,8 @@ export async function checkpointUltragoalGoal(input: {
|
|
|
2350
2380
|
if (input.status === "complete") goal.completedAt = now;
|
|
2351
2381
|
plan.updatedAt = now;
|
|
2352
2382
|
await writePlan(input.cwd, plan);
|
|
2383
|
+
const persistedPlan = await readUltragoalPlan(input.cwd);
|
|
2384
|
+
if (persistedPlan?.state_revision !== undefined) plan.state_revision = persistedPlan.state_revision;
|
|
2353
2385
|
await appendLedger(input.cwd, {
|
|
2354
2386
|
eventId: pendingCheckpointEventId,
|
|
2355
2387
|
event: "goal_checkpointed",
|
|
@@ -2799,6 +2831,8 @@ export async function recordUltragoalReviewBlockers(input: {
|
|
|
2799
2831
|
evidence: input.evidence,
|
|
2800
2832
|
gjcGoalJson: input.gjcGoalJson,
|
|
2801
2833
|
});
|
|
2834
|
+
const persistedPlan = await readUltragoalPlan(input.cwd);
|
|
2835
|
+
if (persistedPlan?.state_revision !== undefined) plan.state_revision = persistedPlan.state_revision;
|
|
2802
2836
|
const now = new Date().toISOString();
|
|
2803
2837
|
const nextId = `G${String(plan.goals.length + 1).padStart(3, "0")}`;
|
|
2804
2838
|
plan.goals.push({
|
|
@@ -2816,6 +2850,33 @@ export async function recordUltragoalReviewBlockers(input: {
|
|
|
2816
2850
|
return plan;
|
|
2817
2851
|
}
|
|
2818
2852
|
|
|
2853
|
+
export type UltragoalBlockerClassification = "human_blocked" | "resolvable";
|
|
2854
|
+
|
|
2855
|
+
/**
|
|
2856
|
+
* Record an audited blocker triage classification in the durable ledger. A
|
|
2857
|
+
* `human_blocked` classification is the only thing that authorizes
|
|
2858
|
+
* `goal({"op":"pause"})` while an Ultragoal run is active; `resolvable` is an
|
|
2859
|
+
* audit note and never unblocks pause.
|
|
2860
|
+
*/
|
|
2861
|
+
export async function recordUltragoalBlockerClassification(input: {
|
|
2862
|
+
cwd: string;
|
|
2863
|
+
classification: UltragoalBlockerClassification;
|
|
2864
|
+
evidence: string;
|
|
2865
|
+
goalId?: string;
|
|
2866
|
+
}): Promise<UltragoalLedgerEvent> {
|
|
2867
|
+
const evidence = input.evidence.trim();
|
|
2868
|
+
if (!evidence) throw new Error("classify-blocker --evidence is required");
|
|
2869
|
+
if (input.classification !== "human_blocked" && input.classification !== "resolvable") {
|
|
2870
|
+
throw new Error('classify-blocker --classification must be "human_blocked" or "resolvable"');
|
|
2871
|
+
}
|
|
2872
|
+
return appendLedger(input.cwd, {
|
|
2873
|
+
event: "blocker_classified",
|
|
2874
|
+
classification: input.classification,
|
|
2875
|
+
...(input.goalId?.trim() ? { goalId: input.goalId.trim() } : {}),
|
|
2876
|
+
evidence,
|
|
2877
|
+
});
|
|
2878
|
+
}
|
|
2879
|
+
|
|
2819
2880
|
type UltragoalReviewMode = "review-only" | "review-start";
|
|
2820
2881
|
type UltragoalReviewContractStrength = "strong" | "thin-derived";
|
|
2821
2882
|
|
|
@@ -2883,11 +2944,33 @@ async function spawnText(
|
|
|
2883
2944
|
}
|
|
2884
2945
|
}
|
|
2885
2946
|
|
|
2886
|
-
async function resolveGitBase(cwd: string, branch?: string): Promise<string> {
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2947
|
+
export async function resolveGitBase(cwd: string, branch?: string): Promise<string> {
|
|
2948
|
+
if (branch) {
|
|
2949
|
+
const exists = await spawnText(["git", "rev-parse", "--verify", branch], { cwd, timeoutMs: 3000 });
|
|
2950
|
+
if (exists.ok) return branch;
|
|
2951
|
+
} else {
|
|
2952
|
+
// Prefer the NEAREST integration base (the branch this work actually forks
|
|
2953
|
+
// from) rather than always `main`. A branch opened against `dev` must be
|
|
2954
|
+
// scoped to `dev`; using a stale `main` sweeps in unrelated trunk history
|
|
2955
|
+
// and mis-attributes other people's changes to this story (e.g. falsely
|
|
2956
|
+
// tripping change-scoped gates). Among existing candidates, pick the one
|
|
2957
|
+
// whose merge-base with HEAD is closest to HEAD (fewest commits ahead).
|
|
2958
|
+
const candidates = ["origin/dev", "dev", "origin/main", "origin/master", "main", "master"];
|
|
2959
|
+
let best: { ref: string; ahead: number } | undefined;
|
|
2960
|
+
for (const candidate of candidates) {
|
|
2961
|
+
const exists = await spawnText(["git", "rev-parse", "--verify", candidate], { cwd, timeoutMs: 3000 });
|
|
2962
|
+
if (!exists.ok) continue;
|
|
2963
|
+
const mergeBase = await spawnText(["git", "merge-base", "HEAD", candidate], { cwd, timeoutMs: 3000 });
|
|
2964
|
+
if (!mergeBase.ok || !mergeBase.stdout.trim()) continue;
|
|
2965
|
+
const count = await spawnText(["git", "rev-list", "--count", `${mergeBase.stdout.trim()}..HEAD`], {
|
|
2966
|
+
cwd,
|
|
2967
|
+
timeoutMs: 3000,
|
|
2968
|
+
});
|
|
2969
|
+
const ahead = Number.parseInt(count.stdout.trim(), 10);
|
|
2970
|
+
if (!Number.isFinite(ahead)) continue;
|
|
2971
|
+
if (!best || ahead < best.ahead) best = { ref: candidate, ahead };
|
|
2972
|
+
}
|
|
2973
|
+
if (best) return best.ref;
|
|
2891
2974
|
}
|
|
2892
2975
|
const mergeBase = await spawnText(["git", "merge-base", "HEAD", "origin/main"], { cwd, timeoutMs: 3000 });
|
|
2893
2976
|
if (mergeBase.ok && mergeBase.stdout.trim()) return mergeBase.stdout.trim();
|
|
@@ -3208,6 +3291,7 @@ const FLAGS_WITH_VALUES = new Set([
|
|
|
3208
3291
|
"--rationale",
|
|
3209
3292
|
"--replacements-json",
|
|
3210
3293
|
"--order-json",
|
|
3294
|
+
"--classification",
|
|
3211
3295
|
]);
|
|
3212
3296
|
|
|
3213
3297
|
function isHelpArg(arg: string): boolean {
|
|
@@ -3282,6 +3366,25 @@ function renderUltragoalHelp(args: readonly string[]): string | null {
|
|
|
3282
3366
|
"",
|
|
3283
3367
|
].join("\n");
|
|
3284
3368
|
}
|
|
3369
|
+
if (subject === "classify-blocker") {
|
|
3370
|
+
return [
|
|
3371
|
+
"Run native GJC Ultragoal workflow commands",
|
|
3372
|
+
"",
|
|
3373
|
+
"USAGE",
|
|
3374
|
+
" $ gjc ultragoal classify-blocker --classification <human_blocked|resolvable> --evidence <text> [FLAGS]",
|
|
3375
|
+
"",
|
|
3376
|
+
"FLAGS",
|
|
3377
|
+
" --classification=<value> Required. human_blocked authorizes pause only as the latest ledger event; resolvable never authorizes pause",
|
|
3378
|
+
" --evidence=<value> Required. Specific blocker evidence; must name the human-only dependency for human_blocked",
|
|
3379
|
+
" --goal-id=<value> Optional durable .gjc/ultragoal goal id, e.g. G001",
|
|
3380
|
+
" --json Output a machine-readable receipt",
|
|
3381
|
+
"",
|
|
3382
|
+
"EXAMPLES",
|
|
3383
|
+
' $ gjc ultragoal classify-blocker --classification resolvable --evidence "failing test can be fixed autonomously"',
|
|
3384
|
+
' $ gjc ultragoal classify-blocker --classification human_blocked --evidence "user must provide production API credentials" --goal-id G001',
|
|
3385
|
+
"",
|
|
3386
|
+
].join("\n");
|
|
3387
|
+
}
|
|
3285
3388
|
return [
|
|
3286
3389
|
"Run native GJC Ultragoal workflow commands",
|
|
3287
3390
|
"",
|
|
@@ -3296,8 +3399,9 @@ function renderUltragoalHelp(args: readonly string[]): string | null {
|
|
|
3296
3399
|
" review",
|
|
3297
3400
|
" steer",
|
|
3298
3401
|
" record-review-blockers",
|
|
3402
|
+
" classify-blocker",
|
|
3299
3403
|
"",
|
|
3300
|
-
"Run `gjc ultragoal checkpoint --help` or `gjc ultragoal
|
|
3404
|
+
"Run `gjc ultragoal checkpoint --help`, `gjc ultragoal review --help`, or `gjc ultragoal classify-blocker --help` for command-specific requirements.",
|
|
3301
3405
|
"",
|
|
3302
3406
|
].join("\n");
|
|
3303
3407
|
}
|
|
@@ -3329,7 +3433,7 @@ function renderCompleteHandoff(
|
|
|
3329
3433
|
goal_id: result.goal?.id,
|
|
3330
3434
|
goal_status: result.goal?.status,
|
|
3331
3435
|
gjc_objective: result.plan.gjcObjective,
|
|
3332
|
-
goals_path: getUltragoalPaths(cwd).goalsPath,
|
|
3436
|
+
goals_path: getUltragoalPaths(cwd, currentUltragoalSessionId(cwd)).goalsPath,
|
|
3333
3437
|
});
|
|
3334
3438
|
}
|
|
3335
3439
|
if (result.allComplete) return "ultragoal complete all=true\n";
|
|
@@ -3353,7 +3457,7 @@ function renderCheckpointContinuation(
|
|
|
3353
3457
|
ok: true,
|
|
3354
3458
|
goal_id: result.checkpointedGoal.id,
|
|
3355
3459
|
status,
|
|
3356
|
-
goals_path: getUltragoalPaths(cwd).goalsPath,
|
|
3460
|
+
goals_path: getUltragoalPaths(cwd, currentUltragoalSessionId(cwd)).goalsPath,
|
|
3357
3461
|
completion_receipt_kind: result.checkpointedGoal.completionVerification?.receiptKind,
|
|
3358
3462
|
quality_gate_hash: result.checkpointedGoal.completionVerification?.qualityGateHash,
|
|
3359
3463
|
all_complete: result.allComplete,
|
|
@@ -3407,7 +3511,12 @@ async function executeUltragoalSteeringCommand(args: readonly string[], cwd: str
|
|
|
3407
3511
|
return {
|
|
3408
3512
|
kind,
|
|
3409
3513
|
message: "Accepted add_subgoal steering.\n",
|
|
3410
|
-
receipt: {
|
|
3514
|
+
receipt: {
|
|
3515
|
+
ok: true,
|
|
3516
|
+
kind,
|
|
3517
|
+
goal_id: result.goalId,
|
|
3518
|
+
goals_path: getUltragoalPaths(cwd, currentUltragoalSessionId(cwd)).goalsPath,
|
|
3519
|
+
},
|
|
3411
3520
|
};
|
|
3412
3521
|
}
|
|
3413
3522
|
case "split_subgoal": {
|
|
@@ -3427,7 +3536,7 @@ async function executeUltragoalSteeringCommand(args: readonly string[], cwd: str
|
|
|
3427
3536
|
kind,
|
|
3428
3537
|
goal_id: result.goalId,
|
|
3429
3538
|
replacement_goal_ids: result.replacementGoalIds,
|
|
3430
|
-
goals_path: getUltragoalPaths(cwd).goalsPath,
|
|
3539
|
+
goals_path: getUltragoalPaths(cwd, currentUltragoalSessionId(cwd)).goalsPath,
|
|
3431
3540
|
},
|
|
3432
3541
|
};
|
|
3433
3542
|
}
|
|
@@ -3446,7 +3555,7 @@ async function executeUltragoalSteeringCommand(args: readonly string[], cwd: str
|
|
|
3446
3555
|
ok: true,
|
|
3447
3556
|
kind,
|
|
3448
3557
|
pending_goal_ids: result.pendingGoalIds,
|
|
3449
|
-
goals_path: getUltragoalPaths(cwd).goalsPath,
|
|
3558
|
+
goals_path: getUltragoalPaths(cwd, currentUltragoalSessionId(cwd)).goalsPath,
|
|
3450
3559
|
},
|
|
3451
3560
|
};
|
|
3452
3561
|
}
|
|
@@ -3468,7 +3577,7 @@ async function executeUltragoalSteeringCommand(args: readonly string[], cwd: str
|
|
|
3468
3577
|
kind,
|
|
3469
3578
|
goal_id: result.goalId,
|
|
3470
3579
|
changed_fields: result.changedFields,
|
|
3471
|
-
goals_path: getUltragoalPaths(cwd).goalsPath,
|
|
3580
|
+
goals_path: getUltragoalPaths(cwd, currentUltragoalSessionId(cwd)).goalsPath,
|
|
3472
3581
|
},
|
|
3473
3582
|
};
|
|
3474
3583
|
}
|
|
@@ -3477,7 +3586,11 @@ async function executeUltragoalSteeringCommand(args: readonly string[], cwd: str
|
|
|
3477
3586
|
return {
|
|
3478
3587
|
kind,
|
|
3479
3588
|
message: "Accepted annotate_ledger steering.\n",
|
|
3480
|
-
receipt: {
|
|
3589
|
+
receipt: {
|
|
3590
|
+
ok: true,
|
|
3591
|
+
kind,
|
|
3592
|
+
ledger_path: getUltragoalPaths(cwd, currentUltragoalSessionId(cwd)).ledgerPath,
|
|
3593
|
+
},
|
|
3481
3594
|
};
|
|
3482
3595
|
}
|
|
3483
3596
|
case "mark_blocked_superseded": {
|
|
@@ -3496,7 +3609,7 @@ async function executeUltragoalSteeringCommand(args: readonly string[], cwd: str
|
|
|
3496
3609
|
kind,
|
|
3497
3610
|
goal_id: result.goalId,
|
|
3498
3611
|
no_replacement_required: true,
|
|
3499
|
-
goals_path: getUltragoalPaths(cwd).goalsPath,
|
|
3612
|
+
goals_path: getUltragoalPaths(cwd, currentUltragoalSessionId(cwd)).goalsPath,
|
|
3500
3613
|
},
|
|
3501
3614
|
};
|
|
3502
3615
|
}
|
|
@@ -3517,6 +3630,7 @@ async function executeUltragoalSteeringCommand(args: readonly string[], cwd: str
|
|
|
3517
3630
|
}
|
|
3518
3631
|
|
|
3519
3632
|
async function dispatchUltragoalCommand(args: string[], cwd: string): Promise<UltragoalCommandResult> {
|
|
3633
|
+
const sessionId = currentUltragoalSessionId(cwd);
|
|
3520
3634
|
const help = renderUltragoalHelp(args);
|
|
3521
3635
|
if (help) return { status: 0, stdout: help };
|
|
3522
3636
|
try {
|
|
@@ -3524,7 +3638,7 @@ async function dispatchUltragoalCommand(args: string[], cwd: string): Promise<Ul
|
|
|
3524
3638
|
const json = hasFlag(args, "--json");
|
|
3525
3639
|
switch (command) {
|
|
3526
3640
|
case "status":
|
|
3527
|
-
return { status: 0, stdout: renderStatus(await getUltragoalStatus(cwd), json) };
|
|
3641
|
+
return { status: 0, stdout: renderStatus(await getUltragoalStatus(cwd, sessionId), json) };
|
|
3528
3642
|
case "create":
|
|
3529
3643
|
case "create-goals": {
|
|
3530
3644
|
const mode = flagValue(args, "--gjc-goal-mode") === "per-story" ? "per-story" : "aggregate";
|
|
@@ -3537,9 +3651,9 @@ async function dispatchUltragoalCommand(args: string[], cwd: string): Promise<Ul
|
|
|
3537
3651
|
ok: true,
|
|
3538
3652
|
goals_count: plan.goals.length,
|
|
3539
3653
|
goal_ids: plan.goals.map(goal => goal.id),
|
|
3540
|
-
goals_path: getUltragoalPaths(cwd).goalsPath,
|
|
3654
|
+
goals_path: getUltragoalPaths(cwd, currentUltragoalSessionId(cwd)).goalsPath,
|
|
3541
3655
|
})
|
|
3542
|
-
: `Created ultragoal plan with ${plan.goals.length} goal${plan.goals.length === 1 ? "" : "s"} at ${getUltragoalPaths(cwd).goalsPath}.\n`,
|
|
3656
|
+
: `Created ultragoal plan with ${plan.goals.length} goal${plan.goals.length === 1 ? "" : "s"} at ${getUltragoalPaths(cwd, currentUltragoalSessionId(cwd)).goalsPath}.\n`,
|
|
3543
3657
|
};
|
|
3544
3658
|
}
|
|
3545
3659
|
case "complete-goals":
|
|
@@ -3598,10 +3712,32 @@ async function dispatchUltragoalCommand(args: string[], cwd: string): Promise<Ul
|
|
|
3598
3712
|
return {
|
|
3599
3713
|
status: 0,
|
|
3600
3714
|
stdout: json
|
|
3601
|
-
? renderCliWriteReceipt({
|
|
3715
|
+
? renderCliWriteReceipt({
|
|
3716
|
+
ok: true,
|
|
3717
|
+
goal_id: goal?.id,
|
|
3718
|
+
goals_path: getUltragoalPaths(cwd, currentUltragoalSessionId(cwd)).goalsPath,
|
|
3719
|
+
})
|
|
3602
3720
|
: "Recorded review blockers.\n",
|
|
3603
3721
|
};
|
|
3604
3722
|
}
|
|
3723
|
+
case "classify-blocker": {
|
|
3724
|
+
const event = await recordUltragoalBlockerClassification({
|
|
3725
|
+
cwd,
|
|
3726
|
+
classification: (flagValue(args, "--classification") ?? "") as UltragoalBlockerClassification,
|
|
3727
|
+
evidence: flagValue(args, "--evidence") ?? "",
|
|
3728
|
+
goalId: flagValue(args, "--goal-id"),
|
|
3729
|
+
});
|
|
3730
|
+
return {
|
|
3731
|
+
status: 0,
|
|
3732
|
+
stdout: json
|
|
3733
|
+
? renderCliWriteReceipt({
|
|
3734
|
+
ok: true,
|
|
3735
|
+
event: "blocker_classified",
|
|
3736
|
+
classification: event.classification,
|
|
3737
|
+
})
|
|
3738
|
+
: `Recorded blocker classification: ${String(event.classification)}.\n`,
|
|
3739
|
+
};
|
|
3740
|
+
}
|
|
3605
3741
|
default:
|
|
3606
3742
|
return { status: 1, stderr: `Unknown gjc ultragoal command: ${command}\n` };
|
|
3607
3743
|
}
|
|
@@ -3619,6 +3755,7 @@ const RECONCILE_COMMANDS = new Set([
|
|
|
3619
3755
|
"steer",
|
|
3620
3756
|
"record-review-blockers",
|
|
3621
3757
|
"review",
|
|
3758
|
+
"classify-blocker",
|
|
3622
3759
|
]);
|
|
3623
3760
|
|
|
3624
3761
|
/**
|
|
@@ -3632,9 +3769,9 @@ const RECONCILE_COMMANDS = new Set([
|
|
|
3632
3769
|
* beyond that reconcile-failure audit event.
|
|
3633
3770
|
*/
|
|
3634
3771
|
async function reconcileUltragoalState(cwd: string): Promise<void> {
|
|
3635
|
-
const sessionId =
|
|
3772
|
+
const sessionId = currentUltragoalSessionId(cwd);
|
|
3636
3773
|
try {
|
|
3637
|
-
const summary = await getUltragoalStatus(cwd);
|
|
3774
|
+
const summary = await getUltragoalStatus(cwd, sessionId);
|
|
3638
3775
|
const status = summary.status;
|
|
3639
3776
|
const active = summary.exists && status !== "complete";
|
|
3640
3777
|
const payload: Record<string, unknown> = {
|
|
@@ -3653,15 +3790,44 @@ async function reconcileUltragoalState(cwd: string): Promise<void> {
|
|
|
3653
3790
|
const ledgerText = await Bun.file(summary.paths.ledgerPath)
|
|
3654
3791
|
.text()
|
|
3655
3792
|
.catch(() => "");
|
|
3656
|
-
const latestLedger =
|
|
3793
|
+
const latestLedger = ledgerText
|
|
3794
|
+
.split(/\r?\n/)
|
|
3795
|
+
.map(line => line.trim())
|
|
3796
|
+
.filter(Boolean)
|
|
3797
|
+
.toReversed()
|
|
3798
|
+
.map(line => {
|
|
3799
|
+
try {
|
|
3800
|
+
const row = JSON.parse(line) as Record<string, unknown>;
|
|
3801
|
+
const event =
|
|
3802
|
+
typeof row.event === "string" ? row.event : typeof row.type === "string" ? row.type : undefined;
|
|
3803
|
+
return event ? { ...row, event } : undefined;
|
|
3804
|
+
} catch {
|
|
3805
|
+
return undefined;
|
|
3806
|
+
}
|
|
3807
|
+
})
|
|
3808
|
+
.find((row): row is Record<string, unknown> & { event: string } => Boolean(row));
|
|
3657
3809
|
if (latestLedger) {
|
|
3658
3810
|
payload.latestLedgerEvent = {
|
|
3659
3811
|
event: latestLedger.event,
|
|
3660
3812
|
...(latestLedger.goalId ? { goalId: latestLedger.goalId } : {}),
|
|
3661
3813
|
...(latestLedger.timestamp ? { timestamp: latestLedger.timestamp } : {}),
|
|
3814
|
+
...(typeof latestLedger.kind === "string" ? { kind: latestLedger.kind } : {}),
|
|
3815
|
+
...(typeof latestLedger.evidence === "string" ? { evidence: latestLedger.evidence } : {}),
|
|
3662
3816
|
};
|
|
3663
3817
|
}
|
|
3664
|
-
|
|
3818
|
+
const sourceRevision = Math.max(
|
|
3819
|
+
persistedStateRevision(await readUltragoalPlan(cwd, sessionId)),
|
|
3820
|
+
ledgerText.split(/\r?\n/).filter(line => line.trim().length > 0).length,
|
|
3821
|
+
);
|
|
3822
|
+
await reconcileWorkflowSkillState({
|
|
3823
|
+
cwd,
|
|
3824
|
+
mode: "ultragoal",
|
|
3825
|
+
sessionId,
|
|
3826
|
+
active,
|
|
3827
|
+
phase: status,
|
|
3828
|
+
payload,
|
|
3829
|
+
...(sourceRevision > 0 ? { sourceRevision } : {}),
|
|
3830
|
+
});
|
|
3665
3831
|
} catch (error) {
|
|
3666
3832
|
const message = error instanceof Error ? error.message : String(error);
|
|
3667
3833
|
process.stderr.write(`ultragoal state reconciliation failed: ${message}\n`);
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import type
|
|
2
|
-
import { CANONICAL_GJC_WORKFLOW_SKILLS } from "../skill-state/active-state";
|
|
1
|
+
import { CANONICAL_GJC_WORKFLOW_SKILLS, type CanonicalGjcWorkflowSkill } from "../skill-state/canonical-skills";
|
|
3
2
|
|
|
4
3
|
export type CommandRefVisibility = "public" | "hidden" | "planned";
|
|
5
4
|
export type CommandRefIncludeWhen = "implemented-only" | "planned";
|
|
@@ -1443,7 +1443,8 @@
|
|
|
1443
1443
|
"appliesToVerbs": [
|
|
1444
1444
|
"checkpoint",
|
|
1445
1445
|
"record-review-blockers",
|
|
1446
|
-
"steer"
|
|
1446
|
+
"steer",
|
|
1447
|
+
"classify-blocker"
|
|
1447
1448
|
],
|
|
1448
1449
|
"name": "evidence",
|
|
1449
1450
|
"required": true,
|
|
@@ -1471,6 +1472,25 @@
|
|
|
1471
1472
|
"name": "goal-id",
|
|
1472
1473
|
"type": "string"
|
|
1473
1474
|
},
|
|
1475
|
+
{
|
|
1476
|
+
"appliesToVerbs": [
|
|
1477
|
+
"classify-blocker"
|
|
1478
|
+
],
|
|
1479
|
+
"name": "goal-id",
|
|
1480
|
+
"type": "string"
|
|
1481
|
+
},
|
|
1482
|
+
{
|
|
1483
|
+
"appliesToVerbs": [
|
|
1484
|
+
"classify-blocker"
|
|
1485
|
+
],
|
|
1486
|
+
"enumValues": [
|
|
1487
|
+
"human_blocked",
|
|
1488
|
+
"resolvable"
|
|
1489
|
+
],
|
|
1490
|
+
"name": "classification",
|
|
1491
|
+
"required": true,
|
|
1492
|
+
"type": "enum"
|
|
1493
|
+
},
|
|
1474
1494
|
{
|
|
1475
1495
|
"appliesToVerbs": [
|
|
1476
1496
|
"steer"
|
|
@@ -1570,7 +1590,8 @@
|
|
|
1570
1590
|
"review",
|
|
1571
1591
|
"checkpoint",
|
|
1572
1592
|
"record-review-blockers",
|
|
1573
|
-
"steer"
|
|
1593
|
+
"steer",
|
|
1594
|
+
"classify-blocker"
|
|
1574
1595
|
],
|
|
1575
1596
|
"name": "json",
|
|
1576
1597
|
"type": "boolean"
|
|
@@ -1651,6 +1672,10 @@
|
|
|
1651
1672
|
"name": "steer",
|
|
1652
1673
|
"surface": "command-positional"
|
|
1653
1674
|
},
|
|
1675
|
+
{
|
|
1676
|
+
"name": "classify-blocker",
|
|
1677
|
+
"surface": "command-positional"
|
|
1678
|
+
},
|
|
1654
1679
|
{
|
|
1655
1680
|
"name": "graph",
|
|
1656
1681
|
"planned": true,
|