opencode-swarm 7.167.2 → 7.168.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 (102) 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/cli/{coder-settlement-jy9rad28.js → coder-settlement-54a3d97g.js} +12 -12
  4. package/dist/cli/{config-doctor-p66vnpy3.js → config-doctor-vzp6b3ng.js} +3 -3
  5. package/dist/cli/{core-tw0wtntz.js → core-yynse50x.js} +2 -2
  6. package/dist/cli/{curation-policy-ndp27v0c.js → curation-policy-mgwv8h2k.js} +5 -5
  7. package/dist/cli/{curator-5nzde80g.js → curator-agdhhzqt.js} +38 -38
  8. package/dist/cli/{curator-drift-gb651hcw.js → curator-drift-k0zrnm09.js} +5 -5
  9. package/dist/cli/curator-llm-factory-ygxd6hfx.js +71 -0
  10. package/dist/cli/{evidence-summary-service-bzpfaypy.js → evidence-summary-service-6mmcekr7.js} +17 -17
  11. package/dist/cli/{gate-evidence-wa8cj8h6.js → gate-evidence-xqvkqhrk.js} +7 -7
  12. package/dist/cli/guardrail-explain-vjtjhgzs.js +72 -0
  13. package/dist/cli/{guardrail-log-7dv73e0q.js → guardrail-log-5wa5c77w.js} +8 -8
  14. package/dist/cli/{guardrail-reset-1kng6y8x.js → guardrail-reset-dh78tbcf.js} +38 -38
  15. package/dist/cli/{hive-promoter-87kk2pg5.js → hive-promoter-3czsx7c6.js} +38 -38
  16. package/dist/cli/{index-18rfc7qv.js → index-2xbww1x0.js} +7 -7
  17. package/dist/cli/{index-3ws11dq0.js → index-3jmb4ppa.js} +2 -2
  18. package/dist/cli/{index-79234evf.js → index-4kv1ew3q.js} +1 -1
  19. package/dist/cli/{index-vgpedapd.js → index-4r5pmtvk.js} +2 -2
  20. package/dist/cli/{index-rrne6g2m.js → index-5g6rhkn7.js} +6 -2
  21. package/dist/cli/{index-m7cwnt9r.js → index-5zqakgp4.js} +2 -2
  22. package/dist/cli/{index-m3z83nhs.js → index-6df6wbvj.js} +8 -8
  23. package/dist/cli/{index-0q839sg6.js → index-8ybjqg51.js} +1 -1
  24. package/dist/cli/{index-wjet7x0a.js → index-91ww9hyr.js} +1 -1
  25. package/dist/cli/{index-pdcperq5.js → index-9b2105n0.js} +2 -2
  26. package/dist/cli/{index-z6we1abx.js → index-a8xbvsse.js} +2 -2
  27. package/dist/cli/{index-2b1hd1fx.js → index-apy1qfj0.js} +13 -4
  28. package/dist/cli/{index-gmjg65tm.js → index-bvqqwx84.js} +2 -2
  29. package/dist/cli/{index-ce8p9t28.js → index-bw9x8d8n.js} +5 -5
  30. package/dist/cli/{index-dme7wvwg.js → index-chebm5h5.js} +4 -4
  31. package/dist/cli/{index-mtepgqan.js → index-dfyv3xkd.js} +7 -7
  32. package/dist/cli/{index-sjkg2hc4.js → index-f1fps3w9.js} +6 -6
  33. package/dist/cli/index-gh9ybrrs.js +2008 -0
  34. package/dist/cli/{index-3r6k6qa7.js → index-gmpmgtzn.js} +4 -4
  35. package/dist/cli/{index-83r0v5tn.js → index-gp9yzr1v.js} +1 -1
  36. package/dist/cli/{index-962qme08.js → index-h439y187.js} +1 -1
  37. package/dist/cli/{index-5sjq3shs.js → index-j0bxxz9d.js} +8 -8
  38. package/dist/cli/{index-8vbahc4c.js → index-kear8gb7.js} +11 -6
  39. package/dist/cli/{index-y1sj2e1n.js → index-kkmezerc.js} +2094 -1686
  40. package/dist/cli/{index-syedr4e3.js → index-m35hybf0.js} +1 -1
  41. package/dist/cli/{index-f8cc92g7.js → index-nwwk3dej.js} +1 -1
  42. package/dist/cli/{index-g409c7ke.js → index-pyf517sz.js} +2 -2
  43. package/dist/cli/{index-ehq2vtkq.js → index-q8091q8b.js} +4 -4
  44. package/dist/cli/{index-k73ehxa1.js → index-qhey6vc3.js} +1 -1
  45. package/dist/cli/{index-09gv90d7.js → index-qkwtth00.js} +2 -2
  46. package/dist/cli/{index-shrf0wt3.js → index-qthc56c4.js} +4 -4
  47. package/dist/cli/{index-gs12223x.js → index-qwsh0h2g.js} +2 -2
  48. package/dist/cli/{index-n4fzmqz8.js → index-rdm3px0g.js} +4 -2
  49. package/dist/cli/{index-g5m43paw.js → index-sxt7fgcw.js} +1 -0
  50. package/dist/cli/{index-x7pm61wk.js → index-v3xc4sde.js} +9 -8
  51. package/dist/cli/{index-arqv4psy.js → index-w1dfkp1q.js} +57 -101
  52. package/dist/cli/{index-25xeyjfx.js → index-w3x1dmrf.js} +38 -38
  53. package/dist/cli/{index-hhkm64wh.js → index-wst6n478.js} +103 -3
  54. package/dist/cli/{index-f91fhch0.js → index-xhb4gryr.js} +4 -4
  55. package/dist/cli/{index-s7a9dqtb.js → index-xkf3672y.js} +4 -3
  56. package/dist/cli/{index-jhd3pmd1.js → index-y85aptep.js} +7 -7
  57. package/dist/cli/{index-65s0vgb1.js → index-yt9n9zt3.js} +40 -40
  58. package/dist/cli/{index-tcj8v6my.js → index-z6qreakh.js} +6 -6
  59. package/dist/cli/index.js +38 -38
  60. package/dist/cli/{knowledge-escalator-5e4zxan5.js → knowledge-escalator-135dz4eh.js} +13 -13
  61. package/dist/cli/{knowledge-events-abzm5vfh.js → knowledge-events-27gwv47q.js} +11 -11
  62. package/dist/cli/{knowledge-link-9ga6hyd5.js → knowledge-link-dr3xnwyd.js} +4 -4
  63. package/dist/cli/{knowledge-store-q4a92eq7.js → knowledge-store-80m44bfw.js} +5 -5
  64. package/dist/cli/{knowledge-validator-pn3m5r41.js → knowledge-validator-crsfb2cc.js} +7 -7
  65. package/dist/cli/{model-preflight-mw895vgt.js → model-preflight-1ycat9jz.js} +1 -1
  66. package/dist/cli/{pending-delegations-3z0xjppd.js → pending-delegations-gwgjzzkz.js} +12 -12
  67. package/dist/cli/{pr-subscriptions-h7mwnp62.js → pr-subscriptions-g633nhz4.js} +12 -12
  68. package/dist/cli/{pr-workflow-gate-fec04fa0.js → pr-workflow-gate-4dc5nt2e.js} +38 -38
  69. package/dist/cli/{runner-d9833azt.js → runner-k0ycgv8x.js} +5 -5
  70. package/dist/cli/{scan-cursor-ymfvzdkz.js → scan-cursor-avxjsm4w.js} +6 -6
  71. package/dist/cli/{schema-chc4aez6.js → schema-3ja77k4y.js} +4 -2
  72. package/dist/cli/{scope-persistence-3xnr59y8.js → scope-persistence-f540tc50.js} +16 -16
  73. package/dist/cli/{skill-generator-3mvaghxk.js → skill-generator-kcqqpg1g.js} +15 -15
  74. package/dist/cli/{snapshot-coordination-init-arnc77r9.js → snapshot-coordination-init-e4s8bn4p.js} +38 -38
  75. package/dist/cli/{sqlite-loader-xrnf6bq8.js → sqlite-loader-amp9z7ty.js} +1 -1
  76. package/dist/cli/{telemetry-g9pppt9e.js → telemetry-2wzapf11.js} +1 -1
  77. package/dist/cli/{workspace-snapshot-hvsjtepd.js → workspace-snapshot-rkgxhj9b.js} +3 -3
  78. package/dist/cli/{worktree-collision-ownership-vj8anvb7.js → worktree-collision-ownership-rk9gz638.js} +13 -13
  79. package/dist/cli/{worktree-isolation-mt7z75hz.js → worktree-isolation-1bdzfgky.js} +38 -38
  80. package/dist/commands/reset.d.ts +10 -0
  81. package/dist/commands/rollback.d.ts +9 -0
  82. package/dist/config/schema.d.ts +29 -0
  83. package/dist/db/project-db.d.ts +8 -0
  84. package/dist/db/sqlite-loader.d.ts +2 -1
  85. package/dist/dispatch/spawn-circuit.d.ts +121 -0
  86. package/dist/dispatch/token-bucket.d.ts +46 -0
  87. package/dist/hooks/delegation-gate/dead-lane-reclaim.d.ts +61 -0
  88. package/dist/hooks/delegation-gate/worktree-isolation.d.ts +22 -0
  89. package/dist/hooks/issue-trace.d.ts +3 -0
  90. package/dist/hooks/utils.d.ts +1 -1
  91. package/dist/index.js +657 -572
  92. package/dist/plan/ledger-sqlite.d.ts +226 -0
  93. package/dist/plan/ledger.d.ts +24 -0
  94. package/dist/plan/manager.d.ts +19 -0
  95. package/dist/retention/sweep.d.ts +2 -0
  96. package/dist/services/spec-drift-recovery.d.ts +2 -1
  97. package/dist/utils/ephemeral-session-teardown.d.ts +55 -2
  98. package/opencode-swarm.schema.json +41 -0
  99. package/package.json +1 -1
  100. package/dist/cli/curator-llm-factory-xy96x5x8.js +0 -71
  101. package/dist/cli/guardrail-explain-1ef5he6j.js +0 -72
  102. package/dist/cli/index-z7z3g5wt.js +0 -1017
