harnery 0.46.0 → 0.47.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 (187) hide show
  1. package/README.md +24 -0
  2. package/bin/README.md +10 -0
  3. package/bin/agent-coord.mjs +3 -0
  4. package/bin/agent-hook.mjs +3 -0
  5. package/bin/harn.mjs +3 -0
  6. package/bin/run.mjs +43 -0
  7. package/dist/commander.d.ts +18 -6
  8. package/dist/commander.d.ts.map +1 -1
  9. package/dist/commander.js +74 -2
  10. package/dist/commands/agents.d.ts +25 -0
  11. package/dist/commands/agents.d.ts.map +1 -1
  12. package/dist/commands/agents.js +70 -27
  13. package/dist/commands/autoupdate.d.ts +12 -0
  14. package/dist/commands/autoupdate.d.ts.map +1 -0
  15. package/dist/commands/autoupdate.js +190 -0
  16. package/dist/commands/computer.d.ts +45 -0
  17. package/dist/commands/computer.d.ts.map +1 -0
  18. package/dist/commands/computer.js +509 -0
  19. package/dist/commands/docs.js +3 -1
  20. package/dist/commands/fetch.js +11 -1
  21. package/dist/commands/grep.d.ts +72 -0
  22. package/dist/commands/grep.d.ts.map +1 -1
  23. package/dist/commands/grep.js +200 -47
  24. package/dist/commands/init.d.ts.map +1 -1
  25. package/dist/commands/init.js +15 -9
  26. package/dist/commands/rm.js +2 -2
  27. package/dist/commands/web.d.ts.map +1 -1
  28. package/dist/commands/web.js +2 -0
  29. package/dist/core/agents/canonical-emit.d.ts.map +1 -1
  30. package/dist/core/agents/canonical-emit.js +2 -3
  31. package/dist/core/agents/coord-bin.d.ts +3 -0
  32. package/dist/core/agents/coord-bin.d.ts.map +1 -1
  33. package/dist/core/agents/coord-bin.js +6 -0
  34. package/dist/core/agents/coord-client.d.ts.map +1 -1
  35. package/dist/core/agents/coord-client.js +6 -2
  36. package/dist/core/agents/render/prompt-context.d.ts +55 -7
  37. package/dist/core/agents/render/prompt-context.d.ts.map +1 -1
  38. package/dist/core/agents/render/prompt-context.js +122 -48
  39. package/dist/core/agents/rules/claim-conflict.d.ts.map +1 -1
  40. package/dist/core/agents/rules/claim-conflict.js +36 -16
  41. package/dist/core/agents/rules/stop-hook.d.ts +6 -0
  42. package/dist/core/agents/rules/stop-hook.d.ts.map +1 -1
  43. package/dist/core/agents/rules/stop-hook.js +20 -1
  44. package/dist/core/agents/state/proc-start.d.ts +3 -1
  45. package/dist/core/agents/state/proc-start.d.ts.map +1 -1
  46. package/dist/core/agents/state/proc-start.js +26 -4
  47. package/dist/core/autoupdate/engine.d.ts +97 -0
  48. package/dist/core/autoupdate/engine.d.ts.map +1 -0
  49. package/dist/core/autoupdate/engine.js +548 -0
  50. package/dist/core/autoupdate/fingerprint.d.ts +16 -0
  51. package/dist/core/autoupdate/fingerprint.d.ts.map +1 -0
  52. package/dist/core/autoupdate/fingerprint.js +73 -0
  53. package/dist/core/autoupdate/git.d.ts +30 -0
  54. package/dist/core/autoupdate/git.d.ts.map +1 -0
  55. package/dist/core/autoupdate/git.js +82 -0
  56. package/dist/core/autoupdate/index.d.ts +6 -0
  57. package/dist/core/autoupdate/index.d.ts.map +1 -0
  58. package/dist/core/autoupdate/index.js +4 -0
  59. package/dist/core/autoupdate/state.d.ts +59 -0
  60. package/dist/core/autoupdate/state.d.ts.map +1 -0
  61. package/dist/core/autoupdate/state.js +214 -0
  62. package/dist/core/autoupdate/types.d.ts +113 -0
  63. package/dist/core/autoupdate/types.d.ts.map +1 -0
  64. package/dist/core/autoupdate/types.js +35 -0
  65. package/dist/core/config.d.ts +53 -1
  66. package/dist/core/config.d.ts.map +1 -1
  67. package/dist/core/config.js +114 -1
  68. package/dist/core/events/v3/bootstrap.js +1 -0
  69. package/dist/core/events/v3/runtime-build.d.ts.map +1 -1
  70. package/dist/core/events/v3/runtime-build.js +1 -0
  71. package/dist/core/hooks/adapter/wiring.d.ts +12 -2
  72. package/dist/core/hooks/adapter/wiring.d.ts.map +1 -1
  73. package/dist/core/hooks/adapter/wiring.js +38 -8
  74. package/dist/core/hooks/autoupdate-cue.d.ts +29 -0
  75. package/dist/core/hooks/autoupdate-cue.d.ts.map +1 -0
  76. package/dist/core/hooks/autoupdate-cue.js +53 -0
  77. package/dist/core/hooks/cli.js +52 -4
  78. package/dist/core/hooks/effects/index.js +4 -4
  79. package/dist/core/hooks/resolve/coord-root.js +1 -0
  80. package/dist/core/hooks/resolve/transcript.d.ts +12 -0
  81. package/dist/core/hooks/resolve/transcript.d.ts.map +1 -1
  82. package/dist/core/hooks/resolve/transcript.js +54 -0
  83. package/dist/core/semantic/contract.d.ts +3 -3
  84. package/dist/core/semantic/service.d.ts.map +1 -1
  85. package/dist/core/semantic/service.js +4 -2
  86. package/dist/core/storage/modes.d.ts +1 -1
  87. package/dist/core/storage/modes.d.ts.map +1 -1
  88. package/dist/core/storage/modes.js +5 -1
  89. package/dist/core/workflow/durable-record.d.ts +2 -0
  90. package/dist/core/workflow/durable-record.d.ts.map +1 -1
  91. package/dist/core/workflow/durable-record.js +13 -1
  92. package/dist/core/workflow/engine.js +4 -0
  93. package/dist/core/workflow/spawn-claude.d.ts +7 -0
  94. package/dist/core/workflow/spawn-claude.d.ts.map +1 -1
  95. package/dist/core/workflow/spawn-claude.js +16 -4
  96. package/dist/core/workflow/specialists.d.ts.map +1 -1
  97. package/dist/core/workflow/specialists.js +1 -0
  98. package/dist/core/workflow/types.d.ts +10 -0
  99. package/dist/core/workflow/types.d.ts.map +1 -1
  100. package/dist/core/workflow/workspaces/leases.d.ts.map +1 -1
  101. package/dist/core/workflow/workspaces/leases.js +1 -9
  102. package/dist/lib/computer/cua.d.ts +50 -0
  103. package/dist/lib/computer/cua.d.ts.map +1 -0
  104. package/dist/lib/computer/cua.js +474 -0
  105. package/dist/lib/computer/host.d.ts +19 -0
  106. package/dist/lib/computer/host.d.ts.map +1 -0
  107. package/dist/lib/computer/host.js +72 -0
  108. package/dist/lib/computer/lease.d.ts +13 -0
  109. package/dist/lib/computer/lease.d.ts.map +1 -0
  110. package/dist/lib/computer/lease.js +269 -0
  111. package/dist/lib/computer/types.d.ts +163 -0
  112. package/dist/lib/computer/types.d.ts.map +1 -0
  113. package/dist/lib/computer/types.js +10 -0
  114. package/dist/lib/docs-metadata-v2.d.ts.map +1 -1
  115. package/dist/lib/docs-metadata-v2.js +6 -5
  116. package/dist/lib/exec.d.ts.map +1 -1
  117. package/dist/lib/exec.js +1 -0
  118. package/dist/lib/guarded-remove.d.ts.map +1 -1
  119. package/dist/lib/guarded-remove.js +5 -4
  120. package/dist/lib/headless/index.d.ts +33 -0
  121. package/dist/lib/headless/index.d.ts.map +1 -1
  122. package/dist/lib/headless/index.js +38 -2
  123. package/dist/lib/http/client.d.ts +2 -9
  124. package/dist/lib/http/client.d.ts.map +1 -1
  125. package/dist/lib/http/client.js +30 -9
  126. package/dist/lib/instructions/apply.d.ts +9 -0
  127. package/dist/lib/instructions/apply.d.ts.map +1 -1
  128. package/dist/lib/instructions/apply.js +92 -14
  129. package/dist/lib/instructions/git-hooks.d.ts.map +1 -1
  130. package/dist/lib/instructions/git-hooks.js +8 -4
  131. package/dist/lib/instructions/templates.d.ts +11 -0
  132. package/dist/lib/instructions/templates.d.ts.map +1 -1
  133. package/dist/lib/instructions/templates.js +81 -1
  134. package/package.json +5 -5
  135. package/schemas/config.schema.json +89 -1
  136. package/src/commander.ts +98 -8
  137. package/src/commands/agents.ts +100 -32
  138. package/src/commands/autoupdate.ts +250 -0
  139. package/src/commands/computer.ts +682 -0
  140. package/src/commands/docs.ts +3 -1
  141. package/src/commands/fetch.ts +11 -1
  142. package/src/commands/grep.ts +274 -59
  143. package/src/commands/init.ts +17 -7
  144. package/src/commands/rm.ts +2 -2
  145. package/src/commands/web.ts +2 -0
  146. package/src/core/agents/canonical-emit.ts +2 -3
  147. package/src/core/agents/coord-bin.ts +30 -0
  148. package/src/core/agents/coord-client.ts +6 -2
  149. package/src/core/agents/render/prompt-context.ts +152 -53
  150. package/src/core/agents/rules/claim-conflict.ts +50 -18
  151. package/src/core/agents/rules/stop-hook.ts +28 -1
  152. package/src/core/agents/state/proc-start.ts +29 -5
  153. package/src/core/autoupdate/engine.ts +691 -0
  154. package/src/core/autoupdate/fingerprint.ts +89 -0
  155. package/src/core/autoupdate/git.ts +120 -0
  156. package/src/core/autoupdate/index.ts +29 -0
  157. package/src/core/autoupdate/state.ts +269 -0
  158. package/src/core/autoupdate/types.ts +135 -0
  159. package/src/core/config.ts +142 -1
  160. package/src/core/events/v3/bootstrap.ts +1 -0
  161. package/src/core/events/v3/runtime-build.ts +1 -0
  162. package/src/core/hooks/adapter/wiring.ts +51 -6
  163. package/src/core/hooks/autoupdate-cue.ts +72 -0
  164. package/src/core/hooks/cli.ts +54 -1
  165. package/src/core/hooks/effects/index.ts +4 -4
  166. package/src/core/hooks/resolve/coord-root.ts +1 -0
  167. package/src/core/hooks/resolve/transcript.ts +61 -0
  168. package/src/core/semantic/service.ts +6 -2
  169. package/src/core/storage/modes.ts +7 -1
  170. package/src/core/workflow/durable-record.ts +15 -1
  171. package/src/core/workflow/engine.ts +3 -0
  172. package/src/core/workflow/spawn-claude.ts +16 -4
  173. package/src/core/workflow/specialists.ts +1 -0
  174. package/src/core/workflow/types.ts +10 -0
  175. package/src/core/workflow/workspaces/leases.ts +1 -9
  176. package/src/lib/computer/cua.ts +572 -0
  177. package/src/lib/computer/host.ts +87 -0
  178. package/src/lib/computer/lease.ts +299 -0
  179. package/src/lib/computer/types.ts +177 -0
  180. package/src/lib/docs-metadata-v2.ts +24 -5
  181. package/src/lib/exec.ts +1 -0
  182. package/src/lib/guarded-remove.ts +5 -3
  183. package/src/lib/headless/index.ts +66 -2
  184. package/src/lib/http/client.ts +33 -19
  185. package/src/lib/instructions/apply.ts +100 -12
  186. package/src/lib/instructions/git-hooks.ts +8 -4
  187. package/src/lib/instructions/templates.ts +95 -1
