opencode-swarm 7.138.2 → 7.138.4

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 (59) hide show
  1. package/.opencode/skills/execute/SKILL.md +11 -2
  2. package/.opencode/skills/swarm-implement/SKILL.md +1 -1
  3. package/.opencode/skills/swarm-pr-review/SKILL.md +5 -1
  4. package/dist/background/pr-review-trigger-contract.d.ts +38 -1
  5. package/dist/cli/{config-doctor-hzb0bck9.js → config-doctor-31yppse4.js} +2 -2
  6. package/dist/cli/{core-v6bte964.js → core-65c7rvqf.js} +1 -1
  7. package/dist/cli/{curation-policy-aj37yvz8.js → curation-policy-hs9pc1rp.js} +2 -2
  8. package/dist/cli/{curator-jt6dza8y.js → curator-54n1y4j8.js} +16 -15
  9. package/dist/cli/{curator-llm-factory-m9f4h8t4.js → curator-llm-factory-wm27ra25.js} +16 -15
  10. package/dist/cli/{evidence-summary-service-6cttrkzw.js → evidence-summary-service-hrxcf29a.js} +1 -1
  11. package/dist/cli/{guardrail-explain-rks41rpx.js → guardrail-explain-1729nse8.js} +17 -16
  12. package/dist/cli/{guardrail-log-h39jxftx.js → guardrail-log-yjj5srkw.js} +4 -3
  13. package/dist/cli/{hive-promoter-34y2x4vt.js → hive-promoter-es2x2b0e.js} +16 -15
  14. package/dist/cli/{index-49ygvqvm.js → index-1g6xpjk3.js} +4 -4
  15. package/dist/cli/{index-bakfqtye.js → index-33q2gmgd.js} +1 -1
  16. package/dist/cli/{index-xm07cqy2.js → index-50mwt8fx.js} +5 -5
  17. package/dist/cli/index-556ja8an.js +62 -0
  18. package/dist/cli/{index-r9pn41rj.js → index-57stye65.js} +1 -1
  19. package/dist/cli/{index-exq36v6w.js → index-5q009kc4.js} +1 -1
  20. package/dist/cli/{index-89dwrz8n.js → index-a18hk2fw.js} +225 -63
  21. package/dist/cli/{index-8emf08eb.js → index-a9xny52r.js} +2 -2
  22. package/dist/cli/{index-yxswbd1t.js → index-c60whfgh.js} +1 -1
  23. package/dist/cli/{index-gpxg7wx8.js → index-e1kgxchq.js} +30 -68
  24. package/dist/cli/{index-qt3jjjw9.js → index-gm3pjfhb.js} +271 -94
  25. package/dist/cli/{index-qg5smxv9.js → index-jbge0dyh.js} +3 -3
  26. package/dist/cli/{index-s7ac0xrf.js → index-k27a4e5g.js} +18 -17
  27. package/dist/cli/{index-k6cq9wwh.js → index-m1pwkwfe.js} +1 -1
  28. package/dist/cli/{index-ze4we97d.js → index-m40ea3zk.js} +1 -1
  29. package/dist/cli/{index-da98750t.js → index-m8txs2a9.js} +1 -1
  30. package/dist/cli/{index-y06a43sk.js → index-mycqmsz5.js} +4 -0
  31. package/dist/cli/index-smsy2p8n.js +1725 -0
  32. package/dist/cli/{index-d01d4102.js → index-tjwz5tct.js} +2 -2
  33. package/dist/cli/{index-j0xx9wpj.js → index-y28n2wmq.js} +1 -1
  34. package/dist/cli/index.js +16 -15
  35. package/dist/cli/{knowledge-escalator-qmpfh5yz.js → knowledge-escalator-s6z1x65b.js} +3 -3
  36. package/dist/cli/{knowledge-events-7neg8x0p.js → knowledge-events-nnyn6hst.js} +1 -1
  37. package/dist/cli/{knowledge-store-a6d4625r.js → knowledge-store-x4yfc7v3.js} +1 -1
  38. package/dist/cli/{knowledge-validator-q1qrdyvx.js → knowledge-validator-1v047gsa.js} +4 -4
  39. package/dist/cli/{scan-cursor-3tqshkb2.js → scan-cursor-jxajj6s7.js} +2 -2
  40. package/dist/cli/{schema-mtyaeh18.js → schema-fj32eyae.js} +1 -1
  41. package/dist/cli/{scope-persistence-n1bryhzf.js → scope-persistence-w7zen2wz.js} +25 -2
  42. package/dist/cli/{skill-generator-t3m5qajm.js → skill-generator-rt0jqcsa.js} +5 -5
  43. package/dist/hooks/guardrails/destructive-command.d.ts +35 -0
  44. package/dist/hooks/guardrails/file-authority.d.ts +71 -26
  45. package/dist/hooks/guardrails/index.d.ts +2 -0
  46. package/dist/hooks/guardrails/tool-before.d.ts +5 -0
  47. package/dist/hooks/scope-guard.d.ts +3 -1
  48. package/dist/index.js +408 -396
  49. package/dist/scope/path-identity.d.ts +27 -0
  50. package/dist/scope/scope-binding.d.ts +90 -2
  51. package/dist/scope/scope-lease-renewal.d.ts +28 -0
  52. package/dist/scope/scope-persistence.d.ts +102 -19
  53. package/dist/scope/scope-resolution-diagnostic.d.ts +7 -0
  54. package/dist/tools/declare-scope.d.ts +3 -1
  55. package/dist/tools/save-plan.d.ts +2 -0
  56. package/dist/tools/write-pr-review-trigger-eval.d.ts +2 -2
  57. package/dist/turbo/lean/lane-scope.d.ts +1 -1
  58. package/package.json +1 -1
  59. package/dist/cli/index-2y4jy0de.js +0 -642