@@ -21,66 +21,66 @@ import {
21
21
  sanitizeWorktreeTaskId,
22
22
  standardWorktreeByCallID,
23
23
  standardWorktreeSerializationSessions
24
- } from "./index-y1sj2e1n.js";
24
+ } from "./index-kkmezerc.js";
25
25
  import"./index-d5qf7hvh.js";
26
- import"./index-k73ehxa1.js";
27
- import"./index-dme7wvwg.js";
28
- import"./index-f8cc92g7.js";
29
- import"./index-rrne6g2m.js";
30
- import"./index-arqv4psy.js";
31
- import"./index-83r0v5tn.js";
26
+ import"./index-qhey6vc3.js";
27
+ import"./index-chebm5h5.js";
28
+ import"./index-nwwk3dej.js";
29
+ import"./index-5g6rhkn7.js";
30
+ import"./index-w1dfkp1q.js";
31
+ import"./index-gp9yzr1v.js";
32
32
  import"./index-txdagbh7.js";
33
33
  import"./index-9br68j86.js";
34
34
  import"./index-cw912re7.js";
35
- import"./index-f91fhch0.js";
36
- import"./index-ce8p9t28.js";
37
- import"./index-pdcperq5.js";
35
+ import"./index-xhb4gryr.js";
36
+ import"./index-bw9x8d8n.js";
37
+ import"./index-9b2105n0.js";
38
38
  import"./index-fyfbpz4f.js";
