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.
- package/README.md +24 -0
- package/bin/README.md +10 -0
- package/bin/agent-coord.mjs +3 -0
- package/bin/agent-hook.mjs +3 -0
- package/bin/harn.mjs +3 -0
- package/bin/run.mjs +43 -0
- package/dist/commander.d.ts +18 -6
- package/dist/commander.d.ts.map +1 -1
- package/dist/commander.js +74 -2
- package/dist/commands/agents.d.ts +25 -0
- package/dist/commands/agents.d.ts.map +1 -1
- package/dist/commands/agents.js +70 -27
- package/dist/commands/autoupdate.d.ts +12 -0
- package/dist/commands/autoupdate.d.ts.map +1 -0
- package/dist/commands/autoupdate.js +190 -0
- package/dist/commands/computer.d.ts +45 -0
- package/dist/commands/computer.d.ts.map +1 -0
- package/dist/commands/computer.js +509 -0
- package/dist/commands/docs.js +3 -1
- package/dist/commands/fetch.js +11 -1
- package/dist/commands/grep.d.ts +72 -0
- package/dist/commands/grep.d.ts.map +1 -1
- package/dist/commands/grep.js +200 -47
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +15 -9
- package/dist/commands/rm.js +2 -2
- package/dist/commands/web.d.ts.map +1 -1
- package/dist/commands/web.js +2 -0
- package/dist/core/agents/canonical-emit.d.ts.map +1 -1
- package/dist/core/agents/canonical-emit.js +2 -3
- package/dist/core/agents/coord-bin.d.ts +3 -0
- package/dist/core/agents/coord-bin.d.ts.map +1 -1
- package/dist/core/agents/coord-bin.js +6 -0
- package/dist/core/agents/coord-client.d.ts.map +1 -1
- package/dist/core/agents/coord-client.js +6 -2
- package/dist/core/agents/render/prompt-context.d.ts +55 -7
- package/dist/core/agents/render/prompt-context.d.ts.map +1 -1
- package/dist/core/agents/render/prompt-context.js +122 -48
- package/dist/core/agents/rules/claim-conflict.d.ts.map +1 -1
- package/dist/core/agents/rules/claim-conflict.js +36 -16
- package/dist/core/agents/rules/stop-hook.d.ts +6 -0
- package/dist/core/agents/rules/stop-hook.d.ts.map +1 -1
- package/dist/core/agents/rules/stop-hook.js +20 -1
- package/dist/core/agents/state/proc-start.d.ts +3 -1
- package/dist/core/agents/state/proc-start.d.ts.map +1 -1
- package/dist/core/agents/state/proc-start.js +26 -4
- package/dist/core/autoupdate/engine.d.ts +97 -0
- package/dist/core/autoupdate/engine.d.ts.map +1 -0
- package/dist/core/autoupdate/engine.js +548 -0
- package/dist/core/autoupdate/fingerprint.d.ts +16 -0
- package/dist/core/autoupdate/fingerprint.d.ts.map +1 -0
- package/dist/core/autoupdate/fingerprint.js +73 -0
- package/dist/core/autoupdate/git.d.ts +30 -0
- package/dist/core/autoupdate/git.d.ts.map +1 -0
- package/dist/core/autoupdate/git.js +82 -0
- package/dist/core/autoupdate/index.d.ts +6 -0
- package/dist/core/autoupdate/index.d.ts.map +1 -0
- package/dist/core/autoupdate/index.js +4 -0
- package/dist/core/autoupdate/state.d.ts +59 -0
- package/dist/core/autoupdate/state.d.ts.map +1 -0
- package/dist/core/autoupdate/state.js +214 -0
- package/dist/core/autoupdate/types.d.ts +113 -0
- package/dist/core/autoupdate/types.d.ts.map +1 -0
- package/dist/core/autoupdate/types.js +35 -0
- package/dist/core/config.d.ts +53 -1
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +114 -1
- package/dist/core/events/v3/bootstrap.js +1 -0
- package/dist/core/events/v3/runtime-build.d.ts.map +1 -1
- package/dist/core/events/v3/runtime-build.js +1 -0
- package/dist/core/hooks/adapter/wiring.d.ts +12 -2
- package/dist/core/hooks/adapter/wiring.d.ts.map +1 -1
- package/dist/core/hooks/adapter/wiring.js +38 -8
- package/dist/core/hooks/autoupdate-cue.d.ts +29 -0
- package/dist/core/hooks/autoupdate-cue.d.ts.map +1 -0
- package/dist/core/hooks/autoupdate-cue.js +53 -0
- package/dist/core/hooks/cli.js +52 -4
- package/dist/core/hooks/effects/index.js +4 -4
- package/dist/core/hooks/resolve/coord-root.js +1 -0
- package/dist/core/hooks/resolve/transcript.d.ts +12 -0
- package/dist/core/hooks/resolve/transcript.d.ts.map +1 -1
- package/dist/core/hooks/resolve/transcript.js +54 -0
- package/dist/core/semantic/contract.d.ts +3 -3
- package/dist/core/semantic/service.d.ts.map +1 -1
- package/dist/core/semantic/service.js +4 -2
- package/dist/core/storage/modes.d.ts +1 -1
- package/dist/core/storage/modes.d.ts.map +1 -1
- package/dist/core/storage/modes.js +5 -1
- package/dist/core/workflow/durable-record.d.ts +2 -0
- package/dist/core/workflow/durable-record.d.ts.map +1 -1
- package/dist/core/workflow/durable-record.js +13 -1
- package/dist/core/workflow/engine.js +4 -0
- package/dist/core/workflow/spawn-claude.d.ts +7 -0
- package/dist/core/workflow/spawn-claude.d.ts.map +1 -1
- package/dist/core/workflow/spawn-claude.js +16 -4
- package/dist/core/workflow/specialists.d.ts.map +1 -1
- package/dist/core/workflow/specialists.js +1 -0
- package/dist/core/workflow/types.d.ts +10 -0
- package/dist/core/workflow/types.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/leases.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/leases.js +1 -9
- package/dist/lib/computer/cua.d.ts +50 -0
- package/dist/lib/computer/cua.d.ts.map +1 -0
- package/dist/lib/computer/cua.js +474 -0
- package/dist/lib/computer/host.d.ts +19 -0
- package/dist/lib/computer/host.d.ts.map +1 -0
- package/dist/lib/computer/host.js +72 -0
- package/dist/lib/computer/lease.d.ts +13 -0
- package/dist/lib/computer/lease.d.ts.map +1 -0
- package/dist/lib/computer/lease.js +269 -0
- package/dist/lib/computer/types.d.ts +163 -0
- package/dist/lib/computer/types.d.ts.map +1 -0
- package/dist/lib/computer/types.js +10 -0
- package/dist/lib/docs-metadata-v2.d.ts.map +1 -1
- package/dist/lib/docs-metadata-v2.js +6 -5
- package/dist/lib/exec.d.ts.map +1 -1
- package/dist/lib/exec.js +1 -0
- package/dist/lib/guarded-remove.d.ts.map +1 -1
- package/dist/lib/guarded-remove.js +5 -4
- package/dist/lib/headless/index.d.ts +33 -0
- package/dist/lib/headless/index.d.ts.map +1 -1
- package/dist/lib/headless/index.js +38 -2
- package/dist/lib/http/client.d.ts +2 -9
- package/dist/lib/http/client.d.ts.map +1 -1
- package/dist/lib/http/client.js +30 -9
- package/dist/lib/instructions/apply.d.ts +9 -0
- package/dist/lib/instructions/apply.d.ts.map +1 -1
- package/dist/lib/instructions/apply.js +92 -14
- package/dist/lib/instructions/git-hooks.d.ts.map +1 -1
- package/dist/lib/instructions/git-hooks.js +8 -4
- package/dist/lib/instructions/templates.d.ts +11 -0
- package/dist/lib/instructions/templates.d.ts.map +1 -1
- package/dist/lib/instructions/templates.js +81 -1
- package/package.json +5 -5
- package/schemas/config.schema.json +89 -1
- package/src/commander.ts +98 -8
- package/src/commands/agents.ts +100 -32
- package/src/commands/autoupdate.ts +250 -0
- package/src/commands/computer.ts +682 -0
- package/src/commands/docs.ts +3 -1
- package/src/commands/fetch.ts +11 -1
- package/src/commands/grep.ts +274 -59
- package/src/commands/init.ts +17 -7
- package/src/commands/rm.ts +2 -2
- package/src/commands/web.ts +2 -0
- package/src/core/agents/canonical-emit.ts +2 -3
- package/src/core/agents/coord-bin.ts +30 -0
- package/src/core/agents/coord-client.ts +6 -2
- package/src/core/agents/render/prompt-context.ts +152 -53
- package/src/core/agents/rules/claim-conflict.ts +50 -18
- package/src/core/agents/rules/stop-hook.ts +28 -1
- package/src/core/agents/state/proc-start.ts +29 -5
- package/src/core/autoupdate/engine.ts +691 -0
- package/src/core/autoupdate/fingerprint.ts +89 -0
- package/src/core/autoupdate/git.ts +120 -0
- package/src/core/autoupdate/index.ts +29 -0
- package/src/core/autoupdate/state.ts +269 -0
- package/src/core/autoupdate/types.ts +135 -0
- package/src/core/config.ts +142 -1
- package/src/core/events/v3/bootstrap.ts +1 -0
- package/src/core/events/v3/runtime-build.ts +1 -0
- package/src/core/hooks/adapter/wiring.ts +51 -6
- package/src/core/hooks/autoupdate-cue.ts +72 -0
- package/src/core/hooks/cli.ts +54 -1
- package/src/core/hooks/effects/index.ts +4 -4
- package/src/core/hooks/resolve/coord-root.ts +1 -0
- package/src/core/hooks/resolve/transcript.ts +61 -0
- package/src/core/semantic/service.ts +6 -2
- package/src/core/storage/modes.ts +7 -1
- package/src/core/workflow/durable-record.ts +15 -1
- package/src/core/workflow/engine.ts +3 -0
- package/src/core/workflow/spawn-claude.ts +16 -4
- package/src/core/workflow/specialists.ts +1 -0
- package/src/core/workflow/types.ts +10 -0
- package/src/core/workflow/workspaces/leases.ts +1 -9
- package/src/lib/computer/cua.ts +572 -0
- package/src/lib/computer/host.ts +87 -0
- package/src/lib/computer/lease.ts +299 -0
- package/src/lib/computer/types.ts +177 -0
- package/src/lib/docs-metadata-v2.ts +24 -5
- package/src/lib/exec.ts +1 -0
- package/src/lib/guarded-remove.ts +5 -3
- package/src/lib/headless/index.ts +66 -2
- package/src/lib/http/client.ts +33 -19
- package/src/lib/instructions/apply.ts +100 -12
- package/src/lib/instructions/git-hooks.ts +8 -4
- package/src/lib/instructions/templates.ts +95 -1
package/dist/core/config.js
CHANGED
|
@@ -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),
|
|
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 } }`.
|
|
@@ -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,
|
|
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":"AAAA;;;;;;;;;;;GAWG;AAMH,OAAO,EAEL,KAAK,SAAS,EACd,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,KAAK,SAAS,EACf,MAAM,aAAa,CAAC;AAGrB,gDAAgD;AAChD,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,kDAAkD;IAClD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,8FAA8F;AAC9F,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,iBAAiB,EAAE,CAAC;CAC5B;AACD,0CAA0C;AAC1C,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,2EAA2E;IAC3E,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AACD,MAAM,MAAM,SAAS,GAAG,eAAe,GAAG,eAAe,CAAC;AAE1D,2FAA2F;AAC3F,eAAO,MAAM,+BAA+B,IAAI,CAAC;AAEjD,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,CACvB,KAAK,EAAE,cAAc,EACrB,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,CAAA;CAAE,GAC1E,SAAS,CAgBX;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,iBAAiB,GAAG,iBAAiB,CAS9E;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,WAAW,EACjB,aAAa,EAAE,MAAM,EACrB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,SAAS,EAClB,UAAU,EAAE,MAAM,GACjB,MAAM,CAMR;AAED,0DAA0D;AAC1D,MAAM,WAAW,aAAa;IAC5B,qFAAqF;IACrF,uBAAuB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
+
}
|
package/dist/core/hooks/cli.js
CHANGED
|
@@ -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
|
-
|
|
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 =
|
|
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
|
-
|
|
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"}
|