opencode-swarm 7.139.0 → 7.139.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/.opencode/skills/swarm-pr-review/SKILL.md +15 -0
  2. package/README.md +7 -6
  3. package/dist/cli/{config-doctor-aszp7z1h.js → config-doctor-hrb61yqe.js} +2 -2
  4. package/dist/cli/{core-3s832mxx.js → core-g2dfh9fq.js} +1 -1
  5. package/dist/cli/{curation-policy-a3hs73f7.js → curation-policy-4tp0mbcb.js} +7 -7
  6. package/dist/cli/{curator-drift-jpap6hv4.js → curator-drift-vfh07mqy.js} +5 -2
  7. package/dist/cli/{curator-llm-factory-e8ngwyjm.js → curator-llm-factory-hvw13hmr.js} +28 -28
  8. package/dist/cli/{curator-zxjqcc8r.js → curator-vpcs1p1v.js} +28 -28
  9. package/dist/cli/{evidence-summary-service-qfhjfxdz.js → evidence-summary-service-kzxr71yd.js} +9 -9
  10. package/dist/cli/{gate-evidence-m2grv70v.js → gate-evidence-z2b1ymnw.js} +5 -5
  11. package/dist/cli/{guardrail-explain-rqpmzxyy.js → guardrail-explain-k62h3c92.js} +29 -29
  12. package/dist/cli/{guardrail-log-vd4a0ng5.js → guardrail-log-2ftew0p3.js} +3 -3
  13. package/dist/cli/{hive-promoter-jc5vym27.js → hive-promoter-mpf0cfkk.js} +28 -28
  14. package/dist/cli/{index-4ft523nb.js → index-0wp67gqj.js} +143 -89
  15. package/dist/cli/{index-ymszzvnr.js → index-3eddtgxt.js} +1 -1
  16. package/dist/cli/{index-67yqywan.js → index-3radty3f.js} +2 -2
  17. package/dist/cli/{index-p2dz85tv.js → index-4xbyy6aw.js} +2 -2
  18. package/dist/cli/{index-a614s16f.js → index-5j6chvj8.js} +1 -1
  19. package/dist/cli/{index-tcdcj1g2.js → index-5w7ekpy3.js} +2 -2
  20. package/dist/cli/{index-nbgw5dxa.js → index-5zyk8qgv.js} +2 -2
  21. package/dist/cli/{index-tyh0p5e8.js → index-668dpw5e.js} +1 -1
  22. package/dist/cli/{index-6q240xgm.js → index-6c5f309q.js} +2 -2
  23. package/dist/cli/{index-s428dmy6.js → index-6w1re1qn.js} +2 -2
  24. package/dist/cli/{index-nsnfvckc.js → index-8gftfvpp.js} +1 -1
  25. package/dist/cli/{index-rtetrxxq.js → index-8p9pasnp.js} +8 -3
  26. package/dist/cli/{index-85hstja2.js → index-a12906mj.js} +1 -1
  27. package/dist/cli/{index-chvqee1j.js → index-a5eba0t8.js} +2 -2
  28. package/dist/cli/{index-r3pth9a7.js → index-a7nh382r.js} +508 -441
  29. package/dist/cli/{index-t31cc7kv.js → index-cyw81ngh.js} +7 -7
  30. package/dist/cli/{index-kv36s0x0.js → index-e9tx99ds.js} +6 -3
  31. package/dist/cli/{index-fsrp8wp3.js → index-ed5ykebp.js} +25 -2
  32. package/dist/cli/{index-0tsetsxs.js → index-ffpmqx30.js} +4 -4
  33. package/dist/cli/{index-nc544sfw.js → index-gvhvz176.js} +2 -2
  34. package/dist/cli/{index-3nr2sn32.js → index-ktagrqxw.js} +3 -3
  35. package/dist/cli/{index-t26nfmcs.js → index-prmb5qfp.js} +2 -2
  36. package/dist/cli/{index-q3qtgtd0.js → index-q11t5erh.js} +1 -1
  37. package/dist/cli/{index-x20cgr2q.js → index-q7ezzgwq.js} +16 -2
  38. package/dist/cli/{index-z1tkxzq4.js → index-s608d3hw.js} +2 -2
  39. package/dist/cli/{index-y46anh5e.js → index-se8xc78k.js} +30 -30
  40. package/dist/cli/{index-84s6x604.js → index-w71cq27a.js} +5 -5
  41. package/dist/cli/{index-ddmnhv4h.js → index-wrt6m5ze.js} +1 -1
  42. package/dist/cli/{index-4qzeef9h.js → index-x9q4bbhd.js} +1 -1
  43. package/dist/cli/{index-zd15ya1w.js → index-y47dwge1.js} +1 -1
  44. package/dist/cli/{index-5bkpyvdf.js → index-y64jv2pe.js} +1 -1
  45. package/dist/cli/{index-gytyqv1d.js → index-yr6x707c.js} +2 -2
  46. package/dist/cli/index.js +28 -28
  47. package/dist/cli/{knowledge-escalator-6473ey4c.js → knowledge-escalator-n9pmx4qr.js} +8 -8
  48. package/dist/cli/{knowledge-events-wwzpz8m4.js → knowledge-events-raevm18w.js} +6 -6
  49. package/dist/cli/{knowledge-link-trfydkzm.js → knowledge-link-3tq8w6gs.js} +5 -5
  50. package/dist/cli/{knowledge-store-99gd42jy.js → knowledge-store-bcfqz8fr.js} +6 -6
  51. package/dist/cli/{knowledge-validator-v2eevvdg.js → knowledge-validator-jxqj96cx.js} +9 -9
  52. package/dist/cli/{pending-delegations-p6n83x67.js → pending-delegations-tmyf18p4.js} +5 -5
  53. package/dist/cli/{pr-subscriptions-xbrfr51c.js → pr-subscriptions-hhx6yk24.js} +5 -5
  54. package/dist/cli/{runner-9an52tmz.js → runner-w30gazew.js} +6 -6
  55. package/dist/cli/{scan-cursor-39zxpw34.js → scan-cursor-ah5swtyh.js} +7 -7
  56. package/dist/cli/{schema-xhfwr6b2.js → schema-f7jgrtxj.js} +3 -1
  57. package/dist/cli/{scope-persistence-nsa6ra9s.js → scope-persistence-3f0d4fwv.js} +4 -4
  58. package/dist/cli/{skill-generator-5px81476.js → skill-generator-hp7as46c.js} +10 -10
  59. package/dist/cli/{telemetry-7nt7zhyp.js → telemetry-4tgrfhaz.js} +1 -1
  60. package/dist/cli/{worktree-collision-ownership-9x4s4890.js → worktree-collision-ownership-vexb0b6r.js} +38 -8
  61. package/dist/config/context-window.d.ts +210 -0
  62. package/dist/config/schema.d.ts +18 -0
  63. package/dist/evaluation/ephemeral-agent-dispatcher.d.ts +18 -0
  64. package/dist/evaluation/model-dispatcher.d.ts +1 -0
  65. package/dist/hooks/delegate-ack-collector.d.ts +1 -1
  66. package/dist/hooks/delegation-gate/worktree-collision-ownership.d.ts +7 -0
  67. package/dist/hooks/delegation-gate/worktree-isolation.d.ts +2 -1
  68. package/dist/hooks/delegation-gate/worktree-provisioning-owner.d.ts +6 -0
  69. package/dist/hooks/index.d.ts +2 -2
  70. package/dist/hooks/init-orphan-recovery.d.ts +4 -1
  71. package/dist/hooks/knowledge-application-gate.d.ts +2 -1
  72. package/dist/hooks/knowledge-application.d.ts +5 -4
  73. package/dist/hooks/knowledge-injector.d.ts +16 -0
  74. package/dist/hooks/knowledge-types.d.ts +1 -1
  75. package/dist/hooks/messages-transform.d.ts +18 -0
  76. package/dist/hooks/model-limits.d.ts +88 -30
  77. package/dist/hooks/pr-workflow-gate.d.ts +8 -1
  78. package/dist/index.js +455 -452
  79. package/dist/memory/injector.d.ts +2 -0
  80. package/dist/services/context-budget-service.d.ts +6 -1
  81. package/dist/services/status-service.d.ts +14 -0
  82. package/dist/state.d.ts +37 -0
  83. package/dist/tools/context-status.d.ts +3 -1
  84. package/dist/turbo/lean/runner.d.ts +10 -0
  85. package/dist/utils/ephemeral-session-teardown.d.ts +98 -0
  86. package/dist/utils/path-security.d.ts +75 -5
  87. package/dist/utils/swarm-artifact-cache.d.ts +13 -0
  88. package/dist/worktree/index.d.ts +1 -1
  89. package/dist/worktree/merge.d.ts +36 -3
  90. package/package.json +1 -1
