opencode-swarm 7.107.6 → 7.109.0

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 (84) hide show
  1. package/.opencode/skills/clarify-spec/SKILL.md +15 -9
  2. package/.opencode/skills/critic-gate/SKILL.md +10 -4
  3. package/.opencode/skills/phase-wrap/SKILL.md +2 -2
  4. package/.opencode/skills/plan/SKILL.md +23 -11
  5. package/.opencode/skills/specify/SKILL.md +27 -9
  6. package/dist/cli/{capability-probe-wsjzcp48.js → capability-probe-sh9bwh39.js} +2 -1
  7. package/dist/cli/{config-doctor-kdq3vae4.js → config-doctor-q354tb2w.js} +2 -2
  8. package/dist/cli/core-vev13ej2.js +34 -0
  9. package/dist/cli/{curator-jpwvkpdv.js → curator-3efwdf9x.js} +25 -21
  10. package/dist/cli/{curator-drift-ed7p5mfy.js → curator-drift-169wgaxn.js} +4 -4
  11. package/dist/cli/curator-llm-factory-nttpcx4b.js +40 -0
  12. package/dist/cli/{dispatch-anmxxhen.js → dispatch-zr1xja4t.js} +2 -2
  13. package/dist/cli/{evidence-summary-service-6zsgw7x7.js → evidence-summary-service-j7jwf20f.js} +10 -8
  14. package/dist/cli/{gate-evidence-pgr7d942.js → gate-evidence-v6ds8rcp.js} +5 -4
  15. package/dist/cli/guardrail-explain-e85gbj0r.js +41 -0
  16. package/dist/cli/{guardrail-log-fjypsmek.js → guardrail-log-8mqqsssq.js} +4 -4
  17. package/dist/cli/hive-promoter-rc6z2x8f.js +48 -0
  18. package/dist/cli/{index-9b7qp18e.js → index-1cn967sa.js} +2 -2
  19. package/dist/cli/{index-h28wfp7n.js → index-1mjzvkzj.js} +29 -25
  20. package/dist/cli/{index-n1sptn1w.js → index-2nt4mq9n.js} +1 -1
  21. package/dist/cli/{index-57rthc1z.js → index-3e7jajwe.js} +2 -2
  22. package/dist/cli/{index-bq8kd9r9.js → index-5gnp8fyw.js} +3 -3
  23. package/dist/cli/index-5mkc2f9z.js +154 -0
  24. package/dist/cli/{index-0kxc7t16.js → index-6jng9c8t.js} +1 -1
  25. package/dist/cli/{index-b9v501fr.js → index-7xgqky26.js} +33 -5
  26. package/dist/cli/{index-4r5z8sgw.js → index-85bacexr.js} +2 -2
  27. package/dist/cli/{index-bpgqbwmf.js → index-9qxntjtx.js} +6 -6
  28. package/dist/cli/index-f1qyj61w.js +418 -0
  29. package/dist/cli/{index-wvxhynxq.js → index-fm7xz1ne.js} +1 -1
  30. package/dist/cli/{index-dfdg4ws5.js → index-fz1jgbvw.js} +6 -6
  31. package/dist/cli/{index-pchpahdf.js → index-h4c4rrwx.js} +20 -3
  32. package/dist/cli/{index-kxm3bdjh.js → index-mmny81g1.js} +6 -6
  33. package/dist/cli/{index-v4fcn4tr.js → index-q1exe2b3.js} +2 -198
  34. package/dist/cli/{index-57ymmh7h.js → index-r3j3458j.js} +4 -4
  35. package/dist/cli/{index-91j1sqzm.js → index-scww5b77.js} +47 -0
  36. package/dist/cli/{index-572t1qff.js → index-vb5t1kvs.js} +1477 -2045
  37. package/dist/cli/{index-3naa2ajc.js → index-vvk2g744.js} +10 -156
  38. package/dist/cli/{index-zej8cy0j.js → index-vx76tcxe.js} +1 -1
  39. package/dist/cli/{index-6h82c2h0.js → index-wfq4r95s.js} +1057 -193
  40. package/dist/cli/{index-xmarctsf.js → index-wg0665ft.js} +7 -7
  41. package/dist/cli/{index-4vsgp5a8.js → index-wj4jeavn.js} +1 -1
  42. package/dist/cli/index-wvrj16f0.js +206 -0
  43. package/dist/cli/index-x2q0gnt8.js +254 -0
  44. package/dist/cli/{index-xg18az81.js → index-yw8qpf51.js} +1 -1
  45. package/dist/cli/index.js +25 -21
  46. package/dist/cli/{knowledge-escalator-3sgwrgy9.js → knowledge-escalator-6v7sjprx.js} +8 -7
  47. package/dist/cli/{knowledge-events-kfc6xmkw.js → knowledge-events-6n3x3he2.js} +6 -5
  48. package/dist/cli/{knowledge-store-kyacem71.js → knowledge-store-exkw6yb1.js} +6 -5
  49. package/dist/cli/{knowledge-validator-ez3ws8ef.js → knowledge-validator-exymfcb9.js} +7 -6
  50. package/dist/cli/{pending-delegations-vfnpm8zt.js → pending-delegations-yyz3fcfn.js} +5 -4
  51. package/dist/cli/{pr-subscriptions-bpvazmsw.js → pr-subscriptions-vv8byxe6.js} +6 -5
  52. package/dist/cli/{schema-x0ekqzvs.js → schema-x17zmd03.js} +1 -1
  53. package/dist/cli/scope-persistence-6m5nsp1r.js +20 -0
  54. package/dist/cli/{skill-generator-x83re96d.js → skill-generator-mx9br4ty.js} +9 -8
  55. package/dist/commands/_shared/url-security.d.ts +13 -3
  56. package/dist/commands/close.d.ts +11 -0
  57. package/dist/commands/lanes.d.ts +35 -0
  58. package/dist/commands/registry.d.ts +9 -2
  59. package/dist/commands/sdd.d.ts +10 -0
  60. package/dist/config/schema.d.ts +102 -0
  61. package/dist/git/branch.d.ts +53 -7
  62. package/dist/git/index.d.ts +5 -1
  63. package/dist/git/pr.d.ts +35 -2
  64. package/dist/hooks/delegation-gate/worktree-isolation.d.ts +118 -2
  65. package/dist/hooks/delegation-gate/worktree-merge-status.d.ts +17 -0
  66. package/dist/hooks/init-orphan-recovery-advisory.d.ts +58 -0
  67. package/dist/hooks/init-orphan-recovery.d.ts +65 -0
  68. package/dist/index.js +452 -436
  69. package/dist/sandbox/executor.d.ts +11 -1
  70. package/dist/sandbox/linux/bubblewrap-executor.d.ts +3 -1
  71. package/dist/sandbox/macos/sandbox-exec-executor.d.ts +3 -1
  72. package/dist/sandbox/win32/native-sandbox-executor.d.ts +1 -1
  73. package/dist/sandbox/win32/restricted-environment-executor.d.ts +4 -1
  74. package/dist/sdd/effective-spec.d.ts +21 -0
  75. package/dist/turbo/lean/runner.d.ts +11 -20
  76. package/dist/turbo/lean/worktree.d.ts +9 -3
  77. package/dist/utils/bun-compat.d.ts +30 -0
  78. package/dist/worktree/core.d.ts +55 -0
  79. package/dist/worktree/merge.d.ts +5 -1
  80. package/dist/worktree/types.d.ts +38 -0
  81. package/package.json +1 -1
  82. package/dist/cli/curator-llm-factory-9y15npd5.js +0 -36
  83. package/dist/cli/guardrail-explain-jk0amzae.js +0 -37
  84. package/dist/cli/hive-promoter-j2krbdn9.js +0 -44