@@ -11,7 +11,8 @@
11
11
  * `coord` (heartbeat freshness), `logs` (structured-log storage budgets),
12
12
  * `artifacts` (working-file retention),
13
13
  * `backup` (restic repo/password/prune policy), `sync` (rclone
14
- * remote/prefix), and `web` (dashboard port) sections. The `files` deny/override section
14
+ * remote/prefix), `computer` (opt-in desktop control), `autoUpdate` (activity-fired
15
+ * project self-update), and `web` (dashboard port) sections. The `files` deny/override section
15
16
  * is parsed separately by `web/lib/files.ts`.
16
17
  *
17
18
  * Env vars and CLI flags override any config value per invocation (each accessor
@@ -23,6 +24,7 @@ import { homedir } from "node:os";
23
24
  import { isAbsolute, join, resolve } from "node:path";
24
25
  import { coordEnv } from "../lib/env.js";
25
26
  import { DEFAULT_WEB_PORT } from "../lib/local-file-url.js";
27
+ import { AUTOUPDATE_DEFAULTS } from "./autoupdate/types.js";
26
28
  import { resolveEventLedgerRotateActiveBytesV3 } from "./events/v3/rotation-config.js";
27
29
  import { parsePromptContextConfig, } from "./hooks/prompt-context/contract.js";
28
30
  import { findCoordRoot } from "./hooks/resolve/coord-root.js";
@@ -320,6 +322,17 @@ export function codexWindowsBridgeConfig(projectRoot) {
320
322
  }
321
323
  return { entryPoint, error: null };
322
324
  }
