harnery 0.31.6 → 0.32.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 (218) hide show
  1. package/dist/commander.d.ts.map +1 -1
  2. package/dist/commander.js +2 -0
  3. package/dist/commands/agents.d.ts +0 -9
  4. package/dist/commands/agents.d.ts.map +1 -1
  5. package/dist/commands/agents.js +70 -95
  6. package/dist/commands/browse-session.d.ts +21 -0
  7. package/dist/commands/browse-session.d.ts.map +1 -0
  8. package/dist/commands/browse-session.js +157 -0
  9. package/dist/commands/browse.d.ts.map +1 -1
  10. package/dist/commands/browse.js +205 -37
  11. package/dist/commands/checkpoint.js +1 -1
  12. package/dist/commands/deinit.d.ts.map +1 -1
  13. package/dist/commands/deinit.js +4 -0
  14. package/dist/commands/docs.d.ts.map +1 -1
  15. package/dist/commands/docs.js +40 -0
  16. package/dist/commands/doctor.d.ts.map +1 -1
  17. package/dist/commands/doctor.js +100 -17
  18. package/dist/commands/init.d.ts +1 -2
  19. package/dist/commands/init.d.ts.map +1 -1
  20. package/dist/commands/init.js +16 -5
  21. package/dist/commands/tunnel.d.ts.map +1 -1
  22. package/dist/commands/tunnel.js +2 -3
  23. package/dist/core/agents/canonical-emit.d.ts +1 -2
  24. package/dist/core/agents/canonical-emit.d.ts.map +1 -1
  25. package/dist/core/agents/canonical-emit.js +1 -2
  26. package/dist/core/agents/cli.js +123 -88
  27. package/dist/core/agents/coord-client.d.ts +7 -3
  28. package/dist/core/agents/coord-client.d.ts.map +1 -1
  29. package/dist/core/agents/coord-client.js +5 -4
  30. package/dist/core/agents/finalization.d.ts +68 -0
  31. package/dist/core/agents/finalization.d.ts.map +1 -0
  32. package/dist/core/agents/finalization.js +443 -0
  33. package/dist/core/agents/git-hook.d.ts +51 -0
  34. package/dist/core/agents/git-hook.d.ts.map +1 -0
  35. package/dist/core/agents/git-hook.js +118 -0
  36. package/dist/core/agents/render/prompt-context.d.ts +6 -5
  37. package/dist/core/agents/render/prompt-context.d.ts.map +1 -1
  38. package/dist/core/agents/render/prompt-context.js +26 -13
  39. package/dist/core/agents/render/session-context.d.ts.map +1 -1
  40. package/dist/core/agents/render/session-context.js +15 -2
  41. package/dist/core/agents/rules/claim-conflict.js +3 -3
  42. package/dist/core/agents/rules/commit-conflict.d.ts +15 -6
  43. package/dist/core/agents/rules/commit-conflict.d.ts.map +1 -1
  44. package/dist/core/agents/rules/commit-conflict.js +21 -5
  45. package/dist/core/agents/rules/stop-hook.d.ts +3 -0
  46. package/dist/core/agents/rules/stop-hook.d.ts.map +1 -1
  47. package/dist/core/agents/rules/stop-hook.js +59 -23
  48. package/dist/core/agents/session-events.d.ts +8 -16
  49. package/dist/core/agents/session-events.d.ts.map +1 -1
  50. package/dist/core/agents/session-events.js +12 -26
  51. package/dist/core/agents/state/heartbeat-projector.d.ts +3 -0
  52. package/dist/core/agents/state/heartbeat-projector.d.ts.map +1 -1
  53. package/dist/core/agents/state/heartbeat-projector.js +44 -1
  54. package/dist/core/agents/state/heartbeat-writer.d.ts +32 -5
  55. package/dist/core/agents/state/heartbeat-writer.d.ts.map +1 -1
  56. package/dist/core/agents/state/heartbeat-writer.js +54 -17
  57. package/dist/core/agents/state/names.d.ts +22 -1
  58. package/dist/core/agents/state/names.d.ts.map +1 -1
  59. package/dist/core/agents/state/names.js +40 -2
  60. package/dist/core/config.d.ts +30 -2
  61. package/dist/core/config.d.ts.map +1 -1
  62. package/dist/core/config.js +74 -11
  63. package/dist/core/governor/planning.d.ts.map +1 -1
  64. package/dist/core/governor/planning.js +12 -13
  65. package/dist/core/hooks/adapter/detect.d.ts +2 -4
  66. package/dist/core/hooks/adapter/detect.d.ts.map +1 -1
  67. package/dist/core/hooks/adapter/detect.js +4 -14
  68. package/dist/core/hooks/adapter/output.d.ts +1 -1
  69. package/dist/core/hooks/adapter/output.d.ts.map +1 -1
  70. package/dist/core/hooks/adapter/output.js +5 -4
  71. package/dist/core/hooks/adapter/wiring.d.ts +23 -0
  72. package/dist/core/hooks/adapter/wiring.d.ts.map +1 -1
  73. package/dist/core/hooks/adapter/wiring.js +32 -0
  74. package/dist/core/hooks/cli.d.ts +1 -2
  75. package/dist/core/hooks/cli.d.ts.map +1 -1
  76. package/dist/core/hooks/cli.js +169 -27
  77. package/dist/core/hooks/codex-wsl-bridge.d.ts +46 -0
  78. package/dist/core/hooks/codex-wsl-bridge.d.ts.map +1 -0
  79. package/dist/core/hooks/codex-wsl-bridge.js +137 -0
  80. package/dist/core/hooks/effects/index.d.ts +1 -1
  81. package/dist/core/hooks/effects/index.js +3 -3
  82. package/dist/core/hooks/events/schema.d.ts +27 -0
  83. package/dist/core/hooks/events/schema.d.ts.map +1 -1
  84. package/dist/core/hooks/resolve/owner.d.ts +7 -1
  85. package/dist/core/hooks/resolve/owner.d.ts.map +1 -1
  86. package/dist/core/hooks/resolve/owner.js +15 -0
  87. package/dist/core/hooks/resolve/transcript.d.ts +44 -0
  88. package/dist/core/hooks/resolve/transcript.d.ts.map +1 -1
  89. package/dist/core/hooks/resolve/transcript.js +176 -1
  90. package/dist/core/hooks/session-name-presence.d.ts +30 -0
  91. package/dist/core/hooks/session-name-presence.d.ts.map +1 -0
  92. package/dist/core/hooks/session-name-presence.js +43 -0
  93. package/dist/core/hooks/unsafe-cross-shell.d.ts +13 -0
  94. package/dist/core/hooks/unsafe-cross-shell.d.ts.map +1 -0
  95. package/dist/core/hooks/unsafe-cross-shell.js +151 -0
  96. package/dist/core/work/state.d.ts +4 -5
  97. package/dist/core/work/state.d.ts.map +1 -1
  98. package/dist/core/work/state.js +5 -8
  99. package/dist/core/workflow/index.d.ts +1 -1
  100. package/dist/core/workflow/index.d.ts.map +1 -1
  101. package/dist/core/workflow/proof.d.ts +2 -2
  102. package/dist/core/workflow/proof.d.ts.map +1 -1
  103. package/dist/core/workflow/proof.js +2 -2
  104. package/dist/core/workflow/run-state.d.ts +2 -2
  105. package/dist/core/workflow/run-state.d.ts.map +1 -1
  106. package/dist/core/workflow/run-state.js +2 -2
  107. package/dist/core/workflow/types.d.ts +3 -3
  108. package/dist/core/workflow/types.d.ts.map +1 -1
  109. package/dist/core/workflow/workspaces/execution.d.ts +2 -2
  110. package/dist/core/workflow/workspaces/execution.d.ts.map +1 -1
  111. package/dist/core/workflow/workspaces/execution.js +5 -0
  112. package/dist/core/workflow/workspaces/index.d.ts +1 -1
  113. package/dist/core/workflow/workspaces/index.d.ts.map +1 -1
  114. package/dist/core/workflow/workspaces/local-git.d.ts.map +1 -1
  115. package/dist/core/workflow/workspaces/local-git.js +1 -2
  116. package/dist/core/workflow/workspaces/paths.d.ts +2 -2
  117. package/dist/core/workflow/workspaces/types.d.ts +0 -6
  118. package/dist/core/workflow/workspaces/types.d.ts.map +1 -1
  119. package/dist/core/workflow/workspaces/validate.d.ts +0 -2
  120. package/dist/core/workflow/workspaces/validate.d.ts.map +1 -1
  121. package/dist/core/workflow/workspaces/validate.js +0 -2
  122. package/dist/lib/browser/client.d.ts +118 -1
  123. package/dist/lib/browser/client.d.ts.map +1 -1
  124. package/dist/lib/browser/client.js +435 -6
  125. package/dist/lib/browser/geometry.d.ts.map +1 -1
  126. package/dist/lib/browser/geometry.js +180 -37
  127. package/dist/lib/browser/index.d.ts +5 -1
  128. package/dist/lib/browser/index.d.ts.map +1 -1
  129. package/dist/lib/browser/index.js +5 -1
  130. package/dist/lib/browser/netscape-cookies.d.ts +6 -0
  131. package/dist/lib/browser/netscape-cookies.d.ts.map +1 -0
  132. package/dist/lib/browser/netscape-cookies.js +31 -0
  133. package/dist/lib/browser/proxy.d.ts +24 -0
  134. package/dist/lib/browser/proxy.d.ts.map +1 -0
  135. package/dist/lib/browser/proxy.js +84 -0
  136. package/dist/lib/browser/runts.d.ts +6 -0
  137. package/dist/lib/browser/runts.d.ts.map +1 -1
  138. package/dist/lib/browser/runts.js +21 -4
  139. package/dist/lib/browser/session-control.d.ts +112 -0
  140. package/dist/lib/browser/session-control.d.ts.map +1 -0
  141. package/dist/lib/browser/session-control.js +670 -0
  142. package/dist/lib/docs-links.d.ts +108 -0
  143. package/dist/lib/docs-links.d.ts.map +1 -0
  144. package/dist/lib/docs-links.js +555 -0
  145. package/dist/lib/exec.d.ts +1 -1
  146. package/dist/lib/exec.js +1 -1
  147. package/dist/lib/identities/assume.d.ts +4 -2
  148. package/dist/lib/identities/assume.d.ts.map +1 -1
  149. package/dist/lib/identities/assume.js +15 -2
  150. package/dist/lib/instructions/git-hooks.d.ts +75 -0
  151. package/dist/lib/instructions/git-hooks.d.ts.map +1 -0
  152. package/dist/lib/instructions/git-hooks.js +238 -0
  153. package/dist/lib/instructions/splice.d.ts +10 -4
  154. package/dist/lib/instructions/splice.d.ts.map +1 -1
  155. package/dist/lib/instructions/splice.js +19 -11
  156. package/package.json +1 -1
  157. package/schemas/config.schema.json +32 -0
  158. package/src/commander.ts +2 -0
  159. package/src/commands/agents.ts +96 -115
  160. package/src/commands/browse-session.ts +245 -0
  161. package/src/commands/browse.ts +287 -44
  162. package/src/commands/checkpoint.ts +1 -1
  163. package/src/commands/deinit.ts +7 -1
  164. package/src/commands/docs.ts +56 -0
  165. package/src/commands/doctor.ts +100 -18
  166. package/src/commands/init.ts +17 -9
  167. package/src/commands/tunnel.ts +2 -5
  168. package/src/core/agents/canonical-emit.ts +1 -2
  169. package/src/core/agents/cli.ts +137 -88
  170. package/src/core/agents/coord-client.ts +10 -5
  171. package/src/core/agents/finalization.ts +595 -0
  172. package/src/core/agents/git-hook.ts +126 -0
  173. package/src/core/agents/render/prompt-context.ts +28 -13
  174. package/src/core/agents/render/session-context.ts +15 -2
  175. package/src/core/agents/rules/claim-conflict.ts +3 -3
  176. package/src/core/agents/rules/commit-conflict.ts +35 -8
  177. package/src/core/agents/rules/stop-hook.ts +71 -23
  178. package/src/core/agents/session-events.ts +14 -41
  179. package/src/core/agents/state/heartbeat-projector.ts +45 -1
  180. package/src/core/agents/state/heartbeat-writer.ts +78 -16
  181. package/src/core/agents/state/names.ts +54 -2
  182. package/src/core/config.ts +92 -12
  183. package/src/core/governor/planning.ts +17 -12
  184. package/src/core/hooks/adapter/detect.ts +4 -13
  185. package/src/core/hooks/adapter/output.ts +9 -4
  186. package/src/core/hooks/adapter/wiring.ts +43 -0
  187. package/src/core/hooks/cli.ts +201 -23
  188. package/src/core/hooks/codex-wsl-bridge.ts +188 -0
  189. package/src/core/hooks/effects/index.ts +5 -5
  190. package/src/core/hooks/events/schema.ts +27 -0
  191. package/src/core/hooks/resolve/owner.ts +22 -1
  192. package/src/core/hooks/resolve/transcript.ts +164 -1
  193. package/src/core/hooks/session-name-presence.ts +52 -0
  194. package/src/core/hooks/unsafe-cross-shell.ts +160 -0
  195. package/src/core/work/state.ts +8 -12
  196. package/src/core/workflow/engine.ts +2 -2
  197. package/src/core/workflow/index.ts +0 -1
  198. package/src/core/workflow/proof.ts +4 -4
  199. package/src/core/workflow/run-state.ts +5 -5
  200. package/src/core/workflow/types.ts +3 -3
  201. package/src/core/workflow/workspaces/execution.ts +11 -4
  202. package/src/core/workflow/workspaces/index.ts +0 -3
  203. package/src/core/workflow/workspaces/local-git.ts +1 -2
  204. package/src/core/workflow/workspaces/paths.ts +2 -2
  205. package/src/core/workflow/workspaces/types.ts +0 -9
  206. package/src/core/workflow/workspaces/validate.ts +1 -5
  207. package/src/lib/browser/client.ts +528 -6
  208. package/src/lib/browser/geometry.ts +197 -37
  209. package/src/lib/browser/index.ts +39 -0
  210. package/src/lib/browser/netscape-cookies.ts +39 -0
  211. package/src/lib/browser/proxy.ts +105 -0
  212. package/src/lib/browser/runts.ts +27 -3
  213. package/src/lib/browser/session-control.ts +892 -0
  214. package/src/lib/docs-links.ts +674 -0
  215. package/src/lib/exec.ts +1 -1
  216. package/src/lib/identities/assume.ts +22 -1
  217. package/src/lib/instructions/git-hooks.ts +259 -0
  218. package/src/lib/instructions/splice.ts +41 -11
