opencode-swarm 7.200.12 → 7.200.14

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 (79) hide show
  1. package/.opencode/skills/test-file-split/SKILL.md +6 -1
  2. package/binaries/win32-arm64/swarm-sandbox-runner.exe +0 -0
  3. package/binaries/win32-x64/swarm-sandbox-runner.exe +0 -0
  4. package/dist/cli/{attest-task-0h9adt4t.js → attest-task-1bhnpxsr.js} +26 -26
  5. package/dist/cli/{auto-checkpoint-f7pcj09v.js → auto-checkpoint-v0k01dwk.js} +4 -4
  6. package/dist/cli/{checkpoint-5j4dqdd1.js → checkpoint-w9fkn2v6.js} +8 -8
  7. package/dist/cli/{coder-settlement-n69ee5jz.js → coder-settlement-4t577hx9.js} +4 -4
  8. package/dist/cli/{config-doctor-q23166e4.js → config-doctor-m4c4f4j3.js} +7 -7
  9. package/dist/cli/{core-2th9bfmx.js → core-pqpsbekk.js} +1 -1
  10. package/dist/cli/{curator-drift-b4rcjh23.js → curator-drift-yb05q3a8.js} +5 -5
  11. package/dist/cli/{curator-llm-factory-3b7b55k6.js → curator-llm-factory-r2rsrmz4.js} +26 -26
  12. package/dist/cli/{curator-dsf0966y.js → curator-sxq06cgw.js} +26 -26
  13. package/dist/cli/{doctor-knowledge-receipt-phase-id-4npan6z7.js → doctor-knowledge-receipt-phase-id-7z98yg2z.js} +4 -4
  14. package/dist/cli/{evidence-summary-service-evv73ay3.js → evidence-summary-service-y3g4tg5y.js} +10 -10
  15. package/dist/cli/{gate-evidence-vz9gjwkz.js → gate-evidence-7nasr4dk.js} +3 -3
  16. package/dist/cli/{guardrail-explain-jvvk0at1.js → guardrail-explain-zhq6djgr.js} +27 -27
  17. package/dist/cli/{guardrail-log-b81vyjvz.js → guardrail-log-enq4hp9f.js} +3 -3
  18. package/dist/cli/{guardrail-reset-ygq8e117.js → guardrail-reset-3k2x5vsr.js} +26 -26
  19. package/dist/cli/{hive-promoter-73e5qa2r.js → hive-promoter-sstdct9j.js} +26 -26
  20. package/dist/cli/{index-9t4gxpt5.js → index-11aqm3bt.js} +1 -1
  21. package/dist/cli/{index-213w5jn9.js → index-1520thw9.js} +1 -1
  22. package/dist/cli/{index-9dtd681s.js → index-25v6n1t3.js} +1 -1
  23. package/dist/cli/{index-fk1w7r9k.js → index-39v48pf0.js} +3 -3
  24. package/dist/cli/{index-jkj598w8.js → index-5mbyavx0.js} +1 -1
  25. package/dist/cli/{index-60yd5f2p.js → index-6cnppnh7.js} +2 -2
  26. package/dist/cli/{index-zs5vymnk.js → index-93xekq7n.js} +1 -1
  27. package/dist/cli/{index-0kgqjaaj.js → index-9p3phwap.js} +2 -2
  28. package/dist/cli/{index-dfgqg3qd.js → index-b7y19187.js} +5 -5
  29. package/dist/cli/{index-sfd8kb4k.js → index-fhrcyexn.js} +1 -1
  30. package/dist/cli/{index-fe3dtakd.js → index-g3mrxex7.js} +3 -3
  31. package/dist/cli/{index-0cqr8afr.js → index-gsyv2s9g.js} +4 -4
  32. package/dist/cli/{index-2w17wxc1.js → index-gx2a1xgp.js} +1 -1
  33. package/dist/cli/{index-bxsbm6xx.js → index-h91a4abf.js} +3 -3
  34. package/dist/cli/{index-gkaj31rk.js → index-j3me99q7.js} +3 -3
  35. package/dist/cli/{index-2pvmk43k.js → index-mem1hrkw.js} +1 -1
  36. package/dist/cli/{index-5t3p0nd1.js → index-ne0s5g10.js} +5 -5
  37. package/dist/cli/{index-2ftz9m3d.js → index-pdaycg02.js} +1 -1
  38. package/dist/cli/{index-vzd1w4ra.js → index-phdf1pjq.js} +2 -2
  39. package/dist/cli/{index-5e5s7p5z.js → index-r160hfq9.js} +26 -26
  40. package/dist/cli/{index-phm7gmpq.js → index-sm64f3fc.js} +757 -198
  41. package/dist/cli/{index-1egy4f76.js → index-sxna6jn9.js} +1 -1
  42. package/dist/cli/{index-xdyqfp37.js → index-szwa4tek.js} +2 -2
  43. package/dist/cli/{index-td0bfecx.js → index-szwmgbm4.js} +3 -3
  44. package/dist/cli/{index-n9mb83fx.js → index-t6dkmt0c.js} +3 -3
  45. package/dist/cli/{index-z0jf1tyr.js → index-vjdwrd9r.js} +1 -1
  46. package/dist/cli/{index-gvzf86kf.js → index-vqxvdx7n.js} +2 -2
  47. package/dist/cli/{index-5ecsb26p.js → index-vv9k85h0.js} +6 -6
  48. package/dist/cli/{index-n425a88g.js → index-wj3a023e.js} +1 -1
  49. package/dist/cli/{index-wfx209wp.js → index-yc5e6yr5.js} +2 -2
  50. package/dist/cli/{index-cy2zmsa0.js → index-ztezaknp.js} +28 -28
  51. package/dist/cli/index.js +27 -27
  52. package/dist/cli/{knowledge-escalator-et068ebg.js → knowledge-escalator-h8j3v62j.js} +7 -7
  53. package/dist/cli/{knowledge-events-2ha1zsv5.js → knowledge-events-f80mxhjd.js} +5 -5
  54. package/dist/cli/{knowledge-store-bpchbre8.js → knowledge-store-z0eb6xk5.js} +1 -1
  55. package/dist/cli/{knowledge-validator-0q4xmhch.js → knowledge-validator-k0jn2w06.js} +2 -2
  56. package/dist/cli/{mcp-hh5k6qar.js → mcp-zg75c3e4.js} +1 -1
  57. package/dist/cli/{model-preflight-zh4t5ywj.js → model-preflight-2592b0fv.js} +26 -26
  58. package/dist/cli/{pending-delegations-vxk971ny.js → pending-delegations-ek7600es.js} +2 -2
  59. package/dist/cli/{pr-subscriptions-nhdfz8pc.js → pr-subscriptions-wmzs42h3.js} +1 -1
  60. package/dist/cli/{pr-workflow-gate-bej2nn0c.js → pr-workflow-gate-regg66xa.js} +26 -26
  61. package/dist/cli/{scan-cursor-v5f7s9jb.js → scan-cursor-rxpkxhj3.js} +2 -2
  62. package/dist/cli/{schema-ejerjdcy.js → schema-art9xdhq.js} +1 -1
  63. package/dist/cli/{scope-persistence-5nd08ct5.js → scope-persistence-7ny8a0gk.js} +5 -5
  64. package/dist/cli/{server-e9xvqypk.js → server-b4nczew1.js} +26 -26
  65. package/dist/cli/{skill-generator-6c57ckmm.js → skill-generator-bbzwn7ny.js} +8 -8
  66. package/dist/cli/{snapshot-coordination-init-jbs93ng2.js → snapshot-coordination-init-1v237k29.js} +26 -26
  67. package/dist/cli/{speckit-checkoff-ryx6gh3p.js → speckit-checkoff-tc2pswse.js} +3 -3
  68. package/dist/cli/{workflow-wal-file-3f6ajfce.js → workflow-wal-file-4vh413p1.js} +2 -2
  69. package/dist/cli/{worktree-collision-ownership-vdjhvm3b.js → worktree-collision-ownership-vt740r91.js} +2 -2
  70. package/dist/cli/{worktree-isolation-arqj4g26.js → worktree-isolation-yqfqvtex.js} +26 -26
  71. package/dist/hooks/guardrails/cmd-delete-grammar.d.ts +17 -0
  72. package/dist/hooks/skill-propagation-gate.d.ts +13 -0
  73. package/dist/index.js +100 -83
  74. package/dist/memory/memory-family-migration.d.ts +57 -3
  75. package/dist/turbo/lean/planner.d.ts +8 -5
  76. package/dist/turbo/lean/runner.d.ts +3 -0
  77. package/dist/turbo/lean/upstream-committed.d.ts +94 -0
  78. package/dist/utils/ephemeral-session-teardown.d.ts +24 -5
  79. package/package.json +1 -1