39
- import"./index-mtepgqan.js";
39
+ import"./index-dfyv3xkd.js";
40
40
  import"./index-zsrtt42s.js";
41
- import"./index-5sjq3shs.js";
42
- import"./index-m7cwnt9r.js";
43
- import"./index-gmjg65tm.js";
41
+ import"./index-j0bxxz9d.js";
42
+ import"./index-5zqakgp4.js";
43
+ import"./index-bvqqwx84.js";
44
44
  import"./index-b43rt5ph.js";
45
45
  import"./index-q7sjgr1y.js";
46
- import"./index-3r6k6qa7.js";
47
- import"./index-09gv90d7.js";
48
- import"./index-sjkg2hc4.js";
49
- import"./index-m3z83nhs.js";
50
- import"./index-8vbahc4c.js";
46
+ import"./index-gmpmgtzn.js";
47
+ import"./index-qkwtth00.js";
48
+ import"./index-f1fps3w9.js";
49
+ import"./index-6df6wbvj.js";
50
+ import"./index-kear8gb7.js";
51
51
  import"./index-p612v1mv.js";
52
- import"./index-shrf0wt3.js";
53
- import"./index-syedr4e3.js";
52
+ import"./index-qthc56c4.js";
53
+ import"./index-m35hybf0.js";
54
54
  import"./index-rtry5xyf.js";
55
55
  import {
56
56
  resolveWorktreeIsolationConfig
57
- } from "./index-s7a9dqtb.js";
57
+ } from "./index-xkf3672y.js";
58
58
  import"./index-3qf1vxtb.js";
59
59
  import"./index-n832052r.js";
60
- import"./index-jhd3pmd1.js";
61
- import"./index-z7z3g5wt.js";
62
- import"./index-z6we1abx.js";
63
- import"./index-g409c7ke.js";
64
- import"./index-962qme08.js";
65
- import"./index-hhkm64wh.js";
66
- import"./index-n4fzmqz8.js";
60
+ import"./index-y85aptep.js";
61
+ import"./index-gh9ybrrs.js";
62
+ import"./index-a8xbvsse.js";
63
+ import"./index-pyf517sz.js";
64
+ import"./index-h439y187.js";
65
+ import"./index-wst6n478.js";
66
+ import"./index-rdm3px0g.js";
67
67
  import"./index-ry16d01s.js";
68
- import"./index-gs12223x.js";
69
- import"./index-18rfc7qv.js";
68
+ import"./index-qwsh0h2g.js";
69
+ import"./index-2xbww1x0.js";
70
70
  import"./index-vzm6zre7.js";
71
71
  import"./index-ae75rja9.js";
72
- import"./index-0q839sg6.js";
73
- import"./index-vgpedapd.js";
72
+ import"./index-8ybjqg51.js";
73
+ import"./index-4r5pmtvk.js";
74
74
  import"./index-7g4c7s5r.js";
75
- import"./index-x7pm61wk.js";
76
- import"./index-tcj8v6my.js";
75
+ import"./index-v3xc4sde.js";
76
+ import"./index-z6qreakh.js";
77
77
  import"./index-1xnse449.js";
78
78
  import"./index-ee6ydtfe.js";
79
- import"./index-wjet7x0a.js";
79
+ import"./index-91ww9hyr.js";
80
80
  import"./index-0mhftbpp.js";
