harnery 0.41.0 → 0.43.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (269) hide show
  1. package/dist/commander.d.ts +16 -0
  2. package/dist/commander.d.ts.map +1 -1
  3. package/dist/commander.js +21 -0
  4. package/dist/commands/agents.d.ts.map +1 -1
  5. package/dist/commands/agents.js +63 -5
  6. package/dist/commands/artifacts.d.ts.map +1 -1
  7. package/dist/commands/artifacts.js +113 -12
  8. package/dist/commands/browse.d.ts +164 -0
  9. package/dist/commands/browse.d.ts.map +1 -1
  10. package/dist/commands/browse.js +263 -51
  11. package/dist/commands/claude-desktop.d.ts.map +1 -1
  12. package/dist/commands/claude-desktop.js +52 -0
  13. package/dist/commands/disk.d.ts +6 -0
  14. package/dist/commands/disk.d.ts.map +1 -0
  15. package/dist/commands/disk.js +80 -0
  16. package/dist/commands/doctor.d.ts +8 -0
  17. package/dist/commands/doctor.d.ts.map +1 -1
  18. package/dist/commands/doctor.js +48 -1
  19. package/dist/commands/files.d.ts +16 -0
  20. package/dist/commands/files.d.ts.map +1 -1
  21. package/dist/commands/files.js +54 -2
  22. package/dist/commands/init.d.ts +2 -2
  23. package/dist/commands/init.d.ts.map +1 -1
  24. package/dist/commands/init.js +43 -9
  25. package/dist/commands/rm.d.ts +4 -0
  26. package/dist/commands/rm.d.ts.map +1 -0
  27. package/dist/commands/rm.js +87 -0
  28. package/dist/commands/servers.d.ts +7 -0
  29. package/dist/commands/servers.d.ts.map +1 -0
  30. package/dist/commands/servers.js +394 -0
  31. package/dist/commands/tunnel.d.ts +65 -0
  32. package/dist/commands/tunnel.d.ts.map +1 -1
  33. package/dist/commands/tunnel.js +372 -103
  34. package/dist/commands/web-fetch.d.ts +3 -2
  35. package/dist/commands/web-fetch.d.ts.map +1 -1
  36. package/dist/commands/web-fetch.js +25 -19
  37. package/dist/commands/web.d.ts +7 -1
  38. package/dist/commands/web.d.ts.map +1 -1
  39. package/dist/commands/web.js +9 -3
  40. package/dist/core/adapters/profiles.d.ts +9 -0
  41. package/dist/core/adapters/profiles.d.ts.map +1 -1
  42. package/dist/core/adapters/profiles.js +22 -1
  43. package/dist/core/adapters/types.d.ts +9 -0
  44. package/dist/core/adapters/types.d.ts.map +1 -1
  45. package/dist/core/agents/cli.js +13 -6
  46. package/dist/core/agents/render/prompt-context.d.ts.map +1 -1
  47. package/dist/core/agents/render/prompt-context.js +11 -5
  48. package/dist/core/agents/render/session-context.d.ts.map +1 -1
  49. package/dist/core/agents/render/session-context.js +59 -13
  50. package/dist/core/agents/state/live-coordination-view.d.ts +20 -0
  51. package/dist/core/agents/state/live-coordination-view.d.ts.map +1 -1
  52. package/dist/core/agents/state/live-coordination-view.js +60 -0
  53. package/dist/core/agents/state/names.d.ts +43 -3
  54. package/dist/core/agents/state/names.d.ts.map +1 -1
  55. package/dist/core/agents/state/names.js +87 -3
  56. package/dist/core/artifacts/delivery-card.js +9 -2
  57. package/dist/core/artifacts/index.d.ts +140 -4
  58. package/dist/core/artifacts/index.d.ts.map +1 -1
  59. package/dist/core/artifacts/index.js +522 -49
  60. package/dist/core/config.d.ts +68 -11
  61. package/dist/core/config.d.ts.map +1 -1
  62. package/dist/core/config.js +128 -3
  63. package/dist/core/diagnostics/bundle.d.ts.map +1 -1
  64. package/dist/core/diagnostics/bundle.js +2 -2
  65. package/dist/core/events/v3/producers/recorder.d.ts.map +1 -1
  66. package/dist/core/events/v3/producers/recorder.js +16 -0
  67. package/dist/core/events/v3/projection.js +9 -1
  68. package/dist/core/events/v3/support-storage/pack-reader.d.ts.map +1 -1
  69. package/dist/core/events/v3/support-storage/pack-reader.js +42 -16
  70. package/dist/core/hooks/adapter/events.d.ts +17 -0
  71. package/dist/core/hooks/adapter/events.d.ts.map +1 -1
  72. package/dist/core/hooks/adapter/events.js +5 -0
  73. package/dist/core/hooks/adapter/runtime-telemetry.js +3 -1
  74. package/dist/core/hooks/adapter/wiring.d.ts +37 -7
  75. package/dist/core/hooks/adapter/wiring.d.ts.map +1 -1
  76. package/dist/core/hooks/adapter/wiring.js +62 -4
  77. package/dist/core/hooks/cli.js +131 -23
  78. package/dist/core/hooks/fork-lineage.d.ts +40 -0
  79. package/dist/core/hooks/fork-lineage.d.ts.map +1 -0
  80. package/dist/core/hooks/fork-lineage.js +62 -0
  81. package/dist/core/hooks/resolve/transcript.d.ts +16 -0
  82. package/dist/core/hooks/resolve/transcript.d.ts.map +1 -1
  83. package/dist/core/hooks/resolve/transcript.js +84 -0
  84. package/dist/core/hooks/run-markers.d.ts +37 -0
  85. package/dist/core/hooks/run-markers.d.ts.map +1 -0
  86. package/dist/core/hooks/run-markers.js +109 -0
  87. package/dist/core/hooks/shell-rm.d.ts +2 -0
  88. package/dist/core/hooks/shell-rm.d.ts.map +1 -0
  89. package/dist/core/hooks/shell-rm.js +105 -0
  90. package/dist/core/hooks/shell-tokens.d.ts +12 -0
  91. package/dist/core/hooks/shell-tokens.d.ts.map +1 -0
  92. package/dist/core/hooks/shell-tokens.js +97 -0
  93. package/dist/core/hooks/shell-waiter.d.ts.map +1 -1
  94. package/dist/core/hooks/shell-waiter.js +3 -93
  95. package/dist/core/semantic/contract.d.ts +5 -5
  96. package/dist/core/servers/index.d.ts +211 -0
  97. package/dist/core/servers/index.d.ts.map +1 -0
  98. package/dist/core/servers/index.js +560 -0
  99. package/dist/core/servers/net.d.ts +58 -0
  100. package/dist/core/servers/net.d.ts.map +1 -0
  101. package/dist/core/servers/net.js +270 -0
  102. package/dist/core/servers/tunnels.d.ts +14 -0
  103. package/dist/core/servers/tunnels.d.ts.map +1 -0
  104. package/dist/core/servers/tunnels.js +33 -0
  105. package/dist/core/storage/builtins.js +1 -0
  106. package/dist/core/storage/process-log.d.ts +12 -0
  107. package/dist/core/storage/process-log.d.ts.map +1 -1
  108. package/dist/core/storage/process-log.js +10 -2
  109. package/dist/core/workflow/engine.d.ts.map +1 -1
  110. package/dist/core/workflow/engine.js +30 -1
  111. package/dist/core/workflow/sandbox-projection.d.ts +13 -2
  112. package/dist/core/workflow/sandbox-projection.d.ts.map +1 -1
  113. package/dist/core/workflow/sandbox-projection.js +23 -0
  114. package/dist/core/workflow/spawn-claude.d.ts.map +1 -1
  115. package/dist/core/workflow/spawn-claude.js +6 -1
  116. package/dist/core/workflow/spawn-codex.d.ts +2 -0
  117. package/dist/core/workflow/spawn-codex.d.ts.map +1 -1
  118. package/dist/core/workflow/spawn-codex.js +20 -1
  119. package/dist/core/workflow/spawn-cursor.d.ts.map +1 -1
  120. package/dist/core/workflow/spawn-cursor.js +6 -1
  121. package/dist/core/workflow/spawn-opencode.d.ts.map +1 -1
  122. package/dist/core/workflow/spawn-opencode.js +4 -1
  123. package/dist/core/workflow/types.d.ts +47 -2
  124. package/dist/core/workflow/types.d.ts.map +1 -1
  125. package/dist/core/workflow/worker-access.d.ts +92 -0
  126. package/dist/core/workflow/worker-access.d.ts.map +1 -0
  127. package/dist/core/workflow/worker-access.js +450 -0
  128. package/dist/lib/browser/batch-steps.d.ts +18 -0
  129. package/dist/lib/browser/batch-steps.d.ts.map +1 -0
  130. package/dist/lib/browser/batch-steps.js +82 -0
  131. package/dist/lib/browser/collect/collector.d.ts +99 -0
  132. package/dist/lib/browser/collect/collector.d.ts.map +1 -0
  133. package/dist/lib/browser/collect/collector.js +202 -0
  134. package/dist/lib/browser/collect/fields.d.ts +31 -0
  135. package/dist/lib/browser/collect/fields.d.ts.map +1 -0
  136. package/dist/lib/browser/collect/fields.js +75 -0
  137. package/dist/lib/browser/collect/index.d.ts +6 -0
  138. package/dist/lib/browser/collect/index.d.ts.map +1 -0
  139. package/dist/lib/browser/collect/index.js +5 -0
  140. package/dist/lib/browser/collect/page-driver.d.ts +14 -0
  141. package/dist/lib/browser/collect/page-driver.d.ts.map +1 -0
  142. package/dist/lib/browser/collect/page-driver.js +306 -0
  143. package/dist/lib/browser/collect/presets.d.ts +52 -0
  144. package/dist/lib/browser/collect/presets.d.ts.map +1 -0
  145. package/dist/lib/browser/collect/presets.js +176 -0
  146. package/dist/lib/browser/collect/scroll-plan.d.ts +85 -0
  147. package/dist/lib/browser/collect/scroll-plan.d.ts.map +1 -0
  148. package/dist/lib/browser/collect/scroll-plan.js +118 -0
  149. package/dist/lib/browser/index.d.ts +1 -1
  150. package/dist/lib/browser/index.d.ts.map +1 -1
  151. package/dist/lib/browser/page-review-judge.d.ts +2 -0
  152. package/dist/lib/browser/page-review-judge.d.ts.map +1 -1
  153. package/dist/lib/browser/page-review-judge.js +13 -0
  154. package/dist/lib/browser/qa-run-contracts.d.ts +10 -0
  155. package/dist/lib/browser/qa-run-contracts.d.ts.map +1 -1
  156. package/dist/lib/browser/qa-run.d.ts.map +1 -1
  157. package/dist/lib/browser/qa-run.js +1 -0
  158. package/dist/lib/browser/windows-chrome.d.ts +59 -0
  159. package/dist/lib/browser/windows-chrome.d.ts.map +1 -0
  160. package/dist/lib/browser/windows-chrome.js +179 -0
  161. package/dist/lib/claude-desktop-share.d.ts +136 -0
  162. package/dist/lib/claude-desktop-share.d.ts.map +1 -0
  163. package/dist/lib/claude-desktop-share.js +394 -0
  164. package/dist/lib/disk-usage.d.ts +50 -0
  165. package/dist/lib/disk-usage.d.ts.map +1 -0
  166. package/dist/lib/disk-usage.js +303 -0
  167. package/dist/lib/docs-lint.d.ts +6 -0
  168. package/dist/lib/docs-lint.d.ts.map +1 -1
  169. package/dist/lib/docs-lint.js +8 -3
  170. package/dist/lib/guarded-remove.d.ts +34 -0
  171. package/dist/lib/guarded-remove.d.ts.map +1 -0
  172. package/dist/lib/guarded-remove.js +310 -0
  173. package/dist/lib/instructions/templates.js +8 -8
  174. package/dist/lib/tunnel/allowlist.d.ts +44 -0
  175. package/dist/lib/tunnel/allowlist.d.ts.map +1 -0
  176. package/dist/lib/tunnel/allowlist.js +204 -0
  177. package/dist/lib/tunnel/current-address.d.ts +41 -0
  178. package/dist/lib/tunnel/current-address.d.ts.map +1 -0
  179. package/dist/lib/tunnel/current-address.js +123 -0
  180. package/dist/lib/tunnel/error-page.d.ts +1 -1
  181. package/dist/lib/tunnel/error-page.d.ts.map +1 -1
  182. package/dist/lib/tunnel/error-page.js +19 -8
  183. package/dist/lib/tunnel/gate.js +33 -7
  184. package/dist/lib/tunnel/path-scope.d.ts +22 -0
  185. package/dist/lib/tunnel/path-scope.d.ts.map +1 -0
  186. package/dist/lib/tunnel/path-scope.js +62 -0
  187. package/dist/lib/tunnel/processes.d.ts +39 -0
  188. package/dist/lib/tunnel/processes.d.ts.map +1 -0
  189. package/dist/lib/tunnel/processes.js +121 -0
  190. package/dist/lib/tunnel/state.d.ts +33 -3
  191. package/dist/lib/tunnel/state.d.ts.map +1 -1
  192. package/dist/lib/tunnel/state.js +115 -30
  193. package/package.json +7 -1
  194. package/schemas/config.schema.json +91 -0
  195. package/src/commander.ts +51 -0
  196. package/src/commands/agents.ts +111 -11
  197. package/src/commands/artifacts.ts +171 -19
  198. package/src/commands/browse.ts +400 -57
  199. package/src/commands/claude-desktop.ts +61 -0
  200. package/src/commands/disk.ts +114 -0
  201. package/src/commands/doctor.ts +52 -1
  202. package/src/commands/files.ts +93 -2
  203. package/src/commands/init.ts +55 -5
  204. package/src/commands/rm.ts +115 -0
  205. package/src/commands/servers.ts +506 -0
  206. package/src/commands/tunnel.ts +494 -116
  207. package/src/commands/web-fetch.ts +30 -19
  208. package/src/commands/web.ts +9 -3
  209. package/src/core/adapters/profiles.ts +22 -1
  210. package/src/core/adapters/types.ts +10 -0
  211. package/src/core/agents/cli.ts +14 -6
  212. package/src/core/agents/render/prompt-context.ts +25 -8
  213. package/src/core/agents/render/session-context.ts +84 -16
  214. package/src/core/agents/state/live-coordination-view.ts +73 -0
  215. package/src/core/agents/state/names.ts +117 -6
  216. package/src/core/artifacts/delivery-card.ts +10 -2
  217. package/src/core/artifacts/index.ts +697 -44
  218. package/src/core/config.ts +183 -4
  219. package/src/core/diagnostics/bundle.ts +2 -1
  220. package/src/core/events/v3/producers/recorder.ts +16 -0
  221. package/src/core/events/v3/projection.ts +11 -1
  222. package/src/core/events/v3/support-storage/pack-reader.ts +45 -19
  223. package/src/core/hooks/adapter/events.ts +19 -0
  224. package/src/core/hooks/adapter/runtime-telemetry.ts +3 -1
  225. package/src/core/hooks/adapter/wiring.ts +116 -8
  226. package/src/core/hooks/cli.ts +152 -22
  227. package/src/core/hooks/fork-lineage.ts +82 -0
  228. package/src/core/hooks/resolve/transcript.ts +88 -0
  229. package/src/core/hooks/run-markers.ts +132 -0
  230. package/src/core/hooks/shell-rm.ts +103 -0
  231. package/src/core/hooks/shell-tokens.ts +96 -0
  232. package/src/core/hooks/shell-waiter.ts +4 -91
  233. package/src/core/servers/index.ts +712 -0
  234. package/src/core/servers/net.ts +283 -0
  235. package/src/core/servers/tunnels.ts +39 -0
  236. package/src/core/storage/builtins.ts +1 -0
  237. package/src/core/storage/process-log.ts +17 -2
  238. package/src/core/workflow/engine.ts +38 -1
  239. package/src/core/workflow/sandbox-projection.ts +38 -2
  240. package/src/core/workflow/spawn-claude.ts +5 -1
  241. package/src/core/workflow/spawn-codex.ts +18 -1
  242. package/src/core/workflow/spawn-cursor.ts +5 -1
  243. package/src/core/workflow/spawn-opencode.ts +4 -1
  244. package/src/core/workflow/types.ts +62 -2
  245. package/src/core/workflow/worker-access.ts +525 -0
  246. package/src/lib/browser/batch-steps.ts +79 -0
  247. package/src/lib/browser/collect/collector.ts +306 -0
  248. package/src/lib/browser/collect/fields.ts +87 -0
  249. package/src/lib/browser/collect/index.ts +47 -0
  250. package/src/lib/browser/collect/page-driver.ts +327 -0
  251. package/src/lib/browser/collect/presets.ts +237 -0
  252. package/src/lib/browser/collect/scroll-plan.ts +179 -0
  253. package/src/lib/browser/index.ts +1 -0
  254. package/src/lib/browser/page-review-judge.ts +16 -0
  255. package/src/lib/browser/qa-run-contracts.ts +11 -0
  256. package/src/lib/browser/qa-run.ts +1 -0
  257. package/src/lib/browser/windows-chrome.ts +227 -0
  258. package/src/lib/claude-desktop-share.ts +511 -0
  259. package/src/lib/disk-usage.ts +347 -0
  260. package/src/lib/docs-lint.ts +8 -3
  261. package/src/lib/guarded-remove.ts +376 -0
  262. package/src/lib/instructions/templates.ts +8 -8
  263. package/src/lib/tunnel/allowlist.ts +208 -0
  264. package/src/lib/tunnel/current-address.ts +158 -0
  265. package/src/lib/tunnel/error-page.ts +25 -9
  266. package/src/lib/tunnel/gate.ts +38 -9
  267. package/src/lib/tunnel/path-scope.ts +73 -0
  268. package/src/lib/tunnel/processes.ts +149 -0
  269. package/src/lib/tunnel/state.ts +143 -30