@@ -63,14 +63,67 @@ export interface MemoryFamilyMigrationCounts {
63
63
  filename: string;
64
64
  merged: number;
65
65
  skipped: number;
66
+ /** Same-id rows replaced by a strictly newer version (#3520 PRR-002 truthfulness). */
67
+ superseded: number;
66
68
  }>;
69
+ /**
70
+ * #2958 tombstone / recency audit, one entry per member that had anything
71
+ * to report (members whose three fields are all empty are omitted). Every
72
+ * emitted entry carries all three fields.
73
+ */
74
+ readonly audit: ReadonlyArray<MemoryFamilyMemberAudit>;
67
75
  }
68
- /** Id-keyed union of two append-only JSONL arrays (idempotent on retry). */
69
- declare function appendUnionById<T>(destination: T[], source: T[]): {
76
+ /** Per-member divergence audit (#2958). */
77
+ export interface MemoryFamilyMemberAudit {
78
+ readonly filename: string;
79
+ /** Destination-deleted ids a newer live source row resurrected. */
80
+ readonly resurrectedIds: readonly string[];
81
+ /**
82
+ * Collisions resolved by recency OTHER THAN resurrections: source-newer
83
+ * wins (live or tombstone) plus destination-tombstone suppressions.
84
+ * Destination-newer keep-rows are not supersessions (nothing moved), and
85
+ * resurrections are reported solely via {@link resurrectedIds} so no
86
+ * event renders twice.
87
+ */
88
+ readonly supersededCount: number;
89
+ /** Collisions with no usable recency signal (destination kept, reported). */
90
+ readonly unresolvedCollisions: readonly string[];
91
+ }
92
+ /** Options for {@link appendUnionById}. */
93
+ export interface AppendUnionByIdOptions {
94
+ /**
95
+ * Member filename — selects the member's recency rules
96
+ * ({@link MEMBER_RECENCY_KEYS}). Defaults to the memories shape.
97
+ */
98
+ memberFilename?: string;
99
+ }
100
+ /** Result of {@link appendUnionById} (#2958 recency-aware union). */
101
+ export interface AppendUnionByIdResult<T> {
70
102
  merged: T[];
71
103
  added: number;
72
104
  skipped: number;
73
- };
105
+ /** Source rows that superseded an older destination row for a shared id. */
106
+ superseded: number;
107
+ /** Shared ids with no usable recency signal (destination kept, reported). */
108
+ unresolvedCollisions: readonly string[];
109
+ /** Destination tombstones resurrected by a newer live source row. */
110
+ resurrectedIds: readonly string[];
111
+ }
112
+ /**
113
+ * Id-keyed union of two append-only JSONL arrays — recency-aware (#2958).
114
+ *
115
+ * For a shared id the union compares the source row against the EFFECTIVE last
116
+ * destination row (load is last-row-wins; the map is updated as rows append,
117
+ * so a multi-row source history resolves against the merge's own state). A
118
+ * strictly newer source row is APPENDED (files stay append-only — never
119
+ * rewritten in place); destination-newer or equal keeps today's skip; a
120
+ * byte-equal retry is benign dedup; a collision with no usable recency signal
121
+ * keeps the destination row AND is reported in `unresolvedCollisions`.
122
+ * Proposals use reviewed-outranks-unreviewed ordering (a curator review is a
123
+ * lifecycle advancement); tombstoned destination memories resurrected by a
124
+ * newer live source row are reported in `resurrectedIds`.
125
+ */
126
+ declare function appendUnionById<T>(destination: T[], source: T[], options?: AppendUnionByIdOptions): AppendUnionByIdResult<T>;
74
127
  /**
75
128
  * Outcome event ids are retry identities, not generic append-only row ids.
76
129
  * Apply the provider's shared semantic collision rules while retaining the
@@ -110,6 +163,7 @@ declare function stageSqliteDb(sourceStoragePath: string, destDir: string): {
110
163
  declare function mergeStagedSqlite(destStoragePath: string, stagedPath: string): Promise<{
111
164
  merged: number;
112
165
  skipped: number;
166
+ audit: MemoryFamilyMemberAudit;
113
167
  }>;
114
168
  /** Best-effort row count via a direct DB open (does not enter the pool). */