@@ -7,7 +7,7 @@
7
7
  * 2. `<project-root>/.harnery/config.jsonc` — project override (authoritative)
8
8
  *
9
9
  * Fields owned here: `binName` (host CLI name for agent-facing strings),
10
- * `hooksSetupHint`, `tools`, `workflow`, `skills`, `presence`, plus the tunable
10
+ * `hooksSetupHint`, `agents`, `tools`, `workflow`, `skills`, `presence`, plus the tunable
11
11
  * `coord` (heartbeat freshness), `artifacts` (working-file retention),
12
12
  * `backup` (restic repo/password/prune policy), and `sync` (rclone
13
13
  * remote/prefix) sections. The `files` deny/override section
@@ -21,6 +21,11 @@
21
21
  export declare const DEFAULT_BIN_NAME = "harn";
22
22
  /** Heartbeat-freshness default (seconds): the sweep window when nothing overrides it. */
23
23
  export declare const DEFAULT_FRESHNESS_SECS = 600;
24
+ export type AgentFinalizationDisposition = "git" | "output";
25
+ export interface AgentFinalizationRoot {
26
+ path: string;
27
+ disposition: AgentFinalizationDisposition;
28
+ }
24
29
  /** Strip `//` and `/* *​/` comments from JSONC, ignoring comment-like runs inside strings. */