@@ -1,10 +1,11 @@
1
+ import { spawnSync } from "node:child_process";
1
2
  import type { EmitContext } from "../commander.js";
2
3
  /** bun if available (preferred), else npm. Both support `<runner> install` and `<runner> run <script>`. */
3
- export declare function webRunner(): "bun" | "npm";
4
+ export declare function webRunner(spawn?: typeof spawnSync): "bun" | "npm";
4
5
  /**
5
6
  * Ensure a cached harnery checkout's `web/` exists for this version and return
6
7
  * its path, fetching (clone + install) on first use. Returns null on failure
7
8
  * (after emitting an actionable error).
8
9
  */
9
- export declare function lazyFetchWebRoot(emit: EmitContext): string | null;
10
+ export declare function lazyFetchWebRoot(emit: EmitContext, spawn?: typeof spawnSync): string | null;
10
11
  //# sourceMappingURL=web-fetch.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"web-fetch.d.ts","sourceRoot":"","sources":["../../src/commands/web-fetch.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAiDnD,2GAA2G;AAC3G,wBAAgB,SAAS,IAAI,KAAK,GAAG,KAAK,CAGzC;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,GAAG,IAAI,CAmDjE"}
1
+ {"version":3,"file":"web-fetch.d.ts","sourceRoot":"","sources":["../../src/commands/web-fetch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAK/C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAmDnD,2GAA2G;AAC3G,wBAAgB,SAAS,CAAC,KAAK,GAAE,OAAO,SAAqB,GAAG,KAAK,GAAG,KAAK,CAG5E;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,WAAW,EACjB,KAAK,GAAE,OAAO,SAAqB,GAClC,MAAM,GAAG,IAAI,CAyDf"}
@@ -14,9 +14,11 @@ import { fileURLToPath } from "node:url";
14
14
  * harnery repo at the *matching version tag* into a cache dir and install the
15
15
  * web app's deps. Subsequent runs reuse the cache.
16
16
  *
17
- * The only thing `web/` pulls from `src/` is `harnery/core/journal` (a single,
18
- * dependency-free module), so the install is `web/` deps only: no root install,
19
- * no Playwright browser download.
17
+ * `web/` imports readers from `src/`, and `web/next.config.ts` resolves the
18
+ * root `playwright` package, so the install covers the repository root and
19
+ * then `web/`. Installing the `playwright` package downloads no browsers.
20
+ * Installing `web/` alone left `harn web up` failing with
21
+ * `Cannot find module 'playwright/package.json'`.
20
22
  */
21
23
  const DEFAULT_REPO_URL = "https://github.com/ryanjkelly/harnery.git";
22
24
  /** harnery's own package root: src/commands/ -> ../.. ; valid in both src/ and dist/. */
@@ -46,8 +48,8 @@ function webCacheRoot(ref) {
46
48
  return path.join(base, "harnery", "web", safeRef);
47
49
  }
48
50
  /** bun if available (preferred), else npm. Both support `<runner> install` and `<runner> run <script>`. */
49
- export function webRunner() {
50
- const r = spawnSync("bun", ["--version"], { stdio: "ignore" });
51
+ export function webRunner(spawn = spawnSync) {
52
+ const r = spawn("bun", ["--version"], { stdio: "ignore" });
51
53
  return r.status === 0 ? "bun" : "npm";
52
54
  }
53
55
  /**
@@ -55,13 +57,14 @@ export function webRunner() {
55
57
  * its path, fetching (clone + install) on first use. Returns null on failure
56
58
  * (after emitting an actionable error).
57
59
  */
58
- export function lazyFetchWebRoot(emit) {
60
+ export function lazyFetchWebRoot(emit, spawn = spawnSync) {
59
61
  const { version, repoUrl } = readPkg();
60
62
  const ref = resolveRef(version);
61
63
  const cacheRoot = webCacheRoot(ref);
62
64
  const webDir = path.join(cacheRoot, "web");
63
- // node_modules in the cached web/ is the "fetched + installed" marker.
64
- if (existsSync(path.join(webDir, "node_modules"))) {
65
+ // node_modules in both the cached root and web/ is the "fetched + installed" marker.
66
+ if (existsSync(path.join(cacheRoot, "node_modules")) &&
67
+ existsSync(path.join(webDir, "node_modules"))) {
65
68
  emit.log(`harn web · using cached dashboard (${ref})`, "info");
66
69
  return webDir;
67
70
  }
@@ -71,7 +74,7 @@ export function lazyFetchWebRoot(emit) {
71
74
  if (existsSync(cacheRoot))
72
75
  rmSync(cacheRoot, { recursive: true, force: true });
73
76
  mkdirSync(path.dirname(cacheRoot), { recursive: true });
74
- const clone = spawnSync("git", ["clone", "--depth", "1", "--branch", ref, repoUrl, cacheRoot], {
77
+ const clone = spawn("git", ["clone", "--depth", "1", "--branch", ref, repoUrl, cacheRoot], {
75
78
  stdio: "inherit",
76
79
  });
77
80
  if (clone.status !== 0) {
@@ -84,16 +87,19 @@ export function lazyFetchWebRoot(emit) {
84
87
  });
85
88
  return null;
86
89
  }
87
- const runner = webRunner();
88
- emit.log(`harn web · installing dashboard deps (${runner} install in web/)`, "info");
89
- const install = spawnSync(runner, ["install"], { cwd: webDir, stdio: "inherit" });
90
- if (install.status !== 0) {
91
- emit.error({
92
- code: "web_fetch_failed",
93
- message: `${runner} install in ${webDir} failed (status ${install.status})`,
94
- hint: `Try manually: cd ${webDir} && ${runner} install`,
95
- });
96
- return null;
90
+ const runner = webRunner(spawn);
91
+ for (const dir of [cacheRoot, webDir]) {
92
+ const where = dir === webDir ? "web/" : "the harnery root";
93
+ emit.log(`harn web · installing dashboard deps (${runner} install in ${where})`, "info");
94
+ const install = spawn(runner, ["install"], { cwd: dir, stdio: "inherit" });
95
+ if (install.status !== 0) {
96
+ emit.error({
97
+ code: "web_fetch_failed",
98
+ message: `${runner} install in ${dir} failed (status ${install.status})`,
99
+ hint: `Try manually: cd ${dir} && ${runner} install`,
100
+ });
101
+ return null;
102
+ }
97
103
  }
98
104
  emit.log(`harn web · dashboard ready (cached at ${webDir})`, "info");
99
105
  return webDir;
@@ -19,7 +19,13 @@ export declare function resolveMaxOldSpaceMb(flag?: string): number;
19
19
  * wins without clobbering flags the caller set (source maps, inspector, …).
20
20
  */
21
21
  export declare function nodeOptionsWithHeapCap(mb: number): string | undefined;
22
- /** Preload the request diagnostics hook without replacing Next's HTTP server. */
22
+ /**
23
+ * Preload the dashboard's server hooks (keep-alive and request diagnostics)
24
+ * without replacing Next's HTTP server. NODE_OPTIONS reaches the child that
25
+ * `next dev` forks, but Next re-parses every `--import` into one value, so
26
+ * this names the single combined preload; a second, different `--import`
27
+ * would collapse into an unloadable path (web/server-preload.mjs).
28
+ */
23
29
  export declare function nodeOptionsWithWebDiagnostics(webDir: string, mb: number): string;
24
30
  export declare function webPerformanceLogDestination(coordRoot: string, env?: Readonly<Record<string, string | undefined>>): string;
25
31
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"web.d.ts","sourceRoot":"","sources":["../../src/commands/web.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AA8CnD;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAM1D;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAKrE;AAED,iFAAiF;AACjF,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAKhF;AAED,wBAAgB,4BAA4B,CAC1C,SAAS,EAAE,MAAM,EACjB,GAAG,GAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAe,GAC9D,MAAM,CAQR;AAmDD;;;;GAIG;AACH,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAevE;AAsBD,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,GAAG,IAAI,CA2N5E"}
1
+ {"version":3,"file":"web.d.ts","sourceRoot":"","sources":["../../src/commands/web.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AA8CnD;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAM1D;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAKrE;AAED;;;;;;GAMG;AACH,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAKhF;AAED,wBAAgB,4BAA4B,CAC1C,SAAS,EAAE,MAAM,EACjB,GAAG,GAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAe,GAC9D,MAAM,CAQR;AAmDD;;;;GAIG;AACH,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAevE;AAsBD,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,GAAG,IAAI,CA2N5E"}
@@ -71,12 +71,18 @@ export function nodeOptionsWithHeapCap(mb) {
71
71
  return inherited;
72
72
  return `${inherited} --max-old-space-size=${mb}`.trim();
73
73
  }
74
- /** Preload the request diagnostics hook without replacing Next's HTTP server. */
74
+ /**
75
+ * Preload the dashboard's server hooks (keep-alive and request diagnostics)
76
+ * without replacing Next's HTTP server. NODE_OPTIONS reaches the child that
77
+ * `next dev` forks, but Next re-parses every `--import` into one value, so
78
+ * this names the single combined preload; a second, different `--import`
79
+ * would collapse into an unloadable path (web/server-preload.mjs).
80
+ */
75
81
  export function nodeOptionsWithWebDiagnostics(webDir, mb) {
76
82
  const inherited = nodeOptionsWithHeapCap(mb) ?? "";
77
- if (inherited.includes("server-performance.mjs"))
83
+ if (inherited.includes("server-preload.mjs"))
78
84
  return inherited;
79
- const preload = pathToFileURL(path.join(webDir, "server-performance.mjs")).href;
85
+ const preload = pathToFileURL(path.join(webDir, "server-preload.mjs")).href;
80
86
  return `${inherited} --import=${preload}`.trim();
81
87
  }
82
88
  export function webPerformanceLogDestination(coordRoot, env = process.env) {
@@ -17,6 +17,9 @@ export declare const BUILTIN_ADAPTER_PROFILES: {
17
17
  readonly date: "2026-08-18";
18
18
  readonly version: "2.1.233 (Claude Code)";
19
19
  };
20
+ readonly fullAccess: {
21
+ readonly argv: readonly ["--permission-mode", "bypassPermissions", "--settings", "{\"sandbox\":{\"enabled\":false}}"];
22
+ };
20
23
  readonly capabilities: AdapterCapabilities;
21
24
  };
22
25
  readonly codex: {
@@ -41,6 +44,9 @@ export declare const BUILTIN_ADAPTER_PROFILES: {
41
44
  };
42
45
  readonly writableRoots: true;
43
46
  };
47
+ readonly fullAccess: {
48
+ readonly argv: readonly ["--sandbox", "danger-full-access"];
49
+ };
44
50
  readonly capabilities: AdapterCapabilities;
45
51
  };
46
52
  readonly cursor: {
@@ -58,6 +64,9 @@ export declare const BUILTIN_ADAPTER_PROFILES: {
58
64
  readonly date: "2026-09-20";
59
65
  readonly version: "2026.09.18-9a7762b";
60
66
  };
67
+ readonly fullAccess: {
68
+ readonly argv: readonly ["--sandbox", "disabled"];
69
+ };
61
70
  readonly capabilities: AdapterCapabilities;
62
71
  };
63
72
  readonly opencode: {
@@ -1 +1 @@
1
- {"version":3,"file":"profiles.d.ts","sourceRoot":"","sources":["../../../src/core/adapters/profiles.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,cAAc,EAAmB,MAAM,YAAY,CAAC;AAgCvF;gFACgF;AAChF,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkIc,CAAC;AAEpD,MAAM,MAAM,gBAAgB,GAAG,MAAM,OAAO,wBAAwB,CAAC;AAErE,eAAO,MAAM,mBAAmB,8DAE/B,CAAC;AAEF,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,EAAE,IAAI,gBAAgB,CAEnE;AAED,wBAAgB,qBAAqB,CAAC,EAAE,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAE5E;AAED,wBAAgB,qBAAqB,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAUlF"}
1
+ {"version":3,"file":"profiles.d.ts","sourceRoot":"","sources":["../../../src/core/adapters/profiles.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,cAAc,EAAmB,MAAM,YAAY,CAAC;AAgCvF;gFACgF;AAChF,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuJc,CAAC;AAEpD,MAAM,MAAM,gBAAgB,GAAG,MAAM,OAAO,wBAAwB,CAAC;AAErE,eAAO,MAAM,mBAAmB,8DAE/B,CAAC;AAEF,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,EAAE,IAAI,gBAAgB,CAEnE;AAED,wBAAgB,qBAAqB,CAAC,EAAE,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAE5E;AAED,wBAAgB,qBAAqB,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAUlF"}
@@ -41,6 +41,18 @@ export const BUILTIN_ADAPTER_PROFILES = {
41
41
  modelFamily: "claude",
42
42
  effortValues: ["low", "medium", "high", "xhigh", "max"],
43
43
  verified: { date: "2026-08-18", version: "2.1.233 (Claude Code)" },
44
+ // Checked against 2.1.283 (ADR 0192). Claude Code has no sandbox mode flag;
45
+ // its permission mode and its optional Bash sandbox are separate, so full
46
+ // access needs both: bypass permissions, and a settings layer that turns
47
+ // the Bash sandbox off in case a user or project settings file enabled it.
48
+ fullAccess: {
49
+ argv: [
50
+ "--permission-mode",
51
+ "bypassPermissions",
52
+ "--settings",
53
+ '{"sandbox":{"enabled":false}}',
54
+ ],
55
+ },
44
56
  capabilities: capabilities({
45
57
  effortSelection: supported("Mapped to `--effort <level>`."),
46
58
  maxTurns: supported("Mapped to `--max-turns <n>`."),
@@ -70,6 +82,9 @@ export const BUILTIN_ADAPTER_PROFILES = {
70
82
  modes: { "read-only": "read-only", "workspace-write": "workspace-write" },
71
83
  writableRoots: true,
72
84
  },
85
+ // Checked against codex-cli 0.155.1 (ADR 0192): `--sandbox` accepts
86
+ // danger-full-access, and `codex exec` never prompts for approval.
87
+ fullAccess: { argv: ["--sandbox", "danger-full-access"] },
73
88
  capabilities: capabilities({
74
89
  effortSelection: supported('Mapped to `-c model_reasoning_effort="<level>"`.'),
75
90
  filesystemPolicyProjection: supported("Mode renders to --sandbox; writable roots to sandbox_workspace_write.writable_roots."),
@@ -93,6 +108,10 @@ export const BUILTIN_ADAPTER_PROFILES = {
93
108
  modelFamily: "multi",
94
109
  effortValues: [],
95
110
  verified: { date: "2026-09-20", version: "2026.09.18-9a7762b" },
111
+ // Checked against 2026.09.26-dd393fe (ADR 0192): `--sandbox disabled`
112
+ // overrides the configured sandbox. Cursor carries effort inside the model
113
+ // id, so a full-access floor for it names exact model ids.
114
+ fullAccess: { argv: ["--sandbox", "disabled"] },
96
115
  capabilities: capabilities({
97
116
  effortSelection: unsupported("Cursor embeds effort in some parameterized model ids; Harnery does not rewrite model ids."),
98
117
  maxTurns: unsupported("cursor-agent exposes no turn-ceiling flag."),
@@ -118,7 +137,9 @@ export const BUILTIN_ADAPTER_PROFILES = {
118
137
  authModel: "own-auth",
119
138
  modelFamily: "multi",
120
139
  // Model reasoning is selected through the `provider/model#variant` id;
121
- // OpenCode exposes no separate effort dial for Harnery to map.
140
+ // OpenCode exposes no separate effort dial for Harnery to map. It also has
141
+ // no vendor sandbox to remove, so it declares no full-access rendering and
142
+ // a worker on it is never granted one (ADR 0192).
122
143
  effortValues: [],
123
144
  verified: { date: "2026-09-20", version: "opencode v2.0.11" },
124
145
  capabilities: capabilities({
@@ -42,6 +42,15 @@ export interface AdapterProfile {
42
42
  /** How this adapter projects host filesystem policy into the vendor's own
43
43
  * sandbox (ADR 0039). Absent means it cannot project any of it. */
44
44
  sandboxProjection?: AdapterSandboxProjection;
45
+ /** Vendor-native arguments that launch a worker with no vendor sandbox
46
+ * (ADR 0192). Absent means the adapter has no distinguishable full-access
47
+ * mode, so a worker on it never qualifies for one. */
48
+ fullAccess?: AdapterFullAccessRendering;
49
+ }
50
+ /** How an adapter renders an unsandboxed launch (ADR 0192). The spawner emits
51
+ * exactly these arguments, so the declaration and the argv cannot drift. */
52
+ export interface AdapterFullAccessRendering {
53
+ argv: readonly string[];
45
54
  }
46
55
  /** Fully planned child invocation. `resultFile` is used by adapters such as
47
56
  * Codex that deliver the authoritative final answer out-of-band. */
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/core/adapters/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAE/E;uDACuD;AACvD,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC;AAE/B,MAAM,MAAM,iBAAiB,GAAG,WAAW,GAAG,SAAS,GAAG,aAAa,GAAG,SAAS,CAAC;AAEpF,eAAO,MAAM,6BAA6B,2TAoBhC,CAAC;AAEX,MAAM,MAAM,0BAA0B,GAAG,CAAC,OAAO,6BAA6B,CAAC,CAAC,MAAM,CAAC,CAAC;AAExF,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,iBAAiB,CAAC;IAC3B;iFAC6E;IAC7E,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,MAAM,mBAAmB,GAAG,MAAM,CAAC,0BAA0B,EAAE,eAAe,CAAC,CAAC;AAEtF;;;0DAG0D;AAC1D,MAAM,WAAW,wBAAwB;IACvC,8EAA8E;IAC9E,KAAK,EAAE,MAAM,CAAC,WAAW,GAAG,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC;IAC9D,iEAAiE;IACjE,aAAa,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,SAAS,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,gBAAgB,CAAC;IAClC,SAAS,EAAE,UAAU,CAAC;IACtB,WAAW,EAAE,QAAQ,GAAG,KAAK,GAAG,OAAO,CAAC;IACxC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,YAAY,EAAE,mBAAmB,CAAC;IAClC,2EAA2E;IAC3E,QAAQ,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7C;uEACmE;IACnE,iBAAiB,CAAC,EAAE,wBAAwB,CAAC;CAC9C;AAED;oEACoE;AACpE,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,yEAAyE;AACzE,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;0BAGsB;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;kFAG8E;IAC9E,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,mBAAmB;IAClC,GAAG,EAAE,gBAAgB,CAAC;IACtB,QAAQ,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,GAAG,MAAM,CAAC,GAAG;QAC3C,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;CACH;AAED;;wDAEwD;AACxD,MAAM,WAAW,OAAO;IACtB,OAAO,EAAE,cAAc,CAAC;IACxB,KAAK,EAAE,OAAO,CAAC;IACf,eAAe,EAAE,CAAC,OAAO,EAAE,YAAY,EAAE,UAAU,CAAC,EAAE,MAAM,KAAK,iBAAiB,CAAC;IACnF,eAAe,EAAE,CAAC,GAAG,EAAE,gBAAgB,KAAK,WAAW,CAAC;IACxD,OAAO,EAAE,mBAAmB,CAAC;CAC9B"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/core/adapters/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAE/E;uDACuD;AACvD,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC;AAE/B,MAAM,MAAM,iBAAiB,GAAG,WAAW,GAAG,SAAS,GAAG,aAAa,GAAG,SAAS,CAAC;AAEpF,eAAO,MAAM,6BAA6B,2TAoBhC,CAAC;AAEX,MAAM,MAAM,0BAA0B,GAAG,CAAC,OAAO,6BAA6B,CAAC,CAAC,MAAM,CAAC,CAAC;AAExF,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,iBAAiB,CAAC;IAC3B;iFAC6E;IAC7E,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,MAAM,mBAAmB,GAAG,MAAM,CAAC,0BAA0B,EAAE,eAAe,CAAC,CAAC;AAEtF;;;0DAG0D;AAC1D,MAAM,WAAW,wBAAwB;IACvC,8EAA8E;IAC9E,KAAK,EAAE,MAAM,CAAC,WAAW,GAAG,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC;IAC9D,iEAAiE;IACjE,aAAa,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,SAAS,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,gBAAgB,CAAC;IAClC,SAAS,EAAE,UAAU,CAAC;IACtB,WAAW,EAAE,QAAQ,GAAG,KAAK,GAAG,OAAO,CAAC;IACxC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,YAAY,EAAE,mBAAmB,CAAC;IAClC,2EAA2E;IAC3E,QAAQ,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7C;uEACmE;IACnE,iBAAiB,CAAC,EAAE,wBAAwB,CAAC;IAC7C;;0DAEsD;IACtD,UAAU,CAAC,EAAE,0BAA0B,CAAC;CACzC;AAED;4EAC4E;AAC5E,MAAM,WAAW,0BAA0B;IACzC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;CACzB;AAED;oEACoE;AACpE,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,yEAAyE;AACzE,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;0BAGsB;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;kFAG8E;IAC9E,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,mBAAmB;IAClC,GAAG,EAAE,gBAAgB,CAAC;IACtB,QAAQ,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,GAAG,MAAM,CAAC,GAAG;QAC3C,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;CACH;AAED;;wDAEwD;AACxD,MAAM,WAAW,OAAO;IACtB,OAAO,EAAE,cAAc,CAAC;IACxB,KAAK,EAAE,OAAO,CAAC;IACf,eAAe,EAAE,CAAC,OAAO,EAAE,YAAY,EAAE,UAAU,CAAC,EAAE,MAAM,KAAK,iBAAiB,CAAC;IACnF,eAAe,EAAE,CAAC,GAAG,EAAE,gBAAgB,KAAK,WAAW,CAAC;IACxD,OAAO,EAAE,mBAAmB,CAAC;CAC9B"}
@@ -279,12 +279,19 @@ async function handleStateAction(root, action, rest) {
279
279
  }
280
280
  catch (error) {
281
281
  const detail = error instanceof Error ? error.message : String(error);
282
- // A missing heartbeat here means the session's generation ended
283
- // while its process lived on. Name the reopen command (ADR 0088);
284
- // set-task is usually the first thing such a session runs.
285
- const hint = detail.includes("heartbeat_missing:")
286
- ? `; run \`${resolveBinName(root)} agents lifecycle active\` to open a fresh generation for this continuing session`
287
- : "";
282
+ // A missing heartbeat usually means the session's generation ended
283
+ // while its process lived on, so name the reopen command (ADR 0088).
284
+ // A still-live generation whose authority the ledger withholds looks
285
+ // the same here; name its diagnostics instead, since reopen cannot apply.
286
+ const { describeLiveAuthorityBlockV3, liveAuthorityBlockHintV3, liveAuthorityBlockV3 } = await import("./state/live-coordination-view.js");
287
+ const block = detail.includes("heartbeat_missing:")
288
+ ? liveAuthorityBlockV3(root, owner)
289
+ : null;
290
+ const hint = block
291
+ ? `; ${describeLiveAuthorityBlockV3(block)}; ${liveAuthorityBlockHintV3(resolveBinName(root))}`
292
+ : detail.includes("heartbeat_missing:")
293
+ ? `; run \`${resolveBinName(root)} agents lifecycle active\` to open a fresh generation for this continuing session`
294
+ : "";
288
295
  process.stderr.write(`agent-coord set-task: V3 authority refused (${detail})${hint}\n`);
289
296
  return 1;
290
297
  }
@@ -1 +1 @@
1
- {"version":3,"file":"prompt-context.d.ts","sourceRoot":"","sources":["../../../../src/core/agents/render/prompt-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAgDH,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;8EAC0E;IAC1E,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;kFAC8E;IAC9E,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;kFAC8E;IAC9E,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B;uEACmE;IACnE,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B;;;;wBAIoB;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,iBAAiB,GAAG,MAAM,CAkFnE;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CA6CtF"}
1
+ {"version":3,"file":"prompt-context.d.ts","sourceRoot":"","sources":["../../../../src/core/agents/render/prompt-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAiDH,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;8EAC0E;IAC1E,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;kFAC8E;IAC9E,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;kFAC8E;IAC9E,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B;uEACmE;IACnE,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B;;;;wBAIoB;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,iBAAiB,GAAG,MAAM,CAkFnE;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CA6CtF"}
@@ -43,6 +43,7 @@ import { drainMailbox, formatMailboxDelivery } from "../mailbox.js";
43
43
  import { sessionNameDisplayBlock, sessionNameDisplayPending } from "../session-name-display.js";
44
44
  import { heartbeatPath } from "../state/heartbeat-reader.js";
45
45
  import { readLiveCoordinationRow, readLiveCoordinationRows, } from "../state/live-coordination-view.js";
46
+ import { forkRelationLabels } from "../state/names.js";
46
47
  import { formatPendingCouncils, recordDeliveredMessages } from "./session-context.js";
47
48
  /**
48
49
  * Build the combined UserPromptSubmit additionalContext string. Returns "" when
@@ -337,7 +338,7 @@ function computePeerTableIfChanged(coordRoot, selfInstanceId, selfSessionIdFallb
337
338
  if (oldHash && oldHash === newHash)
338
339
  return "";
339
340
  // Render peer table via the same formatter used at SessionStart.
340
- const local = formatPeerTable(peers, mySessionId);
341
+ const local = formatPeerTable(peers, mySessionId, forkRelationLabels(coordRoot, selfInstanceId, new Set(peers.map((p) => p.instance_id ?? ""))));
341
342
  const remoteTable = formatRemoteTable(remote);
342
343
  const table = [local, remoteTable].filter(Boolean).join("\n\n");
343
344
  if (!table)
@@ -458,7 +459,7 @@ function writeHashFile(path, value) {
458
459
  * intentionally co-located here so the prompt-context renderer is self-contained
459
460
  * (no cross-file imports of formatting internals). If both renderers diverge,
460
461
  * pull the shared bits into a small util module. */
461
- function formatPeerTable(peers, mySessionId) {
462
+ function formatPeerTable(peers, mySessionId, relations = new Map()) {
462
463
  if (peers.length === 0)
463
464
  return "";
464
465
  const nowSec = Math.floor(Date.now() / 1000);
@@ -474,9 +475,13 @@ function formatPeerTable(peers, mySessionId) {
474
475
  .map((p) => {
475
476
  const folded = fold[p.instance_id ?? ""] ?? [];
476
477
  const display = Array.from(new Set([...(p.files_touched ?? []), ...folded])).sort();
477
- return { ...p, display_files: display };
478
+ const relation = relations.get(p.instance_id ?? "");
479
+ return { ...p, display_files: display, ...(relation ? { relation } : {}) };
478
480
  });
479
- const blocking = rows.filter((p) => p.session_id !== mySessionId).sort(byStartedAt);
481
+ // Related sessions sort first so a fork parent never hides in "+N more".
482
+ const blocking = rows
483
+ .filter((p) => p.session_id !== mySessionId)
484
+ .sort((a, b) => Number(!!b.relation) - Number(!!a.relation) || byStartedAt(a, b));
480
485
  const group = rows.filter((p) => p.session_id === mySessionId).sort(byStartedAt);
481
486
  const out = [];
482
487
  const blk = renderSubtable(blocking, "Other agent groups active (their files block you):", nowSec);
@@ -508,7 +513,8 @@ function formatRow(r, nowSec) {
508
513
  // Prefer a short instance_id over a bare "unknown" so an incomplete row is
509
514
  // still identifiable.
510
515
  const label = r.name ?? (r.instance_id ? r.instance_id.slice(0, 8) : "unknown");
511
- return ` - agent-${label}${taskPart} (${statePart}, ${ageFrom}, ${filesPart})`;
516
+ const relation = r.relation ? ` [${r.relation}]` : "";
517
+ return ` - agent-${label}${relation}${taskPart} (${statePart}, ${ageFrom}, ${filesPart})`;
512
518
  }
513
519
  function formatState(r) {
514
520
  const activity = r.activity ?? "unknown";
@@ -1 +1 @@
1
- {"version":3,"file":"session-context.d.ts","sourceRoot":"","sources":["../../../../src/core/agents/render/session-context.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAyC,QAAQ,EAAE,MAAM,SAAS,CAAC;AAM1E,OAAO,EAAuC,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAoB3F,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;+BAC2B;IAC3B,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAwF7D;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,SAAS,gBAAgB,EAAE,GACpC,IAAI,CAUN;AAkID;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,CAwBvD;AA0DD;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAiDlF;AAED;;;GAGG;AACH,eAAO,MAAM,uBAAuB,iBAAW,CAAC"}
1
+ {"version":3,"file":"session-context.d.ts","sourceRoot":"","sources":["../../../../src/core/agents/render/session-context.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAyC,QAAQ,EAAE,MAAM,SAAS,CAAC;AAM1E,OAAO,EAAuC,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAoB3F,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;+BAC2B;IAC3B,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAiG7D;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,SAAS,gBAAgB,EAAE,GACpC,IAAI,CAUN;AA6LD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,CAwBvD;AA0DD;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAiDlF;AAED;;;GAGG;AACH,eAAO,MAAM,uBAAuB,iBAAW,CAAC"}
@@ -15,7 +15,7 @@ import { appendEntry } from "../../journal/index.js";
15
15
  import { readRemoteMachines } from "../../presence/index.js";
16
16
  import { drainMailbox, formatMailboxDelivery } from "../mailbox.js";
17
17
  import { readLiveCoordinationRows } from "../state/live-coordination-view.js";
18
- import { readForkParent } from "../state/names.js";
18
+ import { forkRelationLabels, readForkState } from "../state/names.js";
19
19
  /**
20
20
  * Build the combined SessionStart systemMessage. Returns the additionalContext
21
21
  * string (or "" if there's nothing to say).
@@ -25,7 +25,13 @@ export function renderSessionContext(opts) {
25
25
  const messages = [];
26
26
  // 1. Self-name line + peer table (folded if peers present)
27
27
  const peers = readActivePeers(coordRoot, instanceId);
28
- const localTable = formatPeerTable(peers, sessionId);
28
+ const forkState = readForkState(coordRoot, instanceId);
29
+ const forkParent = forkState?.parent ?? null;
30
+ const parentRow = forkParent
31
+ ? peers.find((peer) => peer.instance_id === forkParent.instance_id)
32
+ : undefined;
33
+ const relations = forkRelationLabels(coordRoot, instanceId, new Set(peers.map((peer) => peer.instance_id ?? "")));
34
+ const localTable = formatPeerTable(peers, sessionId, relations);
29
35
  // Cross-machine presence (ADR 0016): sessions on other machines (advisory).
30
36
  const peerTable = [localTable, formatRemoteMachines(coordRoot)].filter(Boolean).join("\n\n");
31
37
  if (agentName) {
@@ -35,13 +41,11 @@ export function renderSessionContext(opts) {
35
41
  // asserts the parent's name, claims, and task. When recorded fork lineage
36
42
  // (.name-history forked_from) names the parent, say so specifically — the
37
43
  // fork is about to read a transcript full of that exact name. Otherwise
38
- // fall back to the generic clause, which needs no fork detection.
39
- const forkParent = readForkParent(coordRoot, instanceId);
40
- const authority = forkParent?.name
41
- ? `This conversation was branched from agent-${forkParent.name}'s session: earlier context showing agent-${forkParent.name}'s name, task, or file claims belongs to the pre-fork session, not to you.`
42
- : forkParent
43
- ? `This conversation was branched from another session (${forkParent.instance_id}); any agent name in earlier context belongs to that session, not to you.`
44
- : "Any different agent name in earlier context was inherited from another session; this one is authoritative.";
44
+ // fall back to the generic clause, which needs no fork detection. A live
45
+ // parent is the dangerous case (2026-10-07: a fork read its running
46
+ // parent as its own earlier self and offered to close it), so the notice
47
+ // names what the parent is doing and forbids ending it.
48
+ const authority = forkAuthorityClause(forkParent, forkState?.fork === true, parentRow);
45
49
  const selfLine = `You are agent-${agentName}${suffix}. ${authority}`;
46
50
  messages.push(peerTable ? `${selfLine}\n\n${peerTable}` : selfLine);
47
51
  }
@@ -93,6 +97,8 @@ export function renderSessionContext(opts) {
93
97
  bits.push(`missing: ${d.missing.map((m) => m.subcommand).join(", ")}`);
94
98
  if (d.orphans.length > 0)
95
99
  bits.push(`orphaned: ${d.orphans.join(", ")}`);
100
+ if (d.stale.length > 0)
101
+ bits.push(`outdated: ${d.stale.map((m) => m.subcommand).join(", ")}`);
96
102
  return ` - ${d.settingsFile} — ${bits.join("; ")}`;
97
103
  });
98
104
  messages.push(`Harnery hook wiring is out of date${verPart}: an upgrade changed the hook set but the adapter ` +
@@ -149,13 +155,48 @@ function formatRemoteMachines(coordRoot) {
149
155
  function readActivePeers(coordRoot, selfInstanceId) {
150
156
  return readLiveCoordinationRows(coordRoot).filter((heartbeat) => heartbeat.instance_id && heartbeat.instance_id !== selfInstanceId);
151
157
  }
158
+ const DO_NOT_END = "Do not end, release, or finalize that session unless the operator explicitly tells you to.";
159
+ function forkAuthorityClause(parent, fork, parentRow) {
160
+ if (parent?.name && parentRow) {
161
+ const files = parentRow.files_touched ?? [];
162
+ const task = parentRow.task ? ` on "${parentRow.task.slice(0, 80)}"` : "";
163
+ const holds = files.length > 0
164
+ ? ` and holds ${files.length} file${files.length === 1 ? "" : "s"} (${fmtFileList(files)})`
165
+ : "";
166
+ const owned = files.length > 0
167
+ ? parentRow.task
168
+ ? "That name, task, and those files"
169
+ : "That name and those files"
170
+ : parentRow.task
171
+ ? "That name and task"
172
+ : "That name";
173
+ return (`This conversation was forked from agent-${parent.name}, which is still running as a separate session${task}${holds}. ` +
174
+ `${owned} belong${owned === "That name" ? "s" : ""} to agent-${parent.name}, not to you. ${DO_NOT_END}`);
175
+ }
176
+ if (parent?.name) {
177
+ return `This conversation was branched from agent-${parent.name}'s session: earlier context showing agent-${parent.name}'s name, task, or file claims belongs to the pre-fork session, not to you.`;
178
+ }
179
+ if (parent) {
180
+ return `This conversation was branched from another session (${parent.instance_id}); any agent name in earlier context belongs to that session, not to you.`;
181
+ }
182
+ if (fork) {
183
+ return `This conversation was forked from another session, which may still be running. Any agent name, task, or file claim in earlier context belongs to that session, not to you. ${DO_NOT_END}`;
184
+ }
185
+ return "Any different agent name in earlier context was inherited from another session; this one is authoritative.";
186
+ }
187
+ function fmtFileList(files) {
188
+ const sorted = [...files].sort();
189
+ return sorted.length <= 3
190
+ ? sorted.join(", ")
191
+ : `${sorted.slice(0, 3).join(", ")}, +${sorted.length - 3} more`;
192
+ }
152
193
  /**
153
194
  * Renders the peer table as
154
195
  * two subsections: "Other agent groups active" (blocking) and "Your group"
155
196
  * (subagents/siblings, no mutual block). Folds transient subagents' files
156
197
  * into their parent session.
157
198
  */
158
- function formatPeerTable(peers, mySessionId) {
199
+ function formatPeerTable(peers, mySessionId, relations = new Map()) {
159
200
  if (peers.length === 0)
160
201
  return "";
161
202
  const nowSec = Math.floor(Date.now() / 1000);
@@ -172,9 +213,13 @@ function formatPeerTable(peers, mySessionId) {
172
213
  .map((p) => {
173
214
  const folded = fold[p.instance_id ?? ""] ?? [];
174
215
  const display = Array.from(new Set([...(p.files_touched ?? []), ...folded])).sort();
175
- return { ...p, display_files: display };
216
+ const relation = relations.get(p.instance_id ?? "");
217
+ return { ...p, display_files: display, ...(relation ? { relation } : {}) };
176
218
  });
177
- const blocking = rows.filter((p) => p.session_id !== mySessionId).sort(byStartedAt);
219
+ // Related sessions sort first so the parent never hides in "+N more".
220
+ const blocking = rows
221
+ .filter((p) => p.session_id !== mySessionId)
222
+ .sort((a, b) => Number(!!b.relation) - Number(!!a.relation) || byStartedAt(a, b));
178
223
  const group = rows.filter((p) => p.session_id === mySessionId).sort(byStartedAt);
179
224
  const sections = [];
180
225
  const blockingSection = renderSubtable(blocking, "Other agent groups active (their files block you):", nowSec);
@@ -202,7 +247,8 @@ function formatRow(r, nowSec) {
202
247
  const reason = lifecycle === "blocked" && r.task_state_reason ? `: ${r.task_state_reason.slice(0, 80)}` : "";
203
248
  const ageFrom = fmtAge(nowSec - parseIsoSec(r.started_at));
204
249
  const filesPart = fmtFiles(r.display_files);
205
- return ` - agent-${r.name ?? "unknown"}${taskPart} (activity=${activity}, lifecycle=${lifecycle}${reason}, ${ageFrom}, ${filesPart})`;
250
+ const relation = r.relation ? ` [${r.relation}]` : "";
251
+ return ` - agent-${r.name ?? "unknown"}${relation}${taskPart} (activity=${activity}, lifecycle=${lifecycle}${reason}, ${ageFrom}, ${filesPart})`;
206
252
  }
207
253
  function fmtFiles(files) {
208
254
  if (files.length === 0)
@@ -26,4 +26,24 @@ export declare function isCurrentV3HeartbeatCache(cache: Heartbeat | null | unde
26
26
  export declare function projectHeartbeatV3(coordRoot: string, generation: CoordinationGenerationViewV3, cache: Heartbeat | undefined, nativeInstanceId: string | undefined, parent?: CoordinationGenerationViewV3): V3HeartbeatMaterialization;
27
27
  export declare function observedAdapterV3(generation: CoordinationGenerationViewV3): string | undefined;
28
28
  export declare function isAdapterV3(value: string | undefined): value is EventAdapterIdV3;
29
+ /** Why a still-live V3 generation has lost coordination authority. */
30
+ export interface LiveAuthorityBlockV3 {
31
+ generation_id: string;
32
+ scope: "generation" | "ledger";
33
+ diagnostics: {
34
+ code: string;
35
+ event_id?: string;
36
+ }[];
37
+ }
38
+ /**
39
+ * Explain an authority refusal for a generation that is still live. Callers
40
+ * reach this after a lookup came back empty; without it the caller sees only
41
+ * "missing", which reads like an ended session and points at a reopen that
42
+ * cannot apply. Returns null when no live generation exists or nothing blocks.
43
+ */
44
+ export declare function liveAuthorityBlockV3(coordRoot: string, nativeInstanceId: string): LiveAuthorityBlockV3 | null;
45
+ /** One-line description of a live authority block, naming codes and events. */
46
+ export declare function describeLiveAuthorityBlockV3(block: LiveAuthorityBlockV3): string;
47
+ /** Recovery pointer for a live authority block, in place of the reopen hint. */
48
+ export declare function liveAuthorityBlockHintV3(binName: string): string;
29
49
  //# sourceMappingURL=live-coordination-view.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"live-coordination-view.d.ts","sourceRoot":"","sources":["../../../../src/core/agents/state/live-coordination-view.ts"],"names":[],"mappings":"AAEA,OAAO,EAAwB,KAAK,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAC5F,OAAO,EACL,KAAK,4BAA4B,EAIlC,MAAM,sCAAsC,CAAC;AAM9C,OAAO,EAAE,KAAK,SAAS,EAAiB,MAAM,uBAAuB,CAAC;AAGtE;;;GAGG;AACH,MAAM,WAAW,0BAA2B,SAAQ,SAAS;IAC3D,cAAc,EAAE,CAAC,CAAC;IAClB,cAAc,EAAE,QAAQ,MAAM,EAAE,CAAC;IACjC,gBAAgB,EAAE,OAAO,MAAM,EAAE,CAAC;IAClC,sBAAsB,EAAE,MAAM,CAAC;IAC/B,aAAa,EAAE,KAAK,GAAG,SAAS,CAAC;CAClC;AAED,yEAAyE;AACzE,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,MAAM,GAAG,0BAA0B,EAAE,CA2BxF;AAED,kEAAkE;AAClE,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,MAAM,EACjB,gBAAgB,EAAE,MAAM,GACvB,0BAA0B,GAAG,IAAI,CAuBnC;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,MAAM,EACjB,gBAAgB,EAAE,MAAM,GACvB,gBAAgB,GAAG,IAAI,CAWzB;AA8BD,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,SAAS,GAAG,IAAI,GAAG,SAAS,EACnC,UAAU,EAAE,4BAA4B,GACvC,KAAK,IAAI,SAAS,CAMpB;AAED,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,4BAA4B,EACxC,KAAK,EAAE,SAAS,GAAG,SAAS,EAC5B,gBAAgB,EAAE,MAAM,GAAG,SAAS,EACpC,MAAM,CAAC,EAAE,4BAA4B,GACpC,0BAA0B,CAuD5B;AAED,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,4BAA4B,GAAG,MAAM,GAAG,SAAS,CAG9F;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,KAAK,IAAI,gBAAgB,CAEhF"}
1
+ {"version":3,"file":"live-coordination-view.d.ts","sourceRoot":"","sources":["../../../../src/core/agents/state/live-coordination-view.ts"],"names":[],"mappings":"AAEA,OAAO,EAAwB,KAAK,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAC5F,OAAO,EACL,KAAK,4BAA4B,EAIlC,MAAM,sCAAsC,CAAC;AAM9C,OAAO,EAAE,KAAK,SAAS,EAAiB,MAAM,uBAAuB,CAAC;AAGtE;;;GAGG;AACH,MAAM,WAAW,0BAA2B,SAAQ,SAAS;IAC3D,cAAc,EAAE,CAAC,CAAC;IAClB,cAAc,EAAE,QAAQ,MAAM,EAAE,CAAC;IACjC,gBAAgB,EAAE,OAAO,MAAM,EAAE,CAAC;IAClC,sBAAsB,EAAE,MAAM,CAAC;IAC/B,aAAa,EAAE,KAAK,GAAG,SAAS,CAAC;CAClC;AAED,yEAAyE;AACzE,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,MAAM,GAAG,0BAA0B,EAAE,CA2BxF;AAED,kEAAkE;AAClE,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,MAAM,EACjB,gBAAgB,EAAE,MAAM,GACvB,0BAA0B,GAAG,IAAI,CAuBnC;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,MAAM,EACjB,gBAAgB,EAAE,MAAM,GACvB,gBAAgB,GAAG,IAAI,CAWzB;AA8BD,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,SAAS,GAAG,IAAI,GAAG,SAAS,EACnC,UAAU,EAAE,4BAA4B,GACvC,KAAK,IAAI,SAAS,CAMpB;AAED,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,4BAA4B,EACxC,KAAK,EAAE,SAAS,GAAG,SAAS,EAC5B,gBAAgB,EAAE,MAAM,GAAG,SAAS,EACpC,MAAM,CAAC,EAAE,4BAA4B,GACpC,0BAA0B,CAuD5B;AAED,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,4BAA4B,GAAG,MAAM,GAAG,SAAS,CAG9F;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,KAAK,IAAI,gBAAgB,CAEhF;AAWD,sEAAsE;AACtE,MAAM,WAAW,oBAAoB;IACnC,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,YAAY,GAAG,QAAQ,CAAC;IAC/B,WAAW,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CACpD;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,MAAM,EACjB,gBAAgB,EAAE,MAAM,GACvB,oBAAoB,GAAG,IAAI,CA2B7B;AAED,+EAA+E;AAC/E,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,oBAAoB,GAAG,MAAM,CAiBhF;AAED,gFAAgF;AAChF,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAKhE"}
@@ -159,3 +159,63 @@ function observedModel(generation) {
159
159
  function isLifecycleState(value) {
160
160
  return value === "active" || value === "blocked" || value === "done";
161
161
  }
162
+ /**
163
+ * Explain an authority refusal for a generation that is still live. Callers
164
+ * reach this after a lookup came back empty; without it the caller sees only
165
+ * "missing", which reads like an ended session and points at a reopen that
166
+ * cannot apply. Returns null when no live generation exists or nothing blocks.
167
+ */
168
+ export function liveAuthorityBlockV3(coordRoot, nativeInstanceId) {
169
+ let view;
170
+ try {
171
+ if (observeLiveEventLedgerRouteV3(coordRoot).state === "blocked")
172
+ return null;
173
+ view = readCoordinationViewV3(coordRoot);
174
+ }
175
+ catch {
176
+ return null;
177
+ }
178
+ const generation = view.instances[liveInstanceIdV3(nativeInstanceId)];
179
+ if (generation?.phase !== "live" || generation.authority_eligible)
180
+ return null;
181
+ const own = (view.diagnostics_by_generation[generation.generation_id] ?? []).filter((diagnostic) => diagnostic.authority_blocking);
182
+ const blocking = own.length
183
+ ? own
184
+ : view.global_diagnostics.filter((diagnostic) => diagnostic.authority_blocking);
185
+ if (!blocking.length)
186
+ return null;
187
+ return {
188
+ generation_id: generation.generation_id,
189
+ scope: own.length ? "generation" : "ledger",
190
+ diagnostics: blocking.map((diagnostic) => ({
191
+ code: diagnostic.source_code
192
+ ? `${diagnostic.code}:${diagnostic.source_code}`
193
+ : diagnostic.code,
194
+ ...(diagnostic.event_id ? { event_id: diagnostic.event_id } : {}),
195
+ })),
196
+ };
197
+ }
198
+ /** One-line description of a live authority block, naming codes and events. */
199
+ export function describeLiveAuthorityBlockV3(block) {
200
+ const byCode = new Map();
201
+ for (const { code, event_id } of block.diagnostics) {
202
+ const events = byCode.get(code) ?? [];
203
+ if (event_id)
204
+ events.push(event_id);
205
+ byCode.set(code, events);
206
+ }
207
+ const parts = [...byCode].map(([code, events]) => {
208
+ const shown = events.slice(0, 2).join(", ");
209
+ const more = events.length > 2 ? `, +${events.length - 2} more` : "";
210
+ return events.length ? `${code} ×${events.length} (${shown}${more})` : code;
211
+ });
212
+ const where = block.scope === "generation"
213
+ ? `the event ledger holds ${block.diagnostics.length} authority-blocking diagnostic(s) for it`
214
+ : "the event ledger holds authority-blocking diagnostics that block every generation";
215
+ return `generation ${block.generation_id} is still live, but ${where}: ${parts.join("; ")}`;
216
+ }
217
+ /** Recovery pointer for a live authority block, in place of the reopen hint. */
218
+ export function liveAuthorityBlockHintV3(binName) {
219
+ return (`\`${binName} agents lifecycle active\` cannot help because it only reopens an ended ` +
220
+ `generation; \`${binName} agents health\` lists the diagnostics`);
221
+ }