opencode-swarm 7.165.0 → 7.166.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/binaries/win32-arm64/swarm-sandbox-runner.exe +0 -0
  2. package/binaries/win32-x64/swarm-sandbox-runner.exe +0 -0
  3. package/dist/background/delegation-cost-identity.d.ts +41 -0
  4. package/dist/background/delegation-lifecycle.d.ts +24 -5
  5. package/dist/background/pending-delegations.d.ts +2 -0
  6. package/dist/background/pr-monitor-worker.d.ts +60 -6
  7. package/dist/background/pr-subscriptions.d.ts +13 -0
  8. package/dist/cli/{capability-probe-5wa7mcp6.js → capability-probe-faqefhah.js} +2 -1
  9. package/dist/cli/{coder-settlement-89nt4j7g.js → coder-settlement-x0h3h6vd.js} +13 -13
  10. package/dist/cli/{config-doctor-gm6f5chm.js → config-doctor-pjcjeh8f.js} +5 -5
  11. package/dist/cli/{core-91p43zwj.js → core-v11pd1yk.js} +4 -4
  12. package/dist/cli/{curation-policy-bqpmry2n.js → curation-policy-jtzwz6bc.js} +4 -4
  13. package/dist/cli/{curator-drift-hbc3w5zj.js → curator-drift-jpdfwae9.js} +5 -5
  14. package/dist/cli/curator-llm-factory-da5q3gg6.js +70 -0
  15. package/dist/cli/{curator-4bs2hmy9.js → curator-ssvd7evd.js} +40 -40
  16. package/dist/cli/{dispatch-c7xjt7js.js → dispatch-591v13pp.js} +3 -3
  17. package/dist/cli/{evidence-summary-service-g1xd8egd.js → evidence-summary-service-mw6tnsp9.js} +19 -19
  18. package/dist/cli/{gate-evidence-gdmgsz7c.js → gate-evidence-jymaxb82.js} +9 -9
  19. package/dist/cli/guardrail-explain-eva1yrtf.js +71 -0
  20. package/dist/cli/guardrail-log-kzq2sktb.js +23 -0
  21. package/dist/cli/{guardrail-reset-rp9jq0gj.js → guardrail-reset-ea1g3g7d.js} +40 -40
  22. package/dist/cli/hive-promoter-ghjbgsms.js +85 -0
  23. package/dist/cli/{index-6be5caj8.js → index-066xxa4q.js} +3 -3
  24. package/dist/cli/{index-5ythtd9t.js → index-0g5v4s0x.js} +67 -16
  25. package/dist/cli/{index-a0d4fp6r.js → index-0tc0pcmh.js} +1 -1
  26. package/dist/cli/{index-n3pjcks8.js → index-13egyjgv.js} +5 -5
  27. package/dist/cli/{index-tqw8w2n5.js → index-17yszqs5.js} +1 -1
  28. package/dist/cli/{index-8bdk7124.js → index-1zqf2pny.js} +1 -1
  29. package/dist/cli/{index-8d90gzaz.js → index-2sqgbmtq.js} +1 -1
  30. package/dist/cli/{index-xwbn7c8m.js → index-2v17wb75.js} +2 -2
  31. package/dist/cli/{index-y1zhpfk8.js → index-2y4kargd.js} +4 -4
  32. package/dist/cli/{index-hwz46jj7.js → index-399nq780.js} +2509 -1094
  33. package/dist/cli/{index-r5hj3nfe.js → index-3tyym20r.js} +2 -2
  34. package/dist/cli/{index-zycp24b9.js → index-52xdezsh.js} +12 -3
  35. package/dist/cli/{index-2k53pfnc.js → index-6rff2h8x.js} +4 -4
  36. package/dist/cli/{index-6m24v15v.js → index-79sr3fd1.js} +2 -2
  37. package/dist/cli/{index-k1ntjzmf.js → index-8fr2wn18.js} +2 -2
  38. package/dist/cli/{index-dh5th4jn.js → index-8hqkrd2j.js} +1 -1
  39. package/dist/cli/{index-6rx1rdaq.js → index-a7rw4g4s.js} +1 -1
  40. package/dist/cli/{index-w6988bbc.js → index-aftapk6j.js} +75 -1
  41. package/dist/cli/{index-j2svfhzk.js → index-axf65x87.js} +1 -1
  42. package/dist/cli/{index-anxs69ad.js → index-bfr392e7.js} +1 -1
  43. package/dist/cli/{index-c4ddtrqg.js → index-bkd3450m.js} +6 -6
  44. package/dist/cli/{index-ajknebrc.js → index-c20gf089.js} +1 -1
  45. package/dist/cli/{index-qzvry1n1.js → index-crjx4sx0.js} +42 -42
  46. package/dist/cli/{index-jre6tm3v.js → index-edm41q4j.js} +1 -1
  47. package/dist/cli/{index-z6xqpmqg.js → index-ee6ydtfe.js} +1 -1
  48. package/dist/cli/{index-p7hdp3rp.js → index-fc1dqzjp.js} +2 -2
  49. package/dist/cli/{index-4gmt79q9.js → index-gerkwyrr.js} +1 -1
  50. package/dist/cli/{index-hdakb4n9.js → index-gr8ppbq3.js} +16 -13
  51. package/dist/cli/{index-f36hy1x4.js → index-hvk3zs62.js} +1 -1
  52. package/dist/cli/{index-5ebgzb5a.js → index-hwj25q9r.js} +78 -53
  53. package/dist/cli/{index-1v6vc90w.js → index-j29nkq5d.js} +5 -5
  54. package/dist/cli/{index-e45htt92.js → index-jx9f4ke1.js} +1 -1
  55. package/dist/cli/{index-7h94rfem.js → index-k5w284js.js} +16 -14
  56. package/dist/cli/{index-58be2gtd.js → index-nph5g4em.js} +3 -3
  57. package/dist/cli/{index-4fwbbad3.js → index-q1r1cfww.js} +46 -17
  58. package/dist/cli/{index-afpkqsdb.js → index-w11whwn3.js} +14 -7
  59. package/dist/cli/{index-0e9jh9c7.js → index-wf12wckd.js} +3 -3
  60. package/dist/cli/{index-ptsqnxwd.js → index-xezfx7ge.js} +21 -11
  61. package/dist/cli/{index-3xyjvx24.js → index-xwkn5hse.js} +11 -9
  62. package/dist/cli/{index-g8wdekzz.js → index-ybcxvv17.js} +2 -2
  63. package/dist/cli/{index-e6n7cemz.js → index-yt25kpvz.js} +12 -8
  64. package/dist/cli/{index-556ja8an.js → index-yzjaj53h.js} +9 -2
  65. package/dist/cli/{index-gn6ybsc4.js → index-zha9bdj9.js} +8 -8
  66. package/dist/cli/index-zpsr8rpc.js +68 -0
  67. package/dist/cli/index.js +40 -40
  68. package/dist/cli/{knowledge-escalator-eq07pcj3.js → knowledge-escalator-3pjed4tq.js} +14 -14
  69. package/dist/cli/{knowledge-events-rv9q9mkm.js → knowledge-events-a5dwkg30.js} +12 -12
  70. package/dist/cli/{knowledge-link-dgvbqjqg.js → knowledge-link-1zykfk1p.js} +3 -3
  71. package/dist/cli/{knowledge-store-cxcr0ttk.js → knowledge-store-h85efsak.js} +4 -4
  72. package/dist/cli/{knowledge-validator-8qtd9ys0.js → knowledge-validator-76qrf1ev.js} +6 -6
  73. package/dist/cli/{model-preflight-3s1c0zpc.js → model-preflight-b3b5pgsc.js} +2 -2
  74. package/dist/cli/{pending-delegations-dp3g8e7k.js → pending-delegations-zgwfqfac.js} +14 -12
  75. package/dist/cli/{pr-subscriptions-3vx06rar.js → pr-subscriptions-fzy3ks1k.js} +16 -12
  76. package/dist/cli/{pr-workflow-gate-bbet0apk.js → pr-workflow-gate-1gtsn7f0.js} +40 -40
  77. package/dist/cli/{runner-0e3bjeev.js → runner-j3acybhs.js} +4 -4
  78. package/dist/cli/{scan-cursor-zwm0xng7.js → scan-cursor-ahwkxa8j.js} +5 -5
  79. package/dist/cli/{schema-ebfxgya0.js → schema-27sedbfk.js} +3 -3
  80. package/dist/cli/{scope-persistence-6c55akfz.js → scope-persistence-q792yfxh.js} +16 -16
  81. package/dist/cli/{skill-generator-mv5jxzsh.js → skill-generator-g8wbjw6v.js} +16 -16
  82. package/dist/cli/{snapshot-coordination-init-n556wa18.js → snapshot-coordination-init-y6spakwm.js} +40 -40
  83. package/dist/cli/{telemetry-a1yvjerj.js → telemetry-9h1z2w9d.js} +1 -1
  84. package/dist/cli/{worktree-collision-ownership-pp4z4z8p.js → worktree-collision-ownership-pmpnftkd.js} +13 -13
  85. package/dist/cli/{worktree-isolation-69hz9dgg.js → worktree-isolation-4053n0px.js} +40 -40
  86. package/dist/commands/pr-monitor-status.d.ts +2 -0
  87. package/dist/commands/registry.d.ts +8 -0
  88. package/dist/commands/report.d.ts +36 -0
  89. package/dist/db/observability-event-store.d.ts +162 -0
  90. package/dist/git/pr.d.ts +27 -27
  91. package/dist/git/safe-ref.d.ts +51 -0
  92. package/dist/hooks/context-capsule-inject.d.ts +3 -0
  93. package/dist/index.d.ts +6 -1
  94. package/dist/index.js +573 -480
  95. package/dist/observability/catalog.d.ts +8 -4
  96. package/dist/sandbox/executor.d.ts +10 -0
  97. package/dist/sandbox/win32/runner-client.d.ts +7 -0
  98. package/dist/services/context-attribution.d.ts +69 -0
  99. package/dist/services/cost-accounting.d.ts +2 -0
  100. package/dist/telemetry.d.ts +10 -2
  101. package/dist/tools/co-change-analyzer.d.ts +7 -0
  102. package/dist/tools/gh-evidence.d.ts +15 -8
  103. package/dist/tools/pkg-audit.d.ts +23 -0
  104. package/dist/utils/gh-executable.d.ts +106 -0
  105. package/dist/utils/merge.d.ts +26 -0
  106. package/opencode-swarm.schema.json +1 -1
  107. package/package.json +1 -1
  108. package/dist/cli/curator-llm-factory-fhbjwar0.js +0 -70
  109. package/dist/cli/guardrail-explain-1nfbtpgg.js +0 -71
  110. package/dist/cli/guardrail-log-nyggdv04.js +0 -23
  111. package/dist/cli/hive-promoter-39xb4tx2.js +0 -85
  112. package/dist/cli/index-zjygnfay.js +0 -33
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * The event catalog (issue #2029).
3
3
  *
4
- * Exactly 59 entries, matching the `TelemetryEvent` union at
5
- * `src/telemetry.ts:15-165`. Thirty-eight predate the #2029 contract; the 39th is
4
+ * Exactly 61 entries, matching the `TelemetryEvent` union at
5
+ * `src/telemetry.ts:16-172`. Thirty-eight predate the #2029 contract; the 39th is
6
6
  * `agent_conflict_detected` (previously emitted through a force-cast past the
7
7
  * type system), the 40th is `close_archive_result` (issue #2030 — the
8
8
  * structured close/archive result event), the 41st is the bounded diagnostic
@@ -28,7 +28,11 @@
28
28
  * `council_round_transition`, and the 59th is `council_attempt_unscoped`
29
29
  * (issue #2046 item 9 — canonical council attempt / accepted-transition
30
30
  * observations joined to the lifecycle correlation system via the
31
- * server-derived `councilRoundId`). These late
31
+ * server-derived `councilRoundId`). The 60th is
32
+ * `context_source_attribution` and the 61st is `verdict_row_pipe_recovery`
33
+ * (issue #2482 — D3: honest savings attribution with the omit-when-unknown
34
+ * rule, and the #2184 verdict-row pipe-recovery fidelity class in the event
35
+ * lifecycle). These late
32
36
  * additions are instances