@@ -23,19 +23,19 @@ import {
23
23
  validateLesson,
24
24
  validateSkillCandidatePath,
25
25
  validateSkillPath
26
- } from "./index-0tsetsxs.js";
27
- import"./index-67yqywan.js";
26
+ } from "./index-ffpmqx30.js";
27
+ import"./index-3radty3f.js";
28
28
  import"./index-rtry5xyf.js";
29
- import"./index-t31cc7kv.js";
30
- import"./index-kv36s0x0.js";
29
+ import"./index-cyw81ngh.js";
30
+ import"./index-e9tx99ds.js";
31
31
  import"./index-ae75rja9.js";
32
- import"./index-tyh0p5e8.js";
33
- import"./index-nc544sfw.js";
32
+ import"./index-668dpw5e.js";
33
+ import"./index-gvhvz176.js";
34
34
  import"./index-bk5tah7q.js";
35
- import"./index-fsrp8wp3.js";
36
- import"./index-a614s16f.js";
35
+ import"./index-ed5ykebp.js";
36
+ import"./index-5j6chvj8.js";
37
37
  import"./index-7g4c7s5r.js";
38
- import"./index-chvqee1j.js";
38
+ import"./index-a5eba0t8.js";
39
39
  import"./index-bpmtbmy9.js";
40
40
  import"./index-y111zefa.js";
41
41
  import"./index-zgwm4ryv.js";
@@ -41,12 +41,12 @@ import {
41
41
  sweepStaleDelegations,
42
42
  updateCoderSettlement,
43
43
  writeDelegationFallback
44
- } from "./index-t26nfmcs.js";
45
- import"./index-4qzeef9h.js";
46
- import"./index-fsrp8wp3.js";
47
- import"./index-a614s16f.js";
44
+ } from "./index-prmb5qfp.js";
45
+ import"./index-x9q4bbhd.js";
46
+ import"./index-ed5ykebp.js";
47
+ import"./index-5j6chvj8.js";
48
48
  import"./index-7g4c7s5r.js";
49
- import"./index-chvqee1j.js";
49
+ import"./index-a5eba0t8.js";
50
50
  import"./index-bpmtbmy9.js";
51
51
  import"./index-z6xqpmqg.js";
52
52
  import"./index-zjygnfay.js";
@@ -9,12 +9,12 @@ import {
9
9
  sweepStale,
10
10
  unsubscribe,
11
11
  updateSnapshot
12
- } from "./index-nbgw5dxa.js";
13
- import"./index-4qzeef9h.js";
14
- import"./index-fsrp8wp3.js";
15
- import"./index-a614s16f.js";
12
+ } from "./index-5zyk8qgv.js";
13
+ import"./index-x9q4bbhd.js";
14
+ import"./index-ed5ykebp.js";
15
+ import"./index-5j6chvj8.js";
16
16
  import"./index-7g4c7s5r.js";