81
81
  import"./index-a1w58b47.js";
82
- import"./index-2b1hd1fx.js";
83
- import"./index-g5m43paw.js";
82
+ import"./index-apy1qfj0.js";
83
+ import"./index-sxt7fgcw.js";
84
84
  import"./index-bk5tah7q.js";
85
85
  import"./index-bpmtbmy9.js";
86
86
  import"./index-zpsr8rpc.js";
@@ -1,3 +1,6 @@
1
+ import * as fs from 'node:fs';
2
+ import { clearPlanLedgerForReset } from '../plan/ledger.js';
3
+ import { withPlanLifecycleLock } from '../plan/manager.js';
1
4
  import { type ResetBackupResult } from './reset-backup';
2
5
  /**
3
6
  * _internals DI seam so tests can stub the pre-deletion backup without touching
@@ -6,6 +9,13 @@ import { type ResetBackupResult } from './reset-backup';
6
9
  */
7
10
  export declare const _internals: {
8
11
  backupSwarmStateBeforeReset: (directory: string, kind: 'reset' | 'reset-session', relEntries: string[]) => ResetBackupResult;
12
+ clearPlanLedgerForReset: typeof clearPlanLedgerForReset;
13
+ withPlanLifecycleLock: typeof withPlanLifecycleLock;
14
+ existsSync: typeof fs.existsSync;
15
+ readFileSync: typeof fs.readFileSync;
16
+ unlinkSync: typeof fs.unlinkSync;
17
+ writeFileSync: typeof fs.writeFileSync;
18
+ rmSync: typeof fs.rmSync;
9
19
  };
10
20
  /**
11
21
  * Handles the /swarm reset command.
@@ -1,3 +1,12 @@
1
+ import { clearPlanLedgerForReset, peekPlanFromLedger, replacePlanLedgerWithRoot } from '../plan/ledger';
2
+ import { withPlanLifecycleLock } from '../plan/manager';
3
+ /** Test-only seam for the atomic ledger re-root lifecycle transition. */
4
+ export declare const _internals: {
5
+ replacePlanLedgerWithRoot: typeof replacePlanLedgerWithRoot;
6
+ clearPlanLedgerForReset: typeof clearPlanLedgerForReset;
7
+ peekPlanFromLedger: typeof peekPlanFromLedger;
8
+ withPlanLifecycleLock: typeof withPlanLifecycleLock;
9
+ };
1
10
  /**
2
11
  * Handle /swarm rollback command
3
12
  * Restores .swarm/ state from a checkpoint using direct overwrite
@@ -1395,6 +1395,7 @@ export declare const WorktreeIsolationConfigSchema: z.ZodObject<{
1395
1395
  }>>;
1396
1396
  serialization_release_after_dispatches: z.ZodDefault<z.ZodNumber>;
1397
1397
  serialization_release_after_ms: z.ZodDefault<z.ZodNumber>;
1398
+ session_create_timeout_ms: z.ZodDefault<z.ZodNumber>;
1398
1399
  runtime_isolation: z.ZodOptional<z.ZodObject<{
1399
1400
  enabled: z.ZodDefault<z.ZodBoolean>;
1400
1401
  port_base: z.ZodOptional<z.ZodNumber>;
@@ -1889,6 +1890,26 @@ export declare const LaneLivenessWatchdogConfigSchema: z.ZodObject<{
1889
1890
  stall_token_threshold: z.ZodDefault<z.ZodNumber>;
1890
1891
  }, z.core.$strict>;
1891
1892
  export type LaneLivenessWatchdogConfig = z.infer<typeof LaneLivenessWatchdogConfigSchema>;
1893
+ /**
1894
+ * Issue #2507 dispatch protection: an action-local spawn-protection circuit
1895
+ * plus a token-bucket dispatch rate limit for native task delegations.
1896
+ *
1897
+ * Default-ON follows the guardrails family (`guardrails.enabled` defaults
1898
+ * true): the numbers are deliberately conservative (10 dispatches per second
1899
+ * with a burst of 10 never waits in normal use), and every knob is
1900
+ * user-overridable — set `enabled: false` to opt out entirely, or
1901
+ * `rate_per_second: 0` to disable only the limiter. Parameter surface
1902
+ * adopted with credit from opencode-ensemble (reimplemented per ADR 0002 —
1903
+ * no upstream code is ported).
1904
+ */
1905
+ export declare const DispatchProtectionConfigSchema: z.ZodObject<{
1906
+ enabled: z.ZodDefault<z.ZodBoolean>;
1907
+ spawn_failure_threshold: z.ZodDefault<z.ZodNumber>;
1908
+ half_open_after_ms: z.ZodDefault<z.ZodNumber>;
1909
+ rate_per_second: z.ZodDefault<z.ZodNumber>;
1910
+ burst_capacity: z.ZodDefault<z.ZodNumber>;
1911
+ }, z.core.$strict>;
1912
+ export type DispatchProtectionConfig = z.infer<typeof DispatchProtectionConfigSchema>;
1892
1913
  /**
1893
1914
  * Issue #2384: deprecated transcript-row settlement for Profile A PR-review
1894
1915
  * base/micro discovery lanes is an explicit compatibility opt-in. Omitted
@@ -2001,6 +2022,13 @@ export declare const PluginConfigSchema: z.ZodObject<{
2001
2022
  stall_min_steps: z.ZodDefault<z.ZodNumber>;
2002
2023
  stall_token_threshold: z.ZodDefault<z.ZodNumber>;
2003
2024
  }, z.core.$strict>>;
2025
+ dispatch_protection: z.ZodOptional<z.ZodObject<{
2026
+ enabled: z.ZodDefault<z.ZodBoolean>;
2027
+ spawn_failure_threshold: z.ZodDefault<z.ZodNumber>;
2028
+ half_open_after_ms: z.ZodDefault<z.ZodNumber>;
2029
+ rate_per_second: z.ZodDefault<z.ZodNumber>;
2030
+ burst_capacity: z.ZodDefault<z.ZodNumber>;
2031
+ }, z.core.$strict>>;
2004
2032
  pr_review_legacy_transcript_compatibility: z.ZodOptional<z.ZodBoolean>;
2005
2033
  gates: z.ZodOptional<z.ZodObject<{
2006
2034
  syntax_check: z.ZodDefault<z.ZodObject<{
@@ -2801,6 +2829,7 @@ export declare const PluginConfigSchema: z.ZodObject<{
2801
2829
  }>>;
2802
2830
  serialization_release_after_dispatches: z.ZodDefault<z.ZodNumber>;
2803
2831
  serialization_release_after_ms: z.ZodDefault<z.ZodNumber>;
2832
+ session_create_timeout_ms: z.ZodDefault<z.ZodNumber>;
2804
2833
  runtime_isolation: z.ZodOptional<z.ZodObject<{
2805
2834
  enabled: z.ZodDefault<z.ZodBoolean>;
2806
2835
  port_base: z.ZodOptional<z.ZodNumber>;
@@ -39,6 +39,14 @@ export declare function projectDbPath(directory: string): string;
39
39
  * workspace just to check for a missing record.
40
40
  */