33
37
  * of the defect class this contract exists to close: an event kind entering
34
38
  * the stream with no registration.
@@ -84,7 +88,7 @@ export interface CatalogEntry {
84
88
  /**
85
89
  * Whether an event of this kind must carry `trace.parentSpanId`.
86
90
  *
87
- * `false` for all 59 entries today, and that is a truthful statement about
91
+ * `false` for all 61 entries today, and that is a truthful statement about
88
92
  * the current system rather than a placeholder: no producer supplies a
89
93
  * parent span, so `createObservation` never sets one. Setting this to `true`
90
94
  * for a kind whose producer cannot supply a parent would make every
@@ -51,6 +51,16 @@ export interface SandboxExecutor {
51
51
  * Returns a record of env vars to set/unset.
52
52
  */
53
53
  getEnvOverrides(): Record<string, string | null>;
54
+ /**
55
+ * Probe result for executors backed by a native runner binary (Windows).
56
+ * Optional: executors without a runner binary leave it undefined and
57
+ * /swarm diagnose omits the downgrade reason for them.
58
+ */
59
+ readonly probeResult?: {
60
+ error?: string;
61
+ } | null;
62
+ /** Reason recorded via disable(), if this executor was disabled. */
63
+ readonly disabledReason?: string | null;
54
64
  }