17
- import"./index-chvqee1j.js";
17
+ import"./index-a5eba0t8.js";
18
18
  import"./index-bpmtbmy9.js";
19
19
  import"./index-z6xqpmqg.js";
20
20
  import"./index-zjygnfay.js";
@@ -3,14 +3,14 @@ import {
3
3
  _internals,
4
4
  createModelEvaluationExecutor,
5
5
  runEvaluation
6
- } from "./index-ddmnhv4h.js";
7
- import"./index-z1tkxzq4.js";
6
+ } from "./index-wrt6m5ze.js";
7
+ import"./index-s608d3hw.js";
8
8
  import"./index-y8552snf.js";
9
- import"./index-nc544sfw.js";
10
- import"./index-fsrp8wp3.js";
11
- import"./index-a614s16f.js";
9
+ import"./index-gvhvz176.js";
10
+ import"./index-ed5ykebp.js";
11
+ import"./index-5j6chvj8.js";
12
12
  import"./index-7g4c7s5r.js";
13
- import"./index-chvqee1j.js";
13
+ import"./index-a5eba0t8.js";
14
14
  import"./index-bpmtbmy9.js";
15
15
  import"./index-y111zefa.js";
16
16
  import"./index-a76rekgs.js";
@@ -4,16 +4,16 @@ import {
4
4
  alreadyCuratedThisGeneration,
5
5
  claimNextScanBatch,
6
6
  getScanStatus
7
- } from "./index-s428dmy6.js";
8
- import"./index-t31cc7kv.js";
7
+ } from "./index-6w1re1qn.js";
8
+ import"./index-cyw81ngh.js";
9
9
  import"./index-ae75rja9.js";
10
- import"./index-tyh0p5e8.js";
11
- import"./index-nc544sfw.js";
10
+ import"./index-668dpw5e.js";
11
+ import"./index-gvhvz176.js";
12
12
  import"./index-bk5tah7q.js";
13
- import"./index-fsrp8wp3.js";
14
- import"./index-a614s16f.js";
13
+ import"./index-ed5ykebp.js";
14
+ import"./index-5j6chvj8.js";
15
15
  import"./index-7g4c7s5r.js";
16
- import"./index-chvqee1j.js";
16
+ import"./index-a5eba0t8.js";
17
17
  import"./index-bpmtbmy9.js";
18
18
  import"./index-y111zefa.js";
19
19
  import"./index-zgwm4ryv.js";
@@ -25,6 +25,7 @@ import {
25
25
  DEFAULT_AGENT_PROFILES,
26
26
  DEFAULT_ARCHITECT_PROFILE,
27
27
  DEFAULT_EXTERNAL_SKILLS_CONFIG,
28
+ DEFAULT_MODEL_CONTEXT_TOKENS,
28
29
  DEFAULT_SKILLS_CONFIG,
29
30
  DEFAULT_SKILL_OPT_CONFIG,
30
31
  DecisionDecaySchema,
@@ -95,7 +96,7 @@ import {
95
96
  resolveGeneratedAgentRole,
96
97
  resolveGuardrailsConfig,
97
98
  stripKnownSwarmPrefix
98
- } from "./index-rtetrxxq.js";
99
+ } from "./index-8p9pasnp.js";
99
100
  import"./index-bk5tah7q.js";
100
101
  import"./index-3jcyn8g6.js";
101
102
  import"./index-bpmtbmy9.js";
@@ -173,6 +174,7 @@ export {
173
174
  DecisionDecaySchema,
174
175
  DEFAULT_SKILL_OPT_CONFIG,
175
176
  DEFAULT_SKILLS_CONFIG,
177
+ DEFAULT_MODEL_CONTEXT_TOKENS,
176
178
  DEFAULT_EXTERNAL_SKILLS_CONFIG,
177
179
  DEFAULT_ARCHITECT_PROFILE,
178
180
  DEFAULT_AGENT_PROFILES,
@@ -23,13 +23,13 @@ import {
23
23
  tombstoneScopeBinding,
24
24
  writeScopeBindingToDisk,
25
25
  writeScopeToDisk
26
- } from "./index-ymszzvnr.js";
26
+ } from "./index-3eddtgxt.js";
27
27
  import"./index-556ja8an.js";
28
- import"./index-p2dz85tv.js";
28
+ import"./index-4xbyy6aw.js";
29
29
  import"./index-1kz6da87.js";
30
- import"./index-a614s16f.js";
30
+ import"./index-5j6chvj8.js";
31
31
  import"./index-7g4c7s5r.js";
32
- import"./index-chvqee1j.js";
32
+ import"./index-a5eba0t8.js";
33
33
  import"./index-bpmtbmy9.js";
34
34
  import"./index-y111zefa.js";
35
35
  import"./index-zgwm4ryv.js";
@@ -33,21 +33,21 @@ import {
33
33
  sanitizeSlug,
34
34
  selectCandidateEntries,
35
35
  writeEvalStub
36
- } from "./index-3nr2sn32.js";
37
- import"./index-0tsetsxs.js";
38
- import"./index-67yqywan.js";
36
+ } from "./index-ktagrqxw.js";
37
+ import"./index-ffpmqx30.js";
38
+ import"./index-3radty3f.js";
39
39
  import"./index-rtry5xyf.js";
40
- import"./index-t31cc7kv.js";
41
- import"./index-kv36s0x0.js";
40
+ import"./index-cyw81ngh.js";
41
+ import"./index-e9tx99ds.js";
42
42
  import"./index-ae75rja9.js";