325
+ /**
326
+ * Per-project opt-in that makes `init` write the same adapter hook commands on
327
+ * every OS: `agent-hook` from PATH, plus a native Codex `commandWindows`. A
328
+ * project that commits its settings files and is cloned on Windows and POSIX
329
+ * needs it, because the default form depends on the OS that ran `init`. Read
330
+ * from the project config only, for the same reason as the Windows bridge.
331
+ * Anything but `true` keeps the default.
332
+ */
333
+ export function portableHookCommands(projectRoot) {
334
+ return readProjectConfig(projectRoot).hooks?.portableCommands === true;
335
+ }
323
336
  export function hostPromptReminder(coordRoot) {
324
337
  const root = coordRoot ?? findCoordRoot();
325
338
  if (!root)
@@ -480,6 +493,106 @@ export function readAdmissionConfig(coordRoot) {
480
493
  : {}),
481
494
  };
482
495
  }
496
+ /**
497
+ * Desktop-control settings from `.harnery/config.jsonc`:
498
+ *
499
+ * ```jsonc
500
+ * "computer": { "enabled": true, "idle_seconds": 120, "wait_seconds": 30 }
501
+ * ```
502
+ *
503
+ * Project config only: enabling desktop control is a per-project decision, so a
504
+ * user-global value never turns it on. Malformed values are dropped one by one;
505
+ * `enabled` is true only when the project sets it to exactly `true`.
506
+ */
507
+ export function readComputerConfig(coordRoot) {
508
+ const root = coordRoot ?? findCoordRoot();
509
+ if (!root)
510
+ return { enabled: false };
511
+ const raw = readProjectConfig(root).computer;
512
+ if (!raw || typeof raw !== "object" || Array.isArray(raw))
513
+ return { enabled: false };
514
+ const record = raw;
515
+ const idle = positiveNumber(record.idle_seconds, 86_400);
516
+ const wait = record.wait_seconds;
517
+ const waitOk = typeof wait === "number" && Number.isFinite(wait) && wait >= 0 && wait <= 3600;
518
+ return {
519
+ enabled: record.enabled === true,
520
+ ...(idle !== undefined ? { idle_seconds: idle } : {}),
521
+ ...(waitOk ? { wait_seconds: wait } : {}),
522
+ };
523
+ }
524
+ // Project-only parse cache keyed by the file's stat signature. Hooks call the
525
+ // auto-update reader on every prompt, so an unchanged file costs one stat.
526
+ let projectCache = null;
527
+ function readProjectConfigCached(root) {
528
+ const p = join(root, ".harnery", "config.jsonc");
529
+ const signature = statSignature(p);
530
+ if (signature === null)
531
+ return {};
532
+ if (projectCache && projectCache.path === p && projectCache.signature === signature) {
533
+ return projectCache.cfg;
534
+ }
535
+ const cfg = parseConfigFile(p);
536
+ projectCache = { path: p, signature, cfg };
537
+ return cfg;
538
+ }
539
+ function clampInteger(value, min, max, fallback) {
540
+ if (typeof value !== "number" || !Number.isFinite(value))
541
+ return fallback;
542
+ return Math.min(max, Math.max(min, Math.round(value)));
543
+ }
544
+ /** Keep each argv that is a non-empty array of non-empty strings; drop the rest. */
545
+ function argvList(value) {
546
+ if (!Array.isArray(value))
547
+ return [];
548
+ const out = [];
549
+ for (const entry of value) {
550
+ if (!Array.isArray(entry) || entry.length === 0)
551
+ continue;
552
+ if (!entry.every((part) => typeof part === "string" && part.length > 0))
553
+ continue;
554
+ out.push([...entry]);
555
+ }
556
+ return out;
557
+ }
558
+ /**
559
+ * Project self-update settings from `.harnery/config.jsonc` (ADR 0229):
560
+ *
561
+ * ```jsonc
562
+ * "autoUpdate": {
563
+ * "enabled": true,
564
+ * "steps": [["bin/pull-all"]],
565
+ * "dailySteps": [["bin/doctor", "--quiet"]],
566
+ * "watch": ["~/.local/share/example/hooks.json"],
567
+ * "checkMinutes": 15,
568
+ * "timeoutMinutes": 20,
569
+ * "cleanup": true
570
+ * }
571
+ * ```
572
+ *
573
+ * Project config only: running commands on activity is a per-project
574
+ * decision, so a user-global value never turns it on. Null when the project
575
+ * has no `autoUpdate` section. Malformed values are dropped one by one;
576
+ * `enabled` is true only when the project sets it to exactly `true`.
577
+ */
578
+ export function readAutoUpdateConfig(coordRoot) {
579
+ const raw = readProjectConfigCached(coordRoot).autoUpdate;
580
+ if (!raw || typeof raw !== "object" || Array.isArray(raw))
581
+ return null;
582
+ const record = raw;
583
+ const watch = Array.isArray(record.watch)
584
+ ? record.watch.filter((p) => typeof p === "string" && p.trim().length > 0)
585
+ : [];
586
+ return {
587
+ enabled: record.enabled === true,
588
+ checkMinutes: clampInteger(record.checkMinutes, 1, 1440, AUTOUPDATE_DEFAULTS.checkMinutes),
589
+ steps: argvList(record.steps),
590
+ dailySteps: argvList(record.dailySteps),
591
+ watch,
592
+ timeoutMinutes: clampInteger(record.timeoutMinutes, 1, 240, AUTOUPDATE_DEFAULTS.timeoutMinutes),
593
+ cleanup: record.cleanup !== false,
594
+ };
595
+ }
483
596
  /**
484
597
  * Whether this repo pins workflow runs to subscription billing:
485
598
  * `.harnery/config.jsonc` `{ "workflow": { "subscriptionOnly": true } }`.
@@ -443,6 +443,7 @@ function rootOfHarnery() {
443
443
  }
444
444
  function repositoryBuild(root) {
445
445
  const result = spawnSync("git", ["-C", root, "rev-parse", "HEAD"], {
446
+ windowsHide: true,
446
447
  encoding: "utf8",
447
448
  timeout: 5000,
448
449
  });
@@ -1 +1 @@
1
- {"version":3,"file":"runtime-build.d.ts","sourceRoot":"","sources":["../../../../src/core/events/v3/runtime-build.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAE3E;;;;;;GAMG;AACH,wBAAgB,0BAA0B,IAAI,MAAM,CAuBnD;AAED,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,qFAAqF;AACrF,wBAAgB,qBAAqB,IAAI,YAAY,CAkBpD;AAED,MAAM,WAAW,kBAAkB;IACjC,aAAa,EAAE,YAAY,GAAG,IAAI,CAAC;IACnC,eAAe,EAAE,YAAY,CAAC;IAC9B,cAAc,EAAE,OAAO,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,4EAA4E;AAC5E,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,OAAO,GAAG,kBAAkB,CA0BxE"}
1
+ {"version":3,"file":"runtime-build.d.ts","sourceRoot":"","sources":["../../../../src/core/events/v3/runtime-build.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAE3E;;;;;;GAMG;AACH,wBAAgB,0BAA0B,IAAI,MAAM,CAwBnD;AAED,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,qFAAqF;AACrF,wBAAgB,qBAAqB,IAAI,YAAY,CAkBpD;AAED,MAAM,WAAW,kBAAkB;IACjC,aAAa,EAAE,YAAY,GAAG,IAAI,CAAC;IACnC,eAAe,EAAE,YAAY,CAAC;IAC9B,cAAc,EAAE,OAAO,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,4EAA4E;AAC5E,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,OAAO,GAAG,kBAAkB,CA0BxE"}
@@ -14,6 +14,7 @@ export function currentHarneryRuntimeBuild() {
14
14
  const root = harneryPackageRoot();
15
15
  if (existsSync(resolve(root, ".git"))) {
16
16
  const result = spawnSync("git", ["-C", root, "rev-parse", "HEAD"], {
17
+ windowsHide: true,
17
18
  encoding: "utf8",
18
19
  timeout: 5_000,
19
20
  });
@@ -65,7 +65,17 @@ export declare function hookCommandWindows(spec: AdapterSpec, agentHookPath: str
65
65
  export interface WiringOptions {
66
66
  /** Bridge entry point from `hooks.codexWindowsBridge`, or null when not opted in. */
