harnery 0.31.6 → 0.33.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 (264) hide show
  1. package/README.md +2 -0
  2. package/dist/commander.d.ts.map +1 -1
  3. package/dist/commander.js +5 -1
  4. package/dist/commands/agents.d.ts +0 -9
  5. package/dist/commands/agents.d.ts.map +1 -1
  6. package/dist/commands/agents.js +280 -94
  7. package/dist/commands/browse-session.d.ts +21 -0
  8. package/dist/commands/browse-session.d.ts.map +1 -0
  9. package/dist/commands/browse-session.js +157 -0
  10. package/dist/commands/browse.d.ts.map +1 -1
  11. package/dist/commands/browse.js +205 -37
  12. package/dist/commands/checkpoint.js +1 -1
  13. package/dist/commands/claude-desktop.d.ts +2 -2
  14. package/dist/commands/claude-desktop.d.ts.map +1 -1
  15. package/dist/commands/claude-desktop.js +74 -3
  16. package/dist/commands/deinit.d.ts.map +1 -1
  17. package/dist/commands/deinit.js +4 -0
  18. package/dist/commands/docs.d.ts.map +1 -1
  19. package/dist/commands/docs.js +40 -0
  20. package/dist/commands/doctor.d.ts +4 -2
  21. package/dist/commands/doctor.d.ts.map +1 -1
  22. package/dist/commands/doctor.js +141 -19
  23. package/dist/commands/init.d.ts +2 -2
  24. package/dist/commands/init.d.ts.map +1 -1
  25. package/dist/commands/init.js +26 -5
  26. package/dist/commands/instructions.d.ts +4 -0
  27. package/dist/commands/instructions.d.ts.map +1 -0
  28. package/dist/commands/instructions.js +100 -0
  29. package/dist/commands/presence.d.ts.map +1 -1
  30. package/dist/commands/presence.js +4 -1
  31. package/dist/commands/tunnel.d.ts.map +1 -1
  32. package/dist/commands/tunnel.js +2 -3
  33. package/dist/core/agents/canonical-emit.d.ts +2 -3
  34. package/dist/core/agents/canonical-emit.d.ts.map +1 -1
  35. package/dist/core/agents/canonical-emit.js +6 -5
  36. package/dist/core/agents/cli.js +128 -89
  37. package/dist/core/agents/coord-client.d.ts +18 -3
  38. package/dist/core/agents/coord-client.d.ts.map +1 -1
  39. package/dist/core/agents/coord-client.js +5 -4
  40. package/dist/core/agents/finalization.d.ts +68 -0
  41. package/dist/core/agents/finalization.d.ts.map +1 -0
  42. package/dist/core/agents/finalization.js +443 -0
  43. package/dist/core/agents/git-hook.d.ts +51 -0
  44. package/dist/core/agents/git-hook.d.ts.map +1 -0
  45. package/dist/core/agents/git-hook.js +118 -0
  46. package/dist/core/agents/index.d.ts +1 -0
  47. package/dist/core/agents/index.d.ts.map +1 -1
  48. package/dist/core/agents/index.js +1 -0
  49. package/dist/core/agents/render/prompt-context.d.ts +12 -5
  50. package/dist/core/agents/render/prompt-context.d.ts.map +1 -1
  51. package/dist/core/agents/render/prompt-context.js +70 -16
  52. package/dist/core/agents/render/session-context.d.ts.map +1 -1
  53. package/dist/core/agents/render/session-context.js +23 -4
  54. package/dist/core/agents/rules/claim-conflict.js +3 -3
  55. package/dist/core/agents/rules/commit-conflict.d.ts +15 -6
  56. package/dist/core/agents/rules/commit-conflict.d.ts.map +1 -1
  57. package/dist/core/agents/rules/commit-conflict.js +21 -5
  58. package/dist/core/agents/rules/stop-hook.d.ts +3 -0
  59. package/dist/core/agents/rules/stop-hook.d.ts.map +1 -1
  60. package/dist/core/agents/rules/stop-hook.js +59 -23
  61. package/dist/core/agents/session-events.d.ts +8 -16
  62. package/dist/core/agents/session-events.d.ts.map +1 -1
  63. package/dist/core/agents/session-events.js +12 -26
  64. package/dist/core/agents/state/heartbeat-projector.d.ts +14 -0
  65. package/dist/core/agents/state/heartbeat-projector.d.ts.map +1 -1
  66. package/dist/core/agents/state/heartbeat-projector.js +98 -1
  67. package/dist/core/agents/state/heartbeat-writer.d.ts +47 -5
  68. package/dist/core/agents/state/heartbeat-writer.d.ts.map +1 -1
  69. package/dist/core/agents/state/heartbeat-writer.js +86 -17
  70. package/dist/core/agents/state/names.d.ts +22 -1
  71. package/dist/core/agents/state/names.d.ts.map +1 -1
  72. package/dist/core/agents/state/names.js +40 -2
  73. package/dist/core/agents/state/session-state.d.ts +44 -0
  74. package/dist/core/agents/state/session-state.d.ts.map +1 -0
  75. package/dist/core/agents/state/session-state.js +81 -0
  76. package/dist/core/config.d.ts +30 -2
  77. package/dist/core/config.d.ts.map +1 -1
  78. package/dist/core/config.js +74 -11
  79. package/dist/core/governor/planning.d.ts.map +1 -1
  80. package/dist/core/governor/planning.js +12 -13
  81. package/dist/core/hooks/adapter/detect.d.ts +2 -4
  82. package/dist/core/hooks/adapter/detect.d.ts.map +1 -1
  83. package/dist/core/hooks/adapter/detect.js +4 -14
  84. package/dist/core/hooks/adapter/events.d.ts.map +1 -1
  85. package/dist/core/hooks/adapter/events.js +1 -0
  86. package/dist/core/hooks/adapter/output.d.ts +1 -1
  87. package/dist/core/hooks/adapter/output.d.ts.map +1 -1
  88. package/dist/core/hooks/adapter/output.js +5 -4
  89. package/dist/core/hooks/adapter/parse.d.ts +1 -1
  90. package/dist/core/hooks/adapter/parse.d.ts.map +1 -1
  91. package/dist/core/hooks/adapter/parse.js +2 -0
  92. package/dist/core/hooks/adapter/wiring.d.ts +23 -0
  93. package/dist/core/hooks/adapter/wiring.d.ts.map +1 -1
  94. package/dist/core/hooks/adapter/wiring.js +32 -0
  95. package/dist/core/hooks/cli.d.ts +1 -2
  96. package/dist/core/hooks/cli.d.ts.map +1 -1
  97. package/dist/core/hooks/cli.js +258 -32
  98. package/dist/core/hooks/codex-authorization.d.ts +30 -0
  99. package/dist/core/hooks/codex-authorization.d.ts.map +1 -0
  100. package/dist/core/hooks/codex-authorization.js +199 -0
  101. package/dist/core/hooks/codex-wsl-bridge.d.ts +46 -0
  102. package/dist/core/hooks/codex-wsl-bridge.d.ts.map +1 -0
  103. package/dist/core/hooks/codex-wsl-bridge.js +137 -0
  104. package/dist/core/hooks/effects/index.d.ts +1 -1
  105. package/dist/core/hooks/effects/index.js +3 -3
  106. package/dist/core/hooks/events/schema.d.ts +57 -1
  107. package/dist/core/hooks/events/schema.d.ts.map +1 -1
  108. package/dist/core/hooks/resolve/owner.d.ts +7 -1
  109. package/dist/core/hooks/resolve/owner.d.ts.map +1 -1
  110. package/dist/core/hooks/resolve/owner.js +15 -0
  111. package/dist/core/hooks/resolve/transcript.d.ts +44 -0
  112. package/dist/core/hooks/resolve/transcript.d.ts.map +1 -1
  113. package/dist/core/hooks/resolve/transcript.js +176 -1
  114. package/dist/core/hooks/session-name-presence.d.ts +30 -0
  115. package/dist/core/hooks/session-name-presence.d.ts.map +1 -0
  116. package/dist/core/hooks/session-name-presence.js +43 -0
  117. package/dist/core/hooks/unsafe-cross-shell.d.ts +13 -0
  118. package/dist/core/hooks/unsafe-cross-shell.d.ts.map +1 -0
  119. package/dist/core/hooks/unsafe-cross-shell.js +151 -0
  120. package/dist/core/presence/blob.d.ts +4 -0
  121. package/dist/core/presence/blob.d.ts.map +1 -1
  122. package/dist/core/presence/blob.js +12 -0
  123. package/dist/core/presence/index.js +15 -1
  124. package/dist/core/work/state.d.ts +4 -5
  125. package/dist/core/work/state.d.ts.map +1 -1
  126. package/dist/core/work/state.js +5 -8
  127. package/dist/core/workflow/index.d.ts +1 -1
  128. package/dist/core/workflow/index.d.ts.map +1 -1
  129. package/dist/core/workflow/proof.d.ts +2 -2
  130. package/dist/core/workflow/proof.d.ts.map +1 -1
  131. package/dist/core/workflow/proof.js +2 -2
  132. package/dist/core/workflow/run-state.d.ts +2 -2
  133. package/dist/core/workflow/run-state.d.ts.map +1 -1
  134. package/dist/core/workflow/run-state.js +2 -2
  135. package/dist/core/workflow/types.d.ts +3 -3
  136. package/dist/core/workflow/types.d.ts.map +1 -1
  137. package/dist/core/workflow/workspaces/execution.d.ts +2 -2
  138. package/dist/core/workflow/workspaces/execution.d.ts.map +1 -1
  139. package/dist/core/workflow/workspaces/execution.js +5 -0
  140. package/dist/core/workflow/workspaces/index.d.ts +1 -1
  141. package/dist/core/workflow/workspaces/index.d.ts.map +1 -1
  142. package/dist/core/workflow/workspaces/local-git.d.ts.map +1 -1
  143. package/dist/core/workflow/workspaces/local-git.js +1 -2
  144. package/dist/core/workflow/workspaces/paths.d.ts +2 -2
  145. package/dist/core/workflow/workspaces/types.d.ts +0 -6
  146. package/dist/core/workflow/workspaces/types.d.ts.map +1 -1
  147. package/dist/core/workflow/workspaces/validate.d.ts +0 -2
  148. package/dist/core/workflow/workspaces/validate.d.ts.map +1 -1
  149. package/dist/core/workflow/workspaces/validate.js +0 -2
  150. package/dist/lib/browser/client.d.ts +118 -1
  151. package/dist/lib/browser/client.d.ts.map +1 -1
  152. package/dist/lib/browser/client.js +435 -6
  153. package/dist/lib/browser/geometry.d.ts.map +1 -1
  154. package/dist/lib/browser/geometry.js +180 -37
  155. package/dist/lib/browser/index.d.ts +5 -1
  156. package/dist/lib/browser/index.d.ts.map +1 -1
  157. package/dist/lib/browser/index.js +5 -1
  158. package/dist/lib/browser/netscape-cookies.d.ts +6 -0
  159. package/dist/lib/browser/netscape-cookies.d.ts.map +1 -0
  160. package/dist/lib/browser/netscape-cookies.js +31 -0
  161. package/dist/lib/browser/proxy.d.ts +24 -0
  162. package/dist/lib/browser/proxy.d.ts.map +1 -0
  163. package/dist/lib/browser/proxy.js +84 -0
  164. package/dist/lib/browser/runts.d.ts +6 -0
  165. package/dist/lib/browser/runts.d.ts.map +1 -1
  166. package/dist/lib/browser/runts.js +21 -4
  167. package/dist/lib/browser/session-control.d.ts +112 -0
  168. package/dist/lib/browser/session-control.d.ts.map +1 -0
  169. package/dist/lib/browser/session-control.js +670 -0
  170. package/dist/lib/claude-desktop.d.ts +47 -0
  171. package/dist/lib/claude-desktop.d.ts.map +1 -1
  172. package/dist/lib/claude-desktop.js +169 -1
  173. package/dist/lib/docs-links.d.ts +108 -0
  174. package/dist/lib/docs-links.d.ts.map +1 -0
  175. package/dist/lib/docs-links.js +555 -0
  176. package/dist/lib/exec.d.ts +1 -1
  177. package/dist/lib/exec.js +1 -1
  178. package/dist/lib/identities/assume.d.ts +4 -2
  179. package/dist/lib/identities/assume.d.ts.map +1 -1
  180. package/dist/lib/identities/assume.js +15 -2
  181. package/dist/lib/instructions/bundle.d.ts +33 -0
  182. package/dist/lib/instructions/bundle.d.ts.map +1 -0
  183. package/dist/lib/instructions/bundle.js +149 -0
  184. package/dist/lib/instructions/git-hooks.d.ts +75 -0
  185. package/dist/lib/instructions/git-hooks.d.ts.map +1 -0
  186. package/dist/lib/instructions/git-hooks.js +238 -0
  187. package/dist/lib/instructions/splice.d.ts +10 -4
  188. package/dist/lib/instructions/splice.d.ts.map +1 -1
  189. package/dist/lib/instructions/splice.js +19 -11
  190. package/package.json +2 -2
  191. package/schemas/config.schema.json +32 -0
  192. package/src/commander.ts +5 -1
  193. package/src/commands/agents.ts +341 -113
  194. package/src/commands/browse-session.ts +245 -0
  195. package/src/commands/browse.ts +287 -44
  196. package/src/commands/checkpoint.ts +1 -1
  197. package/src/commands/claude-desktop.ts +106 -5
  198. package/src/commands/deinit.ts +7 -1
  199. package/src/commands/docs.ts +56 -0
  200. package/src/commands/doctor.ts +155 -21
  201. package/src/commands/init.ts +28 -9
  202. package/src/commands/instructions.ts +129 -0
  203. package/src/commands/presence.ts +7 -1
  204. package/src/commands/tunnel.ts +2 -5
  205. package/src/core/agents/canonical-emit.ts +7 -6
  206. package/src/core/agents/cli.ts +143 -89
  207. package/src/core/agents/coord-client.ts +21 -5
  208. package/src/core/agents/finalization.ts +595 -0
  209. package/src/core/agents/git-hook.ts +126 -0
  210. package/src/core/agents/index.ts +1 -0
  211. package/src/core/agents/render/prompt-context.ts +96 -16
  212. package/src/core/agents/render/session-context.ts +29 -4
  213. package/src/core/agents/rules/claim-conflict.ts +3 -3
  214. package/src/core/agents/rules/commit-conflict.ts +35 -8
  215. package/src/core/agents/rules/stop-hook.ts +71 -23
  216. package/src/core/agents/session-events.ts +14 -41
  217. package/src/core/agents/state/heartbeat-projector.ts +108 -1
  218. package/src/core/agents/state/heartbeat-writer.ts +129 -16
  219. package/src/core/agents/state/names.ts +54 -2
  220. package/src/core/agents/state/session-state.ts +131 -0
  221. package/src/core/config.ts +92 -12
  222. package/src/core/governor/planning.ts +17 -12
  223. package/src/core/hooks/adapter/detect.ts +4 -13
  224. package/src/core/hooks/adapter/events.ts +1 -0
  225. package/src/core/hooks/adapter/output.ts +9 -4
  226. package/src/core/hooks/adapter/parse.ts +3 -0
  227. package/src/core/hooks/adapter/wiring.ts +43 -0
  228. package/src/core/hooks/cli.ts +296 -27
  229. package/src/core/hooks/codex-authorization.ts +253 -0
  230. package/src/core/hooks/codex-wsl-bridge.ts +188 -0
  231. package/src/core/hooks/effects/index.ts +5 -5
  232. package/src/core/hooks/events/schema.ts +71 -0
  233. package/src/core/hooks/resolve/owner.ts +22 -1
  234. package/src/core/hooks/resolve/transcript.ts +164 -1
  235. package/src/core/hooks/session-name-presence.ts +52 -0
  236. package/src/core/hooks/unsafe-cross-shell.ts +160 -0
  237. package/src/core/presence/blob.ts +18 -0
  238. package/src/core/presence/index.ts +18 -1
  239. package/src/core/work/state.ts +8 -12
  240. package/src/core/workflow/engine.ts +2 -2
  241. package/src/core/workflow/index.ts +0 -1
  242. package/src/core/workflow/proof.ts +4 -4
  243. package/src/core/workflow/run-state.ts +5 -5
  244. package/src/core/workflow/types.ts +3 -3
  245. package/src/core/workflow/workspaces/execution.ts +11 -4
  246. package/src/core/workflow/workspaces/index.ts +0 -3
  247. package/src/core/workflow/workspaces/local-git.ts +1 -2
  248. package/src/core/workflow/workspaces/paths.ts +2 -2
  249. package/src/core/workflow/workspaces/types.ts +0 -9
  250. package/src/core/workflow/workspaces/validate.ts +1 -5
  251. package/src/lib/browser/client.ts +528 -6
  252. package/src/lib/browser/geometry.ts +197 -37
  253. package/src/lib/browser/index.ts +39 -0
  254. package/src/lib/browser/netscape-cookies.ts +39 -0
  255. package/src/lib/browser/proxy.ts +105 -0
  256. package/src/lib/browser/runts.ts +27 -3
  257. package/src/lib/browser/session-control.ts +892 -0
  258. package/src/lib/claude-desktop.ts +232 -1
  259. package/src/lib/docs-links.ts +674 -0
  260. package/src/lib/exec.ts +1 -1
  261. package/src/lib/identities/assume.ts +22 -1
  262. package/src/lib/instructions/bundle.ts +199 -0
  263. package/src/lib/instructions/git-hooks.ts +259 -0
  264. package/src/lib/instructions/splice.ts +41 -11
