opencode-swarm 7.108.0 → 7.109.1
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/.opencode/skills/clarify-spec/SKILL.md +15 -9
- package/.opencode/skills/critic-gate/SKILL.md +12 -4
- package/.opencode/skills/execute/SKILL.md +1 -0
- package/.opencode/skills/phase-wrap/SKILL.md +2 -2
- package/.opencode/skills/plan/SKILL.md +23 -11
- package/.opencode/skills/specify/SKILL.md +27 -9
- package/dist/cli/{core-vev13ej2.js → core-mbd2g302.js} +5 -1
- package/dist/cli/{curator-drift-fdfgj9qf.js → curator-drift-169wgaxn.js} +1 -1
- package/dist/cli/{curator-llm-factory-n70bxf40.js → curator-llm-factory-gtfhwnbr.js} +4 -4
- package/dist/cli/{curator-js92gc8a.js → curator-q4febs18.js} +4 -4
- package/dist/cli/{evidence-summary-service-bjhr75v0.js → evidence-summary-service-8tasw2tt.js} +2 -2
- package/dist/cli/{guardrail-explain-sn2a4pb7.js → guardrail-explain-r2d8ftkv.js} +5 -5
- package/dist/cli/{hive-promoter-3hh8ph4a.js → hive-promoter-mfd5p9f5.js} +4 -4
- package/dist/cli/{index-x06d2qqm.js → index-1capawwy.js} +5 -5
- package/dist/cli/{index-f1qyj61w.js → index-3yk9196e.js} +40 -3
- package/dist/cli/{index-48mc4d48.js → index-j2v3w1ds.js} +8 -2
- package/dist/cli/{index-1emhz3zb.js → index-nq9h2t3x.js} +137 -70
- package/dist/cli/{index-91j1sqzm.js → index-scww5b77.js} +47 -0
- package/dist/cli/{index-7jyndvsy.js → index-wsg3vkss.js} +1 -1
- package/dist/cli/index.js +4 -4
- package/dist/commands/registry.d.ts +2 -2
- package/dist/commands/sdd.d.ts +10 -0
- package/dist/config/index.d.ts +1 -0
- package/dist/config/worktree-isolation-config.d.ts +10 -0
- package/dist/hooks/delegation-gate/worktree-isolation.d.ts +4 -2
- package/dist/hooks/delegation-gate.d.ts +1 -0
- package/dist/hooks/guardrails/index.d.ts +1 -1
- package/dist/hooks/guardrails/tool-before.d.ts +5 -0
- package/dist/index.js +130 -121
- package/dist/plan/ledger.d.ts +60 -0
- package/dist/sdd/effective-spec.d.ts +21 -0
- package/dist/tools/save-plan.d.ts +24 -0
- package/dist/worktree/core.d.ts +58 -7
- package/dist/worktree/index.d.ts +1 -1
- package/package.json +1 -1
package/dist/plan/ledger.d.ts
CHANGED
|
@@ -92,6 +92,29 @@ declare function getPlanJsonPath(directory: string): string;
|
|
|
92
92
|
* @returns Hex-encoded SHA-256 hash
|
|
93
93
|
*/
|
|
94
94
|
export declare function computePlanHash(plan: Plan): string;
|
|
95
|
+
/**
|
|
96
|
+
* Compute a SHA-256 hash of the plan's STRUCTURE, excluding transient
|
|
97
|
+
* execution progress fields (`phase.status` and `task.status`).
|
|
98
|
+
*
|
|
99
|
+
* This mirrors {@link computePlanHash}'s normalization byte-for-byte EXCEPT it
|
|
100
|
+
* omits the two status fields from the hashed payload. It exists solely for the
|
|
101
|
+
* plan-critic execution gate (`assertPlanCriticApprovedForExecution`), which
|
|
102
|
+
* must recognize a plan as "the same plan the critic approved" even after the
|
|
103
|
+
* architect flips a task to `in_progress` before delegating its coder. Including
|
|
104
|
+
* status (as `computePlanHash` does) would make the gate fire on the very first
|
|
105
|
+
* conforming coder dispatch, because `update_task_status(taskId,'in_progress')`
|
|
106
|
+
* runs before it and mutates the status-inclusive hash.
|
|
107
|
+
*
|
|
108
|
+
* IMPORTANT: This is intentionally a SEPARATE function, not a refactor of
|
|
109
|
+
* `computePlanHash`. `computePlanHash` is load-bearing for ledger replay and
|
|
110
|
+
* staleness/integrity detection (its output is persisted on-disk as
|
|
111
|
+
* `plan_hash_after`), so its byte output must never change. Do NOT collapse
|
|
112
|
+
* these two into a shared normalizer.
|
|
113
|
+
*
|
|
114
|
+
* @param plan - The plan to hash
|
|
115
|
+
* @returns Hex-encoded SHA-256 hash of the status-excluded structure
|
|
116
|
+
*/
|
|
117
|
+
export declare function computePlanStructureHash(plan: Plan): string;
|
|
95
118
|
/**
|
|
96
119
|
* Read the current plan.json and compute its hash.
|
|
97
120
|
*
|
|
@@ -206,12 +229,21 @@ export declare function takeSnapshotWithRetry(directory: string, plan: Plan, opt
|
|
|
206
229
|
* - approvalMetadata: optional free-form metadata embedded into the
|
|
207
230
|
* snapshot payload (e.g. phase number, verdict, summary) so that
|
|
208
231
|
* downstream readers can filter without decoding prompts.
|
|
232
|
+
* - payloadHashOverride: when supplied, stored as the snapshot payload's
|
|
233
|
+
* `payload_hash` INSTEAD of the default `computePlanHash(plan)`. Used by the
|
|
234
|
+
* plan-critic gate to persist a status-excluded structural hash
|
|
235
|
+
* (`computePlanStructureHash`) so the gate can match the plan across the
|
|
236
|
+
* architect's pre-delegation `in_progress` status flip. Note this only
|
|
237
|
+
* changes the embedded snapshot `payload_hash`; the ledger event's
|
|
238
|
+
* hash-chain field `plan_hash_after` is unaffected (still governed by
|
|
239
|
+
* `planHashAfter` / on-disk plan.json), preserving replay integrity.
|
|
209
240
|
* @returns The LedgerEvent that was written
|
|
210
241
|
*/
|
|
211
242
|
export declare function takeSnapshotEvent(directory: string, plan: Plan, options?: {
|
|
212
243
|
planHashAfter?: string;
|
|
213
244
|
source?: string;
|
|
214
245
|
approvalMetadata?: Record<string, unknown>;
|
|
246
|
+
payloadHashOverride?: string;
|
|
215
247
|
}): Promise<LedgerEvent>;
|
|
216
248
|
/**
|
|
217
249
|
* Options for replayFromLedger
|
|
@@ -320,8 +352,35 @@ export interface ApprovedSnapshotInfo {
|
|
|
320
352
|
* @returns The most recent approved snapshot info, or null if none exists
|
|
321
353
|
*/
|
|
322
354
|
export declare function loadLastApprovedPlan(directory: string, expectedPlanId?: string): Promise<ApprovedSnapshotInfo | null>;
|
|
355
|
+
/**
|
|
356
|
+
* Find the most recent PLAN-CRITIC-approved snapshot in the ledger.
|
|
357
|
+
*
|
|
358
|
+
* Like {@link loadLastApprovedPlan}, but additionally requires the snapshot's
|
|
359
|
+
* embedded `approval.source === 'plan_critic_gate'`. This distinguishes the
|
|
360
|
+
* plan-critic execution-gate approval (recorded by
|
|
361
|
+
* `recordPlanCriticApprovalSnapshotIfApplicable` in the delegation gate) from
|
|
362
|
+
* the UNRELATED per-phase drift-verification snapshots that
|
|
363
|
+
* `src/tools/write-drift-evidence.ts` also writes with
|
|
364
|
+
* `source: 'critic_approved'` (but `approval: {phase, verdict, summary}` and no
|
|
365
|
+
* `plan_critic_gate` marker).
|
|
366
|
+
*
|
|
367
|
+
* Without this filter, a drift-verification snapshot landing AFTER a legitimate
|
|
368
|
+
* plan-critic approval would shadow it (being more recent), causing the gate to
|
|
369
|
+
* spuriously reject execution. This loader skips non-matching `critic_approved`
|
|
370
|
+
* snapshots and keeps scanning backward to find the plan-critic approval.
|
|
371
|
+
*
|
|
372
|
+
* SAFETY: `loadLastApprovedPlan`'s default behavior is intentionally left
|
|
373
|
+
* unchanged — other callers (`get-approved-plan`, restore/recovery paths) want
|
|
374
|
+
* ANY `critic_approved` snapshot as a restore point regardless of approval shape.
|
|
375
|
+
*
|
|
376
|
+
* @param directory - Working directory containing `.swarm/plan-ledger.jsonl`
|
|
377
|
+
* @param expectedPlanId - Optional plan identity filter (see loadLastApprovedPlan)
|
|
378
|
+
* @returns The most recent plan-critic-approved snapshot info, or null
|
|
379
|
+
*/
|
|
380
|
+
export declare function loadLastPlanCriticApprovedSnapshot(directory: string, expectedPlanId?: string): Promise<ApprovedSnapshotInfo | null>;
|
|
323
381
|
export declare const _internals: {
|
|
324
382
|
computePlanHash: typeof computePlanHash;
|
|
383
|
+
computePlanStructureHash: typeof computePlanStructureHash;
|
|
325
384
|
computeCurrentPlanHash: typeof computeCurrentPlanHash;
|
|
326
385
|
ledgerExists: typeof ledgerExists;
|
|
327
386
|
getLatestLedgerSeq: typeof getLatestLedgerSeq;
|
|
@@ -336,6 +395,7 @@ export declare const _internals: {
|
|
|
336
395
|
quarantineLedgerSuffix: typeof quarantineLedgerSuffix;
|
|
337
396
|
replayWithIntegrity: typeof replayWithIntegrity;
|
|
338
397
|
loadLastApprovedPlan: typeof loadLastApprovedPlan;
|
|
398
|
+
loadLastPlanCriticApprovedSnapshot: typeof loadLastPlanCriticApprovedSnapshot;
|
|
339
399
|
getLedgerPath: typeof getLedgerPath;
|
|
340
400
|
getPlanJsonPath: typeof getPlanJsonPath;
|
|
341
401
|
};
|
|
@@ -203,6 +203,21 @@ export interface ReadEffectiveSpecOpts {
|
|
|
203
203
|
* `.specify/` a non-competing source, matching both citations.
|
|
204
204
|
*/
|
|
205
205
|
export declare function readEffectiveSpecSync(directory: string, opts?: ReadEffectiveSpecOpts): EffectiveSpec | null;
|
|
206
|
+
/**
|
|
207
|
+
* Write an SDD projection to `.swarm/spec.md`.
|
|
208
|
+
*
|
|
209
|
+
* **Overwrite enforcement (FR-004, TOCTOU-safe):**
|
|
210
|
+
* When `overwrite` is `false` (default), the write uses `O_EXCL` exclusive
|
|
211
|
+
* creation (`fs.writeFileSync(target, data, { flag: 'wx' })`). If the
|
|
212
|
+
* target already exists the kernel returns `EEXIST` and the function
|
|
213
|
+
* returns `written: false` with an `error` field — no archive, no replace.
|
|
214
|
+
* This closes the TOCTOU race at the write boundary: a native spec that
|
|
215
|
+
* appears between a pre-check and this call cannot be silently replaced.
|
|
216
|
+
*
|
|
217
|
+
* When `overwrite` is `true`, the existing archive-then-replace path runs.
|
|
218
|
+
*
|
|
219
|
+
* The `--dry-run` early-return remains untouched (before any write).
|
|
220
|
+
*/
|
|
206
221
|
export declare function writeProjectedSpecSync(directory: string, options?: {
|
|
207
222
|
changeId?: string;
|
|
208
223
|
dryRun?: boolean;
|
|
@@ -210,11 +225,17 @@ export declare function writeProjectedSpecSync(directory: string, options?: {
|
|
|
210
225
|
source?: 'openspec' | 'speckit';
|
|
211
226
|
/** Feature selector forwarded to buildSpeckitProjectionSync when source is speckit. */
|
|
212
227
|
feature?: string;
|
|
228
|
+
/**
|
|
229
|
+
* When true, archive the existing spec and overwrite.
|
|
230
|
+
* When false (default), use O_EXCL (wx flag) — refuse if target exists.
|
|
231
|
+
*/
|
|
232
|
+
overwrite?: boolean;
|
|
213
233
|
}): {
|
|
214
234
|
written: boolean;
|
|
215
235
|
projection: EffectiveSpec | null;
|
|
216
236
|
archivePath?: string;
|
|
217
237
|
path: string;
|
|
238
|
+
error?: string;
|
|
218
239
|
};
|
|
219
240
|
/**
|
|
220
241
|
* Validate Spec-Kit artifacts READ-ONLY (FR-007, task 2.3).
|
|
@@ -64,6 +64,12 @@ export interface SavePlanArgs {
|
|
|
64
64
|
* from the existing plan's identity.
|
|
65
65
|
*/
|
|
66
66
|
confirm_identity_change?: boolean;
|
|
67
|
+
/**
|
|
68
|
+
* When true, allows saving a plan even when required FR-### MUST/SHALL
|
|
69
|
+
* requirements from the effective spec are not explicitly mapped in task
|
|
70
|
+
* descriptions or acceptance criteria.
|
|
71
|
+
*/
|
|
72
|
+
confirm_requirement_coverage_gaps?: boolean;
|
|
67
73
|
/**
|
|
68
74
|
* Architect-facing concurrency controls for this plan.
|
|
69
75
|
* When execution_profile.locked is true the profile is immutable — subsequent
|
|
@@ -90,6 +96,7 @@ export interface SavePlanResult {
|
|
|
90
96
|
errors?: string[];
|
|
91
97
|
warnings?: string[];
|
|
92
98
|
recovery_guidance?: string;
|
|
99
|
+
requirement_coverage?: RequirementCoverageResult;
|
|
93
100
|
/** The resolved execution_profile that was persisted, if any. */
|
|
94
101
|
execution_profile?: {
|
|
95
102
|
parallelization_enabled: boolean;
|
|
@@ -99,6 +106,22 @@ export interface SavePlanResult {
|
|
|
99
106
|
auto_proceed?: boolean;
|
|
100
107
|
};
|
|
101
108
|
}
|
|
109
|
+
interface RequirementCoverageEntry {
|
|
110
|
+
id: string;
|
|
111
|
+
obligation: 'MUST' | 'SHOULD' | 'SHALL' | null;
|
|
112
|
+
text: string;
|
|
113
|
+
mapped_task_ids: string[];
|
|
114
|
+
}
|
|
115
|
+
interface RequirementCoverageResult {
|
|
116
|
+
status: 'passed' | 'failed' | 'override';
|
|
117
|
+
total_requirements: number;
|
|
118
|
+
covered_count: number;
|
|
119
|
+
missing_count: number;
|
|
120
|
+
blocking_missing_count: number;
|
|
121
|
+
covered: RequirementCoverageEntry[];
|
|
122
|
+
missing: RequirementCoverageEntry[];
|
|
123
|
+
blocking_missing: RequirementCoverageEntry[];
|
|
124
|
+
}
|
|
102
125
|
/**
|
|
103
126
|
* Detect template placeholder content (e.g., [task], [Project], [description], [N]).
|
|
104
127
|
* These patterns indicate the LLM reproduced template examples literally rather than
|
|
@@ -126,3 +149,4 @@ export declare function executeSavePlan(args: SavePlanArgs, fallbackDir?: string
|
|
|
126
149
|
* Tool definition for save_plan
|
|
127
150
|
*/
|
|
128
151
|
export declare const save_plan: ToolDefinition;
|
|
152
|
+
export {};
|
package/dist/worktree/core.d.ts
CHANGED
|
@@ -180,23 +180,74 @@ export declare function makeWorktreeBranchName(sessionId: string, id: string, op
|
|
|
180
180
|
* @param options - Worktree purpose, branch naming, and path options.
|
|
181
181
|
* @returns A worktree handle on success, or `{ error: string }` on failure.
|
|
182
182
|
*/
|
|
183
|
+
/**
|
|
184
|
+
* Resolves the swarm-managed worktree base directory: `directory/worktreeDir`
|
|
185
|
+
* when an override is configured, otherwise the DD-6 default
|
|
186
|
+
* `<project-parent>/.swarm-worktrees`. Shared by `provisionWorktree` (path
|
|
187
|
+
* construction) and the destructive-command guard / removeWorktree force
|
|
188
|
+
* fallback (containment checks) so both sides agree on what counts as
|
|
189
|
+
* "swarm-managed".
|
|
190
|
+
*
|
|
191
|
+
* @param directory - Project root (an absolute path to the git working tree).
|
|
192
|
+
* @param worktreeDir - Optional worktree-dir override (relative to `directory`
|
|
193
|
+
* or absolute). When absent, the DD-6 default base is used.
|
|
194
|
+
* @returns The absolute worktree base directory.
|
|
195
|
+
*/
|
|
196
|
+
export declare function resolveWorktreeBaseDir(directory: string, worktreeDir?: string): string;
|
|
197
|
+
/**
|
|
198
|
+
* Checks whether `targetPath` is contained within the swarm-managed worktree
|
|
199
|
+
* base directory (default base, plus any `worktreeDirOverrides`), using
|
|
200
|
+
* `fs.realpathSync` on both sides to resolve symlinks/junctions before the
|
|
201
|
+
* containment comparison — this both establishes containment AND defeats a
|
|
202
|
+
* symlink/junction escape in one step. Fails closed (returns false) if the
|
|
203
|
+
* target cannot be resolved (e.g. does not exist, or a permission error).
|
|
204
|
+
* Case-insensitive comparison on Windows, matching `isInDeclaredScope` in
|
|
205
|
+
* `src/hooks/guardrails/helpers.ts`.
|
|
206
|
+
*
|
|
207
|
+
* @param targetPath - Path to check (relative to `directory` or absolute).
|
|
208
|
+
* @param directory - Project root, used to resolve relative targets
|
|
209
|
+
* and the default base.
|
|
210
|
+
* @param worktreeDirOverrides - Additional configured worktree-dir overrides
|
|
211
|
+
* whose resolved bases are also treated as trusted.
|
|
212
|
+
* @returns `true` when the resolved target is inside a trusted base, else `false`.
|
|
213
|
+
*/
|
|
214
|
+
export declare function isPathUnderSwarmWorktreeBase(targetPath: string, directory: string, worktreeDirOverrides?: string[]): boolean;
|
|
183
215
|
export declare function provisionWorktree(directory: string, id: string, sessionId: string, options: WorktreeOptions): Promise<WorktreeProvisionResult>;
|
|
184
216
|
/**
|
|
185
|
-
* Removes a git worktree **without** `--force
|
|
217
|
+
* Removes a git worktree, **without** `--force` by default.
|
|
186
218
|
*
|
|
187
219
|
* On Windows (`process.platform === 'win32'`), retries up to 3 times with a
|
|
188
220
|
* 2-second delay when the error contains `EBUSY` or `EPERM` (DD-10). After
|
|
189
221
|
* exhausting retries the worktree is abandoned — the function returns an
|
|
190
222
|
* error but does NOT throw.
|
|
191
223
|
*
|
|
192
|
-
*
|
|
193
|
-
*
|
|
194
|
-
*
|
|
195
|
-
*
|
|
196
|
-
*
|
|
224
|
+
* When `options.force` is set, the removal is escalated (issue #1708): if the
|
|
225
|
+
* default non-forced removal gives up (either a non-retryable error such as the
|
|
226
|
+
* "contains modified or untracked files, use --force" message on the first
|
|
227
|
+
* attempt, or EBUSY/EPERM retries exhausted on Windows), a single
|
|
228
|
+
* `git worktree remove --force` is attempted — but ONLY when `worktreePath`
|
|
229
|
+
* resolves inside the swarm-managed worktree base directory
|
|
230
|
+
* (`isPathUnderSwarmWorktreeBase`). A path outside that trusted base is NEVER
|
|
231
|
+
* force-removed even if `force` is requested. When `force` is not set, behavior
|
|
232
|
+
* is unchanged (non-force only; returns an error, does not throw, on exhaustion).
|
|
233
|
+
*
|
|
234
|
+
* @param worktreePath - Absolute path to the worktree directory to remove.
|
|
235
|
+
* @param projectRoot - Absolute path to the project root (a git repository)
|
|
236
|
+
* used as `cwd` for the `git worktree remove` command.
|
|
237
|
+
* Required because the worktree's parent directory may
|
|
238
|
+
* not itself be a git repository.
|
|
239
|
+
* @param options - Optional escalation controls.
|
|
240
|
+
* @param options.force - When true, opt into the forced-fallback removal
|
|
241
|
+
* described above (scoped to the trusted base).
|
|
242
|
+
* @param options.worktreeDir - The configured worktree-dir override, if any, so
|
|
243
|
+
* the containment check trusts the same base
|
|
244
|
+
* `provisionWorktree` used.
|
|
197
245
|
* @returns `{ success: true }` on success or `{ error: string }` on failure.
|
|
198
246
|
*/
|
|
199
|
-
export declare function removeWorktree(worktreePath: string, projectRoot: string
|
|
247
|
+
export declare function removeWorktree(worktreePath: string, projectRoot: string, options?: {
|
|
248
|
+
force?: boolean;
|
|
249
|
+
worktreeDir?: string;
|
|
250
|
+
}): Promise<RemoveSuccess | RemoveFailure>;
|
|
200
251
|
/**
|
|
201
252
|
* Checks whether a worktree is clean — no uncommitted changes AND no
|
|
202
253
|
* untracked files.
|
package/dist/worktree/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export type { AutoCommitSkip, AutoCommitSuccess, CleanCheckFailure, CleanCheckSuccess, CleanFailure, CleanSuccess, ProvisionFailure, ProvisionSuccess, RemoveFailure, RemoveSuccess, } from './core';
|
|
2
|
-
export { _internals as coreInternals, assertCleanWorkingTree, autoCommitDirty, checkPathBudget, cleanUntrackedFiles, isCleanWorktree, makeWorktreeBranchName, provisionWorktree, removeWorktree, shortenWorktreePath, } from './core';
|
|
2
|
+
export { _internals as coreInternals, assertCleanWorkingTree, autoCommitDirty, checkPathBudget, cleanUntrackedFiles, isCleanWorktree, isPathUnderSwarmWorktreeBase, makeWorktreeBranchName, provisionWorktree, removeWorktree, resolveWorktreeBaseDir, shortenWorktreePath, } from './core';
|
|
3
3
|
export type { CleanupFailure, CleanupSuccess, ConflictHandlingError, ConflictInfo, DirtyMergeFailure, DirtyMergePartial, DirtyMergeSuccess, MergeConflict, MergeFailure, MergeSuccess, OrphanCleanupResult, StartupRecoveryResult, } from './merge';
|
|
4
4
|
export { _internals as mergeInternals, attemptMergeBackFromDirty, cleanupOrphanedBranches, getMergeStrategy, handleMergeConflict, mergeLaneBranch, postMergeCleanup, startupOrphanRecovery, } from './merge';
|
|
5
5
|
export * from './types';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-swarm",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.109.1",
|
|
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",
|