55
65
  export interface SandboxPolicyOptions {
56
66
  network_mode?: 'off' | 'on';
@@ -10,6 +10,8 @@
10
10
  * kill() in finally blocks.
11
11
  */
12
12
  import { spawn, spawnSync } from 'node:child_process';
13
+ /** Policy/probe protocol version this client speaks. */
14
+ export declare const RUNNER_PROTOCOL_SCHEMA_VERSION = 1;
13
15
  /** Result of probing the runner binary for capabilities. */
14
16
  export interface RunnerProbeResult {
15
17
  available: boolean;
@@ -23,6 +25,8 @@ export interface RunnerProbeResult {
23
25
  is_admin: boolean;
24
26
  os_version: string;
25
27
  arch: string;
28
+ runner_version?: string;
29
+ protocol_schema_version?: number;
26
30
  } | null;
27
31
  error?: string;
28
32
  }
@@ -77,6 +81,8 @@ export interface SandboxPolicy {
77
81
  network_mode: 'off' | 'on';
78
82
  env_allowlist: string[];
79
83
  env_overrides: Record<string, string>;
84
+ /** Keys the runner must remove from the child environment (null overrides). */
85
+ env_unsets: string[];
80
86
  path_stubs: string[];
81
87
  private_desktop: boolean;
82
88
  deny_alternate_data_streams: boolean;
@@ -92,6 +98,7 @@ export declare const _internals: {
92
98
  findRunnerBinary: () => string | null;
93
99
  spawnRunner: typeof spawnSync;
94
100
  spawnAsync: typeof spawn;
101
+ runtimeDir: string | null;
95
102
  };
96
103
  /**
97
104
  * Probe the runner binary for capabilities.
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Context-source savings attribution (issue #2482 / D3, absorbing #1990's
3
+ * honesty rule).
4
+ *
5
+ * Records, per injected context source, what the surface returned and what it
6
+ * plausibly saved versus reading the cited files in full:
7
+ *
8
+ * - `tokensReturned` — the token estimate of the actually-injected content.
9
+ * - `tokensSavedEstimate` = max(0, citedFileTokensTotal − tokensReturned),
10
+ * explicitly labeled an estimate (payload flag `estimate: true`).
11
+ *
12
+ * HONESTY RULE (the deliverable, #1990): when the cited-file token total is
13
+ * unknown — no citation set, or no file size could be measured — this module
14
+ * records NOTHING for that call. No zero, no guess: absent measurements are
15
+ * omitted entirely rather than fabricated (a zero would silently claim the
16
+ * source saved nothing, which is a measurement we do not have).
17
+ *
18
+ * Emission is fail-open (never throws), rides the existing telemetry stream
19
+ * (legacy `.swarm/telemetry.jsonl` line + the SQLite observability sink from
20
+ * issue #2482), and is aggregated by `/swarm report`. This module creates no
21
+ * new durable file stream.
22
+ */
23
+ import type { TelemetryEvent } from '../telemetry.js';
24
+ /** Context sources recognized by the attribution event. */
25
+ export type ContextAttributionSource = 'context_pack' | 'lane-orientation' | 'reflection' | 'ask';
26
+ export interface ContextAttributionInput {
27
+ sessionId: string;
28
+ source: ContextAttributionSource;
29
+ /** Token estimate of the content actually returned/injected. */
30
+ tokensReturned: number;
31
+ /**
32
+ * Sum of token estimates over the cited files, or `undefined`/`null` when
33
+ * unknown (module then records nothing — the honesty rule).
34
+ */
35
+ citedFileTokensTotal?: number | null;
36
+ taskId?: string;
37
+ }
38
+ /** Token-per-cited-file measurement for one production injection site. */
39
+ export interface CitedFileTokenMeasurement {
40
+ /** Total token estimate over the files whose sizes were measured. */
41
+ total: number;
42
+ /** Number of files whose size could NOT be measured (stat failed). */
43
+ unmeasured: number;
44
+ }
45
+ /**
46
+ * Estimate tokens from a byte length using the same chars-per-token heuristic
47
+ * family as `estimateTokens` (conservative 4 bytes/token). Used ONLY for
48
+ * file-size-based estimates where full content is not read.
49
+ */
50
+ export declare function estimateTokensFromBytes(bytes: number): number;
51
+ /**
52
+ * Measure the cited-file token total from file sizes. Files whose size cannot
53
+ * be measured are skipped (never counted as zero); `unmeasured` reports how
54
+ * many. The loop is bounded — a pathological citation set never turns into an
55
+ * unbounded stat storm.
56
+ */
57
+ export declare function measureCitedFileTokens(filePaths: readonly string[], statFn: (p: string) => {
58
+ size: number;
59
+ }, maxFiles?: number): CitedFileTokenMeasurement;
60
+ /** DI seam (repo `_internals` convention). */
61
+ export declare const _internals: {
62
+ emit: (event: TelemetryEvent, data: Record<string, unknown>) => void;
63
+ };
64
+ /**
65
+ * Record one context-source attribution. Emits the
66
+ * `context_source_attribution` event ONLY when both measurements are known
67
+ * (#1990 omit-when-unknown); returns true when an event was emitted.
68
+ */
69
+ export declare function recordContextSourceAttribution(input: ContextAttributionInput): boolean;
@@ -66,6 +66,8 @@ export type DelegationCostFields = TokenUsage & {
66
66
  model?: string;
67
67
  gate?: string;
68
68
  retry_index?: number;
69
+ /** #2482: marks a recovered eventless-terminal end (stale sweep / terminal-without-event). */
70
+ recovered?: boolean;
69
71
  };
70
72
  export type DelegationCostInput = {
71
73
  raw?: unknown;
@@ -1,3 +1,4 @@
1
+ import type { ObservabilityEvent } from './observability/envelope.js';
1
2
  import { createObservation, toLegacyTelemetryLine } from './observability/index.js';
2
3
  import type { DelegationCostFields } from './services/cost-accounting.js';
3
4
  export type TelemetryEvent = 'session_started' | 'session_ended' | 'agent_activated' | 'delegation_begin' | 'delegation_end' | 'delegation_cost_correction' | 'delegation_cost_binding' | 'delegation_cost_join' | 'task_state_changed' | 'gate_passed' | 'gate_failed' | 'gate_parse_error' | 'reviewer_gate_decision' | 'phase_changed' | 'budget_updated' | 'context_pruned' | 'retrieval_routed' | 'model_fallback'
@@ -32,7 +33,7 @@ export type TelemetryEvent = 'session_started' | 'session_ended' | 'agent_activa
32
33
  * `prm_hard_stop` TRIGGER emitted by `src/prm/escalation.ts`. A trigger with
33
34
  * no matching delivery means the containment never reached the agent.
34
35
  */
35
- | 'prm_hard_stop_delivered' | 'agent_conflict_detected' | 'close_archive_result' | 'knowledge_receipt_transition' | 'knowledge_maintenance' | 'residue_health' | 'context_telemetry_health' | 'skill_usage_health' | 'core_events_health' | 'shell_audit_health' | 'trajectory_health' | 'learning_health_alarm' | 'pr_subscription_health' | 'council_attempt' | 'council_round_transition' | 'council_attempt_unscoped';
36
+ | 'prm_hard_stop_delivered' | 'agent_conflict_detected' | 'close_archive_result' | 'knowledge_receipt_transition' | 'knowledge_maintenance' | 'residue_health' | 'context_telemetry_health' | 'skill_usage_health' | 'core_events_health' | 'shell_audit_health' | 'trajectory_health' | 'learning_health_alarm' | 'pr_subscription_health' | 'council_attempt' | 'council_round_transition' | 'council_attempt_unscoped' | 'context_source_attribution' | 'verdict_row_pipe_recovery';
36
37
  /** Stable classification for how a reviewer-gate decision was established. */
37
38
  export type ReviewerGateEvidenceKind = 'genuine' | 'fallback' | 'data_quality' | 'block';
38
39
  /**
@@ -42,7 +43,14 @@ export type ReviewerGateEvidenceKind = 'genuine' | 'fallback' | 'data_quality' |
42
43
  * analytics, so additions are allowed but existing values must not be renamed.
43
44
  */
44
45
  export type ReviewerGateReasonCode = 'lean_turbo_completed_lane' | 'standard_turbo_non_tier3' | 'durable_evidence_complete' | 'workflow_state_complete' | 'stage_b_parallel_complete' | 'no_active_sessions' | 'zero_valid_sessions' | 'restart_recovery_complete' | 'scoped_delegation_complete' | 'unscoped_delegation_complete' | 'corrupt_evidence' | 'required_gates_missing' | 'inspection_error';
45
- export type TelemetryListener = (event: TelemetryEvent, data: Record<string, unknown>) => void;
46
+ export type TelemetryListener = (event: TelemetryEvent, data: Record<string, unknown>,
47
+ /**
48
+ * The canonical observability envelope built by this emit (issue #2482).
49
+ * Always passed positionally by `emit()`; optional so every existing
50
+ * two-argument listener stays assignable. The SQLite observability sink
51
+ * (`src/db/observability-event-store.ts`) is the canonical consumer.
52
+ */
53
+ canonical?: ObservabilityEvent) => void;
46
54
  export declare function startHeartbeatTracking(): void;
47
55
  export declare function getLastHeartbeat(sessionId: string): number | undefined;
48
56
  export declare function stopHeartbeatTracking(): void;
@@ -1,5 +1,10 @@
1
+ import * as child_process from 'node:child_process';
1
2
  import type { tool } from '@opencode-ai/plugin';
2
3
  import type { SwarmKnowledgeEntry } from '../hooks/knowledge-types.js';
4
+ /** Lazy-bind so mock.module can intercept at call time (#330); all internal
5
+ * calls route through _internals.getExecFileAsync so tests can replace the
6
+ * seam directly (PRR-020). */
7
+ declare function getExecFileAsync(): typeof child_process.execFile.__promisify__;
3
8
  export interface CoChangeEntry {
4
9
  fileA: string;
5
10
  fileB: string;
@@ -55,4 +60,6 @@ export declare const _internals: {
55
60
  detectDarkMatter: typeof detectDarkMatter;
56
61
  darkMatterToKnowledgeEntries: typeof darkMatterToKnowledgeEntries;
57
62
  formatDarkMatterOutput: typeof formatDarkMatterOutput;
63
+ getExecFileAsync: typeof getExecFileAsync;
58
64
  };
65
+ export {};
@@ -1,18 +1,24 @@
1
1
  import type { ToolDefinition } from '@opencode-ai/plugin/tool';
2
2
  import { resolveExecutableFromPath, runExternalTool } from '../utils/external-tool-runner';
3
+ import { resolveGhExecutable } from '../utils/gh-executable';
3
4
  interface GhBinaryCandidateOptions {
4
- env?: Pick<NodeJS.ProcessEnv, 'ProgramFiles' | 'ProgramFiles(x86)' | 'LOCALAPPDATA'>;
5
+ env?: NodeJS.ProcessEnv;
5
6
  platform?: NodeJS.Platform;
6
7
  }
7
8
  export declare function resolveGhBinaryCandidates(options?: GhBinaryCandidateOptions): string[];
8
9
  /**
9
- * Resolve the `gh` binary to invoke. Exported (issue #2236 hardening, lane
10
- * C1b) so other call sites that need a `gh` executable — e.g. `src/git/pr.ts`,
11
- * `src/commands/pr-monitor-status.ts` — reuse this resolver instead of
12
- * spawning a bare `'gh'` literal or inventing a second gh resolver. Returns
13
- * `null` when no candidate is found; callers should fall back to the bare
14
- * `'gh'` literal (mirrors `resolveGitExecutable()`'s "never regress a working
15
- * host" fallback in `src/utils/git-executable.ts`).
10
+ * Resolve the `gh` binary for the gh_evidence tool. Exported (issue #2236
11
+ * hardening, lane C1b) so other call sites that need a `gh` executable — e.g.
12
+ * `src/git/pr.ts`, `src/commands/pr-monitor-status.ts` — reuse this resolver
13
+ * instead of spawning a bare `'gh'` literal or inventing a second gh resolver.
14
+ *
15
+ * Issue #2476 AC1: delegates to the hardened twin of the git resolver
16
+ * (`src/utils/gh-executable.ts`) — absolute-candidate-first ordering,
17
+ * absoluteness requirement, `gh --version` probe, bounded budget, caching.
18
+ * Returns `null` when nothing validated (the resolver's bare-`'gh'` terminal
19
+ * fallback maps here to null so the tool renders its gh-not-found guidance
20
+ * exactly as a scan-miss did before); callers that spawn directly should use
21
+ * `resolveGhExecutable()` instead, which never returns null.
16
22
  */
17
23
  export declare function resolveGhBinary(): string | null;
18
24
  /**
@@ -26,6 +32,7 @@ export declare const gh_evidence: ToolDefinition;
26
32
  export declare const _internals: {
27
33
  resolveGhBinaryCandidates: typeof resolveGhBinaryCandidates;
28
34
  resolveExecutableFromPath: typeof resolveExecutableFromPath;
35
+ resolveGhExecutable: typeof resolveGhExecutable;
29
36
  resolveGhBinary: typeof resolveGhBinary;
30
37
  runExternalTool: typeof runExternalTool;
31
38
  };
@@ -9,7 +9,30 @@ import { bunSpawn } from '../utils/bun-compat';
9
9
  * functions gate strictly on a non-zero exit and were dispositioned
10
10
  * SAFE-EXIT-CHECK by that sweep.
11
11
  */
12
+ /**
13
+ * Resolve the spawn command prefix for a package-audit binary (issue #2476
14
+ * AC5). On POSIX (or when resolution fails) the bare name is returned -- the
15
+ * historical behavior, which works there. On win32 the absolute candidate is
16
+ * resolved via resolveExecutableFromPath (.exe/.cmd/.bat variants); a
17
+ * `.cmd`/`.bat` hit cannot be spawned directly by Node (EINVAL since the
18
+ * CVE-2024-27980 hardening), so it is routed through cmd.exe as
19
+ * `/d /s /c call "<resolved>"` -- everything after `/c` is cmd's own command
20
+ * line, the repo-documented windowsVerbatimArguments pattern. Empirically
21
+ * verified on Windows (node & Bun): a bare quoted tail `"<path>"` is mangled
22
+ * by cmd's /s quote-stripping (the last quote in the line is removed), while
23
+ * the `call` prefix keeps the quoted path intact for paths containing spaces
24
+ * such as C:\Program Files. Callers append their fixed literal arguments
25
+ * (`audit --json`) as separate argv elements; verbatim joining keeps them
26
+ * outside the quoted path. The only interpolated value is the resolved
27
+ * ABSOLUTE path, rejected when it contains any cmd metacharacter
28
+ * (`" & | < > ^ ! %`) so the verbatim command line degrades to the bare-name
29
+ * fallback rather than through any cmd re-interpretation; the remaining
30
+ * tokens are fixed literals.
31
+ */
32
+ declare function resolveAuditCommandDefault(name: 'npm' | 'cargo'): string[];
12
33
  export declare const _internals: {
13
34
  bunSpawn: typeof bunSpawn;
35
+ resolveAuditCommand: typeof resolveAuditCommandDefault;
14
36
  };
15
37
  export declare const pkg_audit: ReturnType<typeof tool>;
38
+ export {};
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Single source of truth for "what absolute path do we invoke for gh" — the
3
+ * gh twin of `resolveGitExecutable()` in `src/utils/git-executable.ts`
4
+ * (issue #2476 AC1 / source issue #2262).
5
+ *
6
+ * The pre-fix resolver (`resolveGhBinaryCandidates` in
7
+ * `src/tools/gh-evidence.ts` + `resolveExecutableFromPath`) put the bare
8
+ * name FIRST, so a full PATH scan for `gh` beat every ProgramFiles absolute
9
+ * candidate; accepted any stat-able regular file (a 20-byte text file named
10
+ * gh.exe passed); and had no `gh --version` behavioral probe, no budget, and
11
+ * no cache. That matters MORE than the git case: `gh` runs with the user's
12
+ * GitHub token, so a hijack is credential theft in addition to code
13
+ * execution.
14
+ *
15
+ * Contract (mirrors git-executable.ts; deviations called out inline):
16
+ *
17
+ * 1. explicit override — the `OPENCODE_SWARM_GH_BINARY` env var ONLY.
18
+ * There is deliberately NO config-file `gh.binary` key: the config path
19
+ * is the attack surface `enforceGitBinaryProvenance` exists to strip
20
+ * for git, and gh never had one. Env-only keeps every override
21
+ * user-controlled by construction.
22
+ * 2. platform absolute candidates (win32 ProgramFiles/LOCALAPPDATA — the
23
+ * set `resolveGhBinaryCandidates` already knew — plus darwin/linux
24
+ * install locations, which the old resolver lacked entirely);
25
+ * 3. ALL PATH matches for `gh` (win32: `.exe`/`.cmd`/`.bat` variants);
26
+ * 4. bare `'gh'` LAST, unprobed, so a host that works via plain PATH
27
+ * lookup never regresses.
28
+ *
29
+ * Each non-bare candidate must be ABSOLUTE and is validated once with
30
+ * `gh --version` (bounded, explicit cwd) whose output must match
31
+ * GH_VERSION_PATTERN — exit 0 alone does not accept a candidate. NOT AN
32
+ * ANTI-TAMPERING CONTROL (a hostile program can print `gh version 2.x`); it
33
+ * stops ACCIDENTS — a non-gh that merely exits 0, a broken shim. The
34
+ * trust-boundary control is that no repository-controlled value can name a
35
+ * candidate at all (env-only override).
36
+ *
37
+ * Bounded probing (AGENTS.md invariant 1): per-probe timeout 250 ms, total
38
+ * first-resolution budget 1000 ms. gh resolution is LAZY (tool/ghExec call
39
+ * paths, never plugin init), so the sync API below is sufficient — there is
40
+ * no init-path need for an async variant.
41
+ *
42
+ * NEVER throws: both non-accepting outcomes (budget exhausted, every
43
+ * candidate rejected) return the bare `'gh'` fallback, memoized with a 60 s
44
+ * TTL so a host that installs gh mid-session recovers (same rationale as
45
+ * git-executable.ts — a slash-less spawn does not resolve against the PATH
46
+ * this module enumerates, so "gh is missing" is not a state this resolver
47
+ * may report).
48
+ */
49
+ import { spawnSync } from 'node:child_process';
50
+ /** Env var escape hatch — a blocked user can set this without editing files. */
51
+ export declare const GH_BINARY_ENV_VAR = "OPENCODE_SWARM_GH_BINARY";
52
+ /**
53
+ * `gh --version` prints `gh version 2.74.0 (2025-...)` — a fixed format
54
+ * string in gh's own root command. Same accident-not-attacker contract as
55
+ * `GIT_VERSION_PATTERN` (see git-executable.ts); anchored to the first line.
56
+ */
57
+ export declare const GH_VERSION_PATTERN: RegExp;
58
+ export type GhResolutionCandidateSource = 'override' | 'platform' | 'path';
59
+ export interface GhResolutionAttempt {
60
+ source: GhResolutionCandidateSource;
61
+ candidate: string;
62
+ accepted: boolean;
63
+ /** Rejection reason; absent when `accepted` is true. */
64
+ reason?: string;
65
+ }
66
+ export interface GhResolutionDescription {
67
+ resolved: boolean;
68
+ resolvedPath?: string;
69
+ attempts: GhResolutionAttempt[];
70
+ overrideValue?: string;
71
+ }
72
+ /**
73
+ * Windows install locations, kept in one place so the legacy
74
+ * `resolveGhBinaryCandidates` export in gh-evidence.ts can share the set.
75
+ * Paths are built with native separators via path.join by the caller.
76
+ */
77
+ export declare function windowsGhAbsoluteCandidates(env: NodeJS.ProcessEnv): string[];
78
+ /**
79
+ * Resolve the gh executable to invoke. Lazy, memoized, bounded by
80
+ * TOTAL_BUDGET_MS, never throws. Returns a validated absolute path or the
81
+ * bare `'gh'` fallback.
82
+ */
83
+ export declare function resolveGhExecutable(): string;
84
+ /** Exported for tests; clears the memoized cache (and bumps the generation). */
85
+ export declare function resetGhExecutableCache(): void;
86
+ /**
87
+ * TEST-ONLY seam — NOT a production API, do not call from `src/`. Pre-seeds
88
+ * the resolver cache with an explicit "success" entry so
89
+ * `resolveGhExecutable()` returns `value` with zero probe spawns. Distinct
90
+ * from gh-evidence.ts's `__seedGhBinaryForTests` (which pins only that
91
+ * wrapper's legacy layer): neither bypasses the other.
92
+ */
93
+ export declare function __seedGhExecutableForTests(value: string): void;
94
+ /** Diagnostic surface: candidates tried in the most recent probe cycle. */
95
+ export declare function describeGhResolution(): GhResolutionDescription;
96
+ /**
97
+ * DI seam for testability (repo convention — see git-executable.ts).
98
+ * `platform`/`env` let tests drive every platform branch regardless of the
99
+ * host OS; `now` makes the TTL and budget deterministically testable.
100
+ */
101
+ export declare const _internals: {
102
+ spawnSync: typeof spawnSync;
103
+ platform: () => NodeJS.Platform;
104
+ env: () => NodeJS.ProcessEnv;
105
+ now: () => number;
106
+ };
@@ -1,5 +1,31 @@
1
1
  export declare const MAX_MERGE_DEPTH = 10;
2
+ /**
3
+ * Keys that must never be merged, at any depth (issue #2476 AC2 / source
4
+ * issue #2264). `JSON.parse` creates `__proto__` as an OWN ENUMERABLE data
5
+ * property (CreateDataProperty, not [[Set]]), so `Object.keys(override)`
6
+ * yields it and the plain assignment below would invoke the
7
+ * `Object.prototype.__proto__` setter and reparent the merged object.
8
+ * `constructor`/`prototype` are the sibling prototype-pollution carriers.
9
+ * Only the OVERRIDE side is checked: that is the untrusted side at every
10
+ * production call site (repo-supplied project config over user config at
11
+ * `src/config/loader.ts`; user scoring config over defaults at
12
+ * `src/config/constants.ts`) — `base` is either caller-built defaults or an
13
+ * already-vetted earlier merge.
14
+ */
15
+ export declare const DANGEROUS_MERGE_KEYS: ReadonlySet<string>;
16
+ /** Typed, fail-closed rejection of a dangerous merge key (issue #2476 AC2). */
17
+ export declare class DangerousMergeKeyError extends Error {
18
+ readonly key: string;
19
+ readonly path: string;
20
+ constructor(key: string, path: string);
21
+ }
2
22
  /**
3
23
  * Deep merge two objects, with override values taking precedence.
24
+ *
25
+ * Throws `DangerousMergeKeyError` when the override object carries
26
+ * `__proto__`, `constructor`, or `prototype` at ANY depth (issue #2476 AC2).
27
+ * The config loader catches this at the repo-supplied project-config merge
28
+ * and continues with user-level config only; other callers get the typed
29
+ * throw as fail-closed semantics.
4
30
  */
5
31
  export declare function deepMerge<T extends Record<string, unknown>>(base?: T, override?: T): T | undefined;
@@ -1875,7 +1875,7 @@
1875
1875
  },
1876
1876
  "auto_checkpoint_threshold": {
1877
1877
  "default": 3,
1878
- "description": "Maximum number of checkpoints to retain. Oldest checkpoints are evicted when this limit is exceeded.",
1878
+ "description": "Number of completed tasks that trigger an automatic checkpoint. Retention of old checkpoints is controlled separately by max_retention.",
1879
1879
  "type": "integer",
1880
1880
  "minimum": 1,
1881
1881
  "maximum": 20
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-swarm",
3
- "version": "7.165.0",
3
+ "version": "7.166.1",
4
4
  "description": "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -1,70 +0,0 @@
1
- // @bun
2
- import {
3
- createCuratorLLMDelegate
4
- } from "./index-hwz46jj7.js";
5
- import"./index-8d90gzaz.js";
6
- import"./index-f36hy1x4.js";
7
- import"./index-hdakb4n9.js";
8
- import"./index-k1ntjzmf.js";
9
- import"./index-5ythtd9t.js";
10
- import"./index-tqw8w2n5.js";
11
- import"./index-txdagbh7.js";
12
- import"./index-cw912re7.js";
13
- import"./index-6be5caj8.js";
14
- import"./index-n3pjcks8.js";
15
- import"./index-g8wdekzz.js";
16
- import"./index-70ha9e09.js";
17
- import"./index-dh5th4jn.js";
18
- import"./index-9ss2m4rs.js";
19
- import"./index-ptsqnxwd.js";
20
- import"./index-zsrtt42s.js";
21
- import"./index-7h94rfem.js";
22
- import"./index-6chhqq2n.js";
23
- import"./index-8bdk7124.js";
24
- import"./index-b43rt5ph.js";
25
- import"./index-q7sjgr1y.js";
26
- import"./index-e6n7cemz.js";
27
- import"./index-p7hdp3rp.js";
28
- import"./index-afpkqsdb.js";
29
- import"./index-gn6ybsc4.js";
30
- import"./index-anxs69ad.js";
31
- import"./index-z6xqpmqg.js";
32
- import"./index-p612v1mv.js";
33
- import"./index-2k53pfnc.js";
34
- import"./index-ajknebrc.js";
35
- import"./index-rtry5xyf.js";
36
- import"./index-58be2gtd.js";
37
- import"./index-3qf1vxtb.js";
38
- import"./index-n832052r.js";
39
- import"./index-3xyjvx24.js";
40
- import"./index-y1zhpfk8.js";
41
- import"./index-xwbn7c8m.js";
42
- import"./index-556ja8an.js";
43
- import"./index-6m24v15v.js";
44
- import"./index-e45htt92.js";
45
- import"./index-w6988bbc.js";
46
- import"./index-ry16d01s.js";
47
- import"./index-n4fzmqz8.js";
48
- import"./index-j2svfhzk.js";
49
- import"./index-c4ddtrqg.js";
50
- import"./index-ae75rja9.js";
51
- import"./index-6rx1rdaq.js";
52
- import"./index-7qefgq4j.js";
53
- import"./index-jre6tm3v.js";
54
- import"./index-gy0nyfbw.js";
55
- import"./index-5ebgzb5a.js";
56
- import"./index-7g4c7s5r.js";
57
- import"./index-zycp24b9.js";
58
- import"./index-9e6fdz2h.js";
59
- import"./index-4rhhvd1a.js";
60
- import"./index-0e9jh9c7.js";
61
- import"./index-a0d4fp6r.js";
62
- import"./index-zjygnfay.js";
63
- import"./index-bk5tah7q.js";
64
- import"./index-bpmtbmy9.js";
65
- import"./index-4fwbbad3.js";
66
- import"./index-zgwm4ryv.js";
67
- import"./index-a76rekgs.js";
68
- export {
69
- createCuratorLLMDelegate
70
- };
@@ -1,71 +0,0 @@
1
- // @bun
2
- import {
3
- handleGuardrailExplain
4
- } from "./index-r5hj3nfe.js";
5
- import"./index-hwz46jj7.js";
6
- import"./index-8d90gzaz.js";
7
- import"./index-f36hy1x4.js";
8
- import"./index-hdakb4n9.js";
9
- import"./index-k1ntjzmf.js";
10
- import"./index-5ythtd9t.js";
11
- import"./index-tqw8w2n5.js";
12
- import"./index-txdagbh7.js";
13
- import"./index-cw912re7.js";
14
- import"./index-6be5caj8.js";
15
- import"./index-n3pjcks8.js";
16
- import"./index-g8wdekzz.js";
17
- import"./index-70ha9e09.js";
18
- import"./index-dh5th4jn.js";
19
- import"./index-9ss2m4rs.js";
20
- import"./index-ptsqnxwd.js";
21
- import"./index-zsrtt42s.js";
22
- import"./index-7h94rfem.js";
23
- import"./index-6chhqq2n.js";
24
- import"./index-8bdk7124.js";
25
- import"./index-b43rt5ph.js";
26
- import"./index-q7sjgr1y.js";
27
- import"./index-e6n7cemz.js";
28
- import"./index-p7hdp3rp.js";
29
- import"./index-afpkqsdb.js";
30
- import"./index-gn6ybsc4.js";
31
- import"./index-anxs69ad.js";
32
- import"./index-z6xqpmqg.js";
33
- import"./index-p612v1mv.js";
34
- import"./index-2k53pfnc.js";
35
- import"./index-ajknebrc.js";
36
- import"./index-rtry5xyf.js";
37
- import"./index-58be2gtd.js";
38
- import"./index-3qf1vxtb.js";
39
- import"./index-n832052r.js";
40
- import"./index-3xyjvx24.js";
41
- import"./index-y1zhpfk8.js";
42
- import"./index-xwbn7c8m.js";
43
- import"./index-556ja8an.js";
44
- import"./index-6m24v15v.js";
45
- import"./index-e45htt92.js";
46
- import"./index-w6988bbc.js";
47
- import"./index-ry16d01s.js";
48
- import"./index-n4fzmqz8.js";
49
- import"./index-j2svfhzk.js";
50
- import"./index-c4ddtrqg.js";
51
- import"./index-ae75rja9.js";
52
- import"./index-6rx1rdaq.js";
53
- import"./index-7qefgq4j.js";
54
- import"./index-jre6tm3v.js";
55
- import"./index-gy0nyfbw.js";
56
- import"./index-5ebgzb5a.js";
57
- import"./index-7g4c7s5r.js";
58
- import"./index-zycp24b9.js";
59
- import"./index-9e6fdz2h.js";
60
- import"./index-4rhhvd1a.js";
61
- import"./index-0e9jh9c7.js";
62
- import"./index-a0d4fp6r.js";
63
- import"./index-zjygnfay.js";
64
- import"./index-bk5tah7q.js";
65
- import"./index-bpmtbmy9.js";
66
- import"./index-4fwbbad3.js";
67
- import"./index-zgwm4ryv.js";
68
- import"./index-a76rekgs.js";
69
- export {
70
- handleGuardrailExplain
71
- };
@@ -1,23 +0,0 @@
1
- // @bun
2
- import {
3
- handleGuardrailLog
4
- } from "./index-4gmt79q9.js";
5
- import"./index-hdakb4n9.js";
6
- import"./index-z6xqpmqg.js";
7
- import"./index-p612v1mv.js";
8
- import"./index-xwbn7c8m.js";
9
- import"./index-556ja8an.js";
10
- import"./index-j2svfhzk.js";
11
- import"./index-7qefgq4j.js";
12
- import"./index-gy0nyfbw.js";
13
- import"./index-5ebgzb5a.js";
14
- import"./index-0e9jh9c7.js";
15
- import"./index-a0d4fp6r.js";
16
- import"./index-zjygnfay.js";
17
- import"./index-bk5tah7q.js";
18
- import"./index-bpmtbmy9.js";
19
- import"./index-zgwm4ryv.js";
20
- import"./index-a76rekgs.js";
21
- export {
22
- handleGuardrailLog
23
- };