@@ -47,7 +47,9 @@ const MAX_RECORD_BYTES = 256 * 1024;
47
47
  const MAX_EVENTS_BYTES = 512 * 1024;
48
48
  const MAX_REASON = 2_000;
49
49
  const PROPOSAL_ROOT_RULE =
50
- "proposal.root names one newly proposed work key using a root-capable template; it does not preserve or repeat active_root, which is context only";
50
+ "proposal.root is inferred by Harnery as the single final outcome that no other proposed item depends on; it must use a root-capable template and depend transitively on every other proposed item; it never preserves or repeats active_root, which is context only";
51
+ const PLANNER_ROOT_RULE =
52
+ "Dependencies point from later work to earlier prerequisites. Do not return proposal.root. Harnery infers it as the single final outcome that no other proposed item depends on; make that outcome use a root-capable template and depend transitively on every other proposed item.";
51
53
 
52
54
  export interface RunGovernorPlannerInput {
53
55
  coordRoot: string;
@@ -729,7 +731,7 @@ function plannerScript(
729
731
  : "Return decision=apply with a replacement immutable root graph, or decision=attention when human judgment is required.",
730
732
  "Never claim mission completion unless the frozen mission acceptance is met. Never request a workflow outside the frozen template catalog.",
731
733
  "Dependencies may name an active work ID or an earlier key in your proposed work array.",
732
- `Every proposed item must be reachable from root. ${PROPOSAL_ROOT_RULE}.`,
734
+ PLANNER_ROOT_RULE,
733
735
  "Work keys are lowercase identifiers no longer than 32 characters. Keep titles within 200 characters, objectives within 4000 characters, and each acceptance criterion within 500 characters.",
734
736
  `Plan id: ${planId}`,
735
737
  `Planning trigger: ${trigger}`,
@@ -1331,12 +1333,6 @@ function planProposalSchema(
1331
1333
  const applyProperties: Record<string, StageSchema> = {
1332
1334
  decision: { type: "string", enum: ["apply"] },
1333
1335
  rationale,
1334
- root: {
1335
- type: "string",
1336
- minLength: 1,
1337
- maxLength: 32,
1338
- pattern: "^[a-z][a-z0-9-]{0,31}$",
1339
- },
1340
1336
  work: {
1341
1337
  type: "array",
1342
1338
  minItems: 1,
@@ -1344,7 +1340,7 @@ function planProposalSchema(
1344
1340
  items: workItem,
1345
1341
  },
1346
1342
  };
1347
- const applyRequired = ["decision", "rationale", "root", "work"];
1343
+ const applyRequired = ["decision", "rationale", "work"];
1348
1344
  if (record.intent.mission) {
1349
1345
  applyProperties.milestone = milestone;
1350
1346
  applyRequired.push("milestone");
@@ -1390,10 +1386,10 @@ function normalizeProposal(
1390
1386
  const proposedAt = preservedProposedAt ?? new Date().toISOString();
1391
1387
  const decision = enumValue(value.decision, ["apply", "complete", "attention"], "plan decision");
1392
1388
  const rationale = bounded(value.rationale, "plan rationale", MAX_REASON);
1393
- const root = typeof value.root === "string" ? value.root.trim() : "";
1389
+ const terminalRoot = typeof value.root === "string" ? value.root.trim() : "";
1394
1390
  if (!Array.isArray(value.work)) throw new Error("plan work must be an array");
1395
1391
  if (decision === "attention" || decision === "complete") {
1396
- if (root || value.work.length > 0 || value.milestone !== undefined) {
1392
+ if (terminalRoot || value.work.length > 0 || value.milestone !== undefined) {
1397
1393
  throw new Error(`${decision} plan must not contain work or milestone data`);
1398
1394
  }
1399
1395
  if (decision === "complete" && (!record.intent.mission || trigger !== "milestone")) {
@@ -1473,7 +1469,16 @@ function normalizeProposal(
1473
1469
  template,
1474
1470
  };
1475
1471
  });
1476
- if (!seen.has(root)) throw new Error(`plan root ${root || "(empty)"} is not a proposed key`);
1472
+ const dependedOn = new Set(
1473
+ work.flatMap((item) => item.dependencies.filter((dependency) => seen.has(dependency))),
1474
+ );
1475
+ const terminalOutcomes = work.filter((item) => !dependedOn.has(item.key));
1476
+ if (terminalOutcomes.length !== 1) {
1477
+ throw new Error(
1478
+ `plan must have exactly one final outcome; found ${terminalOutcomes.map((item) => item.key).join(", ")}`,
1479
+ );
1480
+ }
1481
+ const root = terminalOutcomes[0]!.key;
1477
1482
  const rootSpec = work.find((item) => item.key === root);
1478
1483
  if (!rootSpec || !policy.templates[rootSpec.template]?.root) {
1479
1484
  throw new Error(`plan root ${root} must use a root-capable template`);
@@ -4,32 +4,23 @@ import type { Adapter } from "../events/schema.ts";
4
4
  /**
5
5
  * Resolve the adapter firing the hook. The dispatcher binary is always
6
6
  * invoked with `--adapter <name>` per the current wiring in each adapter's
7
- * settings file. `--harness` remains an accepted alias because settings files
8
- * written by older releases survive a package upgrade until the consumer
9
- * re-runs `harn init`. Returns null when neither flag is present; caller falls
10
- * through to the env-based fallback or skips emission.
7
+ * settings file. Returns null when the flag is absent; caller falls through to
8
+ * the environment fallback or skips emission.
11
9
  */
12
10
  export function detectAdapter(argv: readonly string[]): Adapter | null {
13
11
  for (let i = 0; i < argv.length; i++) {
14
12
  const a = argv[i]!;
15
- if (a === "--adapter" || a === "--harness") {
13
+ if (a === "--adapter") {
16
14
  return validate(argv[i + 1]);
17
15
  }
18
16
  if (a.startsWith("--adapter=")) {
19
17
  return validate(a.slice("--adapter=".length));
20
18
  }
21
- if (a.startsWith("--harness=")) {
22
- return validate(a.slice("--harness=".length));
23
- }
24
19
  }
25
- return validate(coordEnv("AGENT_COORD_ADAPTER") ?? coordEnv("AGENT_COORD_HARNESS"));
20
+ return validate(coordEnv("AGENT_COORD_ADAPTER"));
26
21
  }
27
22
 
28
23
  function validate(v: string | undefined): Adapter | null {
29
24
  if (v === "claude-code" || v === "cursor" || v === "codex") return v;
30
- // Legacy: some adapters use `claude_code` (underscore). Map
31
- // it through so the env-based fallback works for callers that haven't
32
- // updated yet.
33
- if (v === "claude_code") return "claude-code";
34
25
  return null;
35
26
  }
@@ -87,6 +87,7 @@ export const CURSOR_EVENTS: HookEvent[] = [
87
87
  export const CODEX_EVENTS: HookEvent[] = [
88
88
  { settingsKey: "SessionStart", subcommand: "session-start" },
89
89
  { settingsKey: "PreToolUse", subcommand: "pre-tool-use" },
90
+ { settingsKey: "PermissionRequest", subcommand: "permission-request" },
90
91
  { settingsKey: "PostToolUse", subcommand: "post-tool-use" },
91
92
  { settingsKey: "UserPromptSubmit", subcommand: "user-prompt-submit" },
92
93
  { settingsKey: "SubagentStart", subcommand: "sub-agent-start" },
@@ -19,7 +19,7 @@
19
19
  */
20
20
 
21
21
  import { STOP_REMEDIATION_MARKER } from "../../agents/rules/stop-hook.ts";
22
- import { resolveBinName } from "../../config.ts";
22
+ import { endOfTurnStatusCommand, resolveBinName } from "../../config.ts";
23
23
  import type { Adapter } from "../events/schema.ts";
24
24
 
25
25
  export type SystemEvent = "SessionStart" | "UserPromptSubmit" | "SubagentStart";
@@ -60,7 +60,11 @@ export function emitDeny(adapter: Adapter, reason: string): void {
60
60
  * We exit 0 so Cursor treats the run as a success and honors the output.
61
61
  * (Confirmed against cursor.com/docs/agent/hooks.)
62
62
  */
63
- export function emitStopBlock(adapter: Adapter, verdict: { reason?: string; rule: string }): 0 | 2 {
63
+ export function emitStopBlock(
64
+ adapter: Adapter,
65
+ verdict: { reason?: string; rule: string },
66
+ coordRoot?: string,
67
+ ): 0 | 2 {
64
68
  if (adapter === "codex") return 0;
65
69
 
66
70
  const reason = verdict.reason ?? "End-of-turn coordination ritual incomplete.";
@@ -70,11 +74,12 @@ export function emitStopBlock(adapter: Adapter, verdict: { reason?: string; rule
70
74
  // see in chat that the message came from Harnery rather than from them.
71
75
  // Both commands are named because one message that repairs the whole ritual
72
76
  // ends the chain in a single followup; the failing rule is context.
73
- const bin = resolveBinName();
77
+ const bin = resolveBinName(coordRoot);
78
+ const statusCommand = endOfTurnStatusCommand(coordRoot);
74
79
  const message = [
75
80
  `${STOP_REMEDIATION_MARKER} rule=${verdict.rule}]`,
76
81
  reason,
77
- `Repair the ritual in this turn: run \`${bin} agents set-task "<short focus>"\` and then \`${bin} agents status\` as your last tool call.`,
82
+ `Repair the ritual in this turn: run \`${bin} agents set-task "<short focus>"\` and then \`${statusCommand}\` as your last tool call.`,
78
83
  ].join("\n");
79
84
  process.stdout.write(`${JSON.stringify({ followup_message: message })}\n`);
80
85
  return 0;
@@ -178,6 +178,8 @@ export function normalizeEventName(
178
178
  case "pre-tool-use":
179
179
  case "before-shell-execution":
180
180
  return { event_type: "tool.pre_use", intra_turn: true };
181
+ case "permission-request":
182
+ return { event_type: "interaction.input_requested", intra_turn: true };
181
183
  case "post-tool-use":
182
184
  return { event_type: "tool.post_use", intra_turn: true };
183
185
  case "post-tool-use-failure":
@@ -199,6 +201,7 @@ export type NormalizedEventType =
199
201
  | "subagent.start"
200
202
  | "subagent.stop"
201
203
  | "tool.pre_use"
204
+ | "interaction.input_requested"
202
205
  | "tool.post_use"
203
206
  | "tool.post_use_failure"
204
207
  | "context.compaction.started"
@@ -200,6 +200,49 @@ export function loadAdapterWiring(projectRoot: string): AdapterWiringStatus[] {
200
200
  return out;
201
201
  }
202
202
 
203
+ export interface AdapterWiringSummary {
204
+ /** Adapters carrying at least one harnery hook. */
205
+ wired: AdapterId[];
206
+ /**
207
+ * Adapters carrying none: no settings file at all, or a settings file with
208
+ * none of ours in it. An unparseable file lands in neither list, since
209
+ * `loadAdapterWiring` already reports that as drift.
210
+ */
211
+ unwired: AdapterId[];
212
+ }
213
+
214
+ /**
215
+ * Classify every known adapter as wired or unwired, without judging whether an
216
+ * unwired one is a problem.
217
+ *
218
+ * `loadAdapterWiring` stays deliberately silent about an adapter with zero
219
+ * harnery hooks, because a bare settings file is not an opt-out signal and
220
+ * nagging about it would false-warn every session. That silence is right in
221
+ * isolation and wrong once you also know the adapter's CLI is installed: then
222
+ * an agent can start a session here and register nothing. Splitting the fact
223
+ * from the judgement lets a caller holding both (doctor) tell "not used here"
224
+ * from "never wired" without changing what counts as drift.
225
+ */
226
+ export function summarizeAdapterWiring(projectRoot: string): AdapterWiringSummary {
227
+ const wired: AdapterId[] = [];
228
+ const unwired: AdapterId[] = [];
229
+ for (const [id, spec] of Object.entries(ADAPTER_SPECS) as [AdapterId, AdapterSpec][]) {
230
+ const settingsPath = resolve(projectRoot, spec.settingsFile);
231
+ if (!existsSync(settingsPath)) {
232
+ unwired.push(id);
233
+ continue;
234
+ }
235
+ let settings: SettingsFile;
236
+ try {
237
+ settings = JSON.parse(readFileSync(settingsPath, "utf8")) as SettingsFile;
238
+ } catch {
239
+ continue; // unparseable → already surfaced by loadAdapterWiring
240
+ }
241
+ (diffWiring(settings, spec).present.length > 0 ? wired : unwired).push(id);
242
+ }
243
+ return { wired, unwired };
244
+ }
245
+
203
246
  /**
204
247
  * Resolve the harnery package version for context in nudges/checks. Walks up
205
248
  * from this module to the package root (works under Bun from `src/` and Node