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