@@ -8,9 +8,46 @@
8
8
  * Extracted from delegation-gate.ts (FR-003) for modularity.
9
9
  * The _internals seam allows test injection of worktree operations.
10
10
  */
11
- import type { PluginConfig } from '../../config';
11
+ import type { PluginConfig, WorktreeIsolationConfig } from '../../config';
12
12
  import type { WorktreeHandle } from '../../worktree';
13
13
  import { attemptMergeBackFromDirty, cleanupOrphanedBranches, postMergeCleanup, provisionWorktree, removeWorktree, startupOrphanRecovery } from '../../worktree';
14
+ /**
15
+ * FR-201: Per-lane runtime profile injected into spawned child processes.
16
+ *
17
+ * Produced at lane provisioning time and written as `.swarm/lanes/{laneIndex}.env`
18
+ * (KEY=VAL format, one per line) so any child process spawned inside the lane
19
+ * can source it to get lane-specific PORT, TMPDIR, cache redirects, etc.
20
+ *
21
+ * The profile is computed from the resolved WorktreeIsolationConfig.runtime_isolation:
22
+ * - PORT = (port_base ?? 0) + laneIndex * port_stride
23
+ * - env_overrides merged verbatim
24
+ * - cache_redirects mapped to env vars
25
+ */
26
+ export interface LaneRuntimeProfile {
27
+ /** 0-based lane index used for port and env derivation. */
28
+ laneIndex: number;
29
+ /** Absolute path to the provisioned worktree. */
30
+ worktreePath: string;
31
+ /** Env var overrides for this lane (includes PORT after derivation). */
32
+ envOverrides: Record<string, string>;
33
+ }
34
+ /**
35
+ * Parses a Lean Turbo laneId (e.g. "lane-3") and returns its 0-based index.
36
+ * Returns 0 for unparseable ids.
37
+ */
38
+ export declare function parseLeanLaneIndex(laneId: string): number;
39
+ /**
40
+ * FR-201 SC-122: Computes the per-lane runtime profile from the resolved runtime_isolation config.
41
+ *
42
+ * Derives:
43
+ * - PORT = (port_base ?? 0) + laneIndex * port_stride
44
+ * - Derives PORT from port_base + lane_index * port_stride (when port_base is set)
45
+ * - Merges env_overrides — explicit caller values win over derived PORT
46
+ * - Merges cache_redirects (base → lane-suffixed-path mapped to env vars; wins over env_overrides)
47
+ *
48
+ * Returns undefined when runtime_isolation is disabled (zero behavior change).
49
+ */
50
+ export declare function computeLaneRuntimeProfile(runtime: WorktreeIsolationConfig['runtime_isolation'], laneIndex: number, worktreePath: string): LaneRuntimeProfile | undefined;
14
51
  export declare const MAX_TRACKED_STANDARD_WORKTREE_CALLS = 256;