115
169
  declare function countRowsSafe(dbPath: string): Promise<number>;
@@ -95,11 +95,14 @@ export interface LeanTurboLanePlan {
95
95
  * redesign). When supplied, a cross-batch dependency (a `depends:`
96
96
  * upstream not present in this planning call's task set — typically
97
97
  * completed in a prior phase) is treated as satisfied **only** if
98
- * the predicate returns `true`. Production callers build this from
99
- * `buildIsUpstreamCommitted(directory)` so the check resolves to
100
- * "is there a `swarm(task <id>)` commit in HEAD". When undefined
101
- * the planner falls back to its legacy behavior (cross-batch deps
102
- * are implicitly satisfied) for backward compatibility.
98
+ * the predicate returns `true`. Production lean callers supply it via
99
+ * `resolveLeanRule3Predicate(directory, taskIds)`
100
+ * (`src/turbo/lean/upstream-committed.ts`) ONLY while an Epic is open
101
+ * for the project — `swarm(task <id>):` landing commits exist only
102
+ * under Epic Mode, so wiring it unconditionally would wrongly degrade
103
+ * every healthy pure-lean cross-phase dependent. When undefined (no
104
+ * open Epic) the planner falls back to its legacy behavior (cross-batch
105
+ * deps are implicitly satisfied) for backward compatibility.
103
106
  * @returns Complete lane plan with lanes, degraded tasks, and counters
