opencode-swarm 7.153.0 → 7.153.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/dist/background/pending-delegations.d.ts +7 -0
  2. package/dist/cli/{config-doctor-7s7xga6f.js → config-doctor-tv0ar88m.js} +2 -2
  3. package/dist/cli/{core-vkpy14vv.js → core-kmsm50zn.js} +1 -1
  4. package/dist/cli/{curation-policy-xy7tm4ad.js → curation-policy-twa6agf8.js} +7 -7
  5. package/dist/cli/{curator-llm-factory-q5cjk7mt.js → curator-llm-factory-dxkhdhwg.js} +30 -30
  6. package/dist/cli/{curator-6freqnhf.js → curator-wxe863k9.js} +30 -30
  7. package/dist/cli/{evidence-summary-service-engtgjww.js → evidence-summary-service-9akrdg9t.js} +13 -13
  8. package/dist/cli/{gate-evidence-6bzzz8kq.js → gate-evidence-bdzqbg2y.js} +7 -7
  9. package/dist/cli/{guardrail-explain-vsck39dh.js → guardrail-explain-kx9rem51.js} +31 -31
  10. package/dist/cli/{guardrail-log-0dn8m3k6.js → guardrail-log-zxzyx1de.js} +5 -5
  11. package/dist/cli/{guardrail-reset-6e2vyfn9.js → guardrail-reset-1mc3st34.js} +30 -30
  12. package/dist/cli/{hive-promoter-021abs6z.js → hive-promoter-gncwtq0z.js} +30 -30
  13. package/dist/cli/{index-babtfqa0.js → index-02rbfrab.js} +450 -48
  14. package/dist/cli/{index-eqh3t8eh.js → index-0azn976d.js} +14 -14
  15. package/dist/cli/{index-9gjbe4e4.js → index-1gzdnjg9.js} +2 -2
  16. package/dist/cli/{index-g0m6kypc.js → index-21pt4jwf.js} +1 -1
  17. package/dist/cli/{index-z4bg1hv8.js → index-2mqmvxac.js} +9 -2
  18. package/dist/cli/{index-xv881ahz.js → index-3bh4h6ve.js} +108 -8
  19. package/dist/cli/index-3cegckkq.js +239 -0
  20. package/dist/cli/{index-hkmgzesw.js → index-3fpqpyp6.js} +2 -2
  21. package/dist/cli/{index-1yfpw7w0.js → index-3ttktt56.js} +1 -1
  22. package/dist/cli/{index-x6zy6veh.js → index-4pjkdcgc.js} +1 -1
  23. package/dist/cli/{index-5w915x8b.js → index-56ejcj07.js} +4 -4
  24. package/dist/cli/{index-7q56f3se.js → index-5ad8xcv3.js} +2 -2
  25. package/dist/cli/{index-e2hs0bh7.js → index-5zp4c36c.js} +1 -1
  26. package/dist/cli/{index-9vdh4kdx.js → index-84m4per1.js} +2 -2
  27. package/dist/cli/{index-txbd25bc.js → index-891g7hbf.js} +1 -1
  28. package/dist/cli/{index-3z5jtyan.js → index-a58nmnmz.js} +9 -2
  29. package/dist/cli/{index-77xy577c.js → index-bw55r5bz.js} +9 -9
  30. package/dist/cli/{index-80ekaf5b.js → index-ebshrg4x.js} +3 -3
  31. package/dist/cli/{index-5x67858f.js → index-h06112sh.js} +5 -5
  32. package/dist/cli/{index-6v77adf7.js → index-h3zhb18p.js} +2 -2
  33. package/dist/cli/{index-hw49515c.js → index-hhv2pvab.js} +1 -1
  34. package/dist/cli/{index-95qra69h.js → index-j4f8sz67.js} +4489 -2475
  35. package/dist/cli/{index-dh1gk5c5.js → index-kenz5bja.js} +32 -32
  36. package/dist/cli/{index-hexhzq5j.js → index-kvk65qzz.js} +3 -3
  37. package/dist/cli/{index-0q2mjxp2.js → index-meg33yyv.js} +1 -1
  38. package/dist/cli/{index-6zkm4p7p.js → index-pk1gbqmq.js} +1 -1
  39. package/dist/cli/{index-eajfs7v4.js → index-s6b8jgtn.js} +1 -1
  40. package/dist/cli/{index-k2ydsqs7.js → index-td0jz8xe.js} +4 -4
  41. package/dist/cli/{index-3z2f1cy8.js → index-vhbds89e.js} +4 -4
  42. package/dist/cli/{index-qgfnd206.js → index-x3y6zhgj.js} +1 -1
  43. package/dist/cli/{index-aw492hpn.js → index-x8vw6ap1.js} +58 -41
  44. package/dist/cli/{index-4gn111h3.js → index-yvepnbyd.js} +5 -5
  45. package/dist/cli/{index-0n7nm9e8.js → index-zppxpc3y.js} +2 -2
  46. package/dist/cli/index.js +30 -30
  47. package/dist/cli/{knowledge-escalator-79zbhpz5.js → knowledge-escalator-gp3mpbqe.js} +12 -12
  48. package/dist/cli/{knowledge-events-79cak7eb.js → knowledge-events-nvkhtqvn.js} +10 -10
  49. package/dist/cli/{knowledge-link-40zsr5ja.js → knowledge-link-ge0rddxw.js} +6 -6
  50. package/dist/cli/{knowledge-store-w29aw5w0.js → knowledge-store-2ngh8xvv.js} +7 -7
  51. package/dist/cli/{knowledge-validator-qsecnt2d.js → knowledge-validator-4bphyrec.js} +9 -9
  52. package/dist/cli/{pending-delegations-a2nmssr1.js → pending-delegations-nk78wx7h.js} +4 -4
  53. package/dist/cli/{pr-subscriptions-7879nq5k.js → pr-subscriptions-dq1f61ye.js} +4 -4
  54. package/dist/cli/{runner-fbgsxs74.js → runner-n50w1y4w.js} +7 -7
  55. package/dist/cli/{scan-cursor-1r3pcdqp.js → scan-cursor-c16xtygz.js} +8 -8
  56. package/dist/cli/{schema-19qsv6fw.js → schema-83tbte2g.js} +1 -1
  57. package/dist/cli/{scope-persistence-ypcrvqtt.js → scope-persistence-gdbw8xh8.js} +9 -9
  58. package/dist/cli/{skill-generator-wpp9kpa0.js → skill-generator-gr13xeha.js} +14 -14
  59. package/dist/cli/{telemetry-52pw5xac.js → telemetry-hh1j99za.js} +1 -1
  60. package/dist/cli/{worktree-collision-ownership-p31zm5k0.js → worktree-collision-ownership-4drcjymy.js} +15 -10
  61. package/dist/cli/{worktree-isolation-wcry8qnn.js → worktree-isolation-jjkfg2pg.js} +30 -30
  62. package/dist/commands/lanes.d.ts +25 -0
  63. package/dist/commands/registry.d.ts +1 -1
  64. package/dist/commands/reset-session.d.ts +8 -2
  65. package/dist/consensus/corpus.d.ts +16 -0
  66. package/dist/hooks/delegation-gate/worktree-isolation.d.ts +50 -3
  67. package/dist/hooks/delegation-gate/worktree-provisioning-owner.d.ts +40 -2
  68. package/dist/hooks/delegation-gate/worktree-recovery-authority.d.ts +201 -0
  69. package/dist/hooks/init-orphan-recovery.d.ts +5 -1
  70. package/dist/hooks/knowledge-application-gate.d.ts +10 -1
  71. package/dist/hooks/knowledge-receipt-ledger.d.ts +1 -1
  72. package/dist/hooks/trajectory-logger.d.ts +22 -6
  73. package/dist/hooks/trajectory-step-state.d.ts +43 -2
  74. package/dist/index.js +557 -552
  75. package/dist/observability/catalog.d.ts +6 -4
  76. package/dist/prm/index.d.ts +3 -3
  77. package/dist/prm/replay.d.ts +29 -2
  78. package/dist/prm/trajectory-store.d.ts +210 -20
  79. package/dist/state.d.ts +6 -4
  80. package/dist/telemetry.d.ts +21 -1
  81. package/dist/utils/atomic-write.d.ts +2 -0
  82. package/dist/utils/canonical-root.d.ts +31 -0
  83. package/dist/workflow/coder-settlement.d.ts +2 -0
  84. package/dist/worktree/index.d.ts +2 -2
  85. package/dist/worktree/merge.d.ts +47 -0
  86. package/package.json +8 -1
  87. package/dist/cli/index-fxvgaeq4.js +0 -125
  88. package/dist/cli/worktree-provisioning-owner-cve95q4f.js +0 -22
  89. package/dist/cli/{curator-drift-2h1d2fnq.js → curator-drift-h57z6tm3.js} +1 -1
