harnery 0.46.1 → 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/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 +28 -3
- package/dist/core/hooks/effects/index.js +4 -4
- package/dist/core/hooks/resolve/coord-root.js +1 -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/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 +27 -1
- package/src/core/hooks/effects/index.ts +4 -4
- package/src/core/hooks/resolve/coord-root.ts +1 -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";
|
|
@@ -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
|
}
|
|
@@ -1253,6 +1266,15 @@ async function handleStop(run) {
|
|
|
1253
1266
|
});
|
|
1254
1267
|
}
|
|
1255
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
|
+
}
|
|
1256
1278
|
// Backstop for sessions whose evidence can never land (e.g. a headless
|
|
1257
1279
|
// child whose status command resolves to a different owner): after
|
|
1258
1280
|
// `cap` consecutive blocked stops in one cycle, allow the stop instead
|
|
@@ -2058,7 +2080,7 @@ function cleanupSessionEnd(coordRoot, instanceId) {
|
|
|
2058
2080
|
}
|
|
2059
2081
|
}
|
|
2060
2082
|
}
|
|
2061
|
-
async function emitUserPromptSubmitSystemMessage(coordRoot, instanceId, sessionId, adapter, workspaceCwd, recoveryBriefing = "", hostPromptContext = "") {
|
|
2083
|
+
async function emitUserPromptSubmitSystemMessage(coordRoot, instanceId, sessionId, adapter, workspaceCwd, recoveryBriefing = "", hostPromptContext = "", autoUpdateCue = "") {
|
|
2062
2084
|
// Workflow children get no prompt-time coordination context, matching
|
|
2063
2085
|
// SessionStart. The turn ritual is not enforced for them, the naming nudge
|
|
2064
2086
|
// would register them as named peers, and rendering drains peer mail.
|
|
@@ -2087,6 +2109,9 @@ async function emitUserPromptSubmitSystemMessage(coordRoot, instanceId, sessionI
|
|
|
2087
2109
|
if (hostPromptContext) {
|
|
2088
2110
|
additionalContext = [additionalContext, hostPromptContext].filter(Boolean).join("\n\n");
|
|
2089
2111
|
}
|
|
2112
|
+
if (autoUpdateCue) {
|
|
2113
|
+
additionalContext = [additionalContext, autoUpdateCue].filter(Boolean).join("\n\n");
|
|
2114
|
+
}
|
|
2090
2115
|
if (!additionalContext)
|
|
2091
2116
|
return false;
|
|
2092
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
|
});
|
|
@@ -152,7 +152,7 @@ export declare const SemanticUsageReceiptV1Schema: import("@sinclair/typebox").T
|
|
|
152
152
|
scope: import("@sinclair/typebox").TLiteral<"unreported">;
|
|
153
153
|
}>]>;
|
|
154
154
|
export declare const SemanticEvidenceObservationV1Schema: import("@sinclair/typebox").TObject<{
|
|
155
|
-
kind: import("@sinclair/typebox").TUnion<import("@sinclair/typebox").TLiteral<"
|
|
155
|
+
kind: import("@sinclair/typebox").TUnion<import("@sinclair/typebox").TLiteral<"error" | "recovery" | "artifact" | "operation" | "action" | "terminal" | "task" | "progress" | "intent" | "wait" | "lifecycle" | "claim-conflict">[]>;
|
|
156
156
|
event_id: import("@sinclair/typebox").TString;
|
|
157
157
|
observed_at: import("@sinclair/typebox").TString;
|
|
158
158
|
label: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
@@ -193,7 +193,7 @@ export declare const SemanticEvidenceV1Schema: import("@sinclair/typebox").TObje
|
|
|
193
193
|
started_at: import("@sinclair/typebox").TString;
|
|
194
194
|
}>>;
|
|
195
195
|
recent: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
|
|
196
|
-
kind: import("@sinclair/typebox").TUnion<import("@sinclair/typebox").TLiteral<"
|
|
196
|
+
kind: import("@sinclair/typebox").TUnion<import("@sinclair/typebox").TLiteral<"error" | "recovery" | "artifact" | "operation" | "action" | "terminal" | "task" | "progress" | "intent" | "wait" | "lifecycle" | "claim-conflict">[]>;
|
|
197
197
|
event_id: import("@sinclair/typebox").TString;
|
|
198
198
|
observed_at: import("@sinclair/typebox").TString;
|
|
199
199
|
label: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
@@ -201,7 +201,7 @@ export declare const SemanticEvidenceV1Schema: import("@sinclair/typebox").TObje
|
|
|
201
201
|
error_class: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
202
202
|
}>>;
|
|
203
203
|
attention: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
|
|
204
|
-
kind: import("@sinclair/typebox").TUnion<import("@sinclair/typebox").TLiteral<"
|
|
204
|
+
kind: import("@sinclair/typebox").TUnion<import("@sinclair/typebox").TLiteral<"error" | "recovery" | "artifact" | "operation" | "action" | "terminal" | "task" | "progress" | "intent" | "wait" | "lifecycle" | "claim-conflict">[]>;
|
|
205
205
|
event_id: import("@sinclair/typebox").TString;
|
|
206
206
|
observed_at: import("@sinclair/typebox").TString;
|
|
207
207
|
label: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/core/semantic/service.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/core/semantic/service.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,6 +3,7 @@ import { randomBytes, randomUUID } from "node:crypto";
|
|
|
3
3
|
import { appendFileSync, chmodSync, closeSync, existsSync, mkdirSync, openSync, readFileSync, renameSync, rmSync, statSync, unlinkSync, watch, writeFileSync, } from "node:fs";
|
|
4
4
|
import { hostname } from "node:os";
|
|
5
5
|
import { dirname, join, resolve } from "node:path";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
6
7
|
import { coordEnv } from "../../lib/env.js";
|
|
7
8
|
import { readEventV3ControlState, readLedgerV3Since, } from "../events/v3/index.js";
|
|
8
9
|
import { eventV3ActiveWatchPath } from "../events/v3/reader.js";
|
|
@@ -53,7 +54,7 @@ export async function spawnSemanticService(coordRootRaw, options = {}) {
|
|
|
53
54
|
const logFd = sharedLogs ? undefined : openSync(paths.log, "a", stateFileMode());
|
|
54
55
|
if (logFd !== undefined)
|
|
55
56
|
chmodSync(paths.log, stateFileMode());
|
|
56
|
-
const harnBin = new URL("
|
|
57
|
+
const harnBin = fileURLToPath(new URL(import.meta.url.endsWith(".ts") ? "../../cli.ts" : "../../cli.js", import.meta.url));
|
|
57
58
|
if (!existsSync(harnBin)) {
|
|
58
59
|
if (logFd !== undefined)
|
|
59
60
|
closeSync(logFd);
|
|
@@ -64,7 +65,8 @@ export async function spawnSemanticService(coordRootRaw, options = {}) {
|
|
|
64
65
|
args.push("--calls-per-hour", String(options.callsPerHour));
|
|
65
66
|
}
|
|
66
67
|
let spawnError;
|
|
67
|
-
const child = spawn(harnBin, args, {
|
|
68
|
+
const child = spawn(process.execPath, [harnBin, ...args], {
|
|
69
|
+
windowsHide: true,
|
|
68
70
|
cwd: coordRoot,
|
|
69
71
|
detached: true,
|
|
70
72
|
stdio: logFd === undefined ? ["ignore", "ignore", "ignore"] : ["ignore", logFd, logFd],
|
|
@@ -17,5 +17,5 @@ export declare function stateFileMode(): number;
|
|
|
17
17
|
* True when a state file or directory is readable or writable by someone it should not be: anyone
|
|
18
18
|
* but the owner in private mode, anyone outside the owner and group in group mode.
|
|
19
19
|
*/
|
|
20
|
-
export declare function stateModeTooOpen(mode: number): boolean;
|
|
20
|
+
export declare function stateModeTooOpen(mode: number, platform?: NodeJS.Platform): boolean;
|
|
21
21
|
//# sourceMappingURL=modes.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"modes.d.ts","sourceRoot":"","sources":["../../../src/core/storage/modes.ts"],"names":[],"mappings":"AAgBA,mGAAmG;AACnG,wBAAgB,YAAY,IAAI,SAAS,GAAG,OAAO,CASlD;AAED,iGAAiG;AACjG,eAAO,MAAM,iBAAiB,MAAQ,CAAC;AAEvC,yFAAyF;AACzF,eAAO,MAAM,kBAAkB,MAAQ,CAAC;AAExC,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C;AAED;;;;GAIG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED,wCAAwC;AACxC,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,
|
|
1
|
+
{"version":3,"file":"modes.d.ts","sourceRoot":"","sources":["../../../src/core/storage/modes.ts"],"names":[],"mappings":"AAgBA,mGAAmG;AACnG,wBAAgB,YAAY,IAAI,SAAS,GAAG,OAAO,CASlD;AAED,iGAAiG;AACjG,eAAO,MAAM,iBAAiB,MAAQ,CAAC;AAEvC,yFAAyF;AACzF,eAAO,MAAM,kBAAkB,MAAQ,CAAC;AAExC,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C;AAED;;;;GAIG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED,wCAAwC;AACxC,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,EACZ,QAAQ,GAAE,MAAM,CAAC,QAA2B,GAC3C,OAAO,CAKT"}
|
|
@@ -46,6 +46,10 @@ export function stateFileMode() {
|
|
|
46
46
|
* True when a state file or directory is readable or writable by someone it should not be: anyone
|
|
47
47
|
* but the owner in private mode, anyone outside the owner and group in group mode.
|
|
48
48
|
*/
|
|
49
|
-
export function stateModeTooOpen(mode) {
|
|
49
|
+
export function stateModeTooOpen(mode, platform = process.platform) {
|
|
50
|
+
// Windows synthesizes POSIX mode bits; access is controlled by inherited
|
|
51
|
+
// NTFS ACLs, which chmod and stat.mode cannot inspect or tighten.
|
|
52
|
+
if (platform === "win32")
|
|
53
|
+
return false;
|
|
50
54
|
return (mode & (stateSharing() === "group" ? 0o007 : 0o077)) !== 0;
|
|
51
55
|
}
|