15
52
  export interface StandardWorktreeDispatch {
16
53
  callID: string;
@@ -19,11 +56,54 @@ export interface StandardWorktreeDispatch {
19
56
  planTaskId?: string;
20
57
  handle: WorktreeHandle;
21
58
  mergeStrategy: 'merge' | 'rebase' | 'cherry-pick';
59
+ /** FR-201: 0-based lane index for runtime profile derivation. */
60
+ laneIndex: number;
61
+ }
62
+ export interface AwaitingMergeRecord {
63
+ callID: string;
64
+ parentSessionID: string;
65
+ taskId: string;
66
+ planTaskId?: string;
67
+ branch: string;
68
+ worktreePath: string;
69
+ mergeStrategy: 'merge' | 'rebase' | 'cherry-pick';
70
+ queuedAt: number;
22
71
  }
72
+ /** Map keyed by callID. Lanes waiting for or in the middle of merge-back. */
73
+ export declare const awaitingMergeByCallID: Map<string, AwaitingMergeRecord>;
23
74
  export declare const standardWorktreeByCallID: Map<string, StandardWorktreeDispatch>;
24
75
  export declare const standardWorktreeSerializationSessions: Set<string>;
76
+ /**
77
+ * FR-104 SC-111/SC-112: Per-session state tracking for serialization release.
78
+ * Maps sessionID → serialization state for that session.
79
+ */
80
+ interface SessionSerializationState {
81
+ sessionID: string;
82
+ /** Date.now() when the session was first added to standardWorktreeSerializationSessions */
83
+ serializedAt: number;
84
+ /**
85
+ * Count of successful dispatches (merge-back completed with 'merged') from this
86
+ * session since it entered serialized mode.
87
+ */
88
+ successfulDispatchesSince: number;
89
+ }
25
90
  export declare function resetStandardWorktreeIsolationState(): void;
91
+ /**
92
+ * FR-104 SC-111/SC-112: Check whether a serialized session has met its release conditions
93
+ * (either enough successful dispatches have completed, or the TTL has expired).
94
+ * If so, release it from serialized mode.
95
+ */
96
+ export declare function checkStandardWorktreeSerializationRelease(sessionID: string, config: WorktreeIsolationConfig): void;
97
+ /**
98
+ * FR-104 SC-113: Add a session to the serialization set.
99
+ * When the set is at capacity, evicts the oldest entry whose session has NO
100
+ * in-flight dispatch — never evict an actively-dispatching session.
101
+ * If ALL 256 entries are in-flight, refuses the new entry and logs a warning
102
+ * rather than silently breaking isolation.
103
+ */
104
+ declare function rememberStandardWorktreeSerializationSession(sessionID: string): boolean;
26
105
  export declare function sanitizeWorktreeTaskId(raw: string): string;
106
+ export declare function resolveWorktreeIsolationConfig(config: PluginConfig): WorktreeIsolationConfig;
27
107
  export declare function precreateStandardWorktreeSession(args: {
28
108
  config: PluginConfig;
29
109
  directory: string;
@@ -33,8 +113,31 @@ export declare function precreateStandardWorktreeSession(args: {
33
113
  planTaskId?: string;
34
114
  description?: string;
35
115
  outputArgs: Record<string, unknown>;
116
+ /** Scope to materialize into the lane for durability across restart (FR-102). */
117
+ scope?: {
118
+ taskId: string;
119
+ files: string[];
120
+ };
36
121
  }): Promise<void>;
37
- export declare function finishStandardWorktreeDispatch(directory: string, dispatch: StandardWorktreeDispatch): Promise<void>;
122
+ export declare function finishStandardWorktreeDispatch(directory: string, dispatch: StandardWorktreeDispatch, config?: PluginConfig,
123
+ /**
124
+ * Optional callID for cleanup of awaitingMergeByCallID. When omitted,
125
+ * derived from dispatch.callID (for backward compatibility with test callers
126
+ * that pass StandardWorktreeDispatch objects directly).
127
+ */
128
+ callID?: string): Promise<void>;
129
+ /**
130
+ * FR-201: Read and parse a lane runtime profile from disk.
131
+ *
132
+ * Reads `<worktree>/.swarm/lanes/{laneIndex}.env` (KEY=VALUE format, one per line).
133
+ * - Skips blank lines and lines starting with `#` (comments).
134
+ * - Skips malformed lines (no `=` separator).
135
+ * - Validates each key with `isValidEnvKey`; rejects and skips invalid keys.
136
+ * - Returns an empty record when the file does not exist.
137
+ *
138
+ * Exposed via _internals for testability (no mock.module leakage).
139
+ */
140
+ export declare function readLaneEnvFileFromDisk(worktreePath: string, laneIndex: number): Promise<Record<string, string>>;
38
141
  /**
39
142
  * _internals seam for test injection of worktree operations.
40
143
  * Tests set these entries on delegation-gate's _internals (which proxies
@@ -45,6 +148,19 @@ export declare const _internals: {
45
148
  removeWorktree: typeof removeWorktree;
46
149
  attemptMergeBackFromDirty: typeof attemptMergeBackFromDirty;
47
150
  postMergeCleanup: typeof postMergeCleanup;
151
+ /** FR-201: read lane runtime profile from disk for spawn injection. */
152
+ readLaneEnvFileFromDisk: typeof readLaneEnvFileFromDisk;
153
+ /** FR-104: exposes serializationStateBySessionID for test setup (SC-111/SC-112/SC-113). */
154
+ serializationStateBySessionID: Map<string, SessionSerializationState>;
155
+ /**
156
+ * FR-104 SC-113: exposes the FIFO eviction function for direct test invocation.
157
+ * Tests use this to exercise the cap-check logic without going through the
158
+ * full precreateStandardWorktreeSession path.
159
+ */
160
+ rememberStandardWorktreeSerializationSession: typeof rememberStandardWorktreeSerializationSession;
161
+ /** FR-105 SC-115: exposes awaitingMergeByCallID for test setup. */
162
+ awaitingMergeByCallID: Map<string, AwaitingMergeRecord>;
48
163
  startupOrphanRecovery: typeof startupOrphanRecovery;
49
164
  cleanupOrphanedBranches: typeof cleanupOrphanedBranches;
50
165
  };
166
+ export {};
@@ -34,6 +34,14 @@ export interface WorktreeMergeFailure {
34
34
  stage: string;
35
35
  /** Human-readable detail surfaced in the Rule 2 skip warning. */
36
36
  message: string;
37
+ /** Worktree path where the lane is preserved after a failed/partial merge. */
38
+ worktreePath?: string;
39
+ /** Branch name of the lane. */
40
+ branch?: string;
41
+ /** Timestamp (Date.now()) when the lane entered merge-back. */
42
+ queuedAt?: number;
43
+ /** Timestamp (Date.now()) when merge-back completed (success or failure). */
44
+ completedAt?: number;
37
45
  }
38
46
  declare function getDurableStatusPath(projectDir?: string): string;
39
47
  /**
@@ -70,6 +78,15 @@ export declare function clearWorktreeMergeStatus(taskId: string | undefined): vo
70
78
  * On first read after plugin restart, loads from durable storage.
71
79
  */
72
80
  export declare function getWorktreeMergeFailure(taskId: string): WorktreeMergeFailure | undefined;
81
+ /**
82
+ * Iterate all worktree merge failures. Used by /swarm lanes to surface
83
+ * conflicted lanes that are NOT in awaitingMergeByCallID (i.e., merge
84
+ * has completed with partial/failed outcome).
85
+ */
86
+ export declare function getAllWorktreeMergeFailures(): IterableIterator<[
87
+ string,
88
+ WorktreeMergeFailure
89
+ ]>;
73
90
  /**
74
91
  * @internal test seam. Use `resetForTest()` in afterEach to isolate tests
75
92
  * that set durableStatusPath via `initDurableStatusPath`.
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Init Orphan Recovery Advisory Hook (FR-103 SC-108)
3
+ *
4
+ * At plugin init, `cleanupOrphanedBranches` is called to reclaim orphaned worktrees
5
+ * and branches. Any warnings or errors (state-unreadable conditions) are written
6
+ * to `<directory>/.swarm/advisories/init-orphan-recovery.json`.
7
+ *
8
+ * This hook runs in the `messagesTransform` chain (before `guardrailsHooks.messagesTransform`)
9
+ * and surfaces those advisories to the architect on their NEXT TURN.
10
+ *
11
+ * Advisory file format:
12
+ * ```json
13
+ * {
14
+ * "initTimestamp": "<ISO timestamp>",
15
+ * "warnings": ["warning message 1", "warning message 2"],
16
+ * "errors": [{ "branch": "swarm-lane/sess/lane", "error": "detail" }],
17
+ * "reclaimed": { "removedBranches": [], "prunedWorktrees": true }
18
+ * }
19
+ * ```
20
+ *
21
+ * The file is deleted after consumption (best-effort) so repeated turns don't re-surface.
22
+ */
23
+ export interface InitOrphanAdvisory {
24
+ initTimestamp: string;
25
+ warnings: string[];
26
+ errors: Array<{
27
+ branch: string;
28
+ error: string;
29
+ }>;
30
+ reclaimed: {
31
+ removedBranches: string[];
32
+ removedWorktrees: string[];
33
+ prunedWorktrees: boolean;
34
+ };
35
+ }
36
+ /**
37
+ * Creates a messagesTransform hook that surfaces init orphan recovery advisories
38
+ * on the architect's first turn after plugin init.
39
+ *
40
+ * @param directory - Project root directory (for .swarm/advisories path)
41
+ * @returns A hook object with a messagesTransform handler
42
+ */
43
+ export declare function createInitOrphanRecoveryAdvisoryHook(directory: string): {
44
+ messagesTransform: (input: Record<string, never>, output: {
45
+ messages?: Array<{
46
+ info: {
47
+ role: string;
48
+ agent?: string;
49
+ sessionID?: string;
50
+ };
51
+ parts: Array<{
52
+ type?: string;
53
+ text?: string;
54
+ [key: string]: unknown;
55
+ }>;
56
+ }>;
57
+ }) => Promise<void>;
58
+ };
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Init Orphan Recovery Helper (FR-103 / SC-107..SC-110)
3
+ *
4
+ * Bounded plugin-init wrapper around `cleanupOrphanedBranches` that:
5
+ * - Enumerates orphaned worktree directories under `.swarm-worktrees/<sessionId>/` and removes them
6
+ * - Calls cleanupOrphanedBranches(ctx.directory, []) at plugin init (no sessions active → all swarm-lane branches are orphans)
7
+ * - Writes results to `<directory>/.swarm/advisories/init-orphan-recovery.json`
8
+ * - Is wrapped in `withTimeout` so it never blocks plugin init
9
+ * - Runs via `queueMicrotask` off the `server()` resolution path (precedent: repoGraphHook.init)
10
+ *
11
+ * This module intentionally lives in `src/hooks/` so that `src/index.ts` can import
12
+ * it without matching the forbidden `worktree/` or `merge-back/` patterns.
13
+ *
14
+ * The companion hook `createInitOrphanRecoveryAdvisoryHook` (src/hooks/init-orphan-recovery-advisory.ts)
15
+ * reads the advisory file at session-start and pushes messages to pendingAdvisoryMessages.
16
+ */
17
+ import * as fs from 'node:fs';
18
+ import { isLocked, listActiveLocks, tryAcquireLock } from '../parallel/file-locks';
19
+ import { removeWorktree } from '../worktree/core';
20
+ /**
21
+ * Lock file path for the init orphan recovery advisory lock.
22
+ * advisory-only — signals that another process may be actively using the repo.
23
+ */
24
+ export declare const ORPHAN_RECOVERY_LOCK_FILE = ".swarm/locks/init-orphan-recovery.lock";
25
+ /**
26
+ * DI seam for orphaned worktree removal operations and cross-process lock checking.
27
+ * Exposed so tests can intercept removeWorktree, rmSync, and lock operations
28
+ * without mock.module leakage.
29
+ */
30
+ export declare const _internals: {
31
+ rmSync: typeof fs.rmSync;
32
+ removeWorktree: typeof removeWorktree;
33
+ isLocked: typeof isLocked;
34
+ listActiveLocks: typeof listActiveLocks;
35
+ tryAcquireLock: typeof tryAcquireLock;
36
+ };
37
+ export interface InitOrphanRecoveryResult {
38
+ attempted: boolean;
39
+ /** Set to true when cross-process lock is held by another process — advisory-only cleanup */
40
+ crossProcessLockHeld: boolean;
41
+ warnings: string[];
42
+ orphanedBranches: string[];
43
+ removedWorktrees: string[];
44
+ prunedWorktrees: boolean;
45
+ diagnostic?: {
46
+ file: string;
47
+ reason: string;
48
+ };
49
+ }
50
+ /**
51
+ * Runs bounded orphan cleanup at plugin init time.
52
+ *
53
+ * Active sessions from swarmState are passed to cleanupOrphanedBranches so their
54
+ * branches are skipped and not reclaimed during init recovery.
55
+ *
56
+ * Cross-process safety: before doing any destructive cleanup, checks whether any
57
+ * other opencode process holds the advisory lock at `.swarm/locks/init-orphan-recovery.lock`.
58
+ * If a lock is held (another process is active), skips destructive cleanup entirely
59
+ * and reports detected orphans in result.warnings instead — preventing a second
60
+ * process from deleting the first process's active worktrees/branches.
61
+ *
62
+ * @param directory - Project root directory
63
+ * @returns Result object describing what was attempted and any warnings/diagnostics
64
+ */
65
+ export declare function runInitOrphanRecovery(directory: string): Promise<InitOrphanRecoveryResult>;