41
41
  export declare function projectDbExists(directory: string): boolean;
42
+ /**
43
+ * Open the existing project database for one observational callback.
44
+ *
45
+ * Unlike `getProjectDb`, this never creates directories, negotiates WAL, runs
46
+ * migrations, or enters the shared connection cache. It is the only suitable
47
+ * path for lifecycle previews such as `/swarm close --dry-run`.
48
+ */
49
+ export declare function withProjectDbReadOnly<T>(directory: string, read: (db: Database) => T): T | null;
42
50
  /**
43
51
  * Best-effort WAL checkpoint before close (issue #2480 checkpoint policy).
44
52
  *
@@ -51,8 +51,9 @@ interface NodeDatabaseSync {
51
51
  loadExtension(path: string): void;
52
52
  close(): void;
53
53
  }
54
- type NodeDatabaseSyncCtor = new (filename: string, options?: {
54
+ type NodeDatabaseSyncCtor = new (filename: string | URL, options?: {
55
55
  allowExtension?: boolean;
56
+ readOnly?: boolean;
56
57
  }) => NodeDatabaseSync;
57
58
  /**
58
59
  * Build a `bun:sqlite`-`Database`-compatible constructor backed by `node:sqlite`'s
@@ -0,0 +1,121 @@
1
+ /**
2
+ * Action-local spawn-protection circuit for native task delegations
3
+ * (issue #2507 / ADR 0002 G3 — reimplemented, no upstream code ported).
4
+ *
5
+ * Ownership boundary (one accounting owner per failure category,
6
+ * docs/invocation-failures.md): this circuit owns repeated ACTUAL dispatch
7
+ * failures of the SAME semantic action on the native `task` route. Policy
8
+ * denials stay with the gate-denial tracker, shell-structural failures with
9
+ * the non-transient circuit, PR-review lane provider-terminal with the
10
+ * PR-review resilience circuit, provable-non-acceptance launch retry with
11
+ * #2473, and lane liveness with #2506.
12
+ *
13
+ * State machine (the src/pr-review/circuit.ts timed HALF_OPEN precedent):
14
+ * CLOSED -> (threshold failures) -> OPEN -> (denyUntil elapses, next dispatch
15
+ * admitted) -> HALF_OPEN (exactly one probe) -> completed probe closes |
16
+ * failed probe re-opens with a fresh interval.
17
+ *
18
+ * The state is process-local, invocation-owned, and bounded — the
19
+ * docs/invocation-failures.md contract for action circuits (only the
20
+ * PR-review resilience circuit is durable).
21
+ */
22
+ /** Bounded memory: same discipline as MAX_TRACKED_ACTION_CIRCUITS. */
23
+ export declare const MAX_TRACKED_SPAWN_CIRCUITS = 500;
24
+ export declare const SPAWN_CIRCUIT_TTL_MS: number;
25
+ /** Bounded armed-digest map (late toolAfter results must not grow it). */
26
+ export declare const MAX_ARMED_DISPATCH_IDENTITIES = 500;
27
+ /** Frozen denial code — gate-denial-tracker exempts exactly this code. */
28
+ export declare const SPAWN_CIRCUIT_DENIAL_CODE = "SPAWN PROTECTION CIRCUIT OPEN";
29
+ export interface SpawnCircuitEntry {
30
+ state: 'CLOSED' | 'OPEN' | 'HALF_OPEN';
31
+ sessionID: string;
32
+ invocationID: string;
33
+ actionDigest: string;
34
+ failureCount: number;
35
+ openedAt: number;
36
+ denyUntil: number;
37
+ /** Denials issued in the current OPEN episode (reset on each OPEN). */
38
+ denialsInEpisode: number;
39
+ updatedAt: number;
40
+ }
41
+ export declare function invocationIdForSession(sessionID: string): string;
42
+ /**
43
+ * Compute the dispatch identity for a tool + args WITHOUT storing anything.
44
+ * Shared by armDispatchIdentity (before-hook step 0) and by the after-hook
45
+ * recorder's fallback (which must not re-insert into the bounded armed map
46
+ * — a stored-but-never-consumed entry would evict legitimate pending
47
+ * identities under review feedback WD-1).
48
+ */
49
+ export declare function dispatchIdentityFor(tool: string, args: unknown): {
50
+ digest: string;
51
+ pattern: string;
52
+ };
53
+ /**
54
+ * Arm the pre-mutation dispatch identity for a callID. Step 0 of the
55
+ * fail-closed tool.execute.before region calls this BEFORE any hook can
56
+ * mutate `output.args` (skill / delegate-directive injection), so the
57
+ * toolAfter recorder consumes the SAME digest the circuit was keyed with —
58
+ * a corrected success can never clear a phantom key (plan Round 1
59
+ * revision 2).
60
+ */
61
+ export declare function armDispatchIdentity(callID: string, tool: string, args: unknown): {
62
+ digest: string;
63
+ pattern: string;
64
+ };
65
+ /** Consume the armed identity for a callID (fallback: undefined). */
66
+ export declare function takeArmedDispatchIdentity(callID: string): {
67
+ digest: string;
68
+ pattern: string;
69
+ } | undefined;
70
+ /**
71
+ * Record one ACTUAL dispatch failure for the matching action. Returns the
72
+ * entry and whether this call performed the CLOSED->OPEN transition (the
73
+ * caller emits exactly one bounded telemetry event on that transition).
74
+ */
75
+ export declare function noteDispatchSpawnFailure(input: {
76
+ sessionID: string;
77
+ invocationID: string;
78
+ actionDigest: string;
79
+ threshold: number;
80
+ halfOpenAfterMs: number;
81
+ now?: number;
82
+ }): {
83
+ entry: SpawnCircuitEntry;
84
+ opened: boolean;
85
+ };
86
+ /**
87
+ * Deny when the matching action's circuit is OPEN (before its interval
88
+ * elapses) or when a half-open probe is already in flight. When the open
89
+ * interval has elapsed, this call is ADMITTED as the single probe.
90
+ * Throws an Error whose leading token is the frozen
91
+ * SPAWN_CIRCUIT_DENIAL_CODE so the gate-denial tracker can exempt it.
92
+ */
93
+ export declare function assertDispatchSpawnCircuitAdmits(input: {
94
+ sessionID: string;
95
+ invocationID: string;
96
+ actionDigest: string;
97
+ threshold: number;
98
+ halfOpenAfterMs: number;
99
+ now?: number;
100
+ }): void;
101
+ /**
102
+ * A corrected successful execution clears ONLY the matching action's entry
103
+ * (and closes an in-flight half-open probe). Failures of other actions are
104
+ * never touched.
105
+ */
106
+ export declare function noteDispatchSpawnSuccess(input: {
107
+ sessionID: string;
108
+ invocationID: string;
109
+ actionDigest: string;
110
+ }): void;
111
+ export declare function getSpawnCircuitEntry(input: {
112
+ sessionID: string;
113
+ invocationID: string;
114
+ actionDigest: string;
115
+ }): SpawnCircuitEntry | undefined;
116
+ export declare function spawnCircuitIsTaskTool(tool: string): boolean;
117
+ /** Test seam: reset all circuits + armed identities between test files. */
118
+ export declare function _clearAllSpawnCircuits(): void;
119
+ export declare const _internals: {
120
+ now: () => number;
121
+ };
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Token-bucket dispatch rate limiting for native task delegations
3
+ * (issue #2507 / ADR 0002 G3 — reimplemented, no upstream code ported).
4
+ *
5
+ * Pacing, never denial: an empty bucket awaits until a token refills, so
6
+ * dispatch rate is bounded WITHOUT blocking diagnosis or recovery (only the
7
+ * `task` tool acquires tokens; read/diagnose/repair/rescope/abort controls
8
+ * never wait).
9
+ *
10
+ * Restart-state integration: the per-PROJECT bucket level and refill
11
+ * timestamp persist as one row in the existing `coordination_state` table
12
+ * under namespace `dispatch.token-bucket` (entity `project`), written when
13
+ * tokens are consumed. A fresh process rehydrates from that row and refills
14
+ * by elapsed wall time — an exhausted bucket does not grant a fresh burst
15
+ * after restart. Write failures fail OPEN (debug log, never break
16
+ * dispatch): the in-memory bucket stays authoritative for the process
17
+ * lifetime, and a restart after persistent write failure sees no row and
18
+ * grants a fresh burst (documented limitation — the limiter's purpose is
19
+ * runaway containment within a process).
20
+ */
21
+ export declare const TOKEN_BUCKET_NAMESPACE = "dispatch.token-bucket";
22
+ export declare const TOKEN_BUCKET_ENTITY_KEY = "project";
23
+ /**
24
+ * Acquire one dispatch token, awaiting until one is available (paced, never
25
+ * denied). `ratePerSecond === 0` disables the limiter entirely.
26
+ *
27
+ * Persistence is debounced to the acquires that matter for restart
28
+ * semantics: only a PACED acquire (one that had to wait for a refill)
29
+ * writes the coordination row. Immediate burst consumption is
30
+ * reconstructible within the documented one-burst over-permission bound,
31
+ * and skipping those writes keeps the common fast path free of SQLite I/O
32
+ * (composing gates run under tight timing windows).
33
+ */
34
+ export declare function acquireDispatchToken(input: {
35
+ directory: string;
36
+ ratePerSecond: number;
37
+ burstCapacity: number;
38
+ }): Promise<void>;
39
+ /** Test seam: forget all in-memory buckets (does not touch persisted rows). */
40
+ export declare function _resetDispatchTokenBuckets(): void;
41
+ export declare const _internals: {
42
+ now: () => number;
43
+ sleep: (ms: number) => Promise<void>;
44
+ readState: (directory: string) => import("../db/coordination-store.js").CoordinationState | null;
45
+ onPersistError: (err: unknown) => void;
46
+ };
@@ -0,0 +1,61 @@
1
+ import { closeProjectDb } from '../../db/project-db';
2
+ import { atomicWriteSwarmFileSync } from '../../utils/atomic-write';
3
+ import { bunSpawn } from '../../utils/bun-compat';
4
+ import { canonicalRootKeyFresh } from '../../utils/canonical-root';
5
+ import { resolveGitExecutable } from '../../utils/git-executable.js';
6
+ import { removeWorktree } from '../../worktree/core';
7
+ export interface DeadLaneReclaimEntry {
8
+ lanePath: string;
9
+ branchName: string;
10
+ parentSessionId: string;
11
+ taskId: string;
12
+ /** The removal error that stranded the lane (e.g. `EBUSY: ...`). */
13
+ reason: string;
14
+ recordedAt: number;
15
+ }
16
+ export interface ReclaimDeadLanesContext {
17
+ /**
18
+ * Session ids that still own live state (#2527 interplay: a lane whose
19
+ * parent session is active, or whose path is protected by recovery/
20
+ * ownership machinery, is NOT reclaimable — it is not dead).
21
+ */
22
+ activeSessionIds?: Iterable<string>;
23
+ protectedWorktreePaths?: Iterable<string>;
24
+ }
25
+ export interface ReclaimDeadLanesResult {
26
+ reclaimed: string[];
27
+ retained: Array<{
28
+ lanePath: string;
29
+ reason: string;
30
+ }>;
31
+ }
32
+ /** Record a dead lane for next-start reclaim. Dedupes by lanePath. */
33
+ export declare function recordDeadLaneReclaim(directory: string, entry: Omit<DeadLaneReclaimEntry, 'recordedAt'>): void;
34
+ /** Read-only view for diagnostics and tests. */
35
+ export declare function listDeadLaneReclaims(directory: string): DeadLaneReclaimEntry[];
36
+ declare function isLaneOwnedByActiveSession(lanePath: string, activeSessionIds: Set<string>, parentSessionId?: string): boolean;
37
+ /**
38
+ * Dirty-lane gate (#2508 interplay): a lane with uncommitted changes is NEVER
39
+ * purged without the shared confirmation primitive — fail closed. Any git
40
+ * error also counts as dirty: an unknowable state is not a purgeable state.
41
+ */
42
+ declare function isLaneDirty(lanePath: string): Promise<boolean>;
43
+ /**
44
+ * Reclaim every recorded dead lane whose gates pass. Runs inside the bounded,
45
+ * fail-open next-start init task (`runInitOrphanRecovery`), so it never throws
46
+ * and never blocks init: per-lane failures retain the entry for the next start.
47
+ */
48
+ export declare function reclaimDeadLanes(directory: string, context?: ReclaimDeadLanesContext): Promise<ReclaimDeadLanesResult>;
49
+ declare function pathExists(target: string): Promise<boolean>;
50
+ export declare const _internals: {
51
+ removeWorktree: typeof removeWorktree;
52
+ closeProjectDb: typeof closeProjectDb;
53
+ isLaneOwnedByActiveSession: typeof isLaneOwnedByActiveSession;
54
+ isLaneDirty: typeof isLaneDirty;
55
+ pathExists: typeof pathExists;
56
+ bunSpawn: typeof bunSpawn;
57
+ resolveGitExecutable: typeof resolveGitExecutable;
58
+ atomicWriteSwarmFileSync: typeof atomicWriteSwarmFileSync;
59
+ canonicalRootKeyFresh: typeof canonicalRootKeyFresh;
60
+ };
61
+ export {};
@@ -146,6 +146,16 @@ interface SessionSerializationState {
146
146
  */
147
147
  successfulDispatchesSince: number;
148
148
  }
149
+ /**
150
+ * Issue #2599: bounded lane session.create with deterministic late-settle
151
+ * handling. The create promise's outcome is captured exactly once into a
152
+ * derived settle-state promise — never a mutable flag read across async
153
+ * continuations — so a create that settles after the deadline reaches
154
+ * `onLateResolve` (verified teardown of the late child) under EVERY
155
+ * microtask interleaving, and only after the settle (or this grace bound)
156
+ * does the caller's lane cleanup begin.
157
+ */
158
+ declare function createSessionWithinBudget<T>(promise: Promise<T>, label: string, onLateResolve?: (result: T) => Promise<void> | void, timeoutMs?: number): Promise<T>;
149
159
  interface CleanupStandardWorktreeResult {
150
160
  removedWorktree: boolean;
151
161
  cleanedBranch: boolean;
@@ -384,6 +394,18 @@ export declare const _internals: {
384
394
  preserveDirtyWorktreeAtPath: typeof preserveDirtyWorktreeAtPath;
385
395
  /** Bounded lane session.create timeout (tests may override). */
386
396
  worktreeSessionCreateTimeoutMs: number;
397
+ /**
398
+ * Issue #2599 AC4: bound on how long the deadline path waits for the
399
+ * create promise to settle before proceeding to lane cleanup. Tests
400
+ * override this to keep never-settling-create cases fast.
401
+ */
402
+ worktreeSessionCreateSettleGraceMs: number;
403
+ /**
404
+ * Issue #2599: the settle-state-machine budget wrapper, exposed so tests
405
+ * can drive both late-settle interleavings directly with controlled
406
+ * promises (no racy shared flag is involved).
407
+ */
408
+ createSessionWithinBudget: typeof createSessionWithinBudget;
387
409
  /** FR-001a: abort entry point for in-flight dispatches. */
388
410
  abortStandardWorktreeDispatch: typeof abortStandardWorktreeDispatch;
389
411
  standardWorktreeByCallID: Map<string, StandardWorktreeDispatch>;
@@ -15,6 +15,7 @@
15
15
  * advanced, so the next cycle recomputes and retries — a lost directive can
16
16
  * no longer be permanently suppressed by idempotency while state advances.
17
17
  */
18
+ import { getPlanLedgerStateReadOnly } from '../plan/ledger-sqlite';
18
19
  import { error as _logErrorImpl } from '../utils/logger.js';
19
20
  import { isPlanCriticApproved } from './delegation-gate';
20
21
  import { implementationReviewReceiptExists, publicationReceiptExists, readIssueReference, readPlanPhaseStatus, readSpecIssueNumber, readTraceState, recurrenceSweepReceiptExists, reproductionReceiptExists, specExists, writeTraceState } from './issue-trace-state';
@@ -30,7 +31,9 @@ export declare const _internals: {
30
31
  recurrenceSweepReceiptExists: typeof recurrenceSweepReceiptExists;
31
32
  implementationReviewReceiptExists: typeof implementationReviewReceiptExists;
32
33
  isPlanCriticApproved: typeof isPlanCriticApproved;
34
+ getPlanLedgerState: typeof getPlanLedgerStateReadOnly;
33
35
  logError: typeof _logErrorImpl;
36
+ boundedApprovalCheck: (directory: string, timeoutMs: number) => Promise<boolean>;
34
37
  };
35
38
  export declare function createIssueTraceHook(_config: unknown, directory: string, approvalTimeoutMs?: number): {
36
39
  messagesTransform: (input: unknown, output: unknown) => Promise<void>;
@@ -76,7 +76,7 @@ export declare function composeBlockingHandlers<I, O>(...fns: Array<HookHandler<
76
76
  * @throws Error if the filename is invalid or attempts path traversal
77
77
  */
78
78
  export declare function validateSwarmPath(directory: string, filename: string): string;
79
- export declare function readSwarmFileAsync(directory: string, filename: string, cache?: Map<string, Promise<string | null>>): Promise<string | null>;
79
+ export declare function readSwarmFileAsync(directory: string, filename: string, cache?: Map<string, Promise<string | null>>, reader?: (resolvedPath: string) => Promise<string | null>, useArtifactCache?: boolean): Promise<string | null>;
80
80
  /**
81
81
  * Estimate tokens from a character count using the canonical heuristic.
82
82
  * This is the single sanctioned numeric form (issue #2107 §1).