43
- import"./index-tyh0p5e8.js";
44
- import"./index-nc544sfw.js";
43
+ import"./index-668dpw5e.js";
44
+ import"./index-gvhvz176.js";
45
45
  import"./index-bk5tah7q.js";
46
46
  import"./index-4rhhvd1a.js";
47
- import"./index-fsrp8wp3.js";
48
- import"./index-a614s16f.js";
47
+ import"./index-ed5ykebp.js";
48
+ import"./index-5j6chvj8.js";
49
49
  import"./index-7g4c7s5r.js";
50
- import"./index-chvqee1j.js";
50
+ import"./index-a5eba0t8.js";
51
51
  import"./index-bpmtbmy9.js";
52
52
  import"./index-y111zefa.js";
53
53
  import"./index-zgwm4ryv.js";
@@ -13,7 +13,7 @@ import {
13
13
  startHeartbeatTracking,
14
14
  stopHeartbeatTracking,
15
15
  telemetry
16
- } from "./index-chvqee1j.js";
16
+ } from "./index-a5eba0t8.js";
17
17
  import"./index-bpmtbmy9.js";
18
18
  import"./index-a76rekgs.js";
19
19
  export {
@@ -1,19 +1,21 @@
1
1
  // @bun
2
2
  import {
3
+ WORKTREE_PROVISIONING_OWNER_LEASE_MS,
4
+ removeWorktreeProvisioningOwner,
3
5
  scanWorktreeProvisioningOwnersForRecovery
4
- } from "./index-x20cgr2q.js";
6
+ } from "./index-q7ezzgwq.js";
5
7
  import {
6
8
  scanWorktreeMergeFailuresForRecovery
7
9
  } from "./index-b8zgtz81.js";
8
10
  import {
9
11
  scanDelegationFallbacksForRecovery,
10
12
  scanDelegationsForRecovery
11
- } from "./index-t26nfmcs.js";
12
- import"./index-4qzeef9h.js";
13
- import"./index-fsrp8wp3.js";
14
- import"./index-a614s16f.js";
13
+ } from "./index-prmb5qfp.js";
14
+ import"./index-x9q4bbhd.js";
15
+ import"./index-ed5ykebp.js";
16
+ import"./index-5j6chvj8.js";
15
17
  import"./index-7g4c7s5r.js";
16
- import"./index-chvqee1j.js";
18
+ import"./index-a5eba0t8.js";
17
19
  import"./index-bpmtbmy9.js";
18
20
  import"./index-z6xqpmqg.js";
19
21
  import"./index-zjygnfay.js";
@@ -24,6 +26,7 @@ import"./index-zgwm4ryv.js";
24
26
  import"./index-a76rekgs.js";
25
27
 
26
28
  // src/hooks/delegation-gate/worktree-collision-ownership.ts
29
+ import * as fs2 from "fs";
27
30
  import * as path2 from "path";
28
31
 
29
32
  // src/hooks/delegation-gate/worktree-ownership-tag.ts
@@ -107,6 +110,10 @@ async function scanBackgroundWorktreeOwnershipTagsForRecovery(directory) {
107
110
  }
108
111
 
109
112
  // src/hooks/delegation-gate/worktree-collision-ownership.ts