25
30
  export declare function stripJsonComments(input: string): string;
26
31
  /**
@@ -49,6 +54,29 @@ export declare function pinnedBinName(projectRoot: string): string | null;
49
54
  * `coordRoot` is resolved via `findCoordRoot()` when not passed.
50
55
  */
51
56
  export declare function resolveHooksSetupHint(coordRoot?: string | null): string | null;
57
+ /**
58
+ * Whether the host requires the guarded Git check at the end of tool-using
59
+ * turns. Default false: Harnery exposes `agents status --end-turn` as a capability
60
+ * but does not impose a commit-and-push policy on embedding projects.
61
+ *
62
+ * `.harnery/config.jsonc`:
63
+ * `{ "agents": { "requireGitFinalization": true } }`
64
+ *
65
+ * `HARNERY_AGENTS_REQUIRE_GIT_FINALIZATION=1|0` overrides per process.
66
+ */
67
+ export declare function agentsRequireGitFinalization(coordRoot?: string | null): boolean;
68
+ /**
69
+ * Extra roots whose guarded writes have an explicit end-turn disposition.
70
+ *
71
+ * This trust boundary comes only from the project config. A user-global config
72
+ * may tune ordinary behavior, but it cannot grant one project filesystem
73
+ * authority outside its coordination root. Paths may be absolute or relative
74
+ * to the coordination root. Invalid entries are ignored here and fail closed
75
+ * when the finalization policy validates them.
76
+ */
77
+ export declare function agentsFinalizationRoots(coordRoot?: string | null): AgentFinalizationRoot[];
78
+ /** The status command automatic prompts and Stop remediation should request. */
79
+ export declare function endOfTurnStatusCommand(coordRoot?: string | null): string;
52
80
  /**
53
81
  * Whether the host project consented to automatic ripgrep provisioning:
54
82
  * `.harnery/config.jsonc` `{ "tools": { "ripgrep": { "autoInstall": true } } }`.
@@ -86,7 +114,7 @@ export declare function presenceRelayUrl(coordRoot?: string | null): string | nu
86
114
  * The heartbeat-freshness window (seconds): the age above which the sweeper
87
115
  * prunes an agent, and the cutoff the `agents` surface uses to fold stale peers.
88
116
  * Precedence:
89
- * 1. `HARNERY_AGENT_COORD_FRESHNESS` env (canonical), or `HARNERY_AGENT_FRESHNESS` (legacy alias)
117
+ * 1. `HARNERY_AGENT_COORD_FRESHNESS` env
90
118
  * 2. `.harnery/config.jsonc` `coord.freshness_seconds`
91
119
  * 3. `600` (10 minutes)
92
120
  * `coordRoot` is resolved via `findCoordRoot()` when not passed.
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAQH,oFAAoF;AACpF,eAAO,MAAM,gBAAgB,SAAS,CAAC;AAEvC,yFAAyF;AACzF,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAsE1C,8FAA8F;AAC9F,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAqCvD;AAwFD;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAShE;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGhE;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAK9E;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAOrE;AAED;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAO3E;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAOlE;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAWzE;AAQD;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CASvE;AAED;;;;GAIG;AACH,wBAAgB,4BAA4B,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAe9E;AAED,6EAA6E;AAC7E,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,YAAY,CAmBpE;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GACxB;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAS3C"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAQH,oFAAoF;AACpF,eAAO,MAAM,gBAAgB,SAAS,CAAC;AAEvC,yFAAyF;AACzF,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAE1C,MAAM,MAAM,4BAA4B,GAAG,KAAK,GAAG,QAAQ,CAAC;AAE5D,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,4BAA4B,CAAC;CAC3C;AA+ED,8FAA8F;AAC9F,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAqCvD;AAuGD;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAShE;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGhE;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAK9E;AAED;;;;;;;;;GASG;AACH,wBAAgB,4BAA4B,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAO/E;AAED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,qBAAqB,EAAE,CAY1F;AAED,gFAAgF;AAChF,wBAAgB,sBAAsB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAIxE;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAOrE;AAED;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAO3E;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAOlE;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAWzE;AAQD;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CASvE;AAED;;;;GAIG;AACH,wBAAgB,4BAA4B,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAe9E;AAED,6EAA6E;AAC7E,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,YAAY,CAmBpE;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GACxB;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAS3C"}
@@ -7,7 +7,7 @@
7
7
  * 2. `<project-root>/.harnery/config.jsonc` — project override (authoritative)
8
8
  *
9
9
  * Fields owned here: `binName` (host CLI name for agent-facing strings),
10
- * `hooksSetupHint`, `tools`, `workflow`, `skills`, `presence`, plus the tunable
10
+ * `hooksSetupHint`, `agents`, `tools`, `workflow`, `skills`, `presence`, plus the tunable
11
11
  * `coord` (heartbeat freshness), `artifacts` (working-file retention),
12
12
  * `backup` (restic repo/password/prune policy), and `sync` (rclone
13
13
  * remote/prefix) sections. The `files` deny/override section
@@ -86,6 +86,16 @@ function statMtime(p) {
86
86
  return -1;
87
87
  }
88
88
  }
89
+ /** Cache signature, or null when the file can't be stat'd (missing). */
90
+ function statSignature(p) {
91
+ try {
92
+ const stat = statSync(p);
93
+ return `${stat.mtimeMs}:${stat.ctimeMs}:${stat.size}`;
94
+ }
95
+ catch {
96
+ return null;
97
+ }
98
+ }
89
99
  /** Parse one JSONC config file to an object; missing/unparseable → `{}`. */
