opencode-swarm 7.109.0 → 7.109.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.
- package/.opencode/skills/critic-gate/SKILL.md +2 -0
- package/.opencode/skills/engineering-conventions/SKILL.md +45 -0
- package/.opencode/skills/execute/SKILL.md +1 -0
- package/.opencode/skills/swarm-pr-feedback/SKILL.md +47 -0
- package/dist/cli/{core-vev13ej2.js → core-mbd2g302.js} +5 -1
- package/dist/cli/{curator-3efwdf9x.js → curator-6p9tpprq.js} +3 -3
- package/dist/cli/{curator-llm-factory-nttpcx4b.js → curator-llm-factory-wqbm9mwr.js} +3 -3
- package/dist/cli/{evidence-summary-service-j7jwf20f.js → evidence-summary-service-8tasw2tt.js} +1 -1
- package/dist/cli/{guardrail-explain-e85gbj0r.js → guardrail-explain-ynge4ww3.js} +4 -4
- package/dist/cli/{hive-promoter-rc6z2x8f.js → hive-promoter-qh2rh8x2.js} +3 -3
- package/dist/cli/{index-1mjzvkzj.js → index-3qwaydq1.js} +4 -4
- package/dist/cli/{index-f1qyj61w.js → index-3yk9196e.js} +40 -3
- package/dist/cli/{index-3e7jajwe.js → index-8a8b5wjf.js} +1 -1
- package/dist/cli/{index-vb5t1kvs.js → index-cqbqynzp.js} +10 -10
- package/dist/cli/{index-wfq4r95s.js → index-j2v3w1ds.js} +7 -1
- package/dist/cli/index.js +3 -3
- package/dist/config/index.d.ts +1 -0
- package/dist/config/qa-gate-pipeline.d.ts +67 -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 +39 -35
- package/dist/plan/ledger.d.ts +60 -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
|
@@ -11,6 +11,7 @@ This protocol is loaded on demand by the architect stub in src/agents/architect.
|
|
|
11
11
|
### MODE: CRITIC-GATE
|
|
12
12
|
Delegate plan to the active swarm's critic agent for review BEFORE any implementation begins.
|
|
13
13
|
- Send the full plan.md content and codebase context summary
|
|
14
|
+
- Explicitly reference "plan.md" or "critic-gate" in the dispatch prompt text. This lets the mechanical approval-recording gate reliably detect the review and record the critic's APPROVED verdict, which the EXECUTE-phase coder gate then requires.
|
|
14
15
|
- **APPROVED** → Proceed to MODE: EXECUTE
|
|
15
16
|
- **NEEDS_REVISION** → Revise the plan based on critic feedback, then resubmit (max 2 cycles)
|
|
16
17
|
- **REJECTED** → Inform the user of fundamental issues and ask for guidance before proceeding
|
|
@@ -26,6 +27,7 @@ You MUST NOT proceed to MODE: EXECUTE without printing this checklist with fille
|
|
|
26
27
|
CRITIC-GATE TRIGGER: Run ONCE when you first write the complete .swarm/plan.md.
|
|
27
28
|
Do NOT re-run CRITIC-GATE before every project phase.
|
|
28
29
|
If resuming a project with an existing approved plan, CRITIC-GATE is already satisfied.
|
|
30
|
+
Caveat: this assumption breaks if the plan lacks a `plan_critic_gate`-tagged approval snapshot (e.g. a plan approved before this mechanical gate existed, or one where the recording heuristic didn't fire) — in that case the first coder dispatch will fail with `PLAN_CRITIC_GATE_VIOLATION`. If that happens, do not assume CRITIC-GATE is satisfied; re-run it and get a fresh APPROVED verdict.
|
|
29
31
|
|
|
30
32
|
6j. SPEC-GATE (Execute BEFORE any save_plan call):
|
|
31
33
|
- An effective spec exists iff `/swarm sdd status` reports a resolved spec (it reflects `readEffectiveSpecSync`, which returns null — NO effective spec — for no sources, multiple competing sources (openspec+specify), multi-feature Spec-Kit without a selected feature, or any unresolvable state). `save_plan` rejects (SPEC_REQUIRED) when `/swarm sdd status` reports no resolved spec. The gate is overridable via `SWARM_SKIP_SPEC_GATE=1`.
|
|
@@ -127,3 +127,48 @@ When a sandbox executor (`src/sandbox/{linux,macos,win32}/*.ts`) interpolates en
|
|
|
127
127
|
- Scope-materialization for lane-scoped resources.
|
|
128
128
|
|
|
129
129
|
A divergence between primary and fallback that is not exercised by a parity test is a regression. The existing per-OS test files `tests/unit/sandbox/{linux,macos,win32}.test.ts` must continue to cover both the primary and fallback paths after every env-affecting change — extend these tests rather than relying on dedicated sandbox-envoverride test files that may or may not exist in your branch.
|
|
130
|
+
|
|
131
|
+
## SAST baseline capturing (differential scanning)
|
|
132
|
+
|
|
133
|
+
The `sast_scan` tool supports `capture_baseline: true` with a `phase` parameter
|
|
134
|
+
to snapshot pre-existing findings. Subsequent scans with the same `phase` value
|
|
135
|
+
perform differential checking — they only fail on **new** findings, not
|
|
136
|
+
pre-existing ones.
|
|
137
|
+
|
|
138
|
+
### When to capture a baseline
|
|
139
|
+
|
|
140
|
+
- **Before Phase 1 code changes.** The baseline must reflect the state of the
|
|
141
|
+
codebase *before* any new work is done. This ensures the differential scan
|
|
142
|
+
catches findings introduced by the current session's changes.
|
|
143
|
+
|
|
144
|
+
### Critical safety guard
|
|
145
|
+
|
|
146
|
+
**NEVER capture a baseline after code changes have been made in a phase.**
|
|
147
|
+
A baseline captured post-edit silently encodes the very bugs the scan is meant
|
|
148
|
+
to catch as "pre-existing," suppressing them indefinitely. This turns the SAST
|
|
149
|
+
gate into theater.
|
|
150
|
+
|
|
151
|
+
### How to use it
|
|
152
|
+
|
|
153
|
+
1. Identify the files to scan. In a phase, use the union of declared task-scope
|
|
154
|
+
files plus files the coder is expected to touch. Derive the list from
|
|
155
|
+
`declare_scope` outputs, `git diff --name-only`, or the phase's task specs.
|
|
156
|
+
2. Before any coder delegation in Phase 1, capture the baseline:
|
|
157
|
+
```
|
|
158
|
+
sast_scan(directory, changed_files=[...], capture_baseline=true, phase=1)
|
|
159
|
+
```
|
|
160
|
+
3. After coder work, scan the same file set:
|
|
161
|
+
```
|
|
162
|
+
sast_scan(directory, changed_files=[...], phase=1)
|
|
163
|
+
```
|
|
164
|
+
This returns only NEW findings (absent from the baseline).
|
|
165
|
+
4. If a pre-existing finding is legitimately fixed, the baseline can be
|
|
166
|
+
re-captured at the start of the next phase with the updated file list.
|
|
167
|
+
|
|
168
|
+
### Why this matters
|
|
169
|
+
|
|
170
|
+
During PR #1704 review, SAST flagged `RegExp.prototype.exec()` as
|
|
171
|
+
"command injection via child_process.exec()" — a false positive that blocked
|
|
172
|
+
the gate. With a baseline captured before the phase, this pre-existing false
|
|
173
|
+
positive would have been suppressed, and only genuinely new findings would
|
|
174
|
+
surface.
|
|
@@ -55,6 +55,7 @@ All other gates: failure → return to coder. No self-fixes. No workarounds.
|
|
|
55
55
|
→ Subsequent `pre_check_batch` calls with `phase: <N>` will automatically diff against this baseline — only NEW findings (not in baseline) drive the fail verdict.
|
|
56
56
|
-> PREFLIGHT CHECKLIST: Before first coder delegation, answer "SAST baseline captured before first coder delegation? yes/no/disabled/error". If the answer is no, do not delegate to coder; run 5b-BASE first. If disabled or error, record the exact tool result.
|
|
57
57
|
5b. the active swarm's coder agent - Implement (if designer scaffold produced, include it as INPUT).
|
|
58
|
+
→ If this dispatch fails with `PLAN_CRITIC_GATE_VIOLATION`: the plan has no current critic-approved snapshot (commonly a plan approved before this mechanical gate existed). Do NOT retry the coder dispatch as-is — re-run MODE: CRITIC-GATE to get a fresh critic `APPROVED` verdict, then retry this step.
|
|
58
59
|
5b-bis. **CODER OUTPUT VERIFICATION**: After the coder reports completion, do NOT accept the self-report alone. Run `diff` (step 5c) and inspect at least one of the modified files yourself to confirm the change exists. The coder may report DONE without having produced any diff. A 30-second read of the changed file(s) catches this failure mode. This is NOT a separate explorer dispatch — the existing `diff` tool at step 5c is the verification mechanism; the key discipline is checking that `diff` returns actual changes before proceeding, rather than forwarding the coder's self-report to the next gate.
|
|
59
60
|
5c. Run `diff` tool. If `hasContractChanges` → the active swarm's explorer agent integration analysis. If COMPATIBILITY SIGNALS=INCOMPATIBLE or MIGRATION_SURFACE=yes → coder retry. If COMPATIBILITY SIGNALS=COMPATIBLE and MIGRATION_SURFACE=no → proceed.
|
|
60
61
|
→ REQUIRED: Print "diff: [PASS | CONTRACT CHANGE — details]"
|
|
@@ -102,6 +102,53 @@ current branch before editing:
|
|
|
102
102
|
- **Cache/state claims:** Test both relevant state orders when the behavior
|
|
103
103
|
depends on cache priming, singleton state, or prior calls.
|
|
104
104
|
|
|
105
|
+
### Automated Security Finding Verification
|
|
106
|
+
|
|
107
|
+
Automated security bots (e.g., hermes-pr-review, CodeRabbit, Gemini) frequently
|
|
108
|
+
produce findings rated CRITICAL or HIGH that are false positives. In a recent
|
|
109
|
+
PR review cycle, 7/7 bot security findings were false positives upon source
|
|
110
|
+
verification. Before acting on any bot security finding, perform these
|
|
111
|
+
source-level checks:
|
|
112
|
+
|
|
113
|
+
1. **`child_process.exec` vs `RegExp.exec`**: SAST rules pattern-match on
|
|
114
|
+
`.exec(` and cannot distinguish `child_process.exec(userInput)` (real
|
|
115
|
+
injection risk) from `/^pattern$/.exec(str)` (safe regex test). Read the
|
|
116
|
+
actual line to determine which `.exec` is called.
|
|
117
|
+
|
|
118
|
+
2. **Schema validation already present**: Bots may flag "missing type
|
|
119
|
+
validation" without checking the Zod schema. Search for the field name in
|
|
120
|
+
`src/config/schema.ts` — `z.number().int()`, `z.string().min()`, etc. are
|
|
121
|
+
runtime validators that run before the code path the bot reviewed.
|
|
122
|
+
|
|
123
|
+
3. **`Object.assign` mutation claims**: Bots may claim `Object.assign` mutates
|
|
124
|
+
the source object. Check whether the call is `Object.assign(target, source)`
|
|
125
|
+
(mutates target) vs `Object.assign({}, source)` or a manual copy loop into a
|
|
126
|
+
new `{}` (creates a new object, source is safe). Read the actual assignment.
|
|
127
|
+
|
|
128
|
+
4. **Path containment for system-generated paths**: Bots may flag "path
|
|
129
|
+
traversal" on file paths. Check whether the path is user-controlled (real
|
|
130
|
+
risk) or system-generated from `provisionWorktree`, `mkdtempSync`, or
|
|
131
|
+
similar (no user input reaches the path). Trace the variable's origin.
|
|
132
|
+
|
|
133
|
+
5. **Value validation vs key validation**: Bots may suggest validating env var
|
|
134
|
+
*values* for shell injection characters. Check whether the value is passed
|
|
135
|
+
through a sandbox executor that escapes arguments (e.g., `wrapCommand`
|
|
136
|
+
which returns a shell-quoted / `psStringEscape`-escaped string for the
|
|
137
|
+
`bunSpawn` array-form argv to consume). Value validation would break
|
|
138
|
+
legitimate env vars (PATH with `;`, URLs with `$`); escaping is the
|
|
139
|
+
sandbox's job — see `engineering-conventions` § "Sandbox env overrides"
|
|
140
|
+
for the full escape contract.
|
|
141
|
+
|
|
142
|
+
6. **Deduplication for independent resources**: Bots may suggest deduplicating
|
|
143
|
+
cache redirects or env var entries. Check whether the entries map to
|
|
144
|
+
independent keys (different env var names) — independent keys cannot
|
|
145
|
+
"collide" and deduplication is nonsensical.
|
|
146
|
+
|
|
147
|
+
**Rule:** For any bot finding rated CRITICAL or HIGH, read the actual source
|
|
148
|
+
line AND its surrounding context (parent function, schema definition, type
|
|
149
|
+
annotations) before accepting the finding. If the finding is disproved, record
|
|
150
|
+
it in the closure ledger with the specific source evidence that disproves it.
|
|
151
|
+
|
|
105
152
|
## Operating Stance
|
|
106
153
|
|
|
107
154
|
Treat every review comment, CI failure, bot summary, PR body claim, and pasted note
|
|
@@ -6,13 +6,15 @@ import {
|
|
|
6
6
|
checkPathBudget,
|
|
7
7
|
cleanUntrackedFiles,
|
|
8
8
|
isCleanWorktree,
|
|
9
|
+
isPathUnderSwarmWorktreeBase,
|
|
9
10
|
makeWorktreeBranchName,
|
|
10
11
|
provisionWorktree,
|
|
11
12
|
removeLaneProfileFromDiskReal,
|
|
12
13
|
removeWorktree,
|
|
14
|
+
resolveWorktreeBaseDir,
|
|
13
15
|
shortenWorktreePath,
|
|
14
16
|
writeLaneProfileToDiskReal
|
|
15
|
-
} from "./index-
|
|
17
|
+
} from "./index-3yk9196e.js";
|
|
16
18
|
import"./index-5e4e2hvv.js";
|
|
17
19
|
import"./index-p0arc26j.js";
|
|
18
20
|
import"./index-zgwm4ryv.js";
|
|
@@ -21,10 +23,12 @@ import"./index-a76rekgs.js";
|
|
|
21
23
|
export {
|
|
22
24
|
writeLaneProfileToDiskReal,
|
|
23
25
|
shortenWorktreePath,
|
|
26
|
+
resolveWorktreeBaseDir,
|
|
24
27
|
removeWorktree,
|
|
25
28
|
removeLaneProfileFromDiskReal,
|
|
26
29
|
provisionWorktree,
|
|
27
30
|
makeWorktreeBranchName,
|
|
31
|
+
isPathUnderSwarmWorktreeBase,
|
|
28
32
|
isCleanWorktree,
|
|
29
33
|
cleanUntrackedFiles,
|
|
30
34
|
checkPathBudget,
|
|
@@ -11,12 +11,12 @@ import {
|
|
|
11
11
|
runCuratorInit,
|
|
12
12
|
runCuratorPhase,
|
|
13
13
|
writeCuratorSummary
|
|
14
|
-
} from "./index-
|
|
14
|
+
} from "./index-cqbqynzp.js";
|
|
15
15
|
import"./index-wj4jeavn.js";
|
|
16
16
|
import"./index-5gnp8fyw.js";
|
|
17
17
|
import"./index-c8s9a3zh.js";
|
|
18
18
|
import"./index-fm7xz1ne.js";
|
|
19
|
-
import"./index-
|
|
19
|
+
import"./index-j2v3w1ds.js";
|
|
20
20
|
import"./index-scww5b77.js";
|
|
21
21
|
import"./index-yw8qpf51.js";
|
|
22
22
|
import"./index-85bacexr.js";
|
|
@@ -31,7 +31,7 @@ import"./index-bfwt3abw.js";
|
|
|
31
31
|
import"./index-wvrj16f0.js";
|
|
32
32
|
import"./index-q1exe2b3.js";
|
|
33
33
|
import"./index-x2q0gnt8.js";
|
|
34
|
-
import"./index-
|
|
34
|
+
import"./index-3yk9196e.js";
|
|
35
35
|
import"./index-r3j3458j.js";
|
|
36
36
|
import"./index-jtqkh8jf.js";
|
|
37
37
|
import"./index-5e4e2hvv.js";
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
3
|
createCuratorLLMDelegate
|
|
4
|
-
} from "./index-
|
|
4
|
+
} from "./index-cqbqynzp.js";
|
|
5
5
|
import"./index-wj4jeavn.js";
|
|
6
6
|
import"./index-5gnp8fyw.js";
|
|
7
7
|
import"./index-c8s9a3zh.js";
|
|
8
8
|
import"./index-fm7xz1ne.js";
|
|
9
|
-
import"./index-
|
|
9
|
+
import"./index-j2v3w1ds.js";
|
|
10
10
|
import"./index-scww5b77.js";
|
|
11
11
|
import"./index-yw8qpf51.js";
|
|
12
12
|
import"./index-85bacexr.js";
|
|
@@ -21,7 +21,7 @@ import"./index-bfwt3abw.js";
|
|
|
21
21
|
import"./index-wvrj16f0.js";
|
|
22
22
|
import"./index-q1exe2b3.js";
|
|
23
23
|
import"./index-x2q0gnt8.js";
|
|
24
|
-
import"./index-
|
|
24
|
+
import"./index-3yk9196e.js";
|
|
25
25
|
import"./index-r3j3458j.js";
|
|
26
26
|
import"./index-jtqkh8jf.js";
|
|
27
27
|
import"./index-5e4e2hvv.js";
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
3
|
handleGuardrailExplain
|
|
4
|
-
} from "./index-
|
|
5
|
-
import"./index-
|
|
4
|
+
} from "./index-8a8b5wjf.js";
|
|
5
|
+
import"./index-cqbqynzp.js";
|
|
6
6
|
import"./index-wj4jeavn.js";
|
|
7
7
|
import"./index-5gnp8fyw.js";
|
|
8
8
|
import"./index-c8s9a3zh.js";
|
|
9
9
|
import"./index-fm7xz1ne.js";
|
|
10
|
-
import"./index-
|
|
10
|
+
import"./index-j2v3w1ds.js";
|
|
11
11
|
import"./index-scww5b77.js";
|
|
12
12
|
import"./index-yw8qpf51.js";
|
|
13
13
|
import"./index-85bacexr.js";
|
|
@@ -22,7 +22,7 @@ import"./index-bfwt3abw.js";
|
|
|
22
22
|
import"./index-wvrj16f0.js";
|
|
23
23
|
import"./index-q1exe2b3.js";
|
|
24
24
|
import"./index-x2q0gnt8.js";
|
|
25
|
-
import"./index-
|
|
25
|
+
import"./index-3yk9196e.js";
|
|
26
26
|
import"./index-r3j3458j.js";
|
|
27
27
|
import"./index-jtqkh8jf.js";
|
|
28
28
|
import"./index-5e4e2hvv.js";
|
|
@@ -5,12 +5,12 @@ import {
|
|
|
5
5
|
isHiveEligible,
|
|
6
6
|
promoteFromSwarm,
|
|
7
7
|
promoteToHive
|
|
8
|
-
} from "./index-
|
|
8
|
+
} from "./index-cqbqynzp.js";
|
|
9
9
|
import"./index-wj4jeavn.js";
|
|
10
10
|
import"./index-5gnp8fyw.js";
|
|
11
11
|
import"./index-c8s9a3zh.js";
|
|
12
12
|
import"./index-fm7xz1ne.js";
|
|
13
|
-
import"./index-
|
|
13
|
+
import"./index-j2v3w1ds.js";
|
|
14
14
|
import"./index-scww5b77.js";
|
|
15
15
|
import"./index-yw8qpf51.js";
|
|
16
16
|
import"./index-85bacexr.js";
|
|
@@ -25,7 +25,7 @@ import"./index-bfwt3abw.js";
|
|
|
25
25
|
import"./index-wvrj16f0.js";
|
|
26
26
|
import"./index-q1exe2b3.js";
|
|
27
27
|
import"./index-x2q0gnt8.js";
|
|
28
|
-
import"./index-
|
|
28
|
+
import"./index-3yk9196e.js";
|
|
29
29
|
import"./index-r3j3458j.js";
|
|
30
30
|
import"./index-jtqkh8jf.js";
|
|
31
31
|
import"./index-5e4e2hvv.js";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
3
|
handleGuardrailExplain
|
|
4
|
-
} from "./index-
|
|
4
|
+
} from "./index-8a8b5wjf.js";
|
|
5
5
|
import {
|
|
6
6
|
handleGuardrailLog
|
|
7
7
|
} from "./index-vx76tcxe.js";
|
|
@@ -80,12 +80,12 @@ import {
|
|
|
80
80
|
handleWriteRetroCommand,
|
|
81
81
|
normalizeSwarmCommandInput,
|
|
82
82
|
resolveCommand
|
|
83
|
-
} from "./index-
|
|
83
|
+
} from "./index-cqbqynzp.js";
|
|
84
84
|
import"./index-wj4jeavn.js";
|
|
85
85
|
import"./index-5gnp8fyw.js";
|
|
86
86
|
import"./index-c8s9a3zh.js";
|
|
87
87
|
import"./index-fm7xz1ne.js";
|
|
88
|
-
import"./index-
|
|
88
|
+
import"./index-j2v3w1ds.js";
|
|
89
89
|
import"./index-scww5b77.js";
|
|
90
90
|
import"./index-yw8qpf51.js";
|
|
91
91
|
import"./index-85bacexr.js";
|
|
@@ -104,7 +104,7 @@ import"./index-bfwt3abw.js";
|
|
|
104
104
|
import"./index-wvrj16f0.js";
|
|
105
105
|
import"./index-q1exe2b3.js";
|
|
106
106
|
import"./index-x2q0gnt8.js";
|
|
107
|
-
import"./index-
|
|
107
|
+
import"./index-3yk9196e.js";
|
|
108
108
|
import"./index-r3j3458j.js";
|
|
109
109
|
import"./index-jtqkh8jf.js";
|
|
110
110
|
import"./index-5e4e2hvv.js";
|
|
@@ -162,9 +162,39 @@ function makeWorktreeBranchName(sessionId, id, options) {
|
|
|
162
162
|
}
|
|
163
163
|
return `swarm/${options.purpose}/${sessionId}/${id}`;
|
|
164
164
|
}
|
|
165
|
+
function resolveWorktreeBaseDir(directory, worktreeDir) {
|
|
166
|
+
return worktreeDir ? path.resolve(directory, worktreeDir) : path.resolve(path.dirname(directory), ".swarm-worktrees");
|
|
167
|
+
}
|
|
168
|
+
function isPathUnderSwarmWorktreeBase(targetPath, directory, worktreeDirOverrides = []) {
|
|
169
|
+
const caseInsensitive = process.platform === "win32";
|
|
170
|
+
let realTarget;
|
|
171
|
+
try {
|
|
172
|
+
realTarget = fs.realpathSync(path.resolve(directory, targetPath));
|
|
173
|
+
} catch {
|
|
174
|
+
return false;
|
|
175
|
+
}
|
|
176
|
+
const bases = [
|
|
177
|
+
resolveWorktreeBaseDir(directory),
|
|
178
|
+
...worktreeDirOverrides.map((d) => resolveWorktreeBaseDir(directory, d))
|
|
179
|
+
];
|
|
180
|
+
const cmpTarget = caseInsensitive ? realTarget.toLowerCase() : realTarget;
|
|
181
|
+
return bases.some((base) => {
|
|
182
|
+
let realBase;
|
|
183
|
+
try {
|
|
184
|
+
realBase = fs.realpathSync(base);
|
|
185
|
+
} catch {
|
|
186
|
+
realBase = path.resolve(base);
|
|
187
|
+
}
|
|
188
|
+
const cmpBase = caseInsensitive ? realBase.toLowerCase() : realBase;
|
|
189
|
+
if (cmpTarget === cmpBase)
|
|
190
|
+
return true;
|
|
191
|
+
const rel = path.relative(cmpBase, cmpTarget);
|
|
192
|
+
return rel.length > 0 && !rel.startsWith("..") && !path.isAbsolute(rel);
|
|
193
|
+
});
|
|
194
|
+
}
|
|
165
195
|
async function provisionWorktree(directory, id, sessionId, options) {
|
|
166
196
|
const branchName = makeWorktreeBranchName(sessionId, id, options);
|
|
167
|
-
let worktreePath =
|
|
197
|
+
let worktreePath = path.resolve(resolveWorktreeBaseDir(directory, options.worktreeDir), sessionId, id);
|
|
168
198
|
const budgetResult = await checkPathBudget(worktreePath, directory);
|
|
169
199
|
if (budgetResult.ok === false) {
|
|
170
200
|
if (options.worktreeDir) {
|
|
@@ -285,7 +315,7 @@ async function provisionWorktree(directory, id, sessionId, options) {
|
|
|
285
315
|
sessionId
|
|
286
316
|
};
|
|
287
317
|
}
|
|
288
|
-
async function removeWorktree(worktreePath, projectRoot) {
|
|
318
|
+
async function removeWorktree(worktreePath, projectRoot, options) {
|
|
289
319
|
const isWindows = _internals.platform === "win32";
|
|
290
320
|
const MAX_RETRIES = 4;
|
|
291
321
|
const RETRY_DELAY_MS = 2000;
|
|
@@ -300,6 +330,13 @@ async function removeWorktree(worktreePath, projectRoot) {
|
|
|
300
330
|
await _internals.sleep(RETRY_DELAY_MS);
|
|
301
331
|
continue;
|
|
302
332
|
}
|
|
333
|
+
if (options?.force && isPathUnderSwarmWorktreeBase(worktreePath, projectRoot, options.worktreeDir ? [options.worktreeDir] : [])) {
|
|
334
|
+
const forced = await runGit(["worktree", "remove", "--force", worktreePath], projectRoot);
|
|
335
|
+
if (forced.exitCode === 0) {
|
|
336
|
+
return { success: true };
|
|
337
|
+
}
|
|
338
|
+
return { error: forced.stderr.trim() || forced.stdout.trim() };
|
|
339
|
+
}
|
|
303
340
|
return { error: lastError };
|
|
304
341
|
}
|
|
305
342
|
return { error: lastError };
|
|
@@ -415,4 +452,4 @@ async function assertCleanWorkingTree(directory) {
|
|
|
415
452
|
return { clean: true };
|
|
416
453
|
}
|
|
417
454
|
|
|
418
|
-
export { _internals, writeLaneProfileToDiskReal, removeLaneProfileFromDiskReal, checkPathBudget, shortenWorktreePath, makeWorktreeBranchName, provisionWorktree, removeWorktree, isCleanWorktree, autoCommitDirty, cleanUntrackedFiles, assertCleanWorkingTree };
|
|
455
|
+
export { _internals, writeLaneProfileToDiskReal, removeLaneProfileFromDiskReal, checkPathBudget, shortenWorktreePath, makeWorktreeBranchName, resolveWorktreeBaseDir, isPathUnderSwarmWorktreeBase, provisionWorktree, removeWorktree, isCleanWorktree, autoCommitDirty, cleanUntrackedFiles, assertCleanWorkingTree };
|
|
@@ -54,7 +54,7 @@ import {
|
|
|
54
54
|
savePlan,
|
|
55
55
|
transientBackoff,
|
|
56
56
|
validateProjectRoot
|
|
57
|
-
} from "./index-
|
|
57
|
+
} from "./index-j2v3w1ds.js";
|
|
58
58
|
import {
|
|
59
59
|
buildOpenSpecProjectionSync,
|
|
60
60
|
detectSpeckit,
|
|
@@ -7203,11 +7203,11 @@ var _internals7 = {
|
|
|
7203
7203
|
return KnowledgeConfigSchema2.parse({});
|
|
7204
7204
|
},
|
|
7205
7205
|
applyCuratorKnowledgeUpdates: async (directory, recommendations, knowledgeConfig) => {
|
|
7206
|
-
const { applyCuratorKnowledgeUpdates } = await import("./curator-
|
|
7206
|
+
const { applyCuratorKnowledgeUpdates } = await import("./curator-6p9tpprq.js");
|
|
7207
7207
|
return applyCuratorKnowledgeUpdates(directory, recommendations, knowledgeConfig);
|
|
7208
7208
|
},
|
|
7209
7209
|
checkHivePromotions: async (entries, knowledgeConfig) => {
|
|
7210
|
-
const { checkHivePromotions } = await import("./hive-promoter-
|
|
7210
|
+
const { checkHivePromotions } = await import("./hive-promoter-qh2rh8x2.js");
|
|
7211
7211
|
return checkHivePromotions(entries, knowledgeConfig);
|
|
7212
7212
|
},
|
|
7213
7213
|
applyProposalTriage: async (directory, triage) => {
|
|
@@ -16499,8 +16499,8 @@ var _internals21 = {
|
|
|
16499
16499
|
loadCuratorDeps: async () => {
|
|
16500
16500
|
const [{ CuratorConfigSchema }, curator, { createCuratorLLMDelegate: createCuratorLLMDelegate2 }] = await Promise.all([
|
|
16501
16501
|
import("./schema-x17zmd03.js"),
|
|
16502
|
-
import("./curator-
|
|
16503
|
-
import("./curator-llm-factory-
|
|
16502
|
+
import("./curator-6p9tpprq.js"),
|
|
16503
|
+
import("./curator-llm-factory-wqbm9mwr.js")
|
|
16504
16504
|
]);
|
|
16505
16505
|
return { CuratorConfigSchema, curator, createCuratorLLMDelegate: createCuratorLLMDelegate2 };
|
|
16506
16506
|
}
|
|
@@ -16996,7 +16996,7 @@ import { fileURLToPath } from "url";
|
|
|
16996
16996
|
// package.json
|
|
16997
16997
|
var package_default = {
|
|
16998
16998
|
name: "opencode-swarm",
|
|
16999
|
-
version: "7.109.
|
|
16999
|
+
version: "7.109.2",
|
|
17000
17000
|
description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
|
|
17001
17001
|
main: "dist/index.js",
|
|
17002
17002
|
types: "dist/index.d.ts",
|
|
@@ -19254,7 +19254,7 @@ async function handleEvidenceCommand(directory, args) {
|
|
|
19254
19254
|
return formatTaskEvidenceMarkdown(evidenceData);
|
|
19255
19255
|
}
|
|
19256
19256
|
async function handleEvidenceSummaryCommand(directory) {
|
|
19257
|
-
const { buildEvidenceSummary } = await import("./evidence-summary-service-
|
|
19257
|
+
const { buildEvidenceSummary } = await import("./evidence-summary-service-8tasw2tt.js");
|
|
19258
19258
|
const artifact = await buildEvidenceSummary(directory);
|
|
19259
19259
|
if (!artifact) {
|
|
19260
19260
|
return "No plan found. Run `/swarm plan` to check plan status.";
|
|
@@ -31714,7 +31714,7 @@ function buildDetailedHelp(commandName, entry) {
|
|
|
31714
31714
|
async function handleHelpCommand(ctx) {
|
|
31715
31715
|
const targetCommand = ctx.args.join(" ");
|
|
31716
31716
|
if (!targetCommand) {
|
|
31717
|
-
const { buildHelpText } = await import("./index-
|
|
31717
|
+
const { buildHelpText } = await import("./index-3qwaydq1.js");
|
|
31718
31718
|
return buildHelpText();
|
|
31719
31719
|
}
|
|
31720
31720
|
const tokens = targetCommand.split(/\s+/);
|
|
@@ -31723,7 +31723,7 @@ async function handleHelpCommand(ctx) {
|
|
|
31723
31723
|
return _internals46.buildDetailedHelp(resolved.key, resolved.entry);
|
|
31724
31724
|
}
|
|
31725
31725
|
const similar = _internals46.findSimilarCommands(targetCommand);
|
|
31726
|
-
const { buildHelpText: fullHelp } = await import("./index-
|
|
31726
|
+
const { buildHelpText: fullHelp } = await import("./index-3qwaydq1.js");
|
|
31727
31727
|
if (similar.length > 0) {
|
|
31728
31728
|
return `Command '/swarm ${targetCommand}' not found.
|
|
31729
31729
|
|
|
@@ -31856,7 +31856,7 @@ var COMMAND_REGISTRY = {
|
|
|
31856
31856
|
},
|
|
31857
31857
|
"guardrail explain": {
|
|
31858
31858
|
handler: async (ctx) => {
|
|
31859
|
-
const { handleGuardrailExplain } = await import("./guardrail-explain-
|
|
31859
|
+
const { handleGuardrailExplain } = await import("./guardrail-explain-ynge4ww3.js");
|
|
31860
31860
|
return handleGuardrailExplain(ctx.directory, ctx.args);
|
|
31861
31861
|
},
|
|
31862
31862
|
description: "Dry-run: show what the guardrails would do to a command or write target (executes nothing)",
|
|
@@ -2339,7 +2339,7 @@ async function takeSnapshotWithRetry(directory, plan, options) {
|
|
|
2339
2339
|
} catch {}
|
|
2340
2340
|
}
|
|
2341
2341
|
async function takeSnapshotEvent(directory, plan, options) {
|
|
2342
|
-
const payloadHash = computePlanHash(plan);
|
|
2342
|
+
const payloadHash = options?.payloadHashOverride ?? computePlanHash(plan);
|
|
2343
2343
|
const snapshotPayload = {
|
|
2344
2344
|
plan,
|
|
2345
2345
|
payload_hash: payloadHash
|
|
@@ -2536,6 +2536,9 @@ async function quarantineLedgerSuffix(directory, badSuffix) {
|
|
|
2536
2536
|
}
|
|
2537
2537
|
async function loadLastApprovedPlan(directory, expectedPlanId) {
|
|
2538
2538
|
const events = await readLedgerEvents(directory);
|
|
2539
|
+
return findLastApprovedSnapshot(events, expectedPlanId);
|
|
2540
|
+
}
|
|
2541
|
+
function findLastApprovedSnapshot(events, expectedPlanId, extraFilter) {
|
|
2539
2542
|
if (events.length === 0) {
|
|
2540
2543
|
return null;
|
|
2541
2544
|
}
|
|
@@ -2558,6 +2561,9 @@ async function loadLastApprovedPlan(directory, expectedPlanId) {
|
|
|
2558
2561
|
continue;
|
|
2559
2562
|
}
|
|
2560
2563
|
}
|
|
2564
|
+
if (extraFilter && !extraFilter(payload)) {
|
|
2565
|
+
continue;
|
|
2566
|
+
}
|
|
2561
2567
|
return {
|
|
2562
2568
|
plan: payload.plan,
|
|
2563
2569
|
seq: event.seq,
|
package/dist/cli/index.js
CHANGED
|
@@ -7,12 +7,12 @@ import {
|
|
|
7
7
|
getPluginLockFilePaths,
|
|
8
8
|
package_default,
|
|
9
9
|
resolveCommand
|
|
10
|
-
} from "./index-
|
|
10
|
+
} from "./index-cqbqynzp.js";
|
|
11
11
|
import"./index-wj4jeavn.js";
|
|
12
12
|
import"./index-5gnp8fyw.js";
|
|
13
13
|
import"./index-c8s9a3zh.js";
|
|
14
14
|
import"./index-fm7xz1ne.js";
|
|
15
|
-
import"./index-
|
|
15
|
+
import"./index-j2v3w1ds.js";
|
|
16
16
|
import"./index-scww5b77.js";
|
|
17
17
|
import"./index-yw8qpf51.js";
|
|
18
18
|
import"./index-85bacexr.js";
|
|
@@ -29,7 +29,7 @@ import"./index-bfwt3abw.js";
|
|
|
29
29
|
import"./index-wvrj16f0.js";
|
|
30
30
|
import"./index-q1exe2b3.js";
|
|
31
31
|
import"./index-x2q0gnt8.js";
|
|
32
|
-
import"./index-
|
|
32
|
+
import"./index-3yk9196e.js";
|
|
33
33
|
import"./index-r3j3458j.js";
|
|
34
34
|
import"./index-jtqkh8jf.js";
|
|
35
35
|
import"./index-5e4e2hvv.js";
|
package/dist/config/index.d.ts
CHANGED
|
@@ -22,3 +22,4 @@ export type { AgentOverrideConfig, AutomationCapabilities, AutomationConfig, Aut
|
|
|
22
22
|
export { AgentOverrideConfigSchema, AutomationCapabilitiesSchema, AutomationConfigSchema, AutomationModeSchema, LeanTurboConfigSchema, MemoryConfigSchema, ModelPricingConfigSchema, PhaseCompleteConfigSchema, PipelineConfigSchema, PluginConfigSchema, PricingConfigSchema, RepoGraphConfigSchema, SkillPropagationConfigSchema, SwarmConfigSchema, TurboConfigSchema, WorktreeIsolationConfigSchema, } from './schema';
|
|
23
23
|
export type { DeltaSpec, Obligation, SpecDelta, SpecRequirement, SpecScenario, SpecSection, SwarmSpec, } from './spec-schema';
|
|
24
24
|
export { DeltaSpecSchema, ObligationSchema, SpecDeltaSchema, SpecRequirementSchema, SpecScenarioSchema, SpecSectionSchema, SwarmSpecSchema, validateSpecContent, } from './spec-schema';
|
|
25
|
+
export { resolveWorktreeIsolationConfig } from './worktree-isolation-config';
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
export interface QaGatePipelineStep {
|
|
2
|
+
readonly id: string;
|
|
3
|
+
readonly docsLabel: string;
|
|
4
|
+
readonly protocolToken: string;
|
|
5
|
+
}
|
|
6
|
+
export declare const QA_GATE_PIPELINE_STEPS: readonly [{
|
|
7
|
+
readonly id: "diff";
|
|
8
|
+
readonly docsLabel: "`diff`";
|
|
9
|
+
readonly protocolToken: "diff";
|
|
10
|
+
}, {
|
|
11
|
+
readonly id: "syntax_check";
|
|
12
|
+
readonly docsLabel: "`syntax_check`";
|
|
13
|
+
readonly protocolToken: "syntax_check";
|
|
14
|
+
}, {
|
|
15
|
+
readonly id: "placeholder_scan";
|
|
16
|
+
readonly docsLabel: "`placeholder_scan`";
|
|
17
|
+
readonly protocolToken: "placeholder_scan";
|
|
18
|
+
}, {
|
|
19
|
+
readonly id: "imports";
|
|
20
|
+
readonly docsLabel: "`imports`";
|
|
21
|
+
readonly protocolToken: "imports";
|
|
22
|
+
}, {
|
|
23
|
+
readonly id: "lint_fix";
|
|
24
|
+
readonly docsLabel: "`lint fix`";
|
|
25
|
+
readonly protocolToken: "lint";
|
|
26
|
+
}, {
|
|
27
|
+
readonly id: "build_check";
|
|
28
|
+
readonly docsLabel: "`build_check`";
|
|
29
|
+
readonly protocolToken: "build_check";
|
|
30
|
+
}, {
|
|
31
|
+
readonly id: "pre_check_batch";
|
|
32
|
+
readonly docsLabel: "`pre_check_batch`";
|
|
33
|
+
readonly protocolToken: "pre_check_batch";
|
|
34
|
+
}, {
|
|
35
|
+
readonly id: "reviewer";
|
|
36
|
+
readonly docsLabel: "`reviewer`";
|
|
37
|
+
readonly protocolToken: "reviewer";
|
|
38
|
+
}, {
|
|
39
|
+
readonly id: "security_reviewer";
|
|
40
|
+
readonly docsLabel: "`security-reviewer`";
|
|
41
|
+
readonly protocolToken: "security-reviewer";
|
|
42
|
+
}, {
|
|
43
|
+
readonly id: "test_engineer_verification";
|
|
44
|
+
readonly docsLabel: "`test_engineer verification`";
|
|
45
|
+
readonly protocolToken: "testengineer-verification";
|
|
46
|
+
}, {
|
|
47
|
+
readonly id: "regression_sweep";
|
|
48
|
+
readonly docsLabel: "`regression-sweep`";
|
|
49
|
+
readonly protocolToken: "regression-sweep";
|
|
50
|
+
}, {
|
|
51
|
+
readonly id: "test_drift";
|
|
52
|
+
readonly docsLabel: "`test-drift`";
|
|
53
|
+
readonly protocolToken: "test-drift";
|
|
54
|
+
}, {
|
|
55
|
+
readonly id: "test_engineer_adversarial";
|
|
56
|
+
readonly docsLabel: "`test_engineer adversarial`";
|
|
57
|
+
readonly protocolToken: "ADVERSARIAL TEST STEP";
|
|
58
|
+
}, {
|
|
59
|
+
readonly id: "coverage_check";
|
|
60
|
+
readonly docsLabel: "`coverage check`";
|
|
61
|
+
readonly protocolToken: "COVERAGE CHECK";
|
|
62
|
+
}, {
|
|
63
|
+
readonly id: "pre_commit_checklist";
|
|
64
|
+
readonly docsLabel: "`pre-commit checklist`";
|
|
65
|
+
readonly protocolToken: "PRE-COMMIT RULE";
|
|
66
|
+
}];
|
|
67
|
+
export declare const QA_GATE_PIPELINE_STEP_COUNT: 15;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { PluginConfig, WorktreeIsolationConfig } from './schema';
|
|
2
|
+
/**
|
|
3
|
+
* Pure config helper that resolves the worktree-isolation configuration
|
|
4
|
+
* from a PluginConfig. Lives in this leaf module (no heavy imports) so
|
|
5
|
+
* the plugin entry (src/index.ts) can call it during init without
|
|
6
|
+
* pulling in the worktree lifecycle module.
|
|
7
|
+
*
|
|
8
|
+
* @see tests/unit/turbo/lean/init-safety.test.ts (static source check)
|
|
9
|
+
*/
|
|
10
|
+
export declare function resolveWorktreeIsolationConfig(config: PluginConfig): WorktreeIsolationConfig;
|
|
@@ -58,6 +58,8 @@ export interface StandardWorktreeDispatch {
|
|
|
58
58
|
mergeStrategy: 'merge' | 'rebase' | 'cherry-pick';
|
|
59
59
|
/** FR-201: 0-based lane index for runtime profile derivation. */
|
|
60
60
|
laneIndex: number;
|
|
61
|
+
/** Configured worktree-dir override, so cleanup trusts the same base. */
|
|
62
|
+
worktree_dir?: string;
|
|
61
63
|
}
|
|
62
64
|
export interface AwaitingMergeRecord {
|
|
63
65
|
callID: string;
|
|
@@ -103,7 +105,8 @@ export declare function checkStandardWorktreeSerializationRelease(sessionID: str
|
|
|
103
105
|
*/
|
|
104
106
|
declare function rememberStandardWorktreeSerializationSession(sessionID: string): boolean;
|
|
105
107
|
export declare function sanitizeWorktreeTaskId(raw: string): string;
|
|
106
|
-
|
|
108
|
+
import { resolveWorktreeIsolationConfig } from '../../config/worktree-isolation-config';
|
|
109
|
+
export { resolveWorktreeIsolationConfig };
|
|
107
110
|
export declare function precreateStandardWorktreeSession(args: {
|
|
108
111
|
config: PluginConfig;
|
|
109
112
|
directory: string;
|
|
@@ -163,4 +166,3 @@ export declare const _internals: {
|
|
|
163
166
|
startupOrphanRecovery: typeof startupOrphanRecovery;
|
|
164
167
|
cleanupOrphanedBranches: typeof cleanupOrphanedBranches;
|
|
165
168
|
};
|
|
166
|
-
export {};
|
|
@@ -110,6 +110,7 @@ export declare const _internals: {
|
|
|
110
110
|
buildParallelExecutionGuidance: typeof buildParallelExecutionGuidance;
|
|
111
111
|
loadPlanJsonOnly: typeof loadPlanJsonOnly;
|
|
112
112
|
resetStandardWorktreeIsolationState: typeof resetStandardWorktreeIsolationState;
|
|
113
|
+
PLAN_CRITIC_TASK_SIGNALS: readonly ["critic-gate", "plan critic", "review plan", "review the plan", "plan.md", "approve the plan", "plan approval"];
|
|
113
114
|
provisionWorktree: typeof _wtiInternals.provisionWorktree;
|
|
114
115
|
removeWorktree: typeof _wtiInternals.removeWorktree;
|
|
115
116
|
attemptMergeBackFromDirty: typeof _wtiInternals.attemptMergeBackFromDirty;
|
|
@@ -47,7 +47,7 @@ export declare function redactShellCommand(cmd: string): string;
|
|
|
47
47
|
* @param config Guardrails configuration (optional)
|
|
48
48
|
* @returns Tool before/after hooks and messages transform hook
|
|
49
49
|
*/
|
|
50
|
-
export declare function createGuardrailsHooks(directory: string, directoryOrConfig?: string | GuardrailsConfig, config?: GuardrailsConfig, authorityConfig?: AuthorityConfig): {
|
|
50
|
+
export declare function createGuardrailsHooks(directory: string, directoryOrConfig?: string | GuardrailsConfig, config?: GuardrailsConfig, authorityConfig?: AuthorityConfig, worktreeBaseDirOverrides?: string[]): {
|
|
51
51
|
toolBefore: (input: {
|
|
52
52
|
tool: string;
|
|
53
53
|
sessionID: string;
|