113
+ var _internals = {
114
+ statSync: fs2.statSync,
115
+ removeWorktreeProvisioningOwner
116
+ };
110
117
  function normalizedPath(value) {
111
118
  const resolved = path2.normalize(path2.resolve(value));
112
119
  return process.platform === "win32" ? resolved.toLowerCase() : resolved;
@@ -151,16 +158,38 @@ async function inspectStandardWorktreeCollisionOwnership(identity) {
151
158
  const provisioning = scanWorktreeProvisioningOwnersForRecovery(identity.directory);
152
159
  if (provisioning.status === "uncertain")
153
160
  return provisioning;
161
+ const now = Date.now();
154
162
  for (const owner of provisioning.owners) {
155
163
  const sameSession = owner.parentSessionId === identity.parentSessionId || owner.worktreeSessionId === identity.parentSessionId;
156
164
  if (!sameSession)
157
165
  continue;
158
166
  if (owner.schemaVersion === 1 || owner.taskId === identity.taskId) {
167
+ const leaseIsLive = now - owner.createdAt <= WORKTREE_PROVISIONING_OWNER_LEASE_MS;
168
+ if (!leaseIsLive) {
169
+ try {
170
+ _internals.statSync(identity.worktreePath);
171
+ } catch (error) {
172
+ const code = error.code;
173
+ if (code !== "ENOENT" && code !== "ENOTDIR") {
174
+ return {
175
+ status: "uncertain",
176
+ reason: `expired provisioning owner ${owner.callID} lane liveness is unreadable: ${error instanceof Error ? error.message : String(error)}`
177
+ };
178
+ }
179
+ if (!_internals.removeWorktreeProvisioningOwner(identity.directory, owner.callID)) {
180
+ return {
181
+ status: "uncertain",
182
+ reason: `expired provisioning owner ${owner.callID} could not be removed`
183
+ };
184
+ }
185
+ continue;
186
+ }
187
+ }
159
188
  return {
160
189
  status: "protected",
161
190
  ownerKind: "provisioning",
162
191
  lifecycle: "active",
163
- reason: owner.schemaVersion === 1 ? `legacy provisioning owner ${owner.callID} cannot disprove ownership of this same-session lane` : `provisioning owner ${owner.callID} is active for task ${identity.taskId}`
192
+ reason: !leaseIsLive ? `provisioning owner ${owner.callID} lease expired, but its exact lane path still exists` : owner.schemaVersion === 1 ? `legacy provisioning owner ${owner.callID} cannot disprove ownership of this same-session lane` : `provisioning owner ${owner.callID} is active for task ${identity.taskId}`
164
193
  };
165
194
  }
166
195
  }
@@ -217,5 +246,6 @@ async function inspectStandardWorktreeCollisionOwnership(identity) {
217
246
  return { status: "unowned" };
218
247
  }
219
248
  export {
220
- inspectStandardWorktreeCollisionOwnership
249
+ inspectStandardWorktreeCollisionOwnership,
250
+ _internals
221
251
  };
@@ -0,0 +1,210 @@
1
+ /**
2
+ * Context-window denominator resolution — the SINGLE derivation.
3
+ *
4
+ * Every "how many tokens does this model's context window hold?" question in
5
+ * the plugin resolves here: the context-budget denominator (`budgetTokens` in
6
+ * `src/hooks/system-enhancer.ts` Path A and Path B), the hard-enforcement
7
+ * threshold in `src/hooks/context-budget.ts`, the knowledge-injector headroom
8
+ * gate, the `context_status` tool, and the `/swarm status` render.
9
+ *
10
+ * ## Why this exists
11
+ *
12
+ * The denominator used to be a hardcoded 128 000. That number is stale:
13
+ * current frontier and mid-tier models ship 200k–1M windows, and 256k is
14
+ * common even for locally-hosted models. A budget that reports "87 % used"
15
+ * against a window that is really 1M does not just emit a spurious advisory —
16
+ * `context-budget.ts` HARD-PRUNES messages at `critical_threshold × limit`, so
17
+ * a too-small denominator silently deletes context the model still needed.
18
+ *
19
+ * The authoritative value is already in the host's hands. The
20
+ * `experimental.chat.system.transform` hook input carries
21
+ * `model: Model` (`@opencode-ai/plugin`), and `Model.limit.context`
22
+ * (`@opencode-ai/sdk`) is the live window for THAT provider's entry of THAT
23
+ * model. Provider-specific caps are already baked in, because the host's model
24
+ * catalog is keyed `providers[providerID].models[modelID]` — verified against
25
+ * the on-disk catalog, where `github-copilot`'s `claude-sonnet-4.5` and
26
+ * `anthropic`'s `claude-sonnet-4-5` carry DIFFERENT `limit.context` values.
27
+ * A user's `provider.<id>.models.<id>.limit.context` override in
28
+ * `opencode.json` is merged into the same object before it reaches the hook.
29
+ *
30
+ * ## Resolution order (first usable value wins)
31
+ *
32
+ * 1. `context_budget.model_limits["<providerID>/<modelID>"]`
33
+ * 2. `context_budget.model_limits["<modelID>"]`
34
+ * 3. `context_budget.model_limits.default`
35
+ * 4. the LIVE `model.limit.context` from the hook input
36
+ * 5. the static fallback table (`src/hooks/model-limits.ts`), injected as
37
+ * `fallbackLookup` — reachable only when no live value is available
38
+ * 6. `DEFAULT_MODEL_CONTEXT_TOKENS`
39
+ *
40
+ * Steps 1–3 are ABOVE the live value on purpose: a user who writes a
41
+ * `model_limits` entry is asking for a smaller *working* budget than the
42
+ * physical window, and that intent must not be overridden by the hardware.
43
+ * This is why `context_budget.model_limits` no longer carries a zod
44
+ * `.default({ default: … })` — a schema-injected value is not user intent, and
45
+ * would have shadowed the live window for every user who has a
46
+ * `context_budget` block at all. See `ContextBudgetConfigSchema` in
47
+ * `./schema.ts`.
48
+ *
49
+ * Steps 5–6 are last resorts, NOT a cap on step 4. The hand-maintained table
50
+ * is stale in the downward direction (it claims Copilot caps everything at
51
+ * 128 000; the live catalog shows Copilot Claude entries at 200 000 and
52
+ * 1 000 000), so min-capping the live value against it would reintroduce
53
+ * exactly the too-small denominator this module exists to remove.
54
+ */
55
+ /**
56
+ * LAST-RESORT context-budget denominator (tokens) — rung 6 above.
57
+ *
58
+ * Declared HERE rather than imported from `./schema`, deliberately: this module
59
+ * is loaded transitively by `src/hooks/model-limits.ts` and therefore by every
60
+ * `messages.transform` consumer, and several test files replace
61
+ * `src/config/schema` with a non-spreading `mock.module` factory. Importing a
62
+ * symbol from schema here would make Bun throw
63
+ * `SyntaxError: Export named 'DEFAULT_MODEL_CONTEXT_TOKENS' not found` in those
64
+ * files at import time (see the "mock.module() Export Completeness" section of
65
+ * the writing-tests skill). Keeping this module dependency-free removes the
66
+ * whole class. `./schema` re-exports the constant, so every existing importer
67
+ * is unaffected.
68
+ *
69
+ * It is reached only when the user configured no `model_limits` entry, the host
70
+ * supplied no usable `model.limit.context`, and the static fallback table in
71
+ * `src/hooks/model-limits.ts` had no opinion either. It is deliberately NOT the
72
+ * primary source: 128 000 is stale for current models, which routinely ship
73
+ * 200k–1M windows.
74
+ *
75
+ * Historical note: `budgetTokens` used to be derived from
76
+ * `context_budget.model_limits.default` in `src/hooks/system-enhancer.ts`, but
77
+ * `context_budget` is schema-OPTIONAL, so a user with no block fell back to
78
+ * `DEFAULT_CONTEXT_BUDGET_CONFIG.budgetTokens` in
79
+ * `src/services/context-budget-service.ts` instead. Those two numbers had
80
+ * drifted (128000 vs 40000), so the unconfigured default measured the swarm's
81
+ * architect system prompt — approximately 34.5k estimated tokens — against a
82
+ * 40k denominator and reported ~86% on turn one (34500/40000 = 86.25%; an
83
+ * earlier revision of this comment said 87%) — enough to fire the budget
84
+ * warning, the `CONTEXT PRESSURE`
85
+ * advisory (src/index.ts) and the compaction EMERGENCY tier
86
+ * (`observation/reflection/emergency` = 40/60/80) immediately.
87
+ */
88
+ export declare const DEFAULT_MODEL_CONTEXT_TOKENS = 128000;
89
+ /**
90
+ * Smallest context window this module will accept from an untrusted source.
91
+ *
92
+ * Mirrors the `z.number().min(1000)` floor that `ContextBudgetConfigSchema`
93
+ * already enforces on user-authored `model_limits` values, so live catalog data
94
+ * and user config are held to one standard. This is not theoretical: a survey
95
+ * of the host's on-disk model catalog (`~/.cache/opencode/models.json`, ~6.2k
96
+ * entries; the file is a per-machine, auto-refreshing artifact, so the exact
97
+ * total moves) found 124 entries with `limit.context: 0`. Dividing by that
98
+ * yields `Infinity` percent and would fire the EMERGENCY compaction tier on
99
+ * turn one.
100
+ */
101
+ export declare const MIN_PLAUSIBLE_CONTEXT_TOKENS = 1000;
102
+ /** Which rung of the resolution order produced the value. */
103
+ export type ContextWindowSource = 'user_provider_model' | 'user_model' | 'user_default' | 'live_model_limit' | 'static_table' | 'static_default';
104
+ export interface ContextWindowResolution {
105
+ /**
106
+ * The resolved denominator, in tokens. Always a finite integer ≥ 1, so it is
107
+ * never a divide-by-zero. Through a PARSED config it is additionally ≥ 1000:
108
+ * every rung except the user rungs is gated on
109
+ * {@link isUsableContextWindow} (≥ {@link MIN_PLAUSIBLE_CONTEXT_TOKENS}), and
110
+ * the user rungs are themselves floored at 1000 by
111
+ * `ContextBudgetConfigSchema`. A direct programmatic call may still supply a
112
+ * user value between 1 and 999 and get it back — that is deliberate
113
+ * (honouring explicit intent), and it is why the guarantee stated here is
114
+ * ≥ 1 rather than ≥ 1000.
115
+ */
116
+ tokens: number;
117
+ /** Which rung produced `tokens` — surfaced in debug logs and tests. */
118
+ source: ContextWindowSource;
119
+ }
120
+ export interface ContextWindowInputs {
121
+ /**
122
+ * `config.context_budget?.model_limits` exactly as the user authored it.
123
+ * Pass `undefined` when the user has no `context_budget` block.
124
+ */
125
+ userLimits?: Record<string, number> | undefined;
126
+ /** Model identifier, when known (e.g. `claude-sonnet-4-6`). */
127
+ modelID?: string | undefined;
128
+ /** Provider identifier, when known (e.g. `github-copilot`). */
129
+ providerID?: string | undefined;
130
+ /**
131
+ * The live `model.limit.context` for this turn. Deliberately `unknown`:
132
+ * it crosses the plugin-host boundary, and the survey above shows the
133
+ * catalog really does ship `0` for some entries.
134
+ */
135
+ liveContextLimit?: unknown;
136
+ /**
137
+ * Last-resort static lookup. Injected rather than imported so this module
138
+ * stays free of any dependency on `src/hooks/`. Returning `undefined` means
139
+ * "no opinion" and falls through to `DEFAULT_MODEL_CONTEXT_TOKENS`.
140
+ */
141
+ fallbackLookup?: ((modelID?: string, providerID?: string) => number | undefined) | undefined;
142
+ }
143
+ /**
144
+ * True when `value` can be used as a divisor at all: a finite number strictly
145
+ * greater than zero.
146
+ *
147
+ * This is the bar applied to USER-AUTHORED `model_limits` values. It is
148
+ * deliberately weaker than {@link isUsableContextWindow}: `ContextBudgetConfigSchema`
149
+ * already enforces `z.number().min(1000)` on that record, so anything smaller
150
+ * cannot reach here through a parsed config — and silently DISCARDING a value a
151
+ * user explicitly wrote would be worse than honouring it. What this does reject
152
+ * is the set that breaks arithmetic outright (`NaN`, `±Infinity`, `0`,
153
+ * negatives, non-numbers), which a direct programmatic call can still supply.
154
+ *
155
+ * The bar is `>= 1`, not `> 0` (#1619 review round 4). `resolveContextWindow`
156
+ * applies `Math.floor` to whatever this admits, so a fractional value in
157
+ * `(0, 1)` — e.g. `{ default: 0.5 }` from a programmatic caller — passed a
158
+ * `> 0` test and then floored to a **zero denominator**, producing the exact
159
+ * `Infinity %` this guard exists to prevent. `>= 1` closes that without
160
+ * discarding any value a user could author through a parsed config (the schema
161
+ * floor is 1000) and without changing the verdict for any previously-accepted
162
+ * integer.
163
+ */
164
+ export declare function isUsableConfiguredWindow(value: unknown): value is number;
165
+ /**
166
+ * True when `value` is a plausible context-window size reported by an
167
+ * UNTRUSTED source: a finite number at or above
168
+ * {@link MIN_PLAUSIBLE_CONTEXT_TOKENS}.
169
+ *
170
+ * Applied to the live `model.limit.context` and to the static fallback table.
171
+ * Stricter than {@link isUsableConfiguredWindow} because nothing validates the
172
+ * host's model catalog on the way in and no real model ships a sub-1000-token
173
+ * window — so a small value there is corrupt data, not intent. Rejects, by
174
+ * construction, `undefined`, `null`, non-numbers, `NaN`, `Infinity`,
175
+ * `-Infinity`, `0` and every negative: the shapes that turn a percentage into
176
+ * `NaN` / `Infinity` and drive spurious EMERGENCY compaction directives.
177
+ */
178
+ export declare function isUsableContextWindow(value: unknown): value is number;
179
+ /**
180
+ * Safely read `model.limit.context` off the `experimental.chat.system.transform`
181
+ * hook input's `model` object.
182
+ *
183
+ * Typed as `unknown` on purpose. The plugin `.d.ts` declares `model: Model`
184
+ * (non-optional), but this hook runs inside the host's transform chain: a throw
185
+ * here takes down ALL system enhancement for the turn, so the read never
186
+ * assumes the declared shape actually arrived.
187
+ *
188
+ * @returns the raw value, or `undefined` when the path is absent.
189
+ */
190
+ export declare function readModelContextLimit(model: unknown): unknown;
191
+ /**
192
+ * Safely read `model.id` / `model.providerID` off the hook input's `model`.
193
+ *
194
+ * Same defensive posture as {@link readModelContextLimit}: the declared type
195
+ * says these are strings, but this runs on the host boundary. Empty strings are
196
+ * normalised to `undefined` so a blank identity never becomes a config-lookup
197
+ * key like `"/"`.
198
+ */
199
+ export declare function readModelIdentity(model: unknown, key: 'id' | 'providerID'): string | undefined;
200
+ /**
201
+ * Resolve the context-window denominator and report which rung produced it.
202
+ *
203
+ * @see the module header for the full resolution order and its rationale.
204
+ */
205
+ export declare function resolveContextWindow(inputs: ContextWindowInputs): ContextWindowResolution;
206
+ /**
207
+ * Convenience wrapper around {@link resolveContextWindow} for call sites that
208
+ * only need the number.
209
+ */
210
+ export declare function resolveContextWindowTokens(inputs: ContextWindowInputs): number;
@@ -220,6 +220,24 @@ export declare const ScoringConfigSchema: z.ZodObject<{
220
220
  }, z.core.$strip>>;
221
221
  }, z.core.$strip>;
222
222
  export type ScoringConfig = z.infer<typeof ScoringConfigSchema>;
223
+ /**
224
+ * LAST-RESORT context-budget denominator (tokens), used only when nothing
225
+ * better is available — rung 6 of the resolution order.
226
+ *
227
+ * DEFINED in `./context-window.ts` and re-exported here for the existing
228
+ * importers. It cannot live in this file: `context-window.ts` is loaded
229
+ * transitively by every context-budget consumer, and several test files replace
230
+ * `src/config/schema` with a non-spreading `mock.module` factory, so an import
231
+ * edge from `context-window.ts` into this module would make Bun throw
232
+ * `SyntaxError: Export named 'DEFAULT_MODEL_CONTEXT_TOKENS' not found` at
233
+ * import time. See the constant's own doc comment for the full history.
234
+ *
235
+ * A hardcoded denominator is wrong for any model whose window is not 128k. The
236
+ * budget denominator is derived from the live `model.limit.context` the host
237
+ * hands to `experimental.chat.system.transform`; this constant survives only as
238
+ * the no-information floor.
239
+ */
240
+ export { DEFAULT_MODEL_CONTEXT_TOKENS } from './context-window';
223
241
  export declare const ContextBudgetConfigSchema: z.ZodObject<{
224
242
  enabled: z.ZodDefault<z.ZodBoolean>;
225
243
  warn_threshold: z.ZodDefault<z.ZodNumber>;
@@ -4,6 +4,14 @@ import { log } from '../utils/logger.js';
4
4
  import type { ModelOverride } from '../utils/model-dispatch-fallback.js';
5
5
  export declare const DEFAULT_EPHEMERAL_TIMEOUT_MS = 120000;
6
6
  export declare const DEFAULT_EPHEMERAL_CLEANUP_TIMEOUT_MS = 500;
7
+ /**
8
+ * Bounded timeout for the graceful `session.abort()` step that precedes delete
9
+ * in the ephemeral teardown (#2123). opencode's `SessionProcessor.cleanup` can
10
+ * take up to ~250 ms under interruption (it awaits each pending tool-call
11
+ * deferred with a 250 ms timeout), so this must stay well above that or the
12
+ * abort would give up before the final part/message flush lands.
13
+ */
14
+ export declare const DEFAULT_EPHEMERAL_ABORT_TIMEOUT_MS = 5000;
7
15
  export declare const DEFAULT_EPHEMERAL_PROMPT_BYTE_LIMIT: number;
8
16
  export declare const MAX_EPHEMERAL_PROMPT_BYTE_LIMIT: number;
9
17
  export declare const DEFAULT_EPHEMERAL_RESPONSE_BYTE_LIMIT: number;
@@ -48,8 +56,18 @@ export type EphemeralAgentDispatchResult = {
48
56
  responseBytes: number;
49
57
  costFields?: DelegationCostFields;
50
58
  };
59
+ /**
60
+ * Bounded graceful abort of an ephemeral session. opencode's
61
+ * `POST /session/{id}/abort` resolves only after `Fiber.interrupt` on the
62
+ * run-loop fiber — which runs `SessionProcessor.cleanup` (the final
63
+ * `updatePart`/`updateMessage` flush) as a finalizer. Awaiting this BEFORE the
64
+ * delete is what closes the FOREIGN KEY constraint race (#2123). If the session
65
+ * is already idle, abort is a fast no-op. Best-effort: never throws.
66
+ */
67
+ export declare function boundedAbortEphemeralSession(client: OpencodeClient, sessionId: string, timeoutMs?: number): Promise<void>;
51
68
  export declare function boundedDeleteEphemeralSession(client: OpencodeClient, sessionId: string, timeoutMs?: number): Promise<void>;
52
69
  export declare const _internals: {
70
+ boundedAbort: typeof boundedAbortEphemeralSession;
53
71
  boundedDelete: typeof boundedDeleteEphemeralSession;
54
72
  log: typeof log;
55
73
  };
@@ -48,6 +48,7 @@ export declare function resolveEvaluationAgentName(agents: readonly Pick<Agent,
48
48
  * primitive remains the single owner of cleanup and logging behavior.
49
49
  */
50
50
  export declare const _internals: {
51
+ boundedAbort: typeof ephemeralDispatcherInternals.boundedAbort;
51
52
  boundedDelete: typeof ephemeralDispatcherInternals.boundedDelete;
52
53
  log: typeof ephemeralDispatcherInternals.log;
53
54
  };
@@ -7,7 +7,7 @@
7
7
  * prompt) against the ack markers in the subagent's transcript:
8
8
  *
9
9
  * - For every ack whose ID was actually shown, emit a receipt event of the
10
- * matching type (applied / ignored / violated / n_a). Acks for IDs that were
10
+ * matching type (applied / ignored / contradicted / violated / n_a). Acks for IDs that were
11
11
  * never shown are DROPPED (anti-spoofing).
12
12
  * - For every CRITICAL directive that was shown but never acknowledged, emit a
13
13
  * `violated` event with reason `unacknowledged` and append an audit line to
@@ -1,3 +1,10 @@
1
+ import * as fs from 'node:fs';
2
+ import { removeWorktreeProvisioningOwner } from './worktree-provisioning-owner';
3
+ /** File-operation seam for deterministic fail-closed recovery tests. */
4
+ export declare const _internals: {
5
+ statSync: fs.StatSyncFn;
6
+ removeWorktreeProvisioningOwner: typeof removeWorktreeProvisioningOwner;
7
+ };
1
8
  export interface StandardWorktreeCollisionIdentity {
2
9
  directory: string;
3
10
  parentSessionId: string;
@@ -12,7 +12,7 @@ import type { PluginConfig, WorktreeIsolationConfig } from '../../config';
12
12
  import { tryAcquireLock } from '../../parallel/file-locks';
13
13
  import { bunSpawn } from '../../utils/bun-compat';
14
14
  import type { WorktreeHandle } from '../../worktree';
15
- import { attemptMergeBackFromDirty, cleanupOrphanedBranches, postMergeCleanup, provisionWorktree, removeWorktree, startupOrphanRecovery } from '../../worktree';
15
+ import { attemptMergeBackFromDirty, cleanupOrphanedBranches, postMergeCleanup, provisionWorktree, pruneStaleWorktreeMetadata, removeWorktree, startupOrphanRecovery } from '../../worktree';
16
16
  import type { DirtyMergeOptions, MergeOperationProvenance } from '../../worktree/merge';
17
17
  import { recordWorktreeProvisioningOwner, removeWorktreeProvisioningOwner } from './worktree-provisioning-owner';
18
18
  /**
@@ -301,6 +301,7 @@ export declare const _internals: {
301
301
  removeWorktree: typeof removeWorktree;
302
302
  attemptMergeBackFromDirty: typeof attemptMergeBackFromDirty;
303
303
  postMergeCleanup: typeof postMergeCleanup;
304
+ pruneStaleWorktreeMetadata: typeof pruneStaleWorktreeMetadata;
304
305
  /** FR-201: read lane runtime profile from disk for spawn injection. */
305
306
  readLaneEnvFileFromDisk: typeof readLaneEnvFileFromDisk;
306
307
  /** FR-104: exposes serializationStateBySessionID for test setup (SC-111/SC-112/SC-113). */
@@ -1,3 +1,9 @@
1
+ /**
2
+ * A provisional marker covers the bounded gap before `git worktree add`
3
+ * materializes the exact lane path. Once that path exists, path liveness wins
4
+ * and the marker remains protected regardless of age.
5
+ */
6
+ export declare const WORKTREE_PROVISIONING_OWNER_LEASE_MS: number;
1
7
  export declare const WORKTREE_LIFECYCLE_LOCK_FILE = ".swarm/locks/init-orphan-recovery.lock";
2
8
  export interface WorktreeProvisioningOwner {
3
9
  schemaVersion: 1 | 2;
@@ -11,8 +11,8 @@ export { extractCurrentPhase, extractCurrentPhaseFromPlan, extractCurrentTask, e
11
11
  export { createFullAutoInterceptHook } from './full-auto-intercept';
12
12
  export { checkFileAuthority, createGuardrailsHooks, DEFAULT_AGENT_AUTHORITY_RULES, } from './guardrails';
13
13
  export { classifyMessage, classifyMessages, containsPlanContent, getCompletedToolOutputs, getToolNames, getToolParts, isDuplicateToolRead, isStaleError, isToolResult, MessagePriority, type MessagePriorityType, type MessageWithParts, } from './message-priority';
14
- export { consolidateSystemMessages } from './messages-transform';
15
- export { extractModelInfo, NATIVE_MODEL_LIMITS, PROVIDER_CAPS, resolveModelLimit, } from './model-limits';
14
+ export { consolidateSystemMessages, consolidateSystemMessagesInPlace, } from './messages-transform';
15
+ export { extractModelInfo, extractSessionId, lookupStaticModelLimit, NATIVE_MODEL_LIMITS, PROVIDER_CAPS, resolveModelLimit, } from './model-limits';
16
16
  export { type CuratorDelegateFactory, createPhaseMonitorHook, } from './phase-monitor';
17
17
  export { createPipelineTrackerHook } from './pipeline-tracker';
18
18
  export { createRepoGraphBuilderHook, type RepoGraphBuilderHook, } from './repo-graph-builder';