opencode-swarm 7.138.4 → 7.139.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 (60) hide show
  1. package/dist/cli/{config-doctor-31yppse4.js → config-doctor-aszp7z1h.js} +2 -2
  2. package/dist/cli/{core-65c7rvqf.js → core-3s832mxx.js} +1 -1
  3. package/dist/cli/{curation-policy-hs9pc1rp.js → curation-policy-a3hs73f7.js} +6 -6
  4. package/dist/cli/{curator-llm-factory-wm27ra25.js → curator-llm-factory-e8ngwyjm.js} +25 -25
  5. package/dist/cli/{curator-54n1y4j8.js → curator-zxjqcc8r.js} +25 -25
  6. package/dist/cli/{evidence-summary-service-hrxcf29a.js → evidence-summary-service-qfhjfxdz.js} +7 -7
  7. package/dist/cli/{gate-evidence-ecx4djaw.js → gate-evidence-m2grv70v.js} +4 -4
  8. package/dist/cli/{guardrail-explain-1729nse8.js → guardrail-explain-rqpmzxyy.js} +26 -26
  9. package/dist/cli/{guardrail-log-yjj5srkw.js → guardrail-log-vd4a0ng5.js} +3 -3
  10. package/dist/cli/{hive-promoter-es2x2b0e.js → hive-promoter-jc5vym27.js} +25 -25
  11. package/dist/cli/{index-tjwz5tct.js → index-0tsetsxs.js} +4 -4
  12. package/dist/cli/{index-jbge0dyh.js → index-3nr2sn32.js} +3 -3
  13. package/dist/cli/{index-mycqmsz5.js → index-4ft523nb.js} +319 -80
  14. package/dist/cli/{index-gm3pjfhb.js → index-5bkpyvdf.js} +1 -1
  15. package/dist/cli/{index-m40ea3zk.js → index-67yqywan.js} +2 -2
  16. package/dist/cli/{index-e1kgxchq.js → index-6q240xgm.js} +2 -2
  17. package/dist/cli/{index-50mwt8fx.js → index-84s6x604.js} +5 -5
  18. package/dist/cli/{index-y28n2wmq.js → index-85hstja2.js} +1 -1
  19. package/dist/cli/{index-xybtaph7.js → index-a614s16f.js} +1 -1
  20. package/dist/cli/{index-10mz5js6.js → index-chvqee1j.js} +2 -2
  21. package/dist/cli/{index-rrxcfxrd.js → index-ddmnhv4h.js} +1 -1
  22. package/dist/cli/{index-a9xny52r.js → index-gytyqv1d.js} +2 -2
  23. package/dist/cli/{index-57stye65.js → index-kv36s0x0.js} +3 -3
  24. package/dist/cli/{index-z7jgvm9b.js → index-nbgw5dxa.js} +1 -1
  25. package/dist/cli/{index-tqshdzaw.js → index-nc544sfw.js} +1 -1
  26. package/dist/cli/{index-33q2gmgd.js → index-nsnfvckc.js} +1 -1
  27. package/dist/cli/{index-4fmztnrq.js → index-p2dz85tv.js} +2 -2
  28. package/dist/cli/{index-m1pwkwfe.js → index-q3qtgtd0.js} +1 -1
  29. package/dist/cli/{index-a18hk2fw.js → index-r3pth9a7.js} +58 -94
  30. package/dist/cli/{index-5q009kc4.js → index-rtetrxxq.js} +1 -1
  31. package/dist/cli/{index-c60whfgh.js → index-s428dmy6.js} +2 -2
  32. package/dist/cli/{index-q344kj84.js → index-t26nfmcs.js} +1 -1
  33. package/dist/cli/{index-1g6xpjk3.js → index-t31cc7kv.js} +6 -6
  34. package/dist/cli/{index-39k6y018.js → index-tcdcj1g2.js} +2 -2
  35. package/dist/cli/{index-en4fb04r.js → index-tyh0p5e8.js} +1 -1
  36. package/dist/cli/{index-k27a4e5g.js → index-y46anh5e.js} +27 -27
  37. package/dist/cli/{index-smsy2p8n.js → index-ymszzvnr.js} +1 -1
  38. package/dist/cli/{index-ngqxzkqm.js → index-z1tkxzq4.js} +2 -2
  39. package/dist/cli/{index-m8txs2a9.js → index-zd15ya1w.js} +1 -1
  40. package/dist/cli/index.js +25 -25
  41. package/dist/cli/{knowledge-escalator-s6z1x65b.js → knowledge-escalator-6473ey4c.js} +7 -7
  42. package/dist/cli/{knowledge-events-nnyn6hst.js → knowledge-events-wwzpz8m4.js} +5 -5
  43. package/dist/cli/{knowledge-link-xc6yhxmz.js → knowledge-link-trfydkzm.js} +4 -4
  44. package/dist/cli/{knowledge-store-x4yfc7v3.js → knowledge-store-99gd42jy.js} +5 -5
  45. package/dist/cli/{knowledge-validator-1v047gsa.js → knowledge-validator-v2eevvdg.js} +8 -8
  46. package/dist/cli/{pending-delegations-7dbc0j2a.js → pending-delegations-p6n83x67.js} +3 -3
  47. package/dist/cli/{pr-subscriptions-m943zn6g.js → pr-subscriptions-xbrfr51c.js} +3 -3
  48. package/dist/cli/{runner-x1hy047y.js → runner-9an52tmz.js} +5 -5
  49. package/dist/cli/{scan-cursor-jxajj6s7.js → scan-cursor-39zxpw34.js} +6 -6
  50. package/dist/cli/{schema-fj32eyae.js → schema-xhfwr6b2.js} +1 -1
  51. package/dist/cli/{scope-persistence-w7zen2wz.js → scope-persistence-nsa6ra9s.js} +4 -4
  52. package/dist/cli/{skill-generator-rt0jqcsa.js → skill-generator-5px81476.js} +9 -9
  53. package/dist/cli/{telemetry-0yqed3jv.js → telemetry-7nt7zhyp.js} +1 -1
  54. package/dist/cli/{worktree-collision-ownership-hjrt5hx2.js → worktree-collision-ownership-9x4s4890.js} +3 -3
  55. package/dist/index.js +368 -369
  56. package/dist/plan/manager.d.ts +2 -0
  57. package/dist/services/run-memory.d.ts +53 -5
  58. package/dist/tools/update-task-status.d.ts +2 -0
  59. package/dist/utils/path-security.d.ts +25 -1
  60. package/package.json +1 -1