90
100
  function parseConfigFile(p) {
91
101
  try {
@@ -114,7 +124,7 @@ function mergeConfig(base, override) {
114
124
  }
115
125
  return out;
116
126
  }
117
- // mtime-keyed per-process cache (both layers): a stat is cheap, a parse on every render isn't.
127
+ // Stat-signature-keyed per-process cache (both layers): a stat is cheap, a parse on every render isn't.
118
128
  let cache = null;
119
129
  /**
120
130
  * The effective config for `root`: user-global (`~/.config/harnery/config.jsonc`)
@@ -124,18 +134,18 @@ let cache = null;
124
134
  function readConfig(root) {
125
135
  const projPath = join(root, ".harnery", "config.jsonc");
126
136
  const userPath = userConfigPath();
127
- const projMtime = statMtime(projPath);
128
- const userMtime = statMtime(userPath);
137
+ const projSignature = statSignature(projPath);
138
+ const userSignature = statSignature(userPath);
129
139
  if (cache &&
130
140
  cache.root === root &&
131
- cache.projMtime === projMtime &&
132
- cache.userMtime === userMtime) {
141
+ cache.projSignature === projSignature &&
142
+ cache.userSignature === userSignature) {
133
143
  return cache.cfg;
134
144
  }
135
- const user = userMtime === -1 ? {} : parseConfigFile(userPath);
136
- const project = projMtime === -1 ? {} : parseConfigFile(projPath);
145
+ const user = userSignature === null ? {} : parseConfigFile(userPath);
146
+ const project = projSignature === null ? {} : parseConfigFile(projPath);
137
147
  const cfg = mergeConfig(user, project);
138
- cache = { root, projMtime, userMtime, cfg };
148
+ cache = { root, projSignature, userSignature, cfg };
139
149
  return cfg;
140
150
  }
141
151
  /**
@@ -193,6 +203,59 @@ export function resolveHooksSetupHint(coordRoot) {
193
203
  const hint = readConfig(root).hooksSetupHint;
194
204
  return typeof hint === "string" && hint.trim() ? hint.trim() : null;
195
205
  }
206
+ /**
207
+ * Whether the host requires the guarded Git check at the end of tool-using
208
+ * turns. Default false: Harnery exposes `agents status --end-turn` as a capability
209
+ * but does not impose a commit-and-push policy on embedding projects.
210
+ *
211
+ * `.harnery/config.jsonc`:
212
+ * `{ "agents": { "requireGitFinalization": true } }`
213
+ *
214
+ * `HARNERY_AGENTS_REQUIRE_GIT_FINALIZATION=1|0` overrides per process.
215
+ */
216
+ export function agentsRequireGitFinalization(coordRoot) {
217
+ const env = coordEnv("AGENTS_REQUIRE_GIT_FINALIZATION");
218
+ if (env === "1")
219
+ return true;
220
+ if (env === "0")
221
+ return false;
222
+ const root = coordRoot ?? findCoordRoot();
223
+ if (!root)
224
+ return false;
225
+ return readConfig(root).agents?.requireGitFinalization === true;
226
+ }
227
+ /**
228
+ * Extra roots whose guarded writes have an explicit end-turn disposition.
229
+ *
230
+ * This trust boundary comes only from the project config. A user-global config
231
+ * may tune ordinary behavior, but it cannot grant one project filesystem
232
+ * authority outside its coordination root. Paths may be absolute or relative
233
+ * to the coordination root. Invalid entries are ignored here and fail closed
234
+ * when the finalization policy validates them.
235
+ */
236
+ export function agentsFinalizationRoots(coordRoot) {
237
+ const root = coordRoot ?? findCoordRoot();
238
+ if (!root)
239
+ return [];
240
+ const entries = readProjectConfig(root).agents?.finalizationRoots;
241
+ if (!Array.isArray(entries))
242
+ return [];
243
+ return entries.flatMap((entry) => {
244
+ if (!entry || typeof entry !== "object")
245
+ return [];
246
+ const path = typeof entry.path === "string" ? entry.path.trim() : "";
247
+ const disposition = entry.disposition;
248
+ if (!path || (disposition !== "git" && disposition !== "output"))
249
+ return [];
250
+ return [{ path, disposition }];
251
+ });
252
+ }
253
+ /** The status command automatic prompts and Stop remediation should request. */
254
+ export function endOfTurnStatusCommand(coordRoot) {
255
+ const root = coordRoot ?? findCoordRoot();
256
+ const suffix = agentsRequireGitFinalization(root) ? " --end-turn" : "";
257
+ return `${resolveBinName(root)} agents status${suffix}`;
258
+ }
196
259
  /**
197
260
  * Whether the host project consented to automatic ripgrep provisioning:
198
261
  * `.harnery/config.jsonc` `{ "tools": { "ripgrep": { "autoInstall": true } } }`.
@@ -278,13 +341,13 @@ function posIntOr(v, fallback) {
278
341
  * The heartbeat-freshness window (seconds): the age above which the sweeper
279
342
  * prunes an agent, and the cutoff the `agents` surface uses to fold stale peers.
280
343
  * Precedence:
281
- * 1. `HARNERY_AGENT_COORD_FRESHNESS` env (canonical), or `HARNERY_AGENT_FRESHNESS` (legacy alias)
344
+ * 1. `HARNERY_AGENT_COORD_FRESHNESS` env
282
345
  * 2. `.harnery/config.jsonc` `coord.freshness_seconds`
283
346
  * 3. `600` (10 minutes)
284
347
  * `coordRoot` is resolved via `findCoordRoot()` when not passed.
285
348
  */
286
349
  export function coordFreshnessSeconds(coordRoot) {
287
- const env = coordEnv("AGENT_COORD_FRESHNESS") ?? coordEnv("AGENT_FRESHNESS");
350
+ const env = coordEnv("AGENT_COORD_FRESHNESS");
288
351
  if (env !== undefined) {
289
352
  const n = Number.parseInt(env, 10);
290
353
  if (Number.isFinite(n) && n > 0)
@@ -1 +1 @@
1
- {"version":3,"file":"planning.d.ts","sourceRoot":"","sources":["../../../src/core/governor/planning.ts"],"names":[],"mappings":"AAcA,OAAO,EAEL,KAAK,UAAU,EAQhB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAIL,KAAK,mBAAmB,EAUzB,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAUjD,MAAM,WAAW,uBAAuB;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,cAAc,CAAC;IACvB,MAAM,EAAE,IAAI,CAAC,UAAU,EAAE,WAAW,GAAG,OAAO,GAAG,aAAa,GAAG,aAAa,CAAC,CAAC;IAChF,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAChC;AAED,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,uBAAuB,GAC7B,OAAO,CAAC,mBAAmB,CAAC,CAsM9B;AAkMD,wBAAgB,yBAAyB,CAAC,KAAK,EAAE;IAC/C,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,cAAc,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GAAG,mBAAmB,CAkHtB;AAED,wBAAgB,0BAA0B,CAAC,KAAK,EAAE;IAChD,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,mBAAmB,CAYtB;AAED;;;;;;;;gEAQgE;AAChE,wBAAgB,yBAAyB,CAAC,KAAK,EAAE;IAC/C,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,cAAc,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,mBAAmB,CAoBtB;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE;IAC/C,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,cAAc,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,mBAAmB,CA4CtB"}
1
+ {"version":3,"file":"planning.d.ts","sourceRoot":"","sources":["../../../src/core/governor/planning.ts"],"names":[],"mappings":"AAcA,OAAO,EAEL,KAAK,UAAU,EAQhB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAIL,KAAK,mBAAmB,EAUzB,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAYjD,MAAM,WAAW,uBAAuB;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,cAAc,CAAC;IACvB,MAAM,EAAE,IAAI,CAAC,UAAU,EAAE,WAAW,GAAG,OAAO,GAAG,aAAa,GAAG,aAAa,CAAC,CAAC;IAChF,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAChC;AAED,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,uBAAuB,GAC7B,OAAO,CAAC,mBAAmB,CAAC,CAsM9B;AAkMD,wBAAgB,yBAAyB,CAAC,KAAK,EAAE;IAC/C,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,cAAc,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GAAG,mBAAmB,CAkHtB;AAED,wBAAgB,0BAA0B,CAAC,KAAK,EAAE;IAChD,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,mBAAmB,CAYtB;AAED;;;;;;;;gEAQgE;AAChE,wBAAgB,yBAAyB,CAAC,KAAK,EAAE;IAC/C,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,cAAc,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,mBAAmB,CAoBtB;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE;IAC/C,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,cAAc,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,mBAAmB,CA4CtB"}
@@ -10,7 +10,8 @@ const TEMPLATE_ID = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;
10
10
  const MAX_RECORD_BYTES = 256 * 1024;
11
11
  const MAX_EVENTS_BYTES = 512 * 1024;
12
12
  const MAX_REASON = 2_000;
13
- const PROPOSAL_ROOT_RULE = "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";
13
+ const PROPOSAL_ROOT_RULE = "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";
14
+ const PLANNER_ROOT_RULE = "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.";
14
15
  export async function runGovernorPlanner(input) {
15
16
  const coordRoot = resolve(input.coordRoot);
16
17
  const policy = input.record.intent.replanning;
@@ -527,7 +528,7 @@ function plannerScript(coordRoot, record, planId, trigger) {
527
528
  : "Return decision=apply with a replacement immutable root graph, or decision=attention when human judgment is required.",
528
529
  "Never claim mission completion unless the frozen mission acceptance is met. Never request a workflow outside the frozen template catalog.",
529
530
  "Dependencies may name an active work ID or an earlier key in your proposed work array.",
530
- `Every proposed item must be reachable from root. ${PROPOSAL_ROOT_RULE}.`,
531
+ PLANNER_ROOT_RULE,
531
532
  "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.",
532
533
  `Plan id: ${planId}`,
533
534
  `Planning trigger: ${trigger}`,
@@ -1040,12 +1041,6 @@ function planProposalSchema(record, trigger) {
1040
1041
  const applyProperties = {
1041
1042
  decision: { type: "string", enum: ["apply"] },
1042
1043
  rationale,
1043
- root: {
1044
- type: "string",
1045
- minLength: 1,
1046
- maxLength: 32,
1047
- pattern: "^[a-z][a-z0-9-]{0,31}$",
1048
- },
1049
1044
  work: {
1050
1045
  type: "array",
1051
1046
  minItems: 1,
@@ -1053,7 +1048,7 @@ function planProposalSchema(record, trigger) {
1053
1048
  items: workItem,
1054
1049
  },
1055
1050
  };
1056
- const applyRequired = ["decision", "rationale", "root", "work"];
1051
+ const applyRequired = ["decision", "rationale", "work"];
1057
1052
  if (record.intent.mission) {
1058
1053
  applyProperties.milestone = milestone;
1059
1054
  applyRequired.push("milestone");
@@ -1094,11 +1089,11 @@ function normalizeProposal(planId, raw, record, previouslyApplied, trigger, pres
1094
1089
  const proposedAt = preservedProposedAt ?? new Date().toISOString();
1095
1090
  const decision = enumValue(value.decision, ["apply", "complete", "attention"], "plan decision");
1096
1091
  const rationale = bounded(value.rationale, "plan rationale", MAX_REASON);
1097
- const root = typeof value.root === "string" ? value.root.trim() : "";
1092
+ const terminalRoot = typeof value.root === "string" ? value.root.trim() : "";
1098
1093
  if (!Array.isArray(value.work))
1099
1094
  throw new Error("plan work must be an array");
1100
1095
  if (decision === "attention" || decision === "complete") {
1101
- if (root || value.work.length > 0 || value.milestone !== undefined) {
1096
+ if (terminalRoot || value.work.length > 0 || value.milestone !== undefined) {
1102
1097
  throw new Error(`${decision} plan must not contain work or milestone data`);
1103
1098
  }
1104
1099
  if (decision === "complete" && (!record.intent.mission || trigger !== "milestone")) {
@@ -1170,8 +1165,12 @@ function normalizeProposal(planId, raw, record, previouslyApplied, trigger, pres
1170
1165
  template,
1171
1166
  };
1172
1167
  });
1173
- if (!seen.has(root))
1174
- throw new Error(`plan root ${root || "(empty)"} is not a proposed key`);
1168
+ const dependedOn = new Set(work.flatMap((item) => item.dependencies.filter((dependency) => seen.has(dependency))));
1169
+ const terminalOutcomes = work.filter((item) => !dependedOn.has(item.key));
1170
+ if (terminalOutcomes.length !== 1) {
1171
+ throw new Error(`plan must have exactly one final outcome; found ${terminalOutcomes.map((item) => item.key).join(", ")}`);
1172
+ }
1173
+ const root = terminalOutcomes[0].key;
1175
1174
  const rootSpec = work.find((item) => item.key === root);
1176
1175
  if (!rootSpec || !policy.templates[rootSpec.template]?.root) {
1177
1176
  throw new Error(`plan root ${root} must use a root-capable template`);
@@ -2,10 +2,8 @@ import type { Adapter } from "../events/schema.js";
2
2
  /**
3
3
  * Resolve the adapter firing the hook. The dispatcher binary is always
4
4
  * invoked with `--adapter <name>` per the current wiring in each adapter's
5
- * settings file. `--harness` remains an accepted alias because settings files
6
- * written by older releases survive a package upgrade until the consumer
7
- * re-runs `harn init`. Returns null when neither flag is present; caller falls
8
- * through to the env-based fallback or skips emission.
5
+ * settings file. Returns null when the flag is absent; caller falls through to
6
+ * the environment fallback or skips emission.
9
7
  */
10
8
  export declare function detectAdapter(argv: readonly string[]): Adapter | null;
11
9
  //# sourceMappingURL=detect.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"detect.d.ts","sourceRoot":"","sources":["../../../../src/core/hooks/adapter/detect.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAEnD;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,GAAG,IAAI,CAcrE"}
1
+ {"version":3,"file":"detect.d.ts","sourceRoot":"","sources":["../../../../src/core/hooks/adapter/detect.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAEnD;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,GAAG,IAAI,CAWrE"}
@@ -2,33 +2,23 @@ import { coordEnv } from "../../../lib/env.js";
2
2
  /**
3
3
  * Resolve the adapter firing the hook. The dispatcher binary is always
4
4
  * invoked with `--adapter <name>` per the current wiring in each adapter's
5
- * settings file. `--harness` remains an accepted alias because settings files
6
- * written by older releases survive a package upgrade until the consumer
7
- * re-runs `harn init`. Returns null when neither flag is present; caller falls
8
- * through to the env-based fallback or skips emission.
5
+ * settings file. Returns null when the flag is absent; caller falls through to
6
+ * the environment fallback or skips emission.
9
7
  */
10
8
  export function detectAdapter(argv) {
11
9
  for (let i = 0; i < argv.length; i++) {
12
10
  const a = argv[i];
13
- if (a === "--adapter" || a === "--harness") {
11
+ if (a === "--adapter") {
14
12
  return validate(argv[i + 1]);
15
13
  }
16
14
  if (a.startsWith("--adapter=")) {
17
15
  return validate(a.slice("--adapter=".length));
18
16
  }
19
- if (a.startsWith("--harness=")) {
20
- return validate(a.slice("--harness=".length));
21
- }
22
17
  }
23
- return validate(coordEnv("AGENT_COORD_ADAPTER") ?? coordEnv("AGENT_COORD_HARNESS"));
18
+ return validate(coordEnv("AGENT_COORD_ADAPTER"));
24
19
  }
25
20
  function validate(v) {
26
21
  if (v === "claude-code" || v === "cursor" || v === "codex")
27
22
  return v;
28
- // Legacy: some adapters use `claude_code` (underscore). Map
29
- // it through so the env-based fallback works for callers that haven't
30
- // updated yet.
31
- if (v === "claude_code")
32
- return "claude-code";
33
23
  return null;
34
24
  }
@@ -48,5 +48,5 @@ export declare function emitDeny(adapter: Adapter, reason: string): void;
48
48
  export declare function emitStopBlock(adapter: Adapter, verdict: {
49
49
  reason?: string;
50
50
  rule: string;
51
- }): 0 | 2;
51
+ }, coordRoot?: string): 0 | 2;
52
52
  //# sourceMappingURL=output.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../../../../src/core/hooks/adapter/output.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAIH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAEnD,MAAM,MAAM,WAAW,GAAG,cAAc,GAAG,kBAAkB,GAAG,eAAe,CAAC;AAEhF,+EAA+E;AAC/E,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAIpF;AAED,qFAAqF;AACrF,wBAAgB,QAAQ,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAI/D;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,CAAC,GAAG,CAAC,CAuBjG"}
1
+ {"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../../../../src/core/hooks/adapter/output.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAIH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAEnD,MAAM,MAAM,WAAW,GAAG,cAAc,GAAG,kBAAkB,GAAG,eAAe,CAAC;AAEhF,+EAA+E;AAC/E,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAIpF;AAED,qFAAqF;AACrF,wBAAgB,QAAQ,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAI/D;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAC1C,SAAS,CAAC,EAAE,MAAM,GACjB,CAAC,GAAG,CAAC,CAwBP"}
@@ -18,7 +18,7 @@
18
18
  * fire-and-forget. Empty text → no-op (no JSON written).
19
19
  */
20
20
  import { STOP_REMEDIATION_MARKER } from "../../agents/rules/stop-hook.js";
21
- import { resolveBinName } from "../../config.js";
21
+ import { endOfTurnStatusCommand, resolveBinName } from "../../config.js";
22
22
  /** Emit a context-injection (peer table, wiring check, council pending, …). */
23
23
  export function emitContext(adapter, event, text) {
24
24
  if (!text || text.length === 0)
@@ -55,7 +55,7 @@ export function emitDeny(adapter, reason) {
55
55
  * We exit 0 so Cursor treats the run as a success and honors the output.
56
56
  * (Confirmed against cursor.com/docs/agent/hooks.)
57
57
  */
58
- export function emitStopBlock(adapter, verdict) {
58
+ export function emitStopBlock(adapter, verdict, coordRoot) {
59
59
  if (adapter === "codex")
60
60
  return 0;
61
61
  const reason = verdict.reason ?? "End-of-turn coordination ritual incomplete.";
@@ -65,11 +65,12 @@ export function emitStopBlock(adapter, verdict) {
65
65
  // see in chat that the message came from Harnery rather than from them.
66
66
  // Both commands are named because one message that repairs the whole ritual
67
67
  // ends the chain in a single followup; the failing rule is context.
68
- const bin = resolveBinName();
68
+ const bin = resolveBinName(coordRoot);
69
+ const statusCommand = endOfTurnStatusCommand(coordRoot);
69
70
  const message = [
70
71
  `${STOP_REMEDIATION_MARKER} rule=${verdict.rule}]`,
71
72
  reason,
72
- `Repair the ritual in this turn: run \`${bin} agents set-task "<short focus>"\` and then \`${bin} agents status\` as your last tool call.`,
73
+ `Repair the ritual in this turn: run \`${bin} agents set-task "<short focus>"\` and then \`${statusCommand}\` as your last tool call.`,
73
74
  ].join("\n");
74
75
  process.stdout.write(`${JSON.stringify({ followup_message: message })}\n`);
75
76
  return 0;
@@ -84,6 +84,29 @@ export interface AdapterWiringStatus {
84
84
  * with no settings file at all, or an unparseable one, is skipped.
85
85
  */
86
86
  export declare function loadAdapterWiring(projectRoot: string): AdapterWiringStatus[];
87
+ export interface AdapterWiringSummary {
88
+ /** Adapters carrying at least one harnery hook. */
89
+ wired: AdapterId[];
90
+ /**
91
+ * Adapters carrying none: no settings file at all, or a settings file with
92
+ * none of ours in it. An unparseable file lands in neither list, since
93
+ * `loadAdapterWiring` already reports that as drift.
94
+ */
95
+ unwired: AdapterId[];
96
+ }
97
+ /**
98
+ * Classify every known adapter as wired or unwired, without judging whether an
99
+ * unwired one is a problem.
100
+ *
101
+ * `loadAdapterWiring` stays deliberately silent about an adapter with zero
102
+ * harnery hooks, because a bare settings file is not an opt-out signal and
103
+ * nagging about it would false-warn every session. That silence is right in
104
+ * isolation and wrong once you also know the adapter's CLI is installed: then
105
+ * an agent can start a session here and register nothing. Splitting the fact
106
+ * from the judgement lets a caller holding both (doctor) tell "not used here"
107
+ * from "never wired" without changing what counts as drift.
108
+ */
109
+ export declare function summarizeAdapterWiring(projectRoot: string): AdapterWiringSummary;
87
110
  /**
88
111
  * Resolve the harnery package version for context in nudges/checks. Walks up
89
112
  * from this module to the package root (works under Bun from `src/` and Node
@@ -1 +1 @@
1
- {"version":3,"file":"wiring.d.ts","sourceRoot":"","sources":["../../../../src/core/hooks/adapter/wiring.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAKH,OAAO,EAEL,KAAK,SAAS,EACd,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,KAAK,SAAS,EACf,MAAM,aAAa,CAAC;AAErB,mEAAmE;AACnE,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAC5C;AACD,0CAA0C;AAC1C,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AACD,MAAM,MAAM,SAAS,GAAG,eAAe,GAAG,eAAe,CAAC;AAE1D,MAAM,WAAW,YAAY;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;IACpC,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AAED,iDAAiD;AACjD,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,GAAG,SAAS,CAE3E;AAED,0EAA0E;AAC1E,wBAAgB,aAAa,CAAC,KAAK,EAAE,SAAS,GAAG,MAAM,EAAE,CAMxD;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAEnF;AAQD,MAAM,WAAW,UAAU;IACzB,kDAAkD;IAClD,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,iCAAiC;IACjC,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB;;;;OAIG;IACH,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,4EAA4E;IAC5E,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,yEAAyE;IACzE,gBAAgB,EAAE,MAAM,EAAE,CAAC;CAC5B;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,YAAY,EAAE,IAAI,EAAE,WAAW,GAAG,UAAU,CA2ChF;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,SAAS,CAAC;IACnB,wDAAwD;IACxD,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,mBAAmB,EAAE,CAwC5E;AAED;;;;GAIG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAkBvC"}
1
+ {"version":3,"file":"wiring.d.ts","sourceRoot":"","sources":["../../../../src/core/hooks/adapter/wiring.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAKH,OAAO,EAEL,KAAK,SAAS,EACd,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,KAAK,SAAS,EACf,MAAM,aAAa,CAAC;AAErB,mEAAmE;AACnE,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAC5C;AACD,0CAA0C;AAC1C,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AACD,MAAM,MAAM,SAAS,GAAG,eAAe,GAAG,eAAe,CAAC;AAE1D,MAAM,WAAW,YAAY;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;IACpC,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AAED,iDAAiD;AACjD,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,GAAG,SAAS,CAE3E;AAED,0EAA0E;AAC1E,wBAAgB,aAAa,CAAC,KAAK,EAAE,SAAS,GAAG,MAAM,EAAE,CAMxD;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAEnF;AAQD,MAAM,WAAW,UAAU;IACzB,kDAAkD;IAClD,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,iCAAiC;IACjC,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB;;;;OAIG;IACH,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,4EAA4E;IAC5E,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,yEAAyE;IACzE,gBAAgB,EAAE,MAAM,EAAE,CAAC;CAC5B;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,YAAY,EAAE,IAAI,EAAE,WAAW,GAAG,UAAU,CA2ChF;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,SAAS,CAAC;IACnB,wDAAwD;IACxD,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,mBAAmB,EAAE,CAwC5E;AAED,MAAM,WAAW,oBAAoB;IACnC,mDAAmD;IACnD,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB;;;;OAIG;IACH,OAAO,EAAE,SAAS,EAAE,CAAC;CACtB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,MAAM,GAAG,oBAAoB,CAkBhF;AAED;;;;GAIG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAkBvC"}
@@ -136,6 +136,38 @@ export function loadAdapterWiring(projectRoot) {
136
136
  }
137
137
  return out;
138
138
  }
139
+ /**
140
+ * Classify every known adapter as wired or unwired, without judging whether an
141
+ * unwired one is a problem.
142
+ *
143
+ * `loadAdapterWiring` stays deliberately silent about an adapter with zero
144
+ * harnery hooks, because a bare settings file is not an opt-out signal and
145
+ * nagging about it would false-warn every session. That silence is right in
146
+ * isolation and wrong once you also know the adapter's CLI is installed: then
147
+ * an agent can start a session here and register nothing. Splitting the fact
148
+ * from the judgement lets a caller holding both (doctor) tell "not used here"
149
+ * from "never wired" without changing what counts as drift.
150
+ */
151
+ export function summarizeAdapterWiring(projectRoot) {
152
+ const wired = [];
153
+ const unwired = [];
154
+ for (const [id, spec] of Object.entries(ADAPTER_SPECS)) {
155
+ const settingsPath = resolve(projectRoot, spec.settingsFile);
156
+ if (!existsSync(settingsPath)) {
157
+ unwired.push(id);
158
+ continue;
159
+ }
160
+ let settings;
161
+ try {
162
+ settings = JSON.parse(readFileSync(settingsPath, "utf8"));
163
+ }
164
+ catch {
165
+ continue; // unparseable → already surfaced by loadAdapterWiring
166
+ }
167
+ (diffWiring(settings, spec).present.length > 0 ? wired : unwired).push(id);
168
+ }
169
+ return { wired, unwired };
170
+ }
139
171
  /**
140
172
  * Resolve the harnery package version for context in nudges/checks. Walks up
141
173
  * from this module to the package root (works under Bun from `src/` and Node
@@ -1,6 +1,5 @@
1
1
  /**
2
- * `agent-hook` CLI entry point. Phase 2: real canonical-event emission
3
- * alongside the legacy stream.
2
+ * `agent-hook` CLI entry point for canonical event emission.
4
3
  *
5
4
  * Flow:
6
5
  * 1. Parse argv → event-name + adapter.
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../../src/core/hooks/cli.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../../src/core/hooks/cli.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG"}