@@ -845,7 +845,7 @@ export declare const COMMAND_REGISTRY: {
845
845
  readonly 'reset-session': {
846
846
  readonly handler: (ctx: CommandContext) => Promise<string>;
847
847
  readonly description: "Clear session state while preserving plan, evidence, and knowledge";
848
- readonly details: "Deletes only .swarm/session/state.json and any other session files. Clears in-memory agent sessions, delegation chains, and active-agent mappings. Preserves plan, evidence, and knowledge for cross-session continuity. Also recovers stale coder settlements, releasing in-flight ownership held by this process, so dispatches cannot stay wedged on CODER_DISPATCH_IN_PROGRESS (issue #2268). Before deleting, auto-backs up the session files it removes to .swarm/reset-backups/<timestamp>/ (newest 5 kept).";
848
+ readonly details: "Deletes only .swarm/session/state.json and other session files. Clears in-memory agent sessions, delegation chains, and active-agent mappings. Preserves plan, evidence, and knowledge. Also releases this session's pending knowledge-gate obligations (#2398) and recovers stale coder settlements so dispatches cannot wedge on CODER_DISPATCH_IN_PROGRESS (#2268). Auto-backs up removed files to .swarm/reset-backups/ (newest 5 kept).";
849
849
  readonly args: "";
850
850
  readonly category: "utility";
851
851
  readonly toolPolicy: "restricted";
@@ -1,3 +1,4 @@
1
+ import { commitGateReleaseBatch, queryLiveMemberships } from '../hooks/knowledge-receipt-ledger';
1
2
  import { recoverStaleCoderSettlements } from '../workflow/coder-settlement.js';
2
3
  import { type OrphanCleanupResult } from '../worktree/merge';
3
4
  import { type ResetBackupResult } from './reset-backup';
@@ -11,11 +12,16 @@ export declare const _internals: {
11
12
  cleanupOrphanedBranches: (directory: string, activeSessionIds: string[]) => Promise<OrphanCleanupResult>;
12
13
  backupSwarmStateBeforeReset: (directory: string, kind: 'reset' | 'reset-session', relEntries: string[]) => ResetBackupResult;
13
14
  recoverStaleCoderSettlements: typeof recoverStaleCoderSettlements;
15
+ queryLiveMemberships: typeof queryLiveMemberships;
16
+ commitGateReleaseBatch: typeof commitGateReleaseBatch;
17
+ releaseKnowledgeGateObligations: (directory: string, sessionID: string) => Promise<string[]>;
14
18
  };
15
19
  /**
16
20
  * Handles the /swarm reset-session command.
17
21
  * Deletes only the session state file (.swarm/session/state.json)
18
22
  * and clears in-memory agent sessions. Preserves plan, evidence,
19
- * and knowledge for continuity across sessions.
23
+ * and knowledge for continuity across sessions — but DOES release this
24
+ * session's pending knowledge-application gate obligations (issue #2398) so
25
+ * the reset is a real escape from an enforce-mode lockout.
20
26
  */
21
- export declare function handleResetSessionCommand(directory: string, _args: string[]): Promise<string>;
27
+ export declare function handleResetSessionCommand(directory: string, _args: string[], sessionID?: string): Promise<string>;
@@ -81,6 +81,7 @@ import { type GateAuditReadSummary } from '../evaluation/store.js';
81
81
  import { type LoadEvidenceResult } from '../evidence/manager.js';
82
82
  import type { RetrievalOutcome } from '../hooks/knowledge-types.js';
83
83
  import { readSkillUsageEntries, type readSkillUsageEntriesWithCoverage } from '../hooks/skill-usage-log.js';
84
+ import { type TrajectoryReadWithCoverage } from '../prm/trajectory-store.js';
84
85
  import type { TrajectoryEntry } from '../prm/types.js';
85
86
  import type { ConsensusCorpusHash, ConsensusSourceKind } from './contracts.js';
86
87
  /**
@@ -129,6 +130,21 @@ export interface CorpusReaders {
129
130
  readTaskTrajectory: (directory: string, taskId: string) => Promise<TrajectoryEntry[]>;
130
131
  listTrajectorySessions: (directory: string) => Promise<string[]>;
131
132
  readTrajectory: (sessionId: string, directory: string) => Promise<TrajectoryEntry[]>;
133
+ /**
134
+ * Additive coverage seam (issue #2041 Required 4), mirroring
135
+ * `readSkillUsageEntriesWithCoverage` above: optional, deliberately NOT
136
+ * part of `defaultReaders()`, and injecting it overrides BOTH the entries
137
+ * and the coverage verdict so an injected fixture stays coherent.
138
+ *
139
+ * Without it, entries keep coming from `readTrajectory` (injected fixtures
140
+ * keep working) and the default coverage verdict comes from the session's
141
+ * persisted checkpoint (`readTrajectoryCheckpoint`) — the same
142
+ * manifest-only precedent the skill-usage source uses. The default path's
143
+ * known limit mirrors that precedent too: it discloses compaction eviction
144
+ * (`droppedEntries`) but not a single read that hit the tail-window byte
145
+ * cap, which for a within-budget store is unreachable.
146
+ */
147
+ readTrajectoryWithCoverage?: (sessionId: string, directory: string) => Promise<TrajectoryReadWithCoverage>;
132
148
  readSkillUsageEntries: typeof readSkillUsageEntries;
133
149
  /**
134
150
  * Additive coverage seam (issue #2038 §7). Optional, and deliberately NOT
@@ -13,9 +13,12 @@ import { tryAcquireLock } from '../../parallel/file-locks';
13
13
  import { bunSpawn } from '../../utils/bun-compat';
14
14
  import { resolveGitExecutable } from '../../utils/git-executable.js';
15
15
  import type { WorktreeHandle } from '../../worktree';
16
- import { attemptMergeBackFromDirty, cleanupOrphanedBranches, postMergeCleanup, provisionWorktree, pruneStaleWorktreeMetadata, removeWorktree, startupOrphanRecovery } from '../../worktree';
17
- import type { DirtyMergeOptions, MergeOperationProvenance } from '../../worktree/merge';
16
+ import { attemptMergeBackFromDirty, cleanupOrphanedBranches, postMergeCleanup, provisionWorktree, pruneStaleWorktreeMetadata, recoverMergeBackFromImmutableCoordinates, removeWorktree, startupOrphanRecovery } from '../../worktree';
17
+ import type { DirtyMergeOptions, ImmutableMergeRecoveryCoordinates, MergeOperationProvenance } from '../../worktree/merge';
18
+ import type { WorktreeProvisioningOwnerRemovalIdentity } from './worktree-provisioning-owner';
18
19
  import { recordWorktreeProvisioningOwner, removeWorktreeProvisioningOwner } from './worktree-provisioning-owner';
20
+ import type { WorktreeRecoveryImmutableIdentityInput } from './worktree-recovery-authority';
21
+ import { claimWorktreeRecoveryAuthority, finalizeWorktreeRecoveryAuthority, lookupWorktreeRecoveryAuthoritiesByTask, publishWorktreeRecoveryAuthority, releaseWorktreeRecoveryClaim, renewWorktreeRecoveryClaim, replayWorktreeRecoveryClaimJournal } from './worktree-recovery-authority';
19
22
  /**
20
23
  * FR-201: Per-lane runtime profile injected into spawned child processes.
21
24
  *
@@ -59,8 +62,23 @@ export interface StandardWorktreeDispatch {
59
62
  parentSessionID: string;
60
63
  taskId: string;
61
64
  planTaskId?: string;
65
+ reservationId?: string;
66
+ generation?: number;
67
+ provisioningOwner?: WorktreeProvisioningOwnerRemovalIdentity;
68
+ canonicalBranch?: string;
69
+ canonicalPath?: string;
62
70
  handle: WorktreeHandle;
63
71
  mergeStrategy: 'merge' | 'rebase' | 'cherry-pick';
72
+ recoveryClaim?: {
73
+ authorityDigest: string;
74
+ claimRevision: number;
75
+ rawToken: string;
76
+ coordinates?: ImmutableMergeRecoveryCoordinates;
77
+ settlement?: {
78
+ sourceCommitOrder: string[];
79
+ rewrittenCommitOrder: string[];
80
+ };
81
+ };
64
82
  /** FR-201: 0-based lane index for runtime profile derivation. */
65
83
  laneIndex: number;
66
84
  /** Configured worktree-dir override, so cleanup trusts the same base. */
@@ -102,6 +120,9 @@ export interface AwaitingMergeRecord {
102
120
  parentSessionID: string;
103
121
  taskId: string;
104
122
  planTaskId?: string;
123
+ /** Exact durable launch identity threaded from the delegation gate. */
124
+ reservationId?: string;
125
+ generation?: number;
105
126
  branch: string;
106
127
  worktreePath: string;
107
128
  mergeStrategy: 'merge' | 'rebase' | 'cherry-pick';
@@ -125,6 +146,11 @@ interface SessionSerializationState {
125
146
  */
126
147
  successfulDispatchesSince: number;
127
148
  }
149
+ interface CleanupStandardWorktreeResult {
150
+ removedWorktree: boolean;
151
+ cleanedBranch: boolean;
152
+ preservedRecoveryLane: boolean;
153
+ }
128
154
  export declare function getStandardWorktreeDegradationReason(sessionID: string): {
129
155
  reason: string;
130
156
  at: number;
@@ -187,6 +213,13 @@ declare function inspectStandardWorktreeCollisionOwnership(identity: {
187
213
  branchName: string;
188
214
  worktreePath: string;
189
215
  }): Promise<import("./worktree-collision-ownership").StandardWorktreeCollisionOwnership>;
216
+ declare function buildWorktreeRecoveryPublishIdentity(input: {
217
+ directory: string;
218
+ dispatch: StandardWorktreeDispatch;
219
+ taskId: string;
220
+ provenance: MergeOperationProvenance;
221
+ conflictFiles?: string[];
222
+ }): Promise<WorktreeRecoveryImmutableIdentityInput | undefined>;
190
223
  export declare function precreateStandardWorktreeSession(args: {
191
224
  config: PluginConfig;
192
225
  directory: string;
@@ -194,6 +227,9 @@ export declare function precreateStandardWorktreeSession(args: {
194
227
  callID: string;
195
228
  taskId: string;
196
229
  planTaskId?: string;
230
+ /** Exact durable launch identity threaded from the delegation gate. */
231
+ reservationId?: string;
232
+ generation?: number;
197
233
  description?: string;
198
234
  outputArgs: Record<string, unknown>;
199
235
  /** Scope to materialize into the lane for durability across restart (FR-102). */
@@ -264,7 +300,7 @@ export declare function preserveDirtyWorktreeAtPath(worktreePath: string, branch
264
300
  * @param directory - The project root (required for git worktree/branch commands).
265
301
  * @param worktree_dir - Configured worktree-dir override.
266
302
  */
267
- export declare function cleanupStandardWorktreeForCallId(callID: string, reason: 'success' | 'denied' | 'cancelled', directory: string, worktree_dir?: string): Promise<void>;
303
+ export declare function cleanupStandardWorktreeForCallId(callID: string, reason: 'success' | 'denied' | 'cancelled', directory: string, worktree_dir?: string): Promise<CleanupStandardWorktreeResult>;
268
304
  /**
269
305
  * FR-001a: Abort an in-flight standard worktree dispatch.
270
306
  *
@@ -310,6 +346,7 @@ export declare const _internals: {
310
346
  provisionWorktree: typeof provisionWorktree;
311
347
  removeWorktree: typeof removeWorktree;
312
348
  attemptMergeBackFromDirty: typeof attemptMergeBackFromDirty;
349
+ recoverMergeBackFromImmutableCoordinates: typeof recoverMergeBackFromImmutableCoordinates;
313
350
  postMergeCleanup: typeof postMergeCleanup;
314
351
  pruneStaleWorktreeMetadata: typeof pruneStaleWorktreeMetadata;
315
352
  /** FR-201: read lane runtime profile from disk for spawn injection. */
@@ -335,8 +372,18 @@ export declare const _internals: {
335
372
  tryAcquireWorktreeLifecycleLock: typeof tryAcquireLock;
336
373
  recordWorktreeProvisioningOwner: typeof recordWorktreeProvisioningOwner;
337
374
  removeWorktreeProvisioningOwner: typeof removeWorktreeProvisioningOwner;
375
+ lookupWorktreeRecoveryAuthoritiesByTask: typeof lookupWorktreeRecoveryAuthoritiesByTask;
376
+ claimWorktreeRecoveryAuthority: typeof claimWorktreeRecoveryAuthority;
377
+ renewWorktreeRecoveryClaim: typeof renewWorktreeRecoveryClaim;
378
+ releaseWorktreeRecoveryClaim: typeof releaseWorktreeRecoveryClaim;
379
+ finalizeWorktreeRecoveryAuthority: typeof finalizeWorktreeRecoveryAuthority;
380
+ publishWorktreeRecoveryAuthority: typeof publishWorktreeRecoveryAuthority;
381
+ replayWorktreeRecoveryClaimJournal: typeof replayWorktreeRecoveryClaimJournal;
382
+ buildWorktreeRecoveryPublishIdentity: typeof buildWorktreeRecoveryPublishIdentity;
338
383
  /** FR-001b SC-004: path-based dirty worktree preservation for stale-lane fallback. */
339
384
  preserveDirtyWorktreeAtPath: typeof preserveDirtyWorktreeAtPath;
385
+ /** Bounded lane session.create timeout (tests may override). */
386
+ worktreeSessionCreateTimeoutMs: number;
340
387
  /** FR-001a: abort entry point for in-flight dispatches. */
341
388
  abortStandardWorktreeDispatch: typeof abortStandardWorktreeDispatch;
342
389
  standardWorktreeByCallID: Map<string, StandardWorktreeDispatch>;
@@ -5,15 +5,36 @@
5
5
  */
6
6
  export declare const WORKTREE_PROVISIONING_OWNER_LEASE_MS: number;
7
7
  export declare const WORKTREE_LIFECYCLE_LOCK_FILE = ".swarm/locks/init-orphan-recovery.lock";
8
+ export declare const WORKTREE_PROVISIONING_LIFECYCLE_STATES: readonly ["OWNER_PUBLISHED", "OWNER_REMOVED"];
9
+ export type WorktreeProvisioningLifecycleState = (typeof WORKTREE_PROVISIONING_LIFECYCLE_STATES)[number];
8
10
  export interface WorktreeProvisioningOwner {
9
- schemaVersion: 1 | 2;
11
+ schemaVersion: 1 | 2 | 3;
10
12
  callID: string;
11
13
  parentSessionId: string;
12
14
  worktreeSessionId: string;
13
15
  /** Added in v2 so restart collision checks can identify the exact lane. */
14
16
  taskId?: string;
17
+ /** Added in v3 so restart recovery can correlate the exact reservation. */
18
+ reservationId?: string;
19
+ /** Added in v3 so restart recovery can fence same-task retries. */
20
+ generation?: number;
21
+ /** Added in v3 so crash recovery can corroborate the exact lane ref. */
22
+ branchName?: string;
15
23
  createdAt: number;
16
24
  }
25
+ export type WorktreeProvisioningOwnerRemovalIdentity = Pick<WorktreeProvisioningOwner, 'reservationId' | 'generation' | 'branchName'>;
26
+ export interface WorktreeProvisioningLifecycleEntry {
27
+ schemaVersion: 1;
28
+ state: WorktreeProvisioningLifecycleState;
29
+ callID: string;
30
+ parentSessionId: string;
31
+ worktreeSessionId: string;
32
+ taskId?: string;
33
+ reservationId?: string;
34
+ generation?: number;
35
+ branchName?: string;
36
+ recordedAt: number;
37
+ }
17
38
  export type WorktreeProvisioningOwnerScan = {
18
39
  status: 'ok';
19
40
  owners: WorktreeProvisioningOwner[];
@@ -21,6 +42,16 @@ export type WorktreeProvisioningOwnerScan = {
21
42
  status: 'uncertain';
22
43
  reason: string;
23
44
  };
45
+ export type WorktreeProvisioningLifecycleJournalScan = {
46
+ status: 'ok';
47
+ entries: WorktreeProvisioningLifecycleEntry[];
48
+ } | {
49
+ status: 'uncertain';
50
+ reason: string;
51
+ };
52
+ declare function ownerPath(directory: string, callID: string): string;
53
+ declare function journalPath(directory: string): string;
54
+ declare function readOwner(directory: string, callID: string): WorktreeProvisioningOwner | null;
24
55
  /**
25
56
  * Publish a provisional owner before a standard worktree can be created.
26
57
  * Callers hold the shared orphan-recovery lifecycle lock during this atomic
@@ -28,9 +59,16 @@ export type WorktreeProvisioningOwnerScan = {
28
59
  */
29
60
  export declare function recordWorktreeProvisioningOwner(directory: string, input: Omit<WorktreeProvisioningOwner, 'schemaVersion' | 'createdAt'>): WorktreeProvisioningOwner;
30
61
  /** Remove a provisional owner only after durable ownership or cleanup exists. */
31
- export declare function removeWorktreeProvisioningOwner(directory: string, callID: string): boolean;
62
+ export declare function removeWorktreeProvisioningOwner(directory: string, callID: string, expected?: WorktreeProvisioningOwnerRemovalIdentity): boolean;
32
63
  /**
33
64
  * Strict recovery scan. Anything except ENOENT is uncertainty because omitting
34
65
  * one marker could allow destructive cleanup to race a live worktree.
35
66
  */
36
67
  export declare function scanWorktreeProvisioningOwnersForRecovery(directory: string): WorktreeProvisioningOwnerScan;
68
+ export declare function scanWorktreeProvisioningLifecycleJournalForRecovery(directory: string): WorktreeProvisioningLifecycleJournalScan;
69
+ export declare const _internals: {
70
+ getOwnerPath: typeof ownerPath;
71
+ getJournalPath: typeof journalPath;
72
+ readOwner: typeof readOwner;
73
+ };
74
+ export {};
@@ -0,0 +1,201 @@
1
+ export declare const WORKTREE_RECOVERY_MUTATOR_NAMES: readonly ["publish", "claim", "renew", "release", "finalize", "replay"];
2
+ export type WorktreeRecoveryMutatorName = (typeof WORKTREE_RECOVERY_MUTATOR_NAMES)[number];
3
+ export type WorktreeRecoveryStrategy = 'merge' | 'rebase' | 'cherry-pick';
4
+ export type WorktreeRecoveryStatus = 'preserved' | 'claimed' | 'released' | 'finalized';
5
+ export type WorktreeRecoveryJournalState = 'PREPARED' | 'COMMITTED' | 'CLAIM_RENEWED' | 'ABORTED' | 'RELEASED' | 'FINALIZED';
6
+ export interface WorktreeRecoveryImmutableIdentityInput {
7
+ originalCallID: string;
8
+ parentSessionId: string;
9
+ taskId: string;
10
+ reservationId: string;
11
+ generation: number;
12
+ canonicalBranch: string;
13
+ canonicalPath: string;
14
+ laneBranch: string;
15
+ lanePath: string;
16
+ expectedPrimaryHead: string;
17
+ sourceBaseOid: string;
18
+ sourceHeadOid: string;
19
+ targetHeadOid: string;
20
+ strategy: WorktreeRecoveryStrategy;
21
+ declaredConflictFiles?: string[];
22
+ }
23
+ export interface WorktreeRecoveryImmutableIdentity extends WorktreeRecoveryImmutableIdentityInput {
24
+ createdAt: number;
25
+ }
26
+ export interface WorktreeRecoveryClaimState {
27
+ claimantCallID: string;
28
+ claimantSessionId: string;
29
+ childSessionId: string;
30
+ claimRevision: number;
31
+ attempt: number;
32
+ leaseExpiresAt: number;
33
+ claimTokenDigest: string;
34
+ claimedAt: number;
35
+ }
36
+ export interface WorktreeRecoveryAuthorityRecord {
37
+ schemaVersion: 2;
38
+ authorityDigest: string;
39
+ immutable: WorktreeRecoveryImmutableIdentity;
40
+ status: WorktreeRecoveryStatus;
41
+ claim?: WorktreeRecoveryClaimState;
42
+ claimCursor?: {
43
+ lastClaimRevision: number;
44
+ lastAttempt: number;
45
+ };
46
+ finalizedAt?: number;
47
+ settlement?: {
48
+ sourceCommitOrder: string[];
49
+ rewrittenCommitOrder: string[];
50
+ };
51
+ }
52
+ interface WorktreeRecoveryStore {
53
+ schemaVersion: 2;
54
+ authorities: WorktreeRecoveryAuthorityRecord[];
55
+ index: {
56
+ bySessionTask: Record<string, string[]>;
57
+ };
58
+ }
59
+ export interface WorktreeRecoveryClaimJournalEntry {
60
+ schemaVersion: 1;
61
+ authorityDigest: string;
62
+ state: WorktreeRecoveryJournalState;
63
+ claimantCallID: string;
64
+ claimantSessionId: string;
65
+ childSessionId?: string;
66
+ claimRevision: number;
67
+ attempt: number;
68
+ leaseExpiresAt: number;
69
+ claimTokenDigest: string;
70
+ preparedAt: number;
71
+ credentialInstalledAt?: number;
72
+ committedAt?: number;
73
+ abortedAt?: number;
74
+ reason?: string;
75
+ }
76
+ interface WorktreeRecoveryClaimJournal {
77
+ schemaVersion: 1;
78
+ entries: WorktreeRecoveryClaimJournalEntry[];
79
+ }
80
+ interface WorktreeRecoveryCredential {
81
+ schemaVersion: 1;
82
+ authorityDigest: string;
83
+ claimantCallID: string;
84
+ claimantSessionId: string;
85
+ childSessionId: string;
86
+ claimRevision: number;
87
+ rawToken: string;
88
+ leaseExpiresAt: number;
89
+ createdAt: number;
90
+ }
91
+ type ScanStatus = 'ok' | 'unsupported-legacy' | 'uncertain';
92
+ export type WorktreeRecoveryScanResult = {
93
+ status: 'ok';
94
+ authorities: WorktreeRecoveryAuthorityRecord[];
95
+ } | {
96
+ status: 'unsupported-legacy';
97
+ reason: string;
98
+ } | {
99
+ status: 'uncertain';
100
+ reason: string;
101
+ };
102
+ export type WorktreeRecoveryLookupResult = {
103
+ status: 'ok';
104
+ authorities: WorktreeRecoveryAuthorityRecord[];
105
+ } | {
106
+ status: Exclude<ScanStatus, 'ok'>;
107
+ reason: string;
108
+ };
109
+ type BaseMutationFailureCode = 'not_found' | 'busy' | 'stale_claim' | 'retry_cap_exceeded' | 'revalidation_required' | 'revalidation_failed' | 'unsupported_legacy' | 'uncertain_store' | 'finalized';
110
+ type BaseMutationFailure = {
111
+ ok: false;
112
+ code: BaseMutationFailureCode;
113
+ reason: string;
114
+ };
115
+ export type PublishWorktreeRecoveryAuthorityResult = {
116
+ ok: true;
117
+ authority: WorktreeRecoveryAuthorityRecord;
118
+ } | BaseMutationFailure;
119
+ export type ClaimWorktreeRecoveryAuthorityResult = {
120
+ ok: true;
121
+ authority: WorktreeRecoveryAuthorityRecord;
122
+ rawToken: string;
123
+ credentialPath: string;
124
+ } | BaseMutationFailure;
125
+ export type MutateWorktreeRecoveryClaimResult = {
126
+ ok: true;
127
+ authority: WorktreeRecoveryAuthorityRecord;
128
+ } | BaseMutationFailure;
129
+ export interface ClaimWorktreeRecoveryAuthorityRequest {
130
+ authorityDigest: string;
131
+ claimantCallID: string;
132
+ claimantSessionId: string;
133
+ now?: number;
134
+ leaseMs: number;
135
+ maxAttempts?: number;
136
+ createChildSession: () => string | Promise<string>;
137
+ revalidateExpiredClaim?: (args: {
138
+ authority: WorktreeRecoveryAuthorityRecord;
139
+ previousClaim: WorktreeRecoveryClaimState;
140
+ }) => {
141
+ ok: true;
142
+ } | {
143
+ ok: false;
144
+ reason: string;
145
+ } | Promise<{
146
+ ok: true;
147
+ } | {
148
+ ok: false;
149
+ reason: string;
150
+ }>;
151
+ }
152
+ interface ExactClaimMutationRequest {
153
+ authorityDigest: string;
154
+ claimantCallID: string;
155
+ claimRevision: number;
156
+ rawToken: string;
157
+ now?: number;
158
+ }
159
+ export interface FinalizeWorktreeRecoveryAuthorityRequest extends ExactClaimMutationRequest {
160
+ settlement?: {
161
+ sourceCommitOrder: string[];
162
+ rewrittenCommitOrder: string[];
163
+ };
164
+ }
165
+ export interface ReplayPreparedClaimOptions {
166
+ onAbortPreparedClaim?: (entry: WorktreeRecoveryClaimJournalEntry) => void;
167
+ }
168
+ export interface ReplayPreparedClaimOutcome {
169
+ authorityDigest: string;
170
+ outcome: 'aborted_prepared_claim' | 'removed_uncommitted_credential' | 'committed_claim_stable' | 'released_orphaned_committed_claim' | 'repaired_terminal_claim' | 'uncertain_committed_without_authority' | 'noop';
171
+ }
172
+ declare function storePath(directory: string): string;
173
+ declare function journalPath(directory: string): string;
174
+ declare function credentialPath(directory: string, authorityDigest: string): string;
175
+ declare function acquireAuthorityLock(directory: string): (() => void) | undefined;
176
+ export declare function publishWorktreeRecoveryAuthority(directory: string, input: WorktreeRecoveryImmutableIdentityInput): PublishWorktreeRecoveryAuthorityResult;
177
+ export declare function scanWorktreeRecoveryAuthoritiesForRecovery(directory: string): WorktreeRecoveryScanResult;
178
+ export declare function lookupWorktreeRecoveryAuthoritiesByTask(directory: string, query: {
179
+ parentSessionId: string;
180
+ taskId: string;
181
+ }): WorktreeRecoveryLookupResult;
182
+ export declare function claimWorktreeRecoveryAuthority(directory: string, request: ClaimWorktreeRecoveryAuthorityRequest): Promise<ClaimWorktreeRecoveryAuthorityResult>;
183
+ export declare function renewWorktreeRecoveryClaim(directory: string, request: ExactClaimMutationRequest & {
184
+ leaseMs: number;
185
+ }): MutateWorktreeRecoveryClaimResult;
186
+ export declare function releaseWorktreeRecoveryClaim(directory: string, request: ExactClaimMutationRequest): MutateWorktreeRecoveryClaimResult;
187
+ export declare function finalizeWorktreeRecoveryAuthority(directory: string, request: FinalizeWorktreeRecoveryAuthorityRequest): MutateWorktreeRecoveryClaimResult;
188
+ export declare function replayWorktreeRecoveryClaimJournal(directory: string, options?: ReplayPreparedClaimOptions): ReplayPreparedClaimOutcome[];
189
+ export declare const _internals: {
190
+ generateRawToken: () => string;
191
+ writeRecoveryStore: (targetPath: string, store: WorktreeRecoveryStore, _phase: "publish" | "claim-commit" | "claim-renew" | "claim-release" | "claim-finalize") => void;
192
+ writeClaimJournal: (targetPath: string, journal: WorktreeRecoveryClaimJournal) => void;
193
+ writeCredentialFile: (targetPath: string, credential: WorktreeRecoveryCredential) => void;
194
+ getRecoveryStorePath: typeof storePath;
195
+ getClaimJournalPath: typeof journalPath;
196
+ getCredentialPath: typeof credentialPath;
197
+ acquireAuthorityLock: typeof acquireAuthorityLock;
198
+ readClaimJournal(directory: string): WorktreeRecoveryClaimJournal;
199
+ resetForTest(): void;
200
+ };
201
+ export {};
@@ -21,7 +21,8 @@ import { isLocked, listActiveLocks, tryAcquireLock } from '../parallel/file-lock
21
21
  import { removeWorktree } from '../worktree/core';
22
22
  import { scanRegisteredWorktreeLiveness } from '../worktree/merge';
23
23
  import { scanWorktreeMergeFailuresForRecovery } from './delegation-gate/worktree-merge-status';
24
- import { removeWorktreeProvisioningOwner, scanWorktreeProvisioningOwnersForRecovery } from './delegation-gate/worktree-provisioning-owner';
24
+ import { removeWorktreeProvisioningOwner, scanWorktreeProvisioningLifecycleJournalForRecovery, scanWorktreeProvisioningOwnersForRecovery } from './delegation-gate/worktree-provisioning-owner';
25
+ import { replayWorktreeRecoveryClaimJournal, scanWorktreeRecoveryAuthoritiesForRecovery } from './delegation-gate/worktree-recovery-authority';
25
26
  type OwnershipTagSessionScan = {
26
27
  status: 'ok';
27
28
  sessionIds: string[];
@@ -51,7 +52,10 @@ export declare const _internals: {
51
52
  recordDelegationRecoveryObservation: typeof recordDelegationRecoveryObservation;
52
53
  scanDelegationFallbacksForRecovery: typeof scanDelegationFallbacksForRecovery;
53
54
  scanWorktreeMergeFailuresForRecovery: typeof scanWorktreeMergeFailuresForRecovery;
55
+ scanWorktreeRecoveryAuthoritiesForRecovery: typeof scanWorktreeRecoveryAuthoritiesForRecovery;
56
+ replayWorktreeRecoveryClaimJournal: typeof replayWorktreeRecoveryClaimJournal;
54
57
  scanWorktreeProvisioningOwnersForRecovery: typeof scanWorktreeProvisioningOwnersForRecovery;
58
+ scanWorktreeProvisioningLifecycleJournalForRecovery: typeof scanWorktreeProvisioningLifecycleJournalForRecovery;
55
59
  scanRegisteredWorktreeLiveness: typeof scanRegisteredWorktreeLiveness;
56
60
  removeWorktreeProvisioningOwner: typeof removeWorktreeProvisioningOwner;
57
61
  };
@@ -30,13 +30,22 @@
30
30
  * - update_task_status
31
31
  * - phase_complete
32
32
  * - Task (delegations to coder/reviewer/test_engineer/sme/docs/designer)
33
+ * - skill_regenerate
34
+ * - skill_retire
33
35
  *
34
36
  * Non-architect agents are never gated.
35
37
  */
36
38
  import { type KnowledgeApplicationConfig } from './knowledge-application.js';
37
39
  import { type ReceiptMembership } from './knowledge-receipt-ledger.js';
38
40
  import type { MessageWithParts } from './knowledge-types.js';
39
- /** Tools that require knowledge-directive acknowledgment before execution. */
41
+ /**
42
+ * Fallback set used only when `config.high_risk_tools` is absent. The parsed
43
+ * config schema (`KnowledgeApplicationConfigSchema`) defaults
44
+ * `high_risk_tools` to a 5-tool list (save_plan, update_task_status,
45
+ * phase_complete, task, Task) that is always populated post-parse, so this
46
+ * constant is shadowed in practice and `skill_regenerate` / `skill_retire`
47
+ * are NOT gated unless the operator's config lists them explicitly.
48
+ */
40
49
  export declare const HIGH_RISK_TOOLS: Set<string>;
41
50
  export interface GateInput {
42
51
  tool: unknown;
@@ -27,7 +27,7 @@ export declare const RECEIPT_TERMINAL_OUTCOMES: ReadonlySet<ReceiptOutcome>;
27
27
  * preserved as `'unknown'` and is never coerced to delegate, ignored, or any
28
28
  * other class. New producers must stamp one of the closed values below.
29
29
  */
30
- export type ReceiptSourceCode = 'delegate' | 'reviewer' | 'architect' | 'architect_marker' | 'test_engineer' | 'phase_override' | 'application_gate_staleness_release' | 'application_gate_denial_limit_release' | 'manual' | 'migration' | 'unknown';
30
+ export type ReceiptSourceCode = 'delegate' | 'reviewer' | 'architect' | 'architect_marker' | 'test_engineer' | 'phase_override' | 'application_gate_staleness_release' | 'application_gate_denial_limit_release' | 'application_gate_session_reset_release' | 'manual' | 'migration' | 'unknown';
31
31
  /** Closed set form of {@link ReceiptSourceCode}. */
32
32
  export declare const CANONICAL_RECEIPT_SOURCES: ReadonlySet<string>;
33
33
  /**
@@ -9,6 +9,13 @@
9
9
  */
10
10
  export interface TrajectoryConfig {
11
11
  enabled: boolean;
12
+ /**
13
+ * Line budget for BOTH the session store's in-memory cache trim AND its
14
+ * on-disk compaction (issue #2041): over budget, the newest
15
+ * floor(max_lines/2) entries are retained on disk and in cache, and the
16
+ * derived byte ceiling is sovereign. The task-evidence copy below uses the
17
+ * same value for its own write-side truncation.
18
+ */
12
19
  max_lines: number;
13
20
  }
14
21
  export interface TrajectoryEntry {
@@ -64,8 +71,8 @@ declare function extractTarget(tool: string, args?: Record<string, unknown>): st
64
71
  /**
65
72
  * Creates the trajectory logger hook pair.
66
73
  *
67
- * @param config - TrajectoryConfig { enabled: boolean (default true), max_lines: number (default 500) }
68
- * @param _directory - Reserved for future use (evidence path derived from session taskId)
74
+ * @param config - TrajectoryConfig { enabled: boolean (default true), max_lines: number (default 500) — bounds the session store's cache AND disk compaction plus the task-evidence truncation }
75
+ * @param _directory - Workspace root (session store + evidence paths derive from it)
69
76
  * @returns Object with toolAfter handler
70
77
  */
71
78
  export declare function createTrajectoryLoggerHook(config: Partial<TrajectoryConfig>, _directory: string): {
@@ -90,8 +97,9 @@ export declare function createTrajectoryLoggerHook(config: Partial<TrajectoryCon
90
97
  * the record of it.
91
98
  *
92
99
  * Contract:
93
- * - The step is minted with the SHARED `nextTrajectoryStep(sessionId)`. Any
94
- * private counter would desynchronise the `prmTrajectoryStep` window and
100
+ * - The step is minted with the SHARED `nextTrajectoryStep(sessionId, directory)`
101
+ * (seeded from the persisted high-water mark see ensureSessionStepSeeded).
102
+ * Any private counter would desynchronise the `prmTrajectoryStep` window and
95
103
  * silently break PRM's step-range filtering.
96
104
  * - `session.delegationActive` gates recording at all (the architect session
97
105
  * is deliberately out of scope); the task-evidence copy additionally
@@ -117,13 +125,18 @@ export declare function recordDeniedToolCall(sessionID: string, input: {
117
125
  export declare function clearDeniedCallMarkers(): void;
118
126
  /**
119
127
  * Resets the step counter for a session. Called when a new session starts
120
- * or when trajectory tracking should restart from step 1.
128
+ * or when trajectory tracking should restart from step 1. The restart-seed
129
+ * gate is invalidated so the next mint re-seeds from the persisted
130
+ * high-water mark (issue #2041 monotonicity).
121
131
  *
122
132
  * @param sessionId - Session identifier
133
+ * @param directory - Workspace root owning the session's trajectory store
123
134
  */
124
- export declare function resetTrajectoryStep(sessionId: string): void;
135
+ export declare function resetTrajectoryStep(sessionId: string, directory?: string): void;
125
136
  /**
126
137
  * Clears trajectory step counters for one session, or all sessions when omitted.
138
+ * The restart-seed gate is invalidated alongside so a cleared session re-seeds
139
+ * from disk on its next mint (issue #2041 monotonicity).
127
140
  *
128
141
  * @param sessionId - Optional session identifier
129
142
  */
@@ -140,6 +153,7 @@ export declare function recordToolCallStart(sessionId: string, callID: string, s
140
153
  /**
141
154
  * Tier-0 pure-function test seam (writing-tests skill). These helpers take no
142
155
  * external dependencies, so testing them directly needs no mocks at all.
156
+ * The seed-gate accessors cover the restart-seeding state machine (issue #2041).
143
157
  */
144
158
  export declare const _test_exports: {
145
159
  readonly deriveAction: typeof deriveAction;
@@ -147,5 +161,7 @@ export declare const _test_exports: {
147
161
  readonly MAX_DENIED_CALL_MARKERS: 500;
148
162
  readonly DENIED_CALL_TTL_MS: number;
149
163
  readonly deniedCallMarkerCount: () => number;
164
+ readonly stepSeedGateSize: () => number;
165
+ readonly clearStepSeedGate: () => void;
150
166
  };
151
167
  export {};
@@ -1,11 +1,52 @@
1
1
  /**
2
2
  * Module-level trajectory step counters shared by runtime reset code and the
3
3
  * trajectory logger without creating a state <-> hook import cycle.
4
+ *
5
+ * Keys are canonical-root + session id (issue #2041 Required 6): the counters
6
+ * are process-global module state, so a host that loads one plugin module
7
+ * instance for several project roots must not let two roots' sessions with
8
+ * the same host session id share a counter — nor let two aliases of one root
9
+ * diverge. The shared `src/utils/canonical-root.ts` helper owns the keying so
10
+ * the trajectory store, these counters, and the logger's restart-seed gate
11
+ * cannot drift. `directory` is required on the minting/seed path; the clear
12
+ * paths may omit it and suffix-scan every root, because the reset entry
13
+ * points legitimately lack a directory.
14
+ */
15
+ /** Current step-counter generation (changes on every clear/reset). */
16
+ export declare function trajectoryStepGeneration(): number;
17
+ /**
18
+ * Mints the next sequential step for a session. Restart continuity is the
19
+ * logger's job (`ensureSessionStepSeeded` in trajectory-logger.ts seeds the
20
+ * counter from the bounded store before the first mint), not this counter's.
21
+ */
22
+ export declare function nextTrajectoryStep(sessionId: string, directory: string): number;
23
+ /**
24
+ * Raises a session's counter to `step` when it is higher than the current
25
+ * value. Used by the restart-seed path so a resumed session continues minting
26
+ * monotonically after the on-disk high-water mark instead of restarting at 1
27
+ * (which would duplicate step numbers against the persisted trajectory).
28
+ * A lower value never lowers the counter (issue #2041 monotonicity).
29
+ */
30
+ export declare function seedTrajectoryStepCounter(sessionId: string, directory: string, step: number): void;
31
+ /**
32
+ * Resets the step counter for a session to zero (module-level semantics —
33
+ * "restart at step one"). The production reset entry points go through
34
+ * trajectory-logger.ts, which also invalidates the per-process restart-seed
35
+ * gate so the next mint re-seeds from disk and steps stay monotonic against
36
+ * the persisted trajectory.
37
+ */
38
+ export declare function resetTrajectoryStepCounter(sessionId: string, directory: string): void;
39
+ /**
40
+ * Clears trajectory step counters for one session (every canonical root — the
41
+ * reset entry points legitimately lack a directory), or all sessions when
42
+ * omitted.
4
43
  */
5
- export declare function nextTrajectoryStep(sessionId: string): number;
6
- export declare function resetTrajectoryStepCounter(sessionId: string): void;
7
44
  export declare function clearTrajectoryStepCounters(sessionId?: string): void;
8
45
  export declare const _test_exports: {
9
46
  MAX_TRACKED_STEP_SESSIONS: number;
10
47
  getTrackedStepSessionCount: () => number;
48
+ /** Whether a counter exists for this session+root in this process. */
49
+ hasTrajectoryStepCounter: (sessionId: string, directory: string) => boolean;
50
+ /** Current generation (test seam: gate-invalidation assertions). */
51
+ getStepCounterGeneration: () => number;
11
52
  };