@@ -41,6 +41,7 @@ export interface AcknowledgedRemovals {
41
41
  import { type Plan, type RuntimePlan, type TaskStatus } from '../config/plan-schema';
42
42
  import { isGitRepo } from '../git/branch';
43
43
  import { getWorktreeMergeFailure } from '../hooks/delegation-gate/worktree-merge-status';
44
+ import { recordTaskAttempt } from '../services/run-memory.js';
44
45
  import { isEpicModeActiveForProject } from '../turbo/epic/state.js';
45
46
  import { commitTaskCompletion } from '../turbo/epic/task-commit.js';
46
47
  import { readTaskScopes } from '../turbo/lean/conflicts.js';
@@ -64,6 +65,7 @@ export declare const _internals: {
64
65
  readTaskScopes: typeof readTaskScopes;
65
66
  commitTaskCompletion: typeof commitTaskCompletion;
66
67
  getWorktreeMergeFailure: typeof getWorktreeMergeFailure;
68
+ recordTaskAttempt: typeof recordTaskAttempt;
67
69
  };
68
70
  /** @internal Test seam for snapshot retry helper */
69
71
  export declare const _snapshot_test_exports: {
@@ -16,7 +16,28 @@ export interface RunMemoryEntry {
16
16
  taskFingerprint: string;
17
17
  /** Which agent executed the task (e.g. "coder") */
18
18
  agent: string;
19
- /** Outcome of the task execution */
19
+ /**
20
+ * Outcome of the task execution.
21
+ *
22
+ * PRODUCER COVERAGE (keep this note accurate — directive 2, no unwired code):
23
+ * - `pass` / `fail` are produced today by TWO call sites, deliberately split:
24
+ * 1. `plan/manager.updateTaskStatus` records the TERMINAL outcome after
25
+ * savePlan succeeds — `completed` -> pass, `blocked` -> fail. It lives
26
+ * there, not in the `update_task_status` tool, because the tool is only
27
+ * one of two writers: the council APPROVE fast-path completes tasks via
28
+ * `advanceTaskStateAndPersist` (src/state.ts) with no tool call.
29
+ * 2. `update_task_status` records a `fail` when a council or QA gate
30
+ * BLOCKS a completion. That is a refusal, not a status transition, so
31
+ * it never reaches updateTaskStatus and must be recorded at the tool.
32
+ * - `retry` has a CONSUMER (`summarizeTask` below treats it like `fail`) but
33
+ * no producer. It is deliberately retained for the guardrails
34
+ * transient-retry path (AGENTS.md invariant 9), which owns retry
35
+ * accounting and is out of scope here. Do not add a `retry` producer from
36
+ * the task-status path — a gate block is a real failure, not a retry.
37
+ * - `skip` has neither producer nor consumer (`summarizeTask` ignores it).
38
+ * It is retained only so pre-existing `.swarm/run-memory.jsonl` lines
39
+ * written by hand or by older builds still parse.
40
+ */
20
41
  outcome: 'pass' | 'fail' | 'retry' | 'skip';
21
42
  /** 1-indexed attempt number */
22
43
  attemptNumber: number;
@@ -51,12 +72,39 @@ export declare function recordOutcome(directory: string, entry: RunMemoryEntry):
51
72
  */
52
73
  export declare function getTaskHistory(directory: string, taskId: string): Promise<RunMemoryEntry[]>;
53
74
  /**
54
- * Get all failure and retry entries
75
+ * Input for {@link recordTaskAttempt}. `attemptNumber` and `taskFingerprint`
76
+ * are derived, not supplied — callers know the task, not its history.
77
+ */
78
+ export interface TaskAttemptInput {
79
+ /** Plan.json task ID (e.g. "3.2") */
80
+ taskId: string;
81
+ /** Which agent executed the task (e.g. "coder") */
82
+ agent: string;
83
+ /** Outcome of this attempt */
84
+ outcome: RunMemoryEntry['outcome'];
85
+ /** One-line failure reason — required in practice for fail/retry to be useful */
86
+ failureReason?: string;
87
+ /** Plan `files_touched` for the task; feeds the fingerprint */
88
+ fileTargets?: string[];
89
+ /** Wall-clock time in milliseconds */
90
+ durationMs?: number;
91
+ }
92
+ /**
93
+ * Record one task attempt, deriving the attempt number from prior history.
94
+ *
95
+ * This is the single production producer for `.swarm/run-memory.jsonl`, which
96
+ * `getRunMemorySummary` reads back for cross-turn failure-pattern avoidance.
97
+ *
98
+ * Advisory-only and fail-open by contract: run memory is context enrichment,
99
+ * never a correctness gate, so a write failure must never surface to — or
100
+ * abort — the caller's primary operation (a task status update). The work is
101
+ * still awaited rather than fire-and-forget, so the entry is durable before the
102
+ * caller returns and a test can observe it.
55
103
  *
56
104
  * @param directory - The swarm workspace directory
57
- * @returns Array of fail/retry entries
105
+ * @param input - The attempt to record
58
106
  */
59
- export declare function getFailures(directory: string): Promise<RunMemoryEntry[]>;
107
+ export declare function recordTaskAttempt(directory: string, input: TaskAttemptInput): Promise<void>;
60
108
  /**
61
109
  * Group entries by taskId
62
110
  */
@@ -79,8 +127,8 @@ export declare function getRunMemorySummary(directory: string): Promise<string |
79
127
  export declare const _internals: {
80
128
  generateTaskFingerprint: typeof generateTaskFingerprint;
81
129
  recordOutcome: typeof recordOutcome;
130
+ recordTaskAttempt: typeof recordTaskAttempt;
82
131
  getTaskHistory: typeof getTaskHistory;
83
- getFailures: typeof getFailures;
84
132
  getRunMemorySummary: typeof getRunMemorySummary;
85
133
  groupByTaskId: typeof groupByTaskId;
86
134
  summarizeTask: typeof summarizeTask;
@@ -6,6 +6,7 @@ import type { ToolContext, ToolDefinition } from '@opencode-ai/plugin/tool';
6
6
  import { readTaskEvidenceRaw } from '../gate-evidence.js';
7
7
  import { tryAcquireLock } from '../parallel/file-locks.js';
8
8
  import { loadPlan, updateTaskStatus } from '../plan/manager';
9
+ import { recordTaskAttempt } from '../services/run-memory.js';
9
10
  import { hasActiveLeanTurbo, hasActiveTurboMode } from '../state';
10
11
  import { type ReviewerGateEvidenceKind, type ReviewerGateReasonCode } from '../telemetry.js';
11
12
  import { verifyLeanTurboTaskCompletion } from '../turbo/lean/task-completion';
@@ -26,6 +27,7 @@ export declare const _internals: {
26
27
  verifyLeanTurboTaskCompletion: typeof verifyLeanTurboTaskCompletion;
27
28
  hasPassedDurableGateEvidence: typeof hasPassedDurableGateEvidence;
28
29
  emitReviewerGateDecision: (sessionId: string, taskId: string, blocked: boolean, reasonCode: ReviewerGateReasonCode, evidenceKind: ReviewerGateEvidenceKind) => void;
30
+ recordTaskAttempt: typeof recordTaskAttempt;
29
31
  };
30
32
  /**
31
33
  * Arguments for the update_task_status tool
@@ -17,10 +17,34 @@ export declare function containsPathTraversal(str: string): boolean;
17
17
  */
18
18
  export declare function containsControlChars(str: string): boolean;
19
19
  /**
20
- * Validate a directory path for safety.
20
+ * Validate a **project/workspace root** for safety.
21
+ *
22
+ * Distinct from {@link validateDirectory}, which additionally rejects absolute
23
+ * paths and is therefore only correct for a *relative sub-path*. A workspace
24
+ * root is absolute by contract — `ctx.directory` injected by `createSwarmTool`
25
+ * is always an absolute project root (AGENTS.md invariant 4) — so applying
26
+ * `validateDirectory` to one rejects 100% of real inputs and silently kills
27
+ * whatever feature depends on it. That is exactly how `.swarm/run-memory.jsonl`
28
+ * came to have no producer and a consumer that threw on every call.
29
+ *
30
+ * This validator keeps the checks that are meaningful for a root (empty,
31
+ * traversal segments, control/bidi characters) and drops the absolute-path
32
+ * rejection. Containment of the actual file is NOT this function's job and is
33
+ * unchanged: `validateSwarmPath(directory, filename)` resolves the target under
34
+ * `<directory>/.swarm`, rejects any path that escapes it, and rejects a
35
+ * symlinked `.swarm` base.
36
+ *
37
+ * @param directory - The workspace root to validate
38
+ * @throws Error if the root is invalid
39
+ */
40
+ export declare function validateWorkspaceRoot(directory: string): void;
41
+ /**
42
+ * Validate a relative directory path for safety.
21
43
  * Rejects empty paths, paths with traversal, control characters, and absolute paths.
22
44
  * Throws an Error if the directory is invalid.
23
45
  *
46
+ * Do NOT use this on a project/workspace root — see {@link validateWorkspaceRoot}.
47
+ *
24
48
  * @param directory - The directory string to validate
25
49
  * @throws Error if directory is invalid
26
50
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-swarm",
3
- "version": "7.138.4",
3
+ "version": "7.139.0",
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",