@@ -0,0 +1,27 @@
1
+ import * as path from 'node:path';
2
+ /** Filesystem identity semantics used for comparisons, never for I/O. */
3
+ export type PathFlavor = 'win32' | 'posix';
4
+ export declare function getPathFlavor(pathLib?: Pick<typeof path, 'sep'>): PathFlavor;
5
+ /**
6
+ * Produces a comparison-only path identity. Windows identities case-fold and
7
+ * normalize both slash forms; POSIX identities preserve case.
8
+ */
9
+ export declare function normalizePathIdentity(value: string, flavor?: PathFlavor): string;
10
+ export declare function pathIdentitiesEqual(a: string, b: string, flavor?: PathFlavor): boolean;
11
+ /** True when target is the container itself or a descendant of it. */
12
+ export declare function isPathIdentityWithin(target: string, container: string, flavor?: PathFlavor): boolean;
13
+ /**
14
+ * Resolves a candidate and declared entries with one filesystem flavor, then
15
+ * applies the canonical identity containment rule. This is the shared scope
16
+ * predicate for guardrails, completion observers, and authority evaluation.
17
+ */
18
+ export declare function isPathWithinDeclaredScope(filePath: string, scopeEntries: readonly string[], cwd?: string, flavor?: PathFlavor): boolean;
19
+ /**
20
+ * Compares drive/UNC/extended-device roots with Windows case-insensitive
21
+ * identity while retaining POSIX case-sensitive path semantics.
22
+ */
23
+ export declare function isOnDifferentPathRoot(target: string, cwd: string, flavor?: PathFlavor): boolean;
24
+ /** Returns a safe, caller-facing reason when path text is deceptive. */
25
+ export declare function unsafePathTextReason(value: string): string | null;
26
+ /** Single-line, bounded rendering for untrusted diagnostic fields. */
27
+ export declare function sanitizeDiagnosticText(value: unknown, maxLength?: number): string;
@@ -1,8 +1,18 @@
1
1
  import type { Plan } from '../config/plan-schema';
2
2
  export declare const MAX_PENDING_SCOPE_BINDINGS = 256;