67
67
  windowsBridgeEntryPoint?: string | null;
68
+ /**
69
+ * `hooks.portableCommands`: write the same `agent-hook` commands from PATH on
70
+ * every OS, plus a native Codex `commandWindows`, so one committed settings
71
+ * file is current everywhere.
72
+ */
73
+ portableCommands?: boolean;
74
+ /** The OS to write for. Defaults to the host; tests inject it. */
75
+ platform?: NodeJS.Platform;
68
76
  }
77
+ /** The wiring options a project's committed config selects. */
78
+ export declare function projectWiringOptions(projectRoot: string): WiringOptions;
69
79
  /** The `commandWindows` init writes for one event, or undefined for none. */
70
80
  export declare function expectedCommandWindows(spec: AdapterSpec, agentHookPath: string, subcommand: string, adapter: AdapterId, options?: WiringOptions): string | undefined;
71
81
  /** The `timeout` init writes on one event's Harnery hook, or undefined for none. */
@@ -83,14 +93,14 @@ export declare function commandWiresSubcommand(command: string, subcommand: stri
83
93
  /** Whether a command invokes Harnery's agent-hook binary at all. */
84
94
  export declare function isAgentHookCommand(command: string): boolean;
85
95
  /** The canonical command installed for one adapter event. */
86
- export declare function hookCommand(spec: AdapterSpec, agentHookPath: string, subcommand: string, adapter: AdapterId): string;
96
+ export declare function hookCommand(spec: AdapterSpec, agentHookPath: string, subcommand: string, adapter: AdapterId, options?: WiringOptions): string;
87
97
  /**
88
98
  * Pick a committed hook target that survives cloning the consumer elsewhere.
89
99
  * Projects that contain Harnery can use its repo-relative launcher. Standalone
90
100
  * consumers use the package's installed `agent-hook` executable from PATH
91
101
  * instead of recording a relative path back into one developer's package tree.
92
102
  */
93
- export declare function agentHookPathForProject(projectRoot: string, packageRoot: string): string;
103
+ export declare function agentHookPathForProject(projectRoot: string, packageRoot: string, options?: WiringOptions): string;
94
104
  export interface WiringDiff {
95
105
  /** Spec events not wired in the settings file. */
96
106
  missing: HookEvent[];
@@ -1 +1 @@
1
- {"version":3,"file":"wiring.d.ts","sourceRoot":"","sources":["../../../../src/core/hooks/adapter/wiring.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"wiring.d.ts","sourceRoot":"","sources":["../../../../src/core/hooks/adapter/wiring.ts"],"names":[],"mappings":"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"}
@@ -13,7 +13,7 @@
13
13
  import { existsSync, readFileSync } from "node:fs";
14
14
  import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
15
15
  import { fileURLToPath } from "node:url";
16
- import { codexWindowsBridgeConfig, resolveBinName } from "../../config.js";
16
+ import { codexWindowsBridgeConfig, portableHookCommands, resolveBinName } from "../../config.js";
17
17
  import { ADAPTER_SPECS, } from "./events.js";
18
18
  import { checkOpenCodePlugin, isOwnedOpenCodePlugin } from "./opencode-plugin.js";
19
19
  /** Bound Cursor Stop `followup_message` retries so a missed ritual cannot loop 5 times. */
@@ -63,10 +63,22 @@ export function hookCommandWindows(spec, agentHookPath, subcommand, adapter, ent
63
63
  return (`if ((Get-Command ${entryPoint} -ErrorAction Ignore) -and $PWD.ProviderPath -like '\\\\wsl*') ` +
64
64
  `{ ${entryPoint} ${subcommand} --adapter ${adapter} } else { ${direct} }; exit $LASTEXITCODE`);
65
65
  }
66
+ /** The wiring options a project's committed config selects. */
67
+ export function projectWiringOptions(projectRoot) {
68
+ return {
69
+ windowsBridgeEntryPoint: codexWindowsBridgeConfig(projectRoot).entryPoint,
70
+ portableCommands: portableHookCommands(projectRoot),
71
+ };
72
+ }
66
73
  /** The `commandWindows` init writes for one event, or undefined for none. */
67
74
  export function expectedCommandWindows(spec, agentHookPath, subcommand, adapter, options) {
68
- if (!spec.windowsBridgeHooks || !options?.windowsBridgeEntryPoint)
75
+ if (!spec.windowsBridgeHooks)
69
76
  return undefined;
77
+ if (!options?.windowsBridgeEntryPoint) {
78
+ return (options?.platform ?? process.platform) === "win32" || options?.portableCommands
79
+ ? nativeHookCommand(agentHookPath, subcommand, adapter)
80
+ : undefined;
81
+ }
70
82
  return hookCommandWindows(spec, agentHookPath, subcommand, adapter, options.windowsBridgeEntryPoint);
71
83
  }
72
84
  /** The `timeout` init writes on one event's Harnery hook, or undefined for none. */
@@ -114,20 +126,35 @@ export function isAgentHookCommand(command) {
114
126
  return commandSubcommand(command) !== null;
115
127
  }
116
128
  /** The canonical command installed for one adapter event. */
117
- export function hookCommand(spec, agentHookPath, subcommand, adapter) {
129
+ export function hookCommand(spec, agentHookPath, subcommand, adapter, options) {
130
+ if ((options?.platform ?? process.platform) === "win32") {
131
+ return nativeHookCommand(agentHookPath, subcommand, adapter);
132
+ }
118
133
  if (agentHookPath === "agent-hook") {
119
134
  return `agent-hook ${subcommand} --adapter ${adapter}`;
120
135
  }
121
136
  const anchor = spec.projectDirEnv ? `"\${${spec.projectDirEnv}:-.}"/` : "";
122
137
  return `bash ${anchor}${agentHookPath} ${subcommand} --adapter ${adapter}`;
123
138
  }
139
+ function nativeHookCommand(agentHookPath, subcommand, adapter) {
140
+ if (agentHookPath === "agent-hook")
141
+ return `agent-hook ${subcommand} --adapter ${adapter}`;
142
+ const runner = join(dirname(agentHookPath), "run.mjs").replaceAll("\\", "/");
143
+ return `node "${runner}" agent-hook ${subcommand} --adapter ${adapter}`;
144
+ }
124
145
  /**
125
146
  * Pick a committed hook target that survives cloning the consumer elsewhere.
126
147
  * Projects that contain Harnery can use its repo-relative launcher. Standalone
127
148
  * consumers use the package's installed `agent-hook` executable from PATH
128
149
  * instead of recording a relative path back into one developer's package tree.
129
150
  */
130
- export function agentHookPathForProject(projectRoot, packageRoot) {
151
+ export function agentHookPathForProject(projectRoot, packageRoot, options) {
152
+ // Native npm shims run the linked source checkout without Bash, and do not
153
+ // depend on a hook's working directory after an agent changes directories.
154
+ // A project that commits one settings file for every OS asks for the same.
155
+ if ((options?.platform ?? process.platform) === "win32" || options?.portableCommands) {
156
+ return "agent-hook";
157
+ }
131
158
  const hook = join(packageRoot, "bin", "agent-hook");
132
159
  const candidate = relative(projectRoot, hook);
133
160
  if (candidate === ".." || candidate.startsWith(`..${sep}`) || isAbsolute(candidate)) {
@@ -155,7 +182,7 @@ export function diffWiring(settings, spec, expected) {
155
182
  if (commands.length > 1)
156
183
  duplicates.push(event);
157
184
  if (expected && commands.length > 0) {
158
- const canonical = hookCommand(spec, expected.agentHookPath, event.subcommand, expected.adapter);
185
+ const canonical = hookCommand(spec, expected.agentHookPath, event.subcommand, expected.adapter, expected);
159
186
  const timeout = hookTimeoutFor(spec, event.subcommand);
160
187
  const commandWindows = expectedCommandWindows(spec, expected.agentHookPath, event.subcommand, expected.adapter, expected);
161
188
  const handlerDrift = groups.some((group) => "hooks" in group &&
@@ -232,7 +259,9 @@ function pluginDrift(projectRoot, id, spec) {
232
259
  const packageRoot = harneryPackageRoot();
233
260
  const check = checkOpenCodePlugin(projectRoot, {
234
261
  binName: resolveBinName(projectRoot),
235
- agentHook: packageRoot ? agentHookPathForProject(projectRoot, packageRoot) : "agent-hook",
262
+ agentHook: packageRoot
263
+ ? agentHookPathForProject(projectRoot, packageRoot, projectWiringOptions(projectRoot))
264
+ : "agent-hook",
236
265
  });
237
266
  if (check.status === "fresh")
238
267
  return null;
@@ -275,11 +304,12 @@ export function loadAdapterWiring(projectRoot) {
275
304
  continue;
276
305
  }
277
306
  const packageRoot = harneryPackageRoot();
307
+ const options = projectWiringOptions(projectRoot);
278
308
  const diff = diffWiring(settings, spec, packageRoot
279
309
  ? {
280
- agentHookPath: agentHookPathForProject(projectRoot, packageRoot),
310
+ agentHookPath: agentHookPathForProject(projectRoot, packageRoot, options),
281
311
  adapter: id,
282
- windowsBridgeEntryPoint: codexWindowsBridgeConfig(projectRoot).entryPoint,
312
+ ...options,
283
313
  }
284
314
  : undefined);
285
315
  if (diff.present.length === 0)
@@ -0,0 +1,29 @@
1
+ import type { AutoUpdateNotice, TickResult } from "../autoupdate/types.js";
2
+ /** Prefix on every self-update line injected into an agent's context. */
3
+ export declare const AUTOUPDATE_CUE_PREFIX = "Auto-update: ";
4
+ export interface AutoUpdateCueDeps {
5
+ tick: (coordRoot: string) => TickResult;
6
+ pendingNotices: (coordRoot: string, sessionKey: string) => AutoUpdateNotice[];
7
+ }
8
+ export interface AutoUpdateCueOptions {
9
+ /**
10
+ * Whether this hook will show context to the agent. When false, the tick
11
+ * still runs but notices stay queued for a session that can read them.
12
+ */
13
+ deliver?: boolean;
14
+ /** Test seam; production loads the engine lazily. */
15
+ deps?: AutoUpdateCueDeps;
16
+ /** Receives tick or delivery failures. The cue itself never throws. */
17
+ onError?: (err: unknown, phase: "autoupdate-tick" | "autoupdate-notices") => void;
18
+ }
19
+ /**
20
+ * Fire the activity-driven self-update check (ADR 0229) and collect the
21
+ * notices this session has not seen yet, one context line each.
22
+ *
23
+ * Projects without an `autoUpdate` section pay one config stat and never load
24
+ * the engine. With the section, the tick's hot path is one stamp stat; any
25
+ * real work runs in a detached child, so the hook never waits on it. Fails
26
+ * open: an error is reported through `onError` and the cue is empty.
27
+ */
28
+ export declare function autoUpdateHookContext(coordRoot: string, sessionKey: string, options?: AutoUpdateCueOptions): Promise<string>;
29
+ //# sourceMappingURL=autoupdate-cue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"autoupdate-cue.d.ts","sourceRoot":"","sources":["../../../src/core/hooks/autoupdate-cue.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAG3E,yEAAyE;AACzE,eAAO,MAAM,qBAAqB,kBAAkB,CAAC;AAErD,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,UAAU,CAAC;IACxC,cAAc,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,gBAAgB,EAAE,CAAC;CAC/E;AAED,MAAM,WAAW,oBAAoB;IACnC;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,qDAAqD;IACrD,IAAI,CAAC,EAAE,iBAAiB,CAAC;IACzB,uEAAuE;IACvE,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,iBAAiB,GAAG,oBAAoB,KAAK,IAAI,CAAC;CACnF;AAUD;;;;;;;;GAQG;AACH,wBAAsB,qBAAqB,CACzC,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,MAAM,CAAC,CA0BjB"}
@@ -0,0 +1,53 @@
1
+ import { coordEnv } from "../../lib/env.js";
2
+ import { readAutoUpdateConfig } from "../config.js";
3
+ /** Prefix on every self-update line injected into an agent's context. */
4
+ export const AUTOUPDATE_CUE_PREFIX = "Auto-update: ";
5
+ async function loadDeps() {
6
+ const engine = await import("../autoupdate/index.js");
7
+ return {
8
+ tick: (root) => engine.autoUpdateTick(root),
9
+ pendingNotices: (root, key) => engine.pendingNotices(root, key),
10
+ };
11
+ }
12
+ /**
13
+ * Fire the activity-driven self-update check (ADR 0229) and collect the
14
+ * notices this session has not seen yet, one context line each.
15
+ *
16
+ * Projects without an `autoUpdate` section pay one config stat and never load
17
+ * the engine. With the section, the tick's hot path is one stamp stat; any
18
+ * real work runs in a detached child, so the hook never waits on it. Fails
19
+ * open: an error is reported through `onError` and the cue is empty.
20
+ */
21
+ export async function autoUpdateHookContext(coordRoot, sessionKey, options = {}) {
22
+ if (coordEnv("AUTOUPDATE_CHILD") === "1")
23
+ return "";
24
+ let deps;
25
+ try {
26
+ if (!readAutoUpdateConfig(coordRoot))
27
+ return "";
28
+ deps = options.deps ?? (await loadDeps());
29
+ }
30
+ catch (err) {
31
+ options.onError?.(err, "autoupdate-tick");
32
+ return "";
33
+ }
34
+ try {
35
+ deps.tick(coordRoot);
36
+ }
37
+ catch (err) {
38
+ options.onError?.(err, "autoupdate-tick");
39
+ }
40
+ if (options.deliver === false || !sessionKey)
41
+ return "";
42
+ try {
43
+ return deps
44
+ .pendingNotices(coordRoot, sessionKey)
45
+ .map((notice) => `${AUTOUPDATE_CUE_PREFIX}${notice.text.trim()}`)
46
+ .filter((line) => line.length > AUTOUPDATE_CUE_PREFIX.length)
47
+ .join("\n");
48
+ }
49
+ catch (err) {
50
+ options.onError?.(err, "autoupdate-notices");
51
+ return "";
52
+ }
53
+ }
@@ -46,6 +46,7 @@ import { detectAdapter, shouldSkipHookAdapter } from "./adapter/detect.js";
46
46
  import { ADAPTER_SPECS } from "./adapter/events.js";
47
47
  import { extractBashCommand, extractToolDescription, normalizeEventName, parsePayload, } from "./adapter/parse.js";
48
48
  import { hookTimeoutFor } from "./adapter/wiring.js";
49
+ import { autoUpdateHookContext } from "./autoupdate-cue.js";
49
50
  import { scheduleBackupSnapshot } from "./backup-schedule.js";
50
51
  import { captureImages, detectPresence, imageJanitor, journalArchive, journalJanitor, journalRecoveryCue, playSound, recordImageArtifactsV3, resetSoundCounters, runSessionSyncExtension, soundForEvent, } from "./effects/index.js";
51
52
  import { toolInputHash, toolTargetHash } from "./events/input-hash.js";
@@ -55,7 +56,7 @@ import { beginHookHealth, observeHookDebug, observeHookError, writeHookHealthCom
55
56
  import { adapterPidFromEnv, parsePsChainLine, selectAnchorPid } from "./resolve/anchor.js";
56
57
  import { extractIntentComment, resolveIntent } from "./resolve/intent.js";
57
58
  import { resolveOwner } from "./resolve/owner.js";
58
- import { inspectSessionNameDisplayImmediately, scanAssistantStatusBoxPresent, scanStatusBoxPresent, scanTranscriptRuntime, } from "./resolve/transcript.js";
59
+ import { inspectSessionNameDisplayImmediately, scanAssistantStatusBoxPresent, scanPendingBackgroundHandoffs, scanStatusBoxPresent, scanTranscriptRuntime, } from "./resolve/transcript.js";
59
60
  import { clearHookRunMarker, writeHookRunMarker } from "./run-markers.js";
60
61
  import { sessionNamePresence } from "./session-name-presence.js";
61
62
  import { shellCommitTreeReason } from "./shell-commit-tree.js";
@@ -1050,6 +1051,13 @@ async function handleSessionStarted(run) {
1050
1051
  catch (err) {
1051
1052
  logError(coordRoot, err, { phase: "backup-schedule" });
1052
1053
  }
1054
+ // Project self-update (ADR 0229) fires on activity. The tick costs one stat
1055
+ // when fresh and otherwise launches a detached child; queued notices for
1056
+ // this session ride the same context as the backup cue.
1057
+ const autoUpdateCue = await autoUpdateHookContext(coordRoot, owner.instance_id, {
1058
+ deliver: coordEnv("WORKFLOW_CHILD") !== "1",
1059
+ onError: (err, phase) => logError(coordRoot, err, { phase }),
1060
+ });
1053
1061
  // Storage maintenance can walk large stores. It runs in a detached worker so
1054
1062
  // session start emits its context without waiting for it; an adapter that
1055
1063
  // stops a slow hook would otherwise drop that context entirely.
@@ -1072,7 +1080,7 @@ async function handleSessionStarted(run) {
1072
1080
  }
1073
1081
  }
1074
1082
  try {
1075
- const injected = await emitSessionStartSystemMessage(coordRoot, owner.instance_id, sessionId, data, adapter, recovery?.briefing ?? "", backupCue);
1083
+ const injected = await emitSessionStartSystemMessage(coordRoot, owner.instance_id, sessionId, data, adapter, recovery?.briefing ?? "", [backupCue, autoUpdateCue].filter(Boolean).join("\n\n"));
1076
1084
  if (injected && recovery) {
1077
1085
  completeRecoveryInjection(coordRoot, owner.instance_id, sessionId, recovery);
1078
1086
  }
@@ -1196,8 +1204,13 @@ async function handleTurnStarted(run) {
1196
1204
  logError(coordRoot, err, { phase: "prompt-context-user-prompt" });
1197
1205
  }
1198
1206
  }
1207
+ // Project self-update (ADR 0229): see handleSessionStarted.
1208
+ const autoUpdateCue = await autoUpdateHookContext(coordRoot, owner.instance_id, {
1209
+ deliver: coordEnv("WORKFLOW_CHILD") !== "1",
1210
+ onError: (err, phase) => logError(coordRoot, err, { phase }),
1211
+ });
1199
1212
  try {
1200
- const injected = await emitUserPromptSubmitSystemMessage(coordRoot, owner.instance_id, sessionId, adapter, payload?.cwd, recovery?.briefing ?? "", hostPromptContext);
1213
+ const injected = await emitUserPromptSubmitSystemMessage(coordRoot, owner.instance_id, sessionId, adapter, payload?.cwd, recovery?.briefing ?? "", hostPromptContext, autoUpdateCue);
1201
1214
  if (injected && recovery) {
1202
1215
  completeRecoveryInjection(coordRoot, owner.instance_id, sessionId, recovery);
1203
1216
  }
@@ -1222,6 +1235,14 @@ async function handleStop(run) {
1222
1235
  catch (err) {
1223
1236
  logError(coordRoot, err, { phase: "stop-presence" });
1224
1237
  }
1238
+ // Claude Code may move a running foreground command (often the agent's own
1239
+ // commit and push) into the background to deliver a user message. Until it
1240
+ // reports back, finalization cannot pass, so the verdict defers the status
1241
+ // demands instead of bouncing the agent in a loop.
1242
+ const pendingBackgroundHandoffs = adapter === "claude-code"
1243
+ ? scanPendingBackgroundHandoffs(payload?.transcript_path ??
1244
+ behavior.discoverTranscript?.(payload?.session_id ?? sessionId))
1245
+ : [];
1225
1246
  // Stop verdict (V3 ritual + task/status gate). Direct in-process call: the
1226
1247
  // rule lives in Harnery. agent-hook already emitted this turn.completed
1227
1248
  // with privacy-safe ritual observations, so the evidence is in the stream.
@@ -1235,8 +1256,25 @@ async function handleStop(run) {
1235
1256
  session_name_observation_unavailable: typeof data.session_name_unavailable_reason === "string",
1236
1257
  bypass: coordEnv("AGENT_COORD_BYPASS_STOP") === "1",
1237
1258
  workflow_child: coordEnv("WORKFLOW_CHILD") === "1",
1259
+ pending_background_handoff: pendingBackgroundHandoffs.length > 0,
1238
1260
  });
1261
+ if (verdict.rule === "stop-hook.background_handoff_deferred") {
1262
+ appendDebug(coordRoot, {
1263
+ ...debugBase,
1264
+ effect: "stop-deferred-background-handoff",
1265
+ background_task_ids: pendingBackgroundHandoffs,
1266
+ });
1267
+ }
1239
1268
  if (!verdict.allow) {
1269
+ // Re-arm the prompt-time ritual reminder; it is otherwise shown only on a
1270
+ // session's first prompt so the per-prompt context stays small.
1271
+ try {
1272
+ const { markTurnRitualBounced } = await import("../agents/render/prompt-context.js");
1273
+ markTurnRitualBounced(coordRoot, owner.instance_id);
1274
+ }
1275
+ catch (err) {
1276
+ logError(coordRoot, err, { phase: "stop-ritual-rearm" });
1277
+ }
1240
1278
  // Backstop for sessions whose evidence can never land (e.g. a headless
1241
1279
  // child whose status command resolves to a different owner): after
1242
1280
  // `cap` consecutive blocked stops in one cycle, allow the stop instead
@@ -1270,6 +1308,13 @@ async function handleStop(run) {
1270
1308
  // until the adapter has committed turn.completed above. Reconcile only
1271
1309
  // when such a request exists; any later real work cancels it in the
1272
1310
  // finalizer instead of being terminated underneath the agent.
1311
+ // A deferred stop proves nothing about finalization; an explicit end must
1312
+ // wait for the turn that reports the background task's result.
1313
+ if (verdict.rule === "stop-hook.background_handoff_deferred") {
1314
+ if (behavior.runtimeContextRetry)
1315
+ scheduleRuntimeContextRetry(coordRoot, adapter, sessionId);
1316
+ return undefined;
1317
+ }
1273
1318
  try {
1274
1319
  const { hasPendingExplicitSessionEndV3, reconcileSessionFinalizationV3 } = await import("../agents/session-finalizer-v3.js");
1275
1320
  if (hasPendingExplicitSessionEndV3(coordRoot)) {
@@ -2035,7 +2080,7 @@ function cleanupSessionEnd(coordRoot, instanceId) {
2035
2080
  }
2036
2081
  }
2037
2082
  }
2038
- async function emitUserPromptSubmitSystemMessage(coordRoot, instanceId, sessionId, adapter, workspaceCwd, recoveryBriefing = "", hostPromptContext = "") {
2083
+ async function emitUserPromptSubmitSystemMessage(coordRoot, instanceId, sessionId, adapter, workspaceCwd, recoveryBriefing = "", hostPromptContext = "", autoUpdateCue = "") {
2039
2084
  // Workflow children get no prompt-time coordination context, matching
2040
2085
  // SessionStart. The turn ritual is not enforced for them, the naming nudge
2041
2086
  // would register them as named peers, and rendering drains peer mail.
@@ -2064,6 +2109,9 @@ async function emitUserPromptSubmitSystemMessage(coordRoot, instanceId, sessionI
2064
2109
  if (hostPromptContext) {
2065
2110
  additionalContext = [additionalContext, hostPromptContext].filter(Boolean).join("\n\n");
2066
2111
  }
2112
+ if (autoUpdateCue) {
2113
+ additionalContext = [additionalContext, autoUpdateCue].filter(Boolean).join("\n\n");
2114
+ }
2067
2115
  if (!additionalContext)
2068
2116
  return false;
2069
2117
  const { emitContext } = await import("./adapter/output.js");
@@ -16,7 +16,7 @@ import { existsSync, readdirSync, rmSync } from "node:fs";
16
16
  import os from "node:os";
17
17
  import { join } from "node:path";
18
18
  import { applyDetection } from "../../../lib/presence.js";
19
- import { coordBinPath } from "../../agents/coord-bin.js";
19
+ import { coordBinPath, spawnCoordBinSync } from "../../agents/coord-bin.js";
20
20
  export { captureImages, imageJanitor, recordImageArtifactsV3 } from "./image-capture.js";
21
21
  /**
22
22
  * Play a notification sound via the cross-platform utility
@@ -62,7 +62,7 @@ export function journalJanitor(repoRoot) {
62
62
  const bin = harnBin(repoRoot);
63
63
  if (!bin)
64
64
  return;
65
- spawnSync("bash", [bin, "journal", "janitor", "--quiet"], {
65
+ spawnCoordBinSync(bin, ["journal", "janitor", "--quiet"], {
66
66
  env: { ...process.env, HARNERY_OUTPUT_SESSION_TEE: "0" },
67
67
  timeout: 5000,
68
68
  stdio: "ignore",
@@ -82,7 +82,7 @@ export function journalRecoveryCue(repoRoot) {
82
82
  const bin = harnBin(repoRoot);
83
83
  if (!bin)
84
84
  return "";
85
- const r = spawnSync("bash", [bin, "journal", "recovery-cue"], {
85
+ const r = spawnCoordBinSync(bin, ["journal", "recovery-cue"], {
86
86
  env: { ...process.env, HARNERY_OUTPUT_SESSION_TEE: "0" },
87
87
  timeout: 5000,
88
88
  encoding: "utf8",
@@ -99,7 +99,7 @@ export function journalArchive(repoRoot, owner) {
99
99
  const bin = harnBin(repoRoot);
100
100
  if (!bin || !owner)
101
101
  return;
102
- spawnSync("bash", [bin, "journal", "archive", "--owner", owner], {
102
+ spawnCoordBinSync(bin, ["journal", "archive", "--owner", owner], {
103
103
  env: { ...process.env, HARNERY_OUTPUT_SESSION_TEE: "0" },
104
104
  timeout: 5000,
105
105
  stdio: "ignore",
@@ -90,6 +90,7 @@ function gitRevParse(start, flag) {
90
90
  // A stale adapter project directory may no longer exist. Treat spawn
91
91
  // failure as no path evidence instead of turning discovery into an error.
92
92
  const result = spawnSync("git", ["rev-parse", flag], {
93
+ windowsHide: true,
93
94
  cwd: start,
94
95
  encoding: "utf8",
95
96
  });
@@ -33,6 +33,18 @@ export declare function scanAssistantTextIncludes(transcriptPath: string | undef
33
33
  * from the adapter's completed assistant response.
34
34
  */
35
35
  export declare function scanAssistantStatusBoxPresent(transcriptPath: string | undefined, lastAssistantMessage: string | undefined): boolean;
36
+ /** A handoff older than this no longer defers Stop, so a lost notification cannot disable the ritual. */
37
+ export declare const BACKGROUND_HANDOFF_MAX_AGE_MS: number;
38
+ /**
39
+ * Claude Code background tasks it moved off the foreground on its own (to
40
+ * deliver a mid-command user message) that have not yet posted a
41
+ * `<task-notification>`. Only the structured `toolUseResult` fields written by
42
+ * Claude Code open a handoff; the agent cannot forge them through tool output.
43
+ * Any later notification text naming the task closes it, so a spoofed
44
+ * notification can only make Stop stricter. A command the agent chose to
45
+ * background (`run_in_background`) or a Monitor opens nothing.
46
+ */
47
+ export declare function scanPendingBackgroundHandoffs(transcriptPath: string | undefined, nowMs?: number): string[];
36
48
  /** Most recent user-visible assistant text across Claude Code and Codex JSONL. */
37
49
  export declare function scanLatestAssistantText(transcriptPath: string | undefined): string | undefined;
38
50
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"transcript.d.ts","sourceRoot":"","sources":["../../../../src/core/hooks/resolve/transcript.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,2BAA2B,wBAAc,CAAC;AAEvD;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAAC,cAAc,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAQhF;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,yBAAyB,CACvC,cAAc,EAAE,MAAM,GAAG,SAAS,EAClC,MAAM,EAAE,MAAM,GACb,OAAO,CAiCT;AAED;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAC3C,cAAc,EAAE,MAAM,GAAG,SAAS,EAClC,oBAAoB,EAAE,MAAM,GAAG,SAAS,GACvC,OAAO,CAKT;AAED,kFAAkF;AAClF,wBAAgB,uBAAuB,CAAC,cAAc,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAgB9F;AAED;;;;;GAKG;AACH,wBAAgB,mCAAmC,CACjD,cAAc,EAAE,MAAM,GAAG,SAAS,EAClC,IAAI,EAAE,MAAM,EACZ,eAAe,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,KAAK,OAAO,GAC/D,OAAO,CAIT;AAED,MAAM,MAAM,4BAA4B,GACpC;IAAE,KAAK,EAAE,SAAS,CAAA;CAAE,GACpB;IAAE,KAAK,EAAE,QAAQ,CAAA;CAAE,GACnB;IACE,KAAK,EAAE,aAAa,CAAC;IACrB,MAAM,EAAE,oBAAoB,GAAG,sBAAsB,GAAG,wBAAwB,CAAC;CAClF,CAAC;AAEN;;;;;GAKG;AACH,wBAAgB,oCAAoC,CAClD,cAAc,EAAE,MAAM,GAAG,SAAS,EAClC,IAAI,EAAE,MAAM,EACZ,eAAe,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,KAAK,OAAO,GAC/D,4BAA4B,CAqD9B;AAgBD;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,cAAc,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,EAAE,CAUrF;AAwDD;4CAC4C;AAC5C,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,MAAM,CAAC;IACd;+EAC2E;IAC3E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iEAAiE;IACjE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,qBAAqB,CACnC,cAAc,EAAE,MAAM,GAAG,SAAS,GACjC,qBAAqB,GAAG,SAAS,CA8BnC;AAgBD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,4BAA4B,CAC1C,cAAc,EAAE,MAAM,GAAG,SAAS,EAClC,SAAS,EAAE,MAAM,GAChB,MAAM,GAAG,SAAS,CAiBpB;AA6CD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,gBAAgB,CAC9B,cAAc,EAAE,MAAM,GAAG,SAAS,EAClC,SAAS,EAAE,MAAM,GAChB,MAAM,GAAG,SAAS,CAkDpB"}
1
+ {"version":3,"file":"transcript.d.ts","sourceRoot":"","sources":["../../../../src/core/hooks/resolve/transcript.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,2BAA2B,wBAAc,CAAC;AAEvD;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAAC,cAAc,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAQhF;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,yBAAyB,CACvC,cAAc,EAAE,MAAM,GAAG,SAAS,EAClC,MAAM,EAAE,MAAM,GACb,OAAO,CAiCT;AAED;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAC3C,cAAc,EAAE,MAAM,GAAG,SAAS,EAClC,oBAAoB,EAAE,MAAM,GAAG,SAAS,GACvC,OAAO,CAKT;AAED,yGAAyG;AACzG,eAAO,MAAM,6BAA6B,QAAiB,CAAC;AAQ5D;;;;;;;;GAQG;AACH,wBAAgB,6BAA6B,CAC3C,cAAc,EAAE,MAAM,GAAG,SAAS,EAClC,KAAK,GAAE,MAAmB,GACzB,MAAM,EAAE,CAsCV;AAED,kFAAkF;AAClF,wBAAgB,uBAAuB,CAAC,cAAc,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAgB9F;AAED;;;;;GAKG;AACH,wBAAgB,mCAAmC,CACjD,cAAc,EAAE,MAAM,GAAG,SAAS,EAClC,IAAI,EAAE,MAAM,EACZ,eAAe,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,KAAK,OAAO,GAC/D,OAAO,CAIT;AAED,MAAM,MAAM,4BAA4B,GACpC;IAAE,KAAK,EAAE,SAAS,CAAA;CAAE,GACpB;IAAE,KAAK,EAAE,QAAQ,CAAA;CAAE,GACnB;IACE,KAAK,EAAE,aAAa,CAAC;IACrB,MAAM,EAAE,oBAAoB,GAAG,sBAAsB,GAAG,wBAAwB,CAAC;CAClF,CAAC;AAEN;;;;;GAKG;AACH,wBAAgB,oCAAoC,CAClD,cAAc,EAAE,MAAM,GAAG,SAAS,EAClC,IAAI,EAAE,MAAM,EACZ,eAAe,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,KAAK,OAAO,GAC/D,4BAA4B,CAqD9B;AAgBD;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,cAAc,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,EAAE,CAUrF;AAwDD;4CAC4C;AAC5C,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,MAAM,CAAC;IACd;+EAC2E;IAC3E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iEAAiE;IACjE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,qBAAqB,CACnC,cAAc,EAAE,MAAM,GAAG,SAAS,GACjC,qBAAqB,GAAG,SAAS,CA8BnC;AAgBD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,4BAA4B,CAC1C,cAAc,EAAE,MAAM,GAAG,SAAS,EAClC,SAAS,EAAE,MAAM,GAChB,MAAM,GAAG,SAAS,CAiBpB;AA6CD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,gBAAgB,CAC9B,cAAc,EAAE,MAAM,GAAG,SAAS,EAClC,SAAS,EAAE,MAAM,GAChB,MAAM,GAAG,SAAS,CAkDpB"}