104
107
  */
105
108
  export declare function planLeanTurboLanes(directory: string, phaseNumber: number, plan: {
@@ -29,6 +29,7 @@ import { attemptMergeBackFromDirty, getMergeStrategy, mergeLaneBranch, postMerge
29
29
  import { planLeanTurboLanes } from './planner';
30
30
  import type { LeanTurboDegradedTask, LeanTurboLane } from './state';
31
31
  import { loadLeanTurboRunState, saveLeanTurboRunState } from './state';
32
+ import { resolveLeanRule3Predicate } from './upstream-committed';
32
33
  import { assertCleanWorkingTree, provisionWorktree, removeLaneProfileFromDiskReal, removeWorktree } from './worktree';
33
34
  /**
34
35
  * Shape of the OpencodeClient session API used by the runner.
@@ -216,6 +217,8 @@ export declare class LeanTurboRunner {
216
217
  static _internals: {
217
218
  loadPlanJsonOnly: typeof loadPlanJsonOnly;
218
219
  planLeanTurboLanes: typeof planLeanTurboLanes;
220
+ /** Issue #2962: epic-gated Rule-3 upstream-commit predicate for lane planning. */
221
+ resolveLeanRule3Predicate: typeof resolveLeanRule3Predicate;
219
222
  acquireLaneLocks: typeof acquireLaneLocks;
220
223
  releaseLaneLocks: typeof releaseLaneLocks;
221
224
  loadLeanTurboRunState: typeof loadLeanTurboRunState;
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Lean Turbo Rule-3 upstream-commit predicate (issue #2962).
3
+ *
4
+ * `planLeanTurboLanes` reserves an optional `isUpstreamCommitted` predicate
5
+ * (greenfield-smart Rule 3): when supplied, a cross-batch `depends:` upstream
6
+ * (a dep not present in this planning call's task set — typically completed in
7
+ * a prior phase) counts as satisfied only when the predicate proves the
8
+ * upstream's work landed in git. Before this module existed, neither
9
+ * production caller supplied it, so `makeDependencySatisfactionChecker`
10
+ * (`partition-common.ts`) treated every cross-batch dep as implicitly
11
+ * satisfied — a dependent task was dispatched in a parallel lane against work
12
+ * that never reached HEAD.
13
+ *
14
+ * The predicate is EPIC-GATED: `swarm(task <id>):` landing commits exist only
15
+ * under Epic Mode (`src/epic/plan-key.ts` → `task-landing.ts`/`residue-commit.ts`;
16
+ * `src/plan/manager.ts` performs no git writes). In pure Lean Turbo no such
17
+ * commits ever exist, so this helper returns `undefined` (the planner's
18
+ * byte-identical legacy branch) unless an Epic is open for the project.
19
+ *
20
+ * Evidence reuses the CURRENT Epic marker machinery — never a re-implemented
21
+ * subject scanner: coder landings are `git merge --no-ff` MERGE commits (the
22
+ * log read is merge-inclusive), task ids repeat across plans (the
23
+ * `Swarm-Plan:` trailer filters by planKey), and ids are scrubbed in subjects
24
+ * (`scrubTaskIdForGitSubject` mapping handled inside `findTaskCommits`).
25
+ *
26
+ * Failure taxonomy:
27
+ * - Unreadable Epic state → Epic reads as OFF (same direction as
28
+ * `isEpicOpenForProject`): `undefined` + operator-visible warn.
29
+ * - Epic closed between the reads → `undefined`, no warn (not an error).
30
+ * - Unborn HEAD (positively
31
+ * classified) → defined predicate, EMPTY committed set
32
+ * (nothing has landed yet).
33
+ * - Genuine git failure (log read
34
+ * fails with HEAD resolvable, or
35
+ * the probe itself fails) → disclosed permissive fallback
36
+ * (`() => true`): legacy degradation,
37
+ * NOT continued Rule-3 enforcement — wave
38
+ * ordering never covers cross-batch deps.
39
+ *
40
+ * This module is the Lean-owned side of a documented Lean→Epic seam (see
41
+ * `src/epic/README.md`, upstream consumers): `src/epic/lifecycle.ts` and
42
+ * `src/epic/markers.ts` import nothing from `src/turbo/lean/`, so the edge is
43
+ * acyclic, and Epic-off costs exactly the sentinel `existsSync` inside
44
+ * `isEpicOpenForProject` (Epic rule zero).
45
+ */
46
+ import { getOpenEpic, isEpicOpenForProject } from '../../epic/lifecycle.js';
47
+ import { epicCommitRange, findTaskCommits } from '../../epic/markers.js';
48
+ import * as logger from '../../utils/logger.js';
49
+ /** Three-way HEAD probe outcome. */
50
+ export type HeadCommitState = 'exists' | 'unborn' | 'unknown';
51
+ /**
52
+ * Bounded HEAD classification. `'exists'` when `git rev-parse --verify HEAD`
53
+ * resolves (exit 0). `'unborn'` ONLY when positively classified: rev-parse
54
+ * fails AND `git symbolic-ref -q HEAD` still resolves the branch (we are on a
55
+ * branch that simply has no commits yet — the structural unborn shape; stderr
56
+ * text varies by git version, so the ref probe is the classifier). Every other
57
+ * outcome — spawn error, timeout, other exit, detached/corrupt HEAD — yields
58
+ * `'unknown'` so a probe failure can never masquerade as "nothing committed".
59
+ */
60
+ declare function headCommitExistsReal(directory: string): HeadCommitState;
61
+ /**
62
+ * Warn once per (resolved directory, failure class). The class key keeps the
63
+ * two semantically distinct degradations from suppressing each other (#2962
64
+ * review PRR-006): an unreadable-Epic warning must not silence a later
65
+ * git-log-failure warning for the same project, and vice versa. The key is
66
+ * the canonical lexical root so path-spelling variants dedup to one entry.
67
+ */
68
+ declare function warnOnceReal(directory: string, failureClass: 'epic-unreadable' | 'rule3-git-failure', message: string): void;
69
+ /**
70
+ * Resolve the Rule-3 predicate for a Lean Turbo planning call.
71
+ *
72
+ * @param directory - Project root directory.
73
+ * @param taskIds - The plan's full task-id set (all phases) — the candidate
74
+ * cross-batch upstreams the marker read scans for. One bounded git
75
+ * call per planning pass; never on the plugin-init path.
76
+ * @returns `undefined` when no Epic is open for the project (pure-lean
77
+ * legacy semantics, byte-identical placement), otherwise a predicate
78
+ * answering "does this task id have a `swarm(task <id>):` landing in
79
+ * the open Epic's commit range for the current plan?".
80
+ */
81
+ export declare function resolveLeanRule3Predicate(directory: string, taskIds: readonly string[]): ((taskId: string) => boolean) | undefined;
82
+ /** DI seam (AGENTS.md invariant 7). Restore in `afterEach`. */
83
+ export declare const _internals: {
84
+ isEpicOpenForProject: typeof isEpicOpenForProject;
85
+ getOpenEpic: typeof getOpenEpic;
86
+ epicCommitRange: typeof epicCommitRange;
87
+ findTaskCommits: typeof findTaskCommits;
88
+ headCommitExists: typeof headCommitExistsReal;
89
+ warnOnce: typeof warnOnceReal;
90
+ criticalWarn: typeof logger.criticalWarn;
91
+ /** Test-reset surface for the module-level dedup registry (lifecycle.ts precedent). */
92
+ warnedDirectories: Set<string>;
93
+ };
94
+ export {};
@@ -128,12 +128,30 @@ export type EphemeralTeardownVerification = {
128
128
  reason: string;
129
129
  };
130
130
  /**
131
- * Bounded existence check via `session.get`. `get` throwing (session-gone
132
- * errors surface as rejections on the SDK surface) or returning an empty body
133
- * both mean the session is gone (mirrors the reason-forwarding resolver
134
- * precedent in `src/hooks/pr-workflow-session-resolver.ts`).
131
+ * Existence verdict for the post-delete verify (`session.get`).
132
+ *
133
+ * - `'gone'` — confirmed-gone signal only: an empty body (`data` undefined or
134
+ * null with no transport-class error envelope), or — for hosts configured
135
+ * `throwOnError: true` — a rejection that is neither the verify deadline
136
+ * error (compared by identity) nor transport-class.
137
+ * - `'unreadable'` — the verify timed out (the locally constructed deadline
138
+ * error, distinguished by identity) or the call failed with a transport-class
139
+ * error (whatwg fetch `TypeError`, connection-reset family). Never a death
140
+ * claim: under the installed SDK's `throwOnError` default-off, session-gone
141
+ * surfaces through the body check, so nearly every rejection/envelope-error
142
+ * reaching these paths is an unproven-death signal (issue #2964).
143
+ * - `'alive'` — non-empty body, or `get` unavailable (cannot disprove).
144
+ */
145
+ type SessionExistence = 'alive' | 'gone' | 'unreadable';
146
+ /**
147
+ * Whether an error looks like a transient transport failure rather than a
148
+ * host-level answer: a whatwg fetch network `TypeError`, a Node/Deno
149
+ * connection error code, or an SDK abort. Used both for rejections of
150
+ * `session.get` and for transport errors normalized into `{data: null, error}`
151
+ * envelopes by the v2 session shim (`src/host/v2/session-client.ts`).
135
152
  */
136
- declare function sessionExists(session: EphemeralSessionLifecycle, sessionId: string, verifyTimeoutMs: number): Promise<boolean>;
153
+ declare function isTransientTransportError(err: unknown): boolean;
154
+ declare function sessionExists(session: EphemeralSessionLifecycle, sessionId: string, verifyTimeoutMs: number): Promise<SessionExistence>;
137
155
  /**
138
156
  * Verified teardown (issue #2599): bounded abort → bounded delete → bounded
139
157
  * existence check, retrying the delete a bounded number of times when the
@@ -146,6 +164,7 @@ export declare const _internals: {
146
164
  boundedAbort: typeof boundedAbortEphemeralSession;
147
165
  boundedDelete: typeof boundedDeleteEphemeralSession;
148
166
  sessionExists: typeof sessionExists;
167
+ isTransientTransportError: typeof isTransientTransportError;
149
168
  log: typeof log;
150
169
  };
151
170
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-swarm",
3
- "version": "7.200.12",
3
+ "version": "7.200.14",
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",