3
+ export declare const DEFAULT_SCOPE_BINDING_TTL_MS: number;
4
+ export declare const MAX_SCOPE_BINDING_TOMBSTONES = 256;
5
+ export type ScopeBindingLifecycleState = 'live' | 'expired' | 'revoked' | 'superseded';
3
6
  export type ScopeBindingSource = 'declare_scope' | 'plan' | 'file_directive' | 'pr_feedback' | 'worktree_derived';
4
7
  export interface ScopeBinding {
5
8
  version: 2;
9
+ /** Stable logical authority identity across lifecycle generations. */
10
+ bindingId: string;
11
+ /** Exact immutable generation identity used by persistence and cleanup. */
12
+ generationId: string;
13
+ /** Monotonic CAS revision within one generation. */
14
+ revision: number;
15
+ lifecycleState: ScopeBindingLifecycleState;
6
16
  workspaceIdentity: string;
7
17
  planId: string;
8
18
  planStructureHash: string;
@@ -14,14 +24,43 @@ export interface ScopeBinding {
14
24
  activation: 'declaration' | 'pending_child' | 'active';
15
25
  parentOwnerSessionId?: string;
16
26
  parentCallId?: string;
27
+ predecessorGenerationId?: string;
28
+ childSessionId?: string;
17
29
  /** PR_FEEDBACK bindings carry their parent workflow identity and revision. */
18
30
  workflowSessionId?: string;
19
31
  workflowRevisionDigest?: string;
20
32
  source: ScopeBindingSource;
21
33
  files: string[];
22
34
  declaredAt: number;
35
+ updatedAt: number;
36
+ leaseStartedAt: number;
23
37
  expiresAt: number;
24
38
  }
39
+ export declare const MAX_SCOPE_PATH_BYTES = 4096;
40
+ export declare const MAX_SCOPE_FILES_BYTES: number;
41
+ export type ScopeBindingAdmissionResult = {
42
+ ok: true;
43
+ binding: ScopeBinding;
44
+ } | {
45
+ ok: false;
46
+ code: 'SCOPE_BINDING_CAPACITY' | 'SCOPE_BINDING_STALE';
47
+ message: string;
48
+ };
49
+ export type ScopeBindingResolution = {
50
+ status: 'found';
51
+ binding: ScopeBinding;
52
+ } | {
53
+ status: 'expired';
54
+ candidates: ScopeBinding[];
55
+ totalCandidates: number;
56
+ } | {
57
+ status: 'ambiguous';
58
+ candidates: ScopeBinding[];
59
+ totalCandidates: number;
60
+ } | {
61
+ status: 'not_declared';
62
+ };
63
+ export declare function isScopeBindingIdentity(value: unknown): value is string;
25
64
  export declare function canonicalWorkspaceIdentity(directory: string): string | null;
26
65
  export declare function normalizeScopeFiles(files: readonly string[]): string[] | null;
27
66
  export declare function createScopeBinding(input: {
@@ -36,7 +75,7 @@ export declare function createScopeBinding(input: {
36
75
  activation?: ScopeBinding['activation'];
37
76
  ttlMs?: number;
38
77
  }): ScopeBinding | null;
39
- export declare function registerScopeBinding(binding: ScopeBinding): void;
78
+ export declare function registerScopeBinding(binding: ScopeBinding): ScopeBindingAdmissionResult;
40
79
  /**
41
80
  * Resolve the binding created for one fully-approved parent Task dispatch.
42
81
  * An already-claimed child binding wins over its pending parent precursor;
@@ -83,6 +122,14 @@ export declare function getAuthorizedScopeBindingByPlanIdentity(input: {
83
122
  taskId: string;
84
123
  activeSessionId: string;
85
124
  }): ScopeBinding | null;
125
+ /** Resolve authorization without collapsing expired and ambiguous states. */
126
+ export declare function resolveAuthorizedScopeBindingByPlanIdentity(input: {
127
+ directory: string;
128
+ planId: string;
129
+ planStructureHash: string;
130
+ taskId: string;
131
+ activeSessionId: string;
132
+ }): ScopeBindingResolution;
86
133
  /**
87
134
  * Issue #2002 recurrence guardrail (detection half).
88
135
  *
@@ -144,6 +191,22 @@ export declare function describeScopeWorkspaceMismatch(input: {
144
191
  taskId?: string | null;
145
192
  }): string | null;
146
193
  export declare function clearScopeBindings(predicate?: (binding: ScopeBinding) => boolean): ScopeBinding[];
194
+ /** Remove one exact generation; sibling generations are never affected. */
195
+ export declare function clearExactScopeBinding(input: {
196
+ bindingId: string;
197
+ generationId: string;
198
+ }): ScopeBinding | null;
199
+ export declare function installScopeBindingTombstone(binding: ScopeBinding): void;
200
+ export declare function hasScopeBindingDenyOverlay(binding: ScopeBinding): boolean;
201
+ /** Fail-closed overlay used only when durable revocation cannot be verified. */
202
+ export declare function installFailedRevocationOverlay(binding: ScopeBinding, reason: Exclude<ScopeBindingLifecycleState, 'live'>): boolean;
203
+ /**
204
+ * Installs an immediate generation-wide deny intent before durable retirement
205
+ * contends with refresh. Unlike the failure-only overlay, cleanup owns the
206
+ * whole exact generation and therefore deliberately follows a newer revision.
207
+ */
208
+ export declare function installScopeBindingRetirementIntent(binding: Pick<ScopeBinding, 'bindingId' | 'generationId'> & Partial<ScopeBinding>): ScopeBinding | null;
209
+ export declare function updateExactScopeBinding(binding: ScopeBinding): ScopeBindingAdmissionResult;
147
210
  /**
148
211
  * Atomically claim the pending scope for the exact Task call whose upstream
149
212
  * metadata identified the actual OpenCode child session. The call id is part of
@@ -158,6 +221,11 @@ export declare function claimScopeBindingForChild(input: {
158
221
  previous: ScopeBinding;
159
222
  claimed: ScopeBinding;
160
223
  } | null;
224
+ export declare function createClaimedScopeBinding(previous: ScopeBinding, input: {
225
+ parentSessionId: string;
226
+ childSessionId: string;
227
+ dispatchCallId: string;
228
+ }): ScopeBinding;
161
229
  export declare function deriveChildScopeBinding(parent: ScopeBinding, input: {
162
230
  childDirectory: string;
163
231
  childSessionId: string;
@@ -181,5 +249,25 @@ export declare function resolveCoderScopeSources(input: {
181
249
  source: 'declare_scope' | 'plan' | 'file_directive';
182
250
  } | {
183
251
  ok: false;
184
- code: 'SCOPE_NOT_DECLARED' | 'SCOPE_CONFLICT';
252
+ code: 'SCOPE_NOT_DECLARED';
253
+ sources?: ScopeSourceSets;
254
+ } | {
255
+ ok: false;
256
+ code: 'SCOPE_CONFLICT';
257
+ authoritativeSource: 'declare_scope' | 'plan';
258
+ authoritativeFiles: string[];
259
+ conflictingSource: 'plan' | 'file_directive';
260
+ conflictingFiles: string[];
261
+ disagreement: string[];
262
+ sources: ScopeSourceSets;
185
263
  };
264
+ interface ScopeSourceSets {
265
+ explicit: string[] | null;
266
+ plan: string[] | null;
267
+ directives: string[] | null;
268
+ }
269
+ /** One bounded renderer shared by normal and PR-feedback preflight paths. */
270
+ export declare function formatCoderScopeConflict(decision: Extract<ReturnType<typeof resolveCoderScopeSources>, {
271
+ ok: false;
272
+ }>): string;
273
+ export {};
@@ -0,0 +1,28 @@
1
+ import type { ScopeBinding } from './scope-binding.js';
2
+ import { refreshScopeBindingLease, type ScopePersistenceResult } from './scope-persistence.js';
3
+ export interface ScopeLeaseCandidateInput {
4
+ callID: string;
5
+ sessionID: string;
6
+ tool: string;
7
+ directory: string;
8
+ binding: ScopeBinding;
9
+ targets: string[];
10
+ args?: unknown;
11
+ }
12
+ export interface ScopeLeaseAfterOutput {
13
+ title?: unknown;
14
+ output?: unknown;
15
+ metadata?: unknown;
16
+ }
17
+ export interface ScopeLeaseRenewalTracker {
18
+ remember(input: ScopeLeaseCandidateInput): void;
19
+ consume(input: {
20
+ callID: string;
21
+ sessionID: string;
22
+ tool: string;
23
+ output: ScopeLeaseAfterOutput | null | undefined;
24
+ }): Promise<ScopePersistenceResult | null>;
25
+ }
26
+ type RefreshLease = typeof refreshScopeBindingLease;
27
+ export declare function createScopeLeaseRenewalTracker(refresh?: RefreshLease, now?: () => number): ScopeLeaseRenewalTracker;
28
+ export {};
@@ -1,9 +1,10 @@
1
1
  /**
2
2
  * Scope persistence for #519 (v6.71.1 hotfix).
3
3
  *
4
- * Persists declared coder scope to `.swarm/scopes/scope-{taskId}.json` so that
5
- * scope survives cross-process delegation in-memory `session.declaredCoderScope`
6
- * is lost when a coder session starts in a separate process (#496 root cause B).
4
+ * Retains the legacy v1 `.swarm/scopes/scope-{taskId}.json` projection used by
5
+ * worktree materialization, and persists authorization-capable v2 bindings as
6
+ * exact identity/generation records. Durable v2 state is authoritative across
7
+ * processes; memory is only a cache and can never revive a retired generation.
7
8
  *
8
9
  * Also exposes a fallback reader that reads `plan.json:phases[].tasks[].files_touched`
9
10
  * for the active task, so architect-authored plans become a durable scope source
@@ -13,7 +14,8 @@
13
14
  * - Atomic write via temp + rename (POSIX atomic on same filesystem).
14
15
  * - File lock via proper-lockfile while writing.
15
16
  * - Schema versioning: readers fail closed on unknown version.
16
- * - TTL: default 24h from declaredAt; expired scopes return null.
17
+ * - Legacy v1 TTL: default 24h from declaredAt; expired projections return null.
18
+ * - V2 lifecycle: typed live/expired/revoked/ambiguous/overloaded decisions.
17
19
  * - Symlink guards (defence in depth):
18
20
  * * realpath containment check on `.swarm/scopes/` (closes parent-dir attack)
19
21
  * * O_NOFOLLOW on both write-create and read-fd (closes leaf-file TOCTOU)
@@ -31,20 +33,15 @@
31
33
  * - This is command-level containment, not an operating-system syscall sandbox.
32
34
  *
33
35
  * RESIDUAL RISKS:
34
- * 1. Platform-portability of symlink guards:
36
+ * 1. Platform-portability of legacy v1 symlink guards:
35
37
  * - realpath resolves POSIX symlinks and Windows junctions, but the
36
38
  * Windows behaviour is not covered by CI (Linux-only test matrix).
37
39
  * - O_NOFOLLOW is a no-op on Windows (falls back to 0). The realpath
38
40
  * containment check on `.swarm/scopes/` remains the primary guard
39
41
  * on that platform; leaf-file TOCTOU on Windows is not closed.
40
- * 2. Stale lockfile DoS: a crashed writer leaves a lock for up to
41
- * LOCK_STALE_MS (30s). During that window, concurrent `declare_scope`
42
- * calls fail silently and the architect relies on in-memory state.
43
- * Acceptable because in-memory state remains authoritative inside the
44
- * live process; disk is a fallback.
45
- * 3. Temp-file leak: a crash between `Bun.write(tmp)` and `renameSync`
46
- * leaves `scope-{id}.json.tmp.{ts}.{rand}` files. No sweeper runs today;
47
- * accumulation is bounded by `/swarm close` (which rm -rf's .swarm/scopes/).
42
+ * 2. Legacy v1 temp-file leak: a crash between atomic-write steps can leave
43
+ * temporary projection files. V2 lifecycle maintenance is bounded and
44
+ * prunes settled receipts, tombstones, sidecars, and retirement intents.
48
45
  *
49
46
  * NOT a standalone syscall security boundary. Shell-write detection and the
50
47
  * central write-target resolver provide command-level interception; this module
@@ -53,6 +50,31 @@
53
50
  import { type Plan } from '../config/plan-schema';
54
51
  import { type ScopeBinding } from './scope-binding';
55
52
  declare const SCOPE_SCHEMA_VERSION: 1;
53
+ export type ScopePersistenceCode = 'SCOPE_NOT_DECLARED' | 'SCOPE_BINDING_PERSISTENCE_FAILED' | 'SCOPE_BINDING_CAPACITY' | 'SCOPE_BINDING_ALREADY_CLAIMED' | 'SCOPE_BINDING_AMBIGUOUS' | 'SCOPE_BINDING_EXPIRED' | 'SCOPE_BINDING_STORE_OVERLOADED' | 'SCOPE_BINDING_STALE';
54
+ export type ScopePersistenceResult<T = ScopeBinding> = {
55
+ ok: true;
56
+ value: T;
57
+ } | {
58
+ ok: false;
59
+ code: ScopePersistenceCode;
60
+ message: string;
61
+ };
62
+ export type DurableScopeBindingResolution = {
63
+ status: 'found';
64
+ binding: ScopeBinding;
65
+ } | {
66
+ status: 'expired';
67
+ candidates: ScopeBinding[];
68
+ totalCandidates: number;
69
+ } | {
70
+ status: 'ambiguous';
71
+ candidates: ScopeBinding[];
72
+ totalCandidates: number;
73
+ } | {
74
+ status: 'overloaded';
75
+ } | {
76
+ status: 'not_declared';
77
+ };
56
78
  export interface PersistedScope {
57
79
  version: typeof SCOPE_SCHEMA_VERSION;
58
80
  taskId: string;
@@ -62,11 +84,11 @@ export interface PersistedScope {
62
84
  }
63
85
  export type PersistedScopeBinding = ScopeBinding;
64
86
  /**
65
- * Write declared scope to `.swarm/scopes/scope-{taskId}.json` atomically.
87
+ * Write the legacy v1 `.swarm/scopes/scope-{taskId}.json` projection atomically.
66
88
  * Safe to call concurrently — proper-lockfile serialises writers per-file.
67
89
  *
68
- * Silent on I/O failure: scope persistence is a defense-in-depth layer, not a
69
- * hard requirement. In-memory state remains authoritative for the live process.
90
+ * Silent on I/O failure for backward compatibility. This projection is not an
91
+ * authorization source; v2 callers use the fail-closed exact-generation APIs.
70
92
  */
71
93
  export declare function writeScopeToDisk(directory: string, taskId: string, files: string[], ttlMs?: number): Promise<void>;
72
94
  /**
@@ -74,7 +96,9 @@ export declare function writeScopeToDisk(directory: string, taskId: string, file
74
96
  * compatibility with older non-authorization consumers, but strict Task
75
97
  * preflight and declare_scope use only this schema.
76
98
  */
77
- export declare function writeScopeBindingToDisk(directory: string, binding: ScopeBinding): Promise<void>;
99
+ export declare function writeScopeBindingToDisk(directory: string, binding: ScopeBinding): Promise<ScopePersistenceResult>;
100
+ /** Mandatory transaction: durable verification precedes memory authority. */
101
+ export declare function persistAndRegisterScopeBinding(directory: string, binding: ScopeBinding): Promise<ScopePersistenceResult>;
78
102
  /** Read and fully validate a v2 binding; v1 records never authorize here. */
79
103
  export declare function readScopeBindingFromDisk(input: {
80
104
  directory: string;
@@ -85,17 +109,67 @@ export declare function readScopeBindingFromDisk(input: {
85
109
  requireDispatchCorrelation?: boolean;
86
110
  requireDeclaration?: boolean;
87
111
  }): ScopeBinding | null;
112
+ export declare function resolveScopeBindingFromDisk(input: {
113
+ directory: string;
114
+ taskId: string;
115
+ plan: Plan;
116
+ ownerSessionId: string;
117
+ parentCallId?: string;
118
+ requireDispatchCorrelation?: boolean;
119
+ requireDeclaration?: boolean;
120
+ includeExpired?: boolean;
121
+ }): DurableScopeBindingResolution;
88
122
  /** Remove one identity-bound authorization without disturbing sibling sessions. */
89
123
  export declare function clearScopeBindingFromDisk(input: {
90
124
  directory: string;
125
+ binding: ScopeBinding;
126
+ }): ScopePersistenceResult;
127
+ export declare function tombstoneScopeBinding(directory: string, binding: ScopeBinding, reason: 'expired' | 'revoked' | 'superseded'): Promise<ScopePersistenceResult>;
128
+ /** CAS renewal for one exact active generation. */
129
+ export declare function refreshScopeBindingLease(input: {
130
+ directory: string;
131
+ bindingId: string;
132
+ generationId: string;
133
+ expectedRevision: number;
134
+ activeSessionId: string;
91
135
  taskId: string;
92
- ownerSessionId: string;
93
- }): void;
136
+ ttlMs?: number;
137
+ }): Promise<ScopePersistenceResult>;
138
+ /**
139
+ * Cross-process, successor-first claim transaction. All contenders for one
140
+ * pending generation lock the same stable receipt path.
141
+ */
142
+ export declare function claimScopeBindingForChildDurably(input: {
143
+ directory: string;
144
+ parentSessionId: string;
145
+ childSessionId: string;
146
+ dispatchCallId: string;
147
+ }): Promise<ScopePersistenceResult<{
148
+ previous: ScopeBinding;
149
+ claimed: ScopeBinding;
150
+ }>>;
151
+ /**
152
+ * Declaration transaction used by declare_scope. Replacement is restricted to
153
+ * the same canonical workspace, task, and owning architect session.
154
+ */
155
+ export declare function replaceExistingScopeDeclaration(input: {
156
+ directory: string;
157
+ binding: ScopeBinding;
158
+ replaceExisting: boolean;
159
+ }): Promise<ScopePersistenceResult>;
160
+ export declare function flushScopeBindingMaintenance(directory?: string): Promise<void>;
161
+ /** Prune old non-authorizing generations and settled receipts under one lock. */
162
+ export declare function pruneScopeBindingTombstones(directory: string): Promise<ScopePersistenceResult<number>>;
94
163
  export declare function resolveAuthorizedScopeBinding(input: {
95
164
  directory: string;
96
165
  taskId: string;
97
166
  activeSessionId: string;
98
167
  }): ScopeBinding | null;
168
+ export declare function resolveAuthorizedScopeBindingDetailed(input: {
169
+ directory: string;
170
+ taskId: string;
171
+ activeSessionId: string;
172
+ }): DurableScopeBindingResolution;
99
173
  /**
100
174
  * Recover one unambiguous child binding after an in-memory session restart.
101
175
  * Every candidate is still checked against current plan identity, exact child
@@ -105,12 +179,21 @@ export declare function resolveAuthorizedScopeBindingForSession(input: {
105
179
  directory: string;
106
180
  activeSessionId: string;
107
181
  }): ScopeBinding | null;
182
+ export declare function resolveAuthorizedScopeBindingForSessionDetailed(input: {
183
+ directory: string;
184
+ activeSessionId: string;
185
+ }): DurableScopeBindingResolution;
108
186
  /** Recover one exact planless PR_FEEDBACK child binding after plugin restart. */
109
187
  export declare function resolveAuthorizedPrFeedbackScopeBindingFromDisk(input: {
110
188
  directory: string;
111
189
  activeSessionId: string;
112
190
  taskId?: string;
113
191
  }): ScopeBinding | null;
192
+ export declare const _scopePersistenceInternals: {
193
+ liveBindingCapacity: number;
194
+ bindingFileScanCapacity: number;
195
+ maintenanceFileScanCapacity: number;
196
+ };
114
197
  /**
115
198
  * Read persisted scope for a task. Returns null on:
116
199
  * - file missing
@@ -0,0 +1,7 @@
1
+ import type { DurableScopeBindingResolution } from './scope-persistence.js';
2
+ /** One bounded, single-line recovery contract for durable binding lookup failures. */
3
+ export declare function formatScopeResolutionDiagnostic(input: {
4
+ resolution: DurableScopeBindingResolution;
5
+ taskId: string | null;
6
+ sessionId: string;
7
+ }): string | null;
@@ -4,6 +4,7 @@
4
4
  * This tool must be called before delegating to coder to enable scope containment checking.
5
5
  */
6
6
  import type { ToolDefinition } from '@opencode-ai/plugin/tool';
7
+ import type { AuthorityConfig } from '../config/schema';
7
8
  /**
8
9
  * Arguments for the declare_scope tool
9
10
  */
@@ -11,6 +12,7 @@ export interface DeclareScopeArgs {
11
12
  taskId: string;
12
13
  files: string[];
13
14
  whitelist?: string[];
15
+ replace_existing?: boolean;
14
16
  working_directory?: string;
15
17
  }
16
18
  /**
@@ -47,7 +49,7 @@ export declare function executeDeclareScope(args: DeclareScopeArgs, fallbackDir?
47
49
  sessionID: string;
48
50
  messageID: string;
49
51
  agentName?: string;
50
- }): Promise<DeclareScopeResult>;
52
+ }, authorityConfig?: AuthorityConfig): Promise<DeclareScopeResult>;
51
53
  /**
52
54
  * Tool definition for declare_scope
53
55
  */
@@ -23,6 +23,8 @@ export interface SavePlanArgs {
23
23
  size?: 'small' | 'medium' | 'large';
24
24
  depends?: string[];
25
25
  acceptance?: string;
26
+ /** Exact project-relative paths this task is expected to modify. */
27
+ files_touched?: string[];
26
28
  /** Spec FR-###/SC-### IDs this task maps to (issue #1687, FR-000). */
27
29
  fr_refs?: string[];
28
30
  }>;
@@ -27,7 +27,7 @@ declare const WritePrReviewTriggerEvalArgsSchema: z.ZodObject<{
27
27
  "unclassified-risk": "unclassified-risk";
28
28
  }>;
29
29
  result: z.ZodLiteral<"MATCHED">;
30
- evidence: z.ZodString;
30
+ evidence: z.ZodOptional<z.ZodString>;
31
31
  source_batch_id: z.ZodString;
32
32
  source_lane_id: z.ZodString;
33
33
  }, z.core.$strict>, z.ZodObject<{
@@ -45,7 +45,7 @@ declare const WritePrReviewTriggerEvalArgsSchema: z.ZodObject<{
45
45
  "unclassified-risk": "unclassified-risk";
46
46
  }>;
47
47
  result: z.ZodLiteral<"NOT_TRIGGERED">;
48
- evidence: z.ZodString;
48
+ evidence: z.ZodOptional<z.ZodString>;
49
49
  }, z.core.$strict>], "result">>;
50
50
  }, z.core.$strict>;
51
51
  export type WritePrReviewTriggerEvalArgs = z.infer<typeof WritePrReviewTriggerEvalArgsSchema>;
@@ -15,7 +15,7 @@
15
15
  *
16
16
  * This module publishes that authority using the same primitives as the
17
17
  * standard worktree path (`src/hooks/delegation-gate.ts`, the
18
- * `savePlan` → `deriveChildScopeBinding` → register + `writeScopeBindingToDisk`
18
+ * `savePlan` → `deriveChildScopeBinding` → `persistAndRegisterScopeBinding`
19
19
  * sequence), so every identity condition in
20
20
  * `getAuthorizedScopeBindingByPlanIdentity` is satisfied without weakening or
21
21
  * bypassing any of them.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-swarm",
3
- "version": "7.138.2",
3
+ "version": "7.138.4",
4
4
  "description": "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",