@gajae-code/coding-agent 0.16.4 → 0.16.6
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 +54 -0
- package/dist/types/capability/types.d.ts +4 -0
- package/dist/types/cli/customize-doctor.d.ts +22 -0
- package/dist/types/config/file-lock.d.ts +31 -3
- package/dist/types/coordinator-mcp/question-state.d.ts +7 -0
- package/dist/types/coordinator-mcp/server.d.ts +7 -0
- package/dist/types/discovery/helpers.d.ts +33 -0
- package/dist/types/exec/bash-executor.d.ts +17 -1
- package/dist/types/exec/bash-shell-guardian.d.ts +15 -0
- package/dist/types/exec/bash-shell-runtime-entry.d.ts +2 -0
- package/dist/types/exec/bash-shell-signals.d.ts +2 -0
- package/dist/types/exec/bash-shell-supervisor-entry.d.ts +1 -0
- package/dist/types/exec/bash-shell-supervisor.d.ts +10 -0
- package/dist/types/exec/bash-shell-worker-entry.d.ts +2 -0
- package/dist/types/exec/bash-shell-worker-protocol.d.ts +63 -0
- package/dist/types/exec/bash-shell-worker.d.ts +1 -0
- package/dist/types/exec/isolated-shell.d.ts +19 -0
- package/dist/types/extensibility/extensions/function-hooks-internal.d.ts +9 -0
- package/dist/types/extensibility/extensions/function-hooks.d.ts +169 -0
- package/dist/types/extensibility/extensions/index.d.ts +1 -0
- package/dist/types/extensibility/extensions/runner.d.ts +46 -6
- package/dist/types/extensibility/extensions/types.d.ts +16 -0
- package/dist/types/extensibility/extensions/wrapper.d.ts +3 -1
- package/dist/types/extensibility/gjc-plugins/constrained-hooks.d.ts +35 -2
- package/dist/types/extensibility/gjc-plugins/types.d.ts +25 -0
- package/dist/types/extensibility/hooks/types.d.ts +4 -0
- package/dist/types/extensibility/runtime-skill-discovery.d.ts +4 -1
- package/dist/types/extensibility/skill-management.d.ts +9 -4
- package/dist/types/extensibility/skills.d.ts +2 -0
- package/dist/types/gjc-runtime/empty-delete-gc.d.ts +4 -1
- package/dist/types/gjc-runtime/linux-proc.d.ts +2 -0
- package/dist/types/gjc-runtime/session-state-lock.d.ts +12 -0
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +41 -3
- package/dist/types/gjc-runtime/ultragoal-succession.d.ts +251 -0
- package/dist/types/modes/components/bash-execution.d.ts +1 -0
- package/dist/types/modes/components/execution-shared.d.ts +1 -0
- package/dist/types/modes/interactive-mode.d.ts +2 -0
- package/dist/types/modes/types.d.ts +6 -0
- package/dist/types/sdk/broker/ensure.d.ts +32 -0
- package/dist/types/sdk/broker/lifecycle-ledger.d.ts +0 -1
- package/dist/types/sdk/broker/lifecycle.d.ts +6 -0
- package/dist/types/sdk/broker/startup-failure.d.ts +4 -1
- package/dist/types/sdk/bus/chat-daemon-control.d.ts +2 -0
- package/dist/types/sdk/bus/chat-effect-journal.d.ts +17 -2
- package/dist/types/sdk/bus/conversation-store.d.ts +11 -0
- package/dist/types/sdk/bus/lifecycle-commands.d.ts +8 -8
- package/dist/types/sdk/bus/slack-daemon.d.ts +1 -1
- package/dist/types/sdk/bus/topic-registry.d.ts +8 -0
- package/dist/types/sdk/client/client.d.ts +6 -0
- package/dist/types/sdk/host/host.d.ts +3 -1
- package/dist/types/sdk/host/session-runtime.d.ts +4 -2
- package/dist/types/sdk/lifecycle/service.d.ts +1 -0
- package/dist/types/sdk/router/session-router.d.ts +10 -2
- package/dist/types/sdk/session.d.ts +5 -1
- package/dist/types/session/agent-session.d.ts +2 -0
- package/dist/types/session/fallback-chain-controller.d.ts +15 -0
- package/dist/types/session/internal/managed-session-storage.d.ts +7 -0
- package/dist/types/session/messages.d.ts +1 -0
- package/dist/types/session/session-manager.d.ts +3 -1
- package/dist/types/setup/paseo/announce.d.ts +4 -3
- package/dist/types/skill-state/canonical-skills.d.ts +4 -0
- package/dist/types/system-prompt.d.ts +8 -0
- package/dist/types/task/executor.d.ts +3 -0
- package/dist/types/tools/bash.d.ts +1 -0
- package/dist/types/tools/github-cache.d.ts +2 -1
- package/dist/types/tools/index.d.ts +2 -0
- package/package.json +9 -7
- package/scripts/generate-sdk-operation-inventory.ts +2 -0
- package/src/capability/index.ts +14 -2
- package/src/capability/types.ts +4 -0
- package/src/cli/customize-doctor.ts +155 -12
- package/src/cli.ts +22 -0
- package/src/commands/sdk.ts +74 -31
- package/src/config/file-lock-gc.ts +40 -2
- package/src/config/file-lock.ts +198 -14
- package/src/config/model-preset-registry.ts +115 -16
- package/src/config/model-registry.ts +16 -12
- package/src/coordinator-mcp/question-state.ts +33 -2
- package/src/coordinator-mcp/server.ts +477 -101
- package/src/crash/sanitize.ts +1 -1
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +22 -0
- package/src/discovery/builtin.ts +50 -62
- package/src/discovery/helpers.ts +297 -32
- package/src/exec/bash-executor.ts +330 -50
- package/src/exec/bash-shell-guardian.ts +388 -0
- package/src/exec/bash-shell-runtime-entry.ts +5 -0
- package/src/exec/bash-shell-signals.ts +29 -0
- package/src/exec/bash-shell-supervisor-entry.ts +3 -0
- package/src/exec/bash-shell-supervisor.ts +359 -0
- package/src/exec/bash-shell-worker-entry.ts +5 -0
- package/src/exec/bash-shell-worker-protocol.ts +36 -0
- package/src/exec/bash-shell-worker.ts +116 -0
- package/src/exec/isolated-shell.ts +393 -0
- package/src/extensibility/extensions/function-hooks-internal.ts +73 -0
- package/src/extensibility/extensions/function-hooks.ts +959 -0
- package/src/extensibility/extensions/index.ts +22 -0
- package/src/extensibility/extensions/loader.ts +53 -2
- package/src/extensibility/extensions/runner.ts +895 -264
- package/src/extensibility/extensions/types.ts +42 -0
- package/src/extensibility/extensions/wrapper.ts +56 -15
- package/src/extensibility/gjc-plugins/compiler.ts +20 -2
- package/src/extensibility/gjc-plugins/constrained-hooks.ts +321 -23
- package/src/extensibility/gjc-plugins/registry.ts +113 -1
- package/src/extensibility/gjc-plugins/runtime-quarantine.ts +20 -2
- package/src/extensibility/gjc-plugins/schema.ts +121 -4
- package/src/extensibility/gjc-plugins/types.ts +25 -0
- package/src/extensibility/hooks/loader.ts +133 -16
- package/src/extensibility/hooks/types.ts +28 -0
- package/src/extensibility/runtime-skill-discovery.ts +80 -47
- package/src/extensibility/skill-management.ts +200 -52
- package/src/extensibility/skills.ts +29 -9
- package/src/gjc-runtime/empty-delete-gc.ts +94 -4
- package/src/gjc-runtime/gc-runtime.ts +29 -0
- package/src/gjc-runtime/linux-proc.ts +14 -0
- package/src/gjc-runtime/session-state-lock.ts +51 -8
- package/src/gjc-runtime/session-state-sidecar.ts +27 -11
- package/src/gjc-runtime/state-writer.ts +30 -29
- package/src/gjc-runtime/ultragoal-runtime.ts +189 -47
- package/src/gjc-runtime/ultragoal-succession.ts +1667 -0
- package/src/gjc-runtime/workflow-manifest.generated.json +52 -1
- package/src/gjc-runtime/workflow-manifest.ts +16 -0
- package/src/harness-control-plane/session-lease.ts +2 -2
- package/src/internal-urls/docs-index.generated.ts +6 -6
- package/src/lsp/config.ts +10 -3
- package/src/lsp/index.ts +1 -1
- package/src/lsp/path-trust.ts +69 -14
- package/src/main.ts +6 -1
- package/src/modes/acp/acp-agent.ts +16 -3
- package/src/modes/components/bash-execution.ts +4 -1
- package/src/modes/components/execution-shared.ts +4 -1
- package/src/modes/components/session-observer-overlay.ts +1 -1
- package/src/modes/components/tool-status-header.ts +3 -1
- package/src/modes/controllers/command-controller.ts +1 -0
- package/src/modes/controllers/event-controller.ts +3 -2
- package/src/modes/controllers/extension-ui-controller.ts +1 -0
- package/src/modes/controllers/input-controller.ts +6 -3
- package/src/modes/interactive-mode.ts +6 -5
- package/src/modes/print-mode.ts +5 -1
- package/src/modes/prompt-action-autocomplete.ts +54 -27
- package/src/modes/runtime-init.ts +2 -0
- package/src/modes/types.ts +16 -3
- package/src/modes/utils/ui-helpers.ts +1 -0
- package/src/prompts/tools/subagent.md +1 -0
- package/src/runtime-mcp/manager.ts +20 -2
- package/src/runtime-mcp/pool.test.ts +20 -11
- package/src/sdk/broker/broker.ts +119 -28
- package/src/sdk/broker/ensure.ts +248 -41
- package/src/sdk/broker/lifecycle-ledger.ts +7 -17
- package/src/sdk/broker/lifecycle.ts +56 -6
- package/src/sdk/broker/startup-failure.ts +15 -6
- package/src/sdk/bus/chat-daemon-control.ts +3 -1
- package/src/sdk/bus/chat-daemon-runtime.ts +35 -5
- package/src/sdk/bus/chat-effect-journal.ts +132 -7
- package/src/sdk/bus/conversation-store.ts +29 -0
- package/src/sdk/bus/lifecycle-commands.ts +17 -11
- package/src/sdk/bus/slack-conversation.ts +1 -0
- package/src/sdk/bus/slack-daemon.ts +387 -48
- package/src/sdk/bus/telegram-daemon.ts +16 -2
- package/src/sdk/bus/topic-registry.ts +19 -0
- package/src/sdk/cli/master-cli.ts +1 -1
- package/src/sdk/cli/session-cli.ts +2 -2
- package/src/sdk/client/client.ts +66 -17
- package/src/sdk/host/host.ts +29 -9
- package/src/sdk/host/query/revision-store.ts +19 -13
- package/src/sdk/host/reverse-leases.ts +7 -4
- package/src/sdk/host/session-runtime.test.ts +50 -8
- package/src/sdk/host/session-runtime.ts +158 -51
- package/src/sdk/lifecycle/service.ts +4 -0
- package/src/sdk/protocol/operation-inventory.generated.json +11 -0
- package/src/sdk/router/session-router.ts +89 -38
- package/src/sdk/session.ts +155 -26
- package/src/sdk/transport/relay.ts +35 -13
- package/src/session/agent-session.ts +117 -52
- package/src/session/fallback-chain-controller.ts +38 -0
- package/src/session/internal/managed-session-storage.ts +19 -5
- package/src/session/messages.ts +5 -0
- package/src/session/session-manager.ts +29 -5
- package/src/session-import/redact.ts +5 -1
- package/src/setup/paseo/announce.ts +49 -43
- package/src/setup/paseo/setup-deps.ts +1 -1
- package/src/skill-state/canonical-skills.ts +12 -0
- package/src/skills/skills.test.ts +41 -21
- package/src/system-prompt.ts +25 -3
- package/src/task/executor.ts +5 -0
- package/src/task/index.ts +4 -0
- package/src/tools/bash.ts +28 -11
- package/src/tools/gh.ts +26 -3
- package/src/tools/github-cache.ts +68 -16
- package/src/tools/index.ts +2 -0
- package/src/tools/job.ts +13 -2
- package/src/tools/read.ts +14 -2
- package/src/tools/render-utils.ts +1 -3
- package/src/tools/resource-gc.ts +28 -8
- package/src/tools/skill-discovery.ts +5 -0
- package/src/tools/skill.ts +15 -0
- package/src/tools/subagent.ts +3 -2
- package/src/tools/tool-catalog.generated.ts +2 -2
- package/src/tools/ultragoal-ask-guard.ts +2 -2
|
@@ -79,6 +79,11 @@ import {
|
|
|
79
79
|
type UltragoalChangeSetPath,
|
|
80
80
|
type UltragoalChangeStatus,
|
|
81
81
|
} from "./ultragoal-change-set";
|
|
82
|
+
import {
|
|
83
|
+
assertUltragoalAdoptionPublished,
|
|
84
|
+
assertUltragoalGoalNotFenced,
|
|
85
|
+
runUltragoalSuccessionCommand,
|
|
86
|
+
} from "./ultragoal-succession";
|
|
82
87
|
import {
|
|
83
88
|
resolveUltragoalValidationApplicability,
|
|
84
89
|
type UltragoalValidationApplicability,
|
|
@@ -560,7 +565,13 @@ export async function recordUltragoalNudgeIfBudgetRemaining(input: {
|
|
|
560
565
|
);
|
|
561
566
|
}
|
|
562
567
|
|
|
563
|
-
export async function writePlan(
|
|
568
|
+
export async function writePlan(
|
|
569
|
+
cwd: string,
|
|
570
|
+
plan: UltragoalPlan,
|
|
571
|
+
sessionId?: string | null,
|
|
572
|
+
/** Set by callers already inside {@link withUltragoalPlanOwnership} for this plan. */
|
|
573
|
+
options: { lockHeld?: boolean } = {},
|
|
574
|
+
): Promise<void> {
|
|
564
575
|
const resolvedSessionId =
|
|
565
576
|
sessionId?.trim() || resolveGjcSessionForWrite(cwd, { envSessionId: process.env.GJC_SESSION_ID }).gjcSessionId;
|
|
566
577
|
const paths = getUltragoalPaths(cwd, resolvedSessionId);
|
|
@@ -571,12 +582,47 @@ export async function writePlan(cwd: string, plan: UltragoalPlan, sessionId?: st
|
|
|
571
582
|
await writeGuardedJsonAtomic(paths.goalsPath, plan, {
|
|
572
583
|
cwd,
|
|
573
584
|
policy: "source",
|
|
585
|
+
lockHeld: options.lockHeld === true,
|
|
574
586
|
expectedRevision: typeof plan.state_revision === "number" ? persistedStateRevision(plan) : undefined,
|
|
575
587
|
audit: { category: "state", verb: "write", owner: "gjc-runtime", sessionId: resolvedSessionId },
|
|
576
588
|
});
|
|
577
589
|
await writeSessionActivityMarker(cwd, resolvedSessionId, { writer: "ultragoal-runtime", path: paths.goalsPath });
|
|
578
590
|
}
|
|
579
591
|
|
|
592
|
+
/**
|
|
593
|
+
* The single exclusion that decides who owns an Ultragoal run (#5353).
|
|
594
|
+
*
|
|
595
|
+
* Establishing ownership is a read-decide-write sequence, not a write: a start
|
|
596
|
+
* reads the plan, checks the outgoing succession fence, then commits `active`.
|
|
597
|
+
* Checking quiescence at a point in time and writing afterwards is not enough —
|
|
598
|
+
* an offer can observe `pending` in the window between an in-flight start's
|
|
599
|
+
* check and its commit, and both runs then believe they own the goal.
|
|
600
|
+
*
|
|
601
|
+
* Every caller that decides ownership — source admission (`start`/`checkpoint`),
|
|
602
|
+
* succession offer/fence issuance, and successor publication — runs its whole
|
|
603
|
+
* decision inside this lock, keyed on the plan it is deciding about, and
|
|
604
|
+
* re-reads the plan under it. Writers inside pass `lockHeld` because
|
|
605
|
+
* `withFileLock` intentionally serializes same-process callers as well.
|
|
606
|
+
*
|
|
607
|
+
* Lock ordering: this lock is always taken BEFORE any ledger lock. The existing
|
|
608
|
+
* ledger-scoped critical sections (nudge budget, critic verdict, critic gate
|
|
609
|
+
* override) never write the plan, so no cycle exists.
|
|
610
|
+
*/
|
|
611
|
+
export async function withUltragoalPlanOwnership<T>(cwd: string, sessionId: string, fn: () => Promise<T>): Promise<T> {
|
|
612
|
+
return withWorkflowStateLock(getUltragoalPaths(cwd, sessionId).goalsPath, fn, { cwd });
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
/**
|
|
616
|
+
* Resolve the session whose plan ownership is being decided, without changing
|
|
617
|
+
* the resolution behaviour callers already depend on.
|
|
618
|
+
*/
|
|
619
|
+
export async function resolveUltragoalOwnershipSession(cwd: string, sessionId?: string | null): Promise<string> {
|
|
620
|
+
return (
|
|
621
|
+
sessionId?.trim() ||
|
|
622
|
+
(await resolveGjcSessionForRead(cwd, { envSessionId: process.env.GJC_SESSION_ID })).gjcSessionId
|
|
623
|
+
);
|
|
624
|
+
}
|
|
625
|
+
|
|
580
626
|
function chooseReceiptKind(
|
|
581
627
|
plan: UltragoalPlan,
|
|
582
628
|
ledger: readonly UltragoalLedgerEvent[],
|
|
@@ -1315,40 +1361,53 @@ export async function startNextUltragoalGoal(input: {
|
|
|
1315
1361
|
allComplete: boolean;
|
|
1316
1362
|
nextAction: UltragoalCompleteNextAction;
|
|
1317
1363
|
}> {
|
|
1318
|
-
const
|
|
1319
|
-
|
|
1320
|
-
//
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
);
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1364
|
+
const sessionId = await resolveUltragoalOwnershipSession(input.cwd, input.sessionId);
|
|
1365
|
+
// Claiming a goal is a read-decide-write sequence. It runs entirely inside the
|
|
1366
|
+
// plan-ownership exclusion so a succession offer cannot observe this run as
|
|
1367
|
+
// idle between the fence check and the commit of `active` (#5353).
|
|
1368
|
+
return withUltragoalPlanOwnership(input.cwd, sessionId, async () => {
|
|
1369
|
+
const plan = await readUltragoalPlan(input.cwd, sessionId);
|
|
1370
|
+
if (!plan) throw new Error("No ultragoal plan found. Run `gjc ultragoal create-goals --brief ...` first.");
|
|
1371
|
+
// Fail closed: delegated execution requires stamped repository authority (#2901).
|
|
1372
|
+
if (!plan.repositoryBinding) {
|
|
1373
|
+
throw new Error(
|
|
1374
|
+
"Ultragoal plan is missing repositoryBinding; recreate goals so the plan is bound to an authoritative repository identity.",
|
|
1375
|
+
);
|
|
1376
|
+
}
|
|
1377
|
+
await assertCwdMatchesRepositoryBinding(input.cwd, plan.repositoryBinding);
|
|
1378
|
+
// Fail closed before any mutation: a run whose cross-repository adoption never
|
|
1379
|
+
// finished publishing does not own its goals yet, however visible goals.json is
|
|
1380
|
+
// (#5353).
|
|
1381
|
+
await assertUltragoalAdoptionPublished(input.cwd, sessionId);
|
|
1382
|
+
const retryFailed = input.retryFailed === true;
|
|
1383
|
+
const goal = chooseNextGoal(plan, retryFailed);
|
|
1384
|
+
// Re-checked under the exclusion, not before it: an offer that won the lock
|
|
1385
|
+
// first has already published its fence by the time we get here.
|
|
1386
|
+
if (goal) await assertUltragoalGoalNotFenced(input.cwd, sessionId, goal.id);
|
|
1387
|
+
if (!goal) {
|
|
1388
|
+
const state = getUltragoalRunCompletionState(plan, { retryFailed });
|
|
1389
|
+
return {
|
|
1390
|
+
plan,
|
|
1391
|
+
allComplete: state.allComplete,
|
|
1392
|
+
nextAction: resolveUltragoalCompleteNextAction(plan, { retryFailed }),
|
|
1393
|
+
};
|
|
1394
|
+
}
|
|
1395
|
+
if (goal.status !== "active") {
|
|
1396
|
+
const now = new Date().toISOString();
|
|
1397
|
+
goal.status = "active";
|
|
1398
|
+
goal.startedAt = goal.startedAt ?? now;
|
|
1399
|
+
goal.updatedAt = now;
|
|
1400
|
+
plan.updatedAt = now;
|
|
1401
|
+
await writePlan(input.cwd, plan, sessionId, { lockHeld: true });
|
|
1402
|
+
await appendLedger(input.cwd, { event: "goal_started", goalId: goal.id }, sessionId);
|
|
1403
|
+
}
|
|
1331
1404
|
return {
|
|
1332
1405
|
plan,
|
|
1333
|
-
|
|
1334
|
-
|
|
1406
|
+
goal,
|
|
1407
|
+
allComplete: false,
|
|
1408
|
+
nextAction: { kind: "execute-goal", goal },
|
|
1335
1409
|
};
|
|
1336
|
-
}
|
|
1337
|
-
if (goal.status !== "active") {
|
|
1338
|
-
const now = new Date().toISOString();
|
|
1339
|
-
goal.status = "active";
|
|
1340
|
-
goal.startedAt = goal.startedAt ?? now;
|
|
1341
|
-
goal.updatedAt = now;
|
|
1342
|
-
plan.updatedAt = now;
|
|
1343
|
-
await writePlan(input.cwd, plan, input.sessionId);
|
|
1344
|
-
await appendLedger(input.cwd, { event: "goal_started", goalId: goal.id }, input.sessionId);
|
|
1345
|
-
}
|
|
1346
|
-
return {
|
|
1347
|
-
plan,
|
|
1348
|
-
goal,
|
|
1349
|
-
allComplete: false,
|
|
1350
|
-
nextAction: { kind: "execute-goal", goal },
|
|
1351
|
-
};
|
|
1410
|
+
});
|
|
1352
1411
|
}
|
|
1353
1412
|
|
|
1354
1413
|
async function readStructuredValue(cwd: string, value: string): Promise<unknown> {
|
|
@@ -3496,17 +3555,41 @@ function validateCompleteCheckpointTargetGoal(goal: UltragoalGoal): void {
|
|
|
3496
3555
|
);
|
|
3497
3556
|
}
|
|
3498
3557
|
|
|
3499
|
-
export
|
|
3558
|
+
export interface UltragoalCheckpointInput {
|
|
3500
3559
|
cwd: string;
|
|
3501
3560
|
goalId: string;
|
|
3502
3561
|
status: UltragoalGoalStatus;
|
|
3503
3562
|
evidence: string;
|
|
3504
3563
|
qualityGateJson?: string;
|
|
3505
|
-
}
|
|
3506
|
-
|
|
3564
|
+
}
|
|
3565
|
+
|
|
3566
|
+
/**
|
|
3567
|
+
* Checkpointing shares its plan with a succession offer, but only its *commit*
|
|
3568
|
+
* is fenced against one (#5353). Completion validation must observe the same
|
|
3569
|
+
* repository basis `quality-gate source-hash` did, and the ownership lock's own
|
|
3570
|
+
* on-disk artifact lives under `.gjc/` — a path repositories are not required to
|
|
3571
|
+
* ignore — so capturing the basis while holding it would make the runtime digest
|
|
3572
|
+
* disagree with the gate the caller was told to produce.
|
|
3573
|
+
*/
|
|
3574
|
+
export async function checkpointUltragoalGoal(input: UltragoalCheckpointInput): Promise<UltragoalPlan> {
|
|
3575
|
+
const sessionId = await resolveUltragoalOwnershipSession(input.cwd, null);
|
|
3576
|
+
return checkpointUltragoalGoalForSession(input, sessionId);
|
|
3577
|
+
}
|
|
3578
|
+
|
|
3579
|
+
async function checkpointUltragoalGoalForSession(
|
|
3580
|
+
input: UltragoalCheckpointInput,
|
|
3581
|
+
sessionId: string,
|
|
3582
|
+
): Promise<UltragoalPlan> {
|
|
3583
|
+
const plan = await readUltragoalPlan(input.cwd, sessionId);
|
|
3507
3584
|
if (!plan) throw new Error("No ultragoal plan found. Run `gjc ultragoal create-goals --brief ...` first.");
|
|
3508
3585
|
const goal = plan.goals.find(item => item.id === input.goalId);
|
|
3509
3586
|
if (!goal) throw new Error(`No ultragoal goal found for ${input.goalId}.`);
|
|
3587
|
+
// A handed-off goal is owned by the successor run; the source must not record
|
|
3588
|
+
// further checkpoints against it (#5353). A run whose own adoption is still
|
|
3589
|
+
// unpublished may not record checkpoints at all — a completion receipt must
|
|
3590
|
+
// never rest on a transaction that never committed.
|
|
3591
|
+
await assertUltragoalAdoptionPublished(input.cwd, sessionId);
|
|
3592
|
+
await assertUltragoalGoalNotFenced(input.cwd, sessionId, goal.id);
|
|
3510
3593
|
const evidence = input.evidence.trim();
|
|
3511
3594
|
if (!evidence) throw new Error("checkpoint evidence is required");
|
|
3512
3595
|
const ledgerBefore = await readUltragoalLedger(input.cwd);
|
|
@@ -3683,17 +3766,27 @@ export async function checkpointUltragoalGoal(input: {
|
|
|
3683
3766
|
goal.updatedAt = now;
|
|
3684
3767
|
if (input.status === "complete") goal.completedAt = now;
|
|
3685
3768
|
plan.updatedAt = now;
|
|
3686
|
-
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
|
|
3691
|
-
|
|
3692
|
-
|
|
3693
|
-
|
|
3694
|
-
|
|
3695
|
-
|
|
3696
|
-
|
|
3769
|
+
// Commit inside the exclusion an offer holds while it decides quiescence and
|
|
3770
|
+
// installs its fence. The earlier assertions ran before validation, which is
|
|
3771
|
+
// slow, and an offer may fence a non-active goal in that window; because an
|
|
3772
|
+
// offer writes no source bytes, the plan's compare-and-swap cannot observe it.
|
|
3773
|
+
// Re-asserting here is what makes "not handed off" true at the instant of the
|
|
3774
|
+
// write rather than merely true earlier.
|
|
3775
|
+
await withUltragoalPlanOwnership(input.cwd, sessionId, async () => {
|
|
3776
|
+
await assertUltragoalAdoptionPublished(input.cwd, sessionId);
|
|
3777
|
+
await assertUltragoalGoalNotFenced(input.cwd, sessionId, goal.id);
|
|
3778
|
+
await writePlan(input.cwd, plan, sessionId, { lockHeld: true });
|
|
3779
|
+
const persistedPlan = await readUltragoalPlan(input.cwd, sessionId);
|
|
3780
|
+
if (persistedPlan?.state_revision !== undefined) plan.state_revision = persistedPlan.state_revision;
|
|
3781
|
+
await appendLedger(input.cwd, {
|
|
3782
|
+
eventId: pendingCheckpointEventId,
|
|
3783
|
+
event: "goal_checkpointed",
|
|
3784
|
+
goalId: goal.id,
|
|
3785
|
+
status: input.status,
|
|
3786
|
+
evidence,
|
|
3787
|
+
qualityGateJson,
|
|
3788
|
+
completionVerification: goal.completionVerification,
|
|
3789
|
+
});
|
|
3697
3790
|
});
|
|
3698
3791
|
return plan;
|
|
3699
3792
|
}
|
|
@@ -4732,6 +4825,10 @@ const FLAGS_WITH_VALUES = new Set([
|
|
|
4732
4825
|
"--validation-batch-json",
|
|
4733
4826
|
"--out",
|
|
4734
4827
|
"--surface",
|
|
4828
|
+
"--target-repo",
|
|
4829
|
+
"--authorize",
|
|
4830
|
+
"--authorized-by",
|
|
4831
|
+
"--offer",
|
|
4735
4832
|
]);
|
|
4736
4833
|
|
|
4737
4834
|
function isHelpArg(arg: string): boolean {
|
|
@@ -4861,6 +4958,46 @@ function renderUltragoalHelp(args: readonly string[]): string | null {
|
|
|
4861
4958
|
].join("\n");
|
|
4862
4959
|
}
|
|
4863
4960
|
|
|
4961
|
+
if (subject === "succession") {
|
|
4962
|
+
return [
|
|
4963
|
+
"Run native GJC Ultragoal workflow commands",
|
|
4964
|
+
"",
|
|
4965
|
+
"USAGE",
|
|
4966
|
+
" $ gjc ultragoal succession offer --target-repo <path> --goal-id <id> [--goal-id <id> ...] --authorize <statement> --authorized-by <identity> [--json]",
|
|
4967
|
+
" $ gjc ultragoal succession adopt --offer <path> [--gjc-goal-mode aggregate|per-story] [--json]",
|
|
4968
|
+
" $ gjc ultragoal succession status [--json]",
|
|
4969
|
+
"",
|
|
4970
|
+
"FLAGS",
|
|
4971
|
+
" --target-repo=<value> Destination repository for the successor run; never the source repository",
|
|
4972
|
+
" --goal-id=<value> Unfinished source goal to hand off (repeatable; no implicit or wildcard selection)",
|
|
4973
|
+
" --authorize=<value> Required. Explicit bounded authorization statement for this source/target/selection",
|
|
4974
|
+
" --authorized-by=<value> Required. Identity that authorized the handoff",
|
|
4975
|
+
" --offer=<value> Offer document recorded by `succession offer`, read from inside the source worktree",
|
|
4976
|
+
" --gjc-goal-mode=<value> Successor validation mode (default aggregate); the source mode is provenance only",
|
|
4977
|
+
" --json Output a machine-readable receipt",
|
|
4978
|
+
"",
|
|
4979
|
+
"OWNERSHIP",
|
|
4980
|
+
" `offer` records a durable outgoing ownership fence, so the source run stops scheduling and checkpointing the",
|
|
4981
|
+
" selected goals immediately — not when the target happens to adopt. Between offer and adoption no run owns them.",
|
|
4982
|
+
" The source brief, goals and ledger are never written. Goals the offer did not select stay schedulable, so",
|
|
4983
|
+
" admission compares a snapshot of the offered work rather than whole-file digests.",
|
|
4984
|
+
" There is deliberately no `revoke` verb: any read-then-delete of the fence races a concurrent adoption and could",
|
|
4985
|
+
" revive the source while the target is starting, so an unadopted offer keeps its goals fenced.",
|
|
4986
|
+
"",
|
|
4987
|
+
"AUTHORITY",
|
|
4988
|
+
" Adoption starts a fresh run bound to the target repository, pinned to the exact worktree the offer named. Source",
|
|
4989
|
+
" statuses, completion receipts, quality gates, reviews and approvals are carried as provenance only and never",
|
|
4990
|
+
" authorize anything in the target. Adoption fails closed on changed offered work, an altered or unfenced offer, an",
|
|
4991
|
+
" unnamed or occupied target, and any duplicate or divergent adoption in the target repository; a retry reconciles",
|
|
4992
|
+
" the exact recorded operation or fails closed. Until publication completes, the target refuses to execute.",
|
|
4993
|
+
"",
|
|
4994
|
+
"EXAMPLES",
|
|
4995
|
+
' $ gjc ultragoal succession offer --target-repo ../payments-api --goal-id G002 --goal-id G003 --authorize "leader approved moving the refund stories" --authorized-by human:release-lead --json',
|
|
4996
|
+
" $ gjc ultragoal succession adopt --offer ../plan-repo/.gjc/_session-abc/ultragoal/succession/offer-<id>.json --json",
|
|
4997
|
+
"",
|
|
4998
|
+
].join("\n");
|
|
4999
|
+
}
|
|
5000
|
+
|
|
4864
5001
|
if (subject === "quality-gate") {
|
|
4865
5002
|
return [
|
|
4866
5003
|
"Run native GJC Ultragoal workflow commands",
|
|
@@ -4906,9 +5043,12 @@ function renderUltragoalHelp(args: readonly string[]): string | null {
|
|
|
4906
5043
|
" quality-gate source-hash",
|
|
4907
5044
|
" quality-gate lane-selection",
|
|
4908
5045
|
" quality-gate validate",
|
|
5046
|
+
" succession offer",
|
|
5047
|
+
" succession adopt",
|
|
5048
|
+
" succession status",
|
|
4909
5049
|
|
|
4910
5050
|
"",
|
|
4911
|
-
"Run `gjc ultragoal checkpoint --help`, `gjc ultragoal review --help`, `gjc ultragoal classify-blocker --help`, `gjc ultragoal record-critic-verdict --help`, or `gjc ultragoal record-critic-gate-override --help`, or `gjc ultragoal quality-gate --help` for command-specific requirements.",
|
|
5051
|
+
"Run `gjc ultragoal checkpoint --help`, `gjc ultragoal review --help`, `gjc ultragoal classify-blocker --help`, `gjc ultragoal record-critic-verdict --help`, or `gjc ultragoal record-critic-gate-override --help`, or `gjc ultragoal quality-gate --help`, or `gjc ultragoal succession --help` for command-specific requirements.",
|
|
4912
5052
|
"",
|
|
4913
5053
|
].join("\n");
|
|
4914
5054
|
}
|
|
@@ -5390,6 +5530,8 @@ async function dispatchUltragoalCommand(
|
|
|
5390
5530
|
.join("\n")}\n`,
|
|
5391
5531
|
};
|
|
5392
5532
|
}
|
|
5533
|
+
case "succession":
|
|
5534
|
+
return await runUltragoalSuccessionCommand(args, cwd);
|
|
5393
5535
|
case "review": {
|
|
5394
5536
|
const result = await runUltragoalReview(cwd, args);
|
|
5395
5537
|
return {
|