harnery 0.45.2 → 0.46.1
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 +13 -0
- package/dist/commander.d.ts.map +1 -1
- package/dist/commands/admission.d.ts.map +1 -1
- package/dist/commands/admission.js +214 -27
- package/dist/commands/agents.d.ts +4 -0
- package/dist/commands/agents.d.ts.map +1 -1
- package/dist/commands/agents.js +102 -25
- package/dist/commands/browse.d.ts +3 -0
- package/dist/commands/browse.d.ts.map +1 -1
- package/dist/commands/browse.js +172 -8
- package/dist/commands/fetch.js +1 -0
- package/dist/commands/ledger-v3.d.ts.map +1 -1
- package/dist/commands/ledger-v3.js +8 -2
- package/dist/commands/presence.d.ts.map +1 -1
- package/dist/commands/presence.js +40 -0
- package/dist/commands/qa-run.d.ts.map +1 -1
- package/dist/commands/qa-run.js +4 -3
- package/dist/commands/review-pack.d.ts.map +1 -1
- package/dist/commands/review-pack.js +33 -6
- package/dist/core/agents/index.d.ts +1 -0
- package/dist/core/agents/index.d.ts.map +1 -1
- package/dist/core/agents/index.js +1 -0
- package/dist/core/agents/live-authority-v3.d.ts.map +1 -1
- package/dist/core/agents/live-authority-v3.js +11 -4
- package/dist/core/agents/render/session-context.d.ts +0 -6
- package/dist/core/agents/render/session-context.d.ts.map +1 -1
- package/dist/core/agents/render/session-context.js +1 -6
- 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/session-events.d.ts.map +1 -1
- package/dist/core/agents/session-events.js +12 -4
- package/dist/core/agents/state/heartbeat-reader.d.ts +3 -0
- package/dist/core/agents/state/heartbeat-reader.d.ts.map +1 -1
- package/dist/core/agents/state/live-coordination-view.d.ts +3 -1
- package/dist/core/agents/state/live-coordination-view.d.ts.map +1 -1
- package/dist/core/agents/state/live-coordination-view.js +6 -2
- package/dist/core/agents/state/parent-reference-contract.d.ts +16 -0
- package/dist/core/agents/state/parent-reference-contract.d.ts.map +1 -0
- package/dist/core/agents/state/parent-reference-contract.js +1 -0
- package/dist/core/agents/state/parent-reference.d.ts +18 -0
- package/dist/core/agents/state/parent-reference.d.ts.map +1 -0
- package/dist/core/agents/state/parent-reference.js +119 -0
- package/dist/core/config.d.ts +39 -0
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +63 -0
- package/dist/core/diagnostics/path-identity.d.ts +1 -1
- package/dist/core/diagnostics/path-identity.d.ts.map +1 -1
- package/dist/core/diagnostics/path-identity.js +51 -6
- package/dist/core/events/v3/canonical.js +43 -14
- package/dist/core/events/v3/index.d.ts +1 -1
- package/dist/core/events/v3/index.d.ts.map +1 -1
- package/dist/core/events/v3/index.js +1 -1
- package/dist/core/events/v3/producers/recorder.d.ts +34 -0
- package/dist/core/events/v3/producers/recorder.d.ts.map +1 -1
- package/dist/core/events/v3/producers/recorder.js +117 -13
- package/dist/core/events/v3/reader.d.ts.map +1 -1
- package/dist/core/events/v3/reader.js +53 -13
- package/dist/core/events/v3/validate.d.ts.map +1 -1
- package/dist/core/events/v3/validate.js +36 -1
- package/dist/core/hooks/adapter/native-parent.d.ts +23 -0
- package/dist/core/hooks/adapter/native-parent.d.ts.map +1 -0
- package/dist/core/hooks/adapter/native-parent.js +91 -0
- package/dist/core/hooks/cli.js +103 -5
- package/dist/core/hooks/resolve/owner.d.ts +0 -11
- package/dist/core/hooks/resolve/owner.d.ts.map +1 -1
- package/dist/core/hooks/resolve/owner.js +0 -23
- 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/hooks/shell-admission.d.ts +84 -0
- package/dist/core/hooks/shell-admission.d.ts.map +1 -0
- package/dist/core/hooks/shell-admission.js +622 -0
- package/dist/core/hooks/shell-commit-tree.d.ts +2 -0
- package/dist/core/hooks/shell-commit-tree.d.ts.map +1 -0
- package/dist/core/hooks/shell-commit-tree.js +104 -0
- package/dist/core/inbox/contract.d.ts +12 -0
- package/dist/core/inbox/contract.d.ts.map +1 -1
- package/dist/core/inbox/contract.js +16 -0
- package/dist/core/inbox/peer-messages.d.ts +41 -16
- package/dist/core/inbox/peer-messages.d.ts.map +1 -1
- package/dist/core/inbox/peer-messages.js +372 -15
- package/dist/core/inbox/service.d.ts +8 -1
- package/dist/core/inbox/service.d.ts.map +1 -1
- package/dist/core/inbox/service.js +83 -3
- package/dist/core/inbox/targets.d.ts +17 -3
- package/dist/core/inbox/targets.d.ts.map +1 -1
- package/dist/core/inbox/targets.js +77 -2
- package/dist/core/presence/git.d.ts +18 -12
- package/dist/core/presence/git.d.ts.map +1 -1
- package/dist/core/presence/git.js +32 -38
- package/dist/core/presence/index.d.ts +2 -2
- package/dist/core/presence/index.d.ts.map +1 -1
- package/dist/core/presence/index.js +8 -6
- package/dist/core/presence/mail.d.ts +133 -0
- package/dist/core/presence/mail.d.ts.map +1 -0
- package/dist/core/presence/mail.js +464 -0
- package/dist/core/semantic/contract.d.ts +5 -5
- package/dist/core/storage/modes.d.ts +4 -0
- package/dist/core/storage/modes.d.ts.map +1 -1
- package/dist/core/storage/modes.js +4 -0
- package/dist/core/storage/segments.d.ts.map +1 -1
- package/dist/core/storage/segments.js +5 -4
- package/dist/lib/admission-history.d.ts +96 -0
- package/dist/lib/admission-history.d.ts.map +1 -0
- package/dist/lib/admission-history.js +196 -0
- package/dist/lib/admission.d.ts +56 -7
- package/dist/lib/admission.d.ts.map +1 -1
- package/dist/lib/admission.js +161 -19
- package/dist/lib/browser/client.d.ts +18 -0
- package/dist/lib/browser/client.d.ts.map +1 -1
- package/dist/lib/browser/client.js +100 -12
- package/dist/lib/browser/content-checks.d.ts +3 -1
- package/dist/lib/browser/content-checks.d.ts.map +1 -1
- package/dist/lib/browser/content-checks.js +10 -2
- package/dist/lib/browser/critique.d.ts +32 -0
- package/dist/lib/browser/critique.d.ts.map +1 -1
- package/dist/lib/browser/critique.js +72 -3
- package/dist/lib/browser/geometry.d.ts +2 -0
- package/dist/lib/browser/geometry.d.ts.map +1 -1
- package/dist/lib/browser/geometry.js +61 -15
- package/dist/lib/browser/index.d.ts +1 -1
- package/dist/lib/browser/index.d.ts.map +1 -1
- package/dist/lib/browser/index.js +1 -1
- package/dist/lib/browser/page-review-contracts.d.ts +6 -1
- package/dist/lib/browser/page-review-contracts.d.ts.map +1 -1
- package/dist/lib/browser/page-review-contracts.js +6 -1
- package/dist/lib/browser/page-review-judge.d.ts +3 -1
- package/dist/lib/browser/page-review-judge.d.ts.map +1 -1
- package/dist/lib/browser/page-review-judge.js +41 -11
- package/dist/lib/browser/page-review-pack.d.ts +3 -0
- package/dist/lib/browser/page-review-pack.d.ts.map +1 -1
- package/dist/lib/browser/page-review-pack.js +5 -2
- package/dist/lib/browser/qa-run-contracts.d.ts +11 -0
- package/dist/lib/browser/qa-run-contracts.d.ts.map +1 -1
- package/dist/lib/browser/qa-run-contracts.js +11 -4
- package/dist/lib/browser/qa-run.d.ts.map +1 -1
- package/dist/lib/browser/qa-run.js +73 -16
- package/dist/lib/browser/runts.d.ts +4 -2
- package/dist/lib/browser/runts.d.ts.map +1 -1
- package/dist/lib/browser/runts.js +84 -33
- package/dist/lib/browser/windows-chrome.d.ts +14 -0
- package/dist/lib/browser/windows-chrome.d.ts.map +1 -1
- package/dist/lib/browser/windows-chrome.js +42 -0
- package/dist/lib/browser/windows-login-sync.d.ts +110 -0
- package/dist/lib/browser/windows-login-sync.d.ts.map +1 -0
- package/dist/lib/browser/windows-login-sync.js +171 -0
- package/dist/lib/cookies/client.d.ts +30 -5
- package/dist/lib/cookies/client.d.ts.map +1 -1
- package/dist/lib/cookies/client.js +55 -10
- package/dist/lib/cookies/index.d.ts +1 -1
- package/dist/lib/cookies/index.d.ts.map +1 -1
- package/dist/lib/cookies/index.js +1 -1
- package/dist/lib/docs-metadata-sync.d.ts.map +1 -1
- package/dist/lib/docs-metadata-sync.js +41 -2
- package/dist/lib/durable-job.d.ts +8 -0
- package/dist/lib/durable-job.d.ts.map +1 -1
- package/dist/lib/durable-job.js +10 -0
- package/dist/lib/http/client.d.ts +9 -8
- package/dist/lib/http/client.d.ts.map +1 -1
- package/dist/lib/http/client.js +44 -2
- package/dist/lib/instructions/templates.js +4 -4
- package/package.json +2 -2
- package/src/commander.ts +13 -0
- package/src/commands/admission.ts +272 -29
- package/src/commands/agents.ts +132 -27
- package/src/commands/browse.ts +208 -6
- package/src/commands/fetch.ts +1 -0
- package/src/commands/ledger-v3.ts +8 -2
- package/src/commands/presence.ts +49 -0
- package/src/commands/qa-run.ts +4 -3
- package/src/commands/review-pack.ts +41 -5
- package/src/core/agents/index.ts +6 -0
- package/src/core/agents/live-authority-v3.ts +11 -4
- package/src/core/agents/render/session-context.ts +1 -7
- package/src/core/agents/rules/claim-conflict.ts +50 -18
- package/src/core/agents/rules/stop-hook.ts +28 -1
- package/src/core/agents/session-events.ts +18 -3
- package/src/core/agents/state/heartbeat-reader.ts +3 -0
- package/src/core/agents/state/live-coordination-view.ts +13 -6
- package/src/core/agents/state/parent-reference-contract.ts +14 -0
- package/src/core/agents/state/parent-reference.ts +179 -0
- package/src/core/config.ts +85 -0
- package/src/core/diagnostics/path-identity.ts +52 -6
- package/src/core/events/v3/canonical.ts +46 -13
- package/src/core/events/v3/index.ts +3 -0
- package/src/core/events/v3/producers/recorder.ts +151 -13
- package/src/core/events/v3/reader.ts +55 -11
- package/src/core/events/v3/validate.ts +42 -1
- package/src/core/hooks/adapter/native-parent.ts +109 -0
- package/src/core/hooks/cli.ts +110 -4
- package/src/core/hooks/resolve/owner.ts +0 -23
- package/src/core/hooks/resolve/transcript.ts +61 -0
- package/src/core/hooks/shell-admission.ts +634 -0
- package/src/core/hooks/shell-commit-tree.ts +102 -0
- package/src/core/inbox/contract.ts +18 -0
- package/src/core/inbox/peer-messages.ts +501 -15
- package/src/core/inbox/service.ts +108 -3
- package/src/core/inbox/targets.ts +94 -3
- package/src/core/presence/git.ts +45 -37
- package/src/core/presence/index.ts +16 -8
- package/src/core/presence/mail.ts +620 -0
- package/src/core/storage/modes.ts +6 -0
- package/src/core/storage/segments.ts +5 -4
- package/src/lib/admission-history.ts +267 -0
- package/src/lib/admission.ts +217 -19
- package/src/lib/browser/client.ts +147 -35
- package/src/lib/browser/content-checks.ts +14 -3
- package/src/lib/browser/critique.ts +113 -3
- package/src/lib/browser/geometry.ts +63 -14
- package/src/lib/browser/index.ts +5 -0
- package/src/lib/browser/page-review-contracts.ts +6 -1
- package/src/lib/browser/page-review-judge.ts +58 -13
- package/src/lib/browser/page-review-pack.ts +13 -2
- package/src/lib/browser/qa-run-contracts.ts +30 -4
- package/src/lib/browser/qa-run.ts +78 -17
- package/src/lib/browser/runts.ts +85 -37
- package/src/lib/browser/windows-chrome.ts +50 -0
- package/src/lib/browser/windows-login-sync.ts +275 -0
- package/src/lib/cookies/client.ts +62 -10
- package/src/lib/cookies/index.ts +3 -0
- package/src/lib/docs-metadata-sync.ts +44 -2
- package/src/lib/durable-job.ts +15 -0
- package/src/lib/http/client.ts +63 -1
- package/src/lib/instructions/templates.ts +4 -4
package/dist/core/hooks/cli.js
CHANGED
|
@@ -32,12 +32,13 @@ import { readLiveCoordinationRow } from "../agents/state/live-coordination-view.
|
|
|
32
32
|
import { ensureLiveCoordinationHeartbeat } from "../agents/state/live-coordination-writer.js";
|
|
33
33
|
import { assignName, readForkParent, readForkState, recordForkDetection, resolveName, } from "../agents/state/names.js";
|
|
34
34
|
import { writePidmapRow } from "../agents/state/pidmap.js";
|
|
35
|
-
import { agentsRequireGitFinalization, coordFreshnessSeconds, hostPromptContextConfig, resolveBinName, } from "../config.js";
|
|
35
|
+
import { agentsRequireGitFinalization, coordFreshnessSeconds, hostPromptContextConfig, readAdmissionConfig, resolveBinName, } from "../config.js";
|
|
36
36
|
import { checkpointContext, completeContextRecovery, extractContextSample, markContextCompactionCompleted, prepareContextRecovery, readContextState, recordContextSample, } from "../context/index.js";
|
|
37
37
|
import { tryWriteLiveDisplayV3 } from "../events/v3/live-feed.js";
|
|
38
38
|
import { liveHookSignalDefersDrainV3, reconcileLivePendingRuntimeContextV3, recordLiveDelegatedChildSessionV3, recordLiveHookSignalV3, resolveLiveEventLedgerRouteV3, } from "../events/v3/live-routing.js";
|
|
39
39
|
import { captureSpanClockV3 } from "../events/v3/span-state.js";
|
|
40
40
|
import { ensureRelayDaemon, fetchPresence, publishPresence } from "../presence/index.js";
|
|
41
|
+
import { importMail, publishMail } from "../presence/mail.js";
|
|
41
42
|
import { closeProcessLoggers, legacyLogFields, processLogger } from "../storage/logger.js";
|
|
42
43
|
import { stableScopeId } from "../workflow/scope-id.js";
|
|
43
44
|
import { adapterBehavior } from "./adapter/behaviors/index.js";
|
|
@@ -54,9 +55,10 @@ import { beginHookHealth, observeHookDebug, observeHookError, writeHookHealthCom
|
|
|
54
55
|
import { adapterPidFromEnv, parsePsChainLine, selectAnchorPid } from "./resolve/anchor.js";
|
|
55
56
|
import { extractIntentComment, resolveIntent } from "./resolve/intent.js";
|
|
56
57
|
import { resolveOwner } from "./resolve/owner.js";
|
|
57
|
-
import { inspectSessionNameDisplayImmediately, scanAssistantStatusBoxPresent, scanStatusBoxPresent, scanTranscriptRuntime, } from "./resolve/transcript.js";
|
|
58
|
+
import { inspectSessionNameDisplayImmediately, scanAssistantStatusBoxPresent, scanPendingBackgroundHandoffs, scanStatusBoxPresent, scanTranscriptRuntime, } from "./resolve/transcript.js";
|
|
58
59
|
import { clearHookRunMarker, writeHookRunMarker } from "./run-markers.js";
|
|
59
60
|
import { sessionNamePresence } from "./session-name-presence.js";
|
|
61
|
+
import { shellCommitTreeReason } from "./shell-commit-tree.js";
|
|
60
62
|
import { shellRmReason } from "./shell-rm.js";
|
|
61
63
|
import { shellWaiterReason } from "./shell-waiter.js";
|
|
62
64
|
let hookHealthState;
|
|
@@ -227,7 +229,18 @@ function healForkLineage(coordRoot, instanceId, payload) {
|
|
|
227
229
|
function ensureSessionDisplayName(coordRoot, instanceId, sessionId, adapter, payload) {
|
|
228
230
|
if (coordEnv("WORKFLOW_CHILD") === "1")
|
|
229
231
|
return;
|
|
230
|
-
|
|
232
|
+
// This runs on every tool call. The heartbeat cache is the surface this
|
|
233
|
+
// function stamps, so a cache that already carries a name, or marks a
|
|
234
|
+
// session that never takes one, means there is nothing to do. Only a cache
|
|
235
|
+
// that cannot answer pays for the authoritative read, which re-validates the
|
|
236
|
+
// whole active ledger and cost about half a second per call at 22 MB.
|
|
237
|
+
const cached = readHeartbeat(coordRoot, instanceId);
|
|
238
|
+
if (cached?.kind === "subagent" || cached?.kind === "transient" || cached?.workflow_run_id) {
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
if (cached?.name?.trim())
|
|
242
|
+
return;
|
|
243
|
+
const row = readLiveCoordinationRow(coordRoot, instanceId) ?? cached;
|
|
231
244
|
if (row?.kind === "subagent" || row?.kind === "transient" || row?.workflow_run_id)
|
|
232
245
|
return;
|
|
233
246
|
if (row?.name?.trim())
|
|
@@ -1009,8 +1022,23 @@ function recordContextTelemetry(run) {
|
|
|
1009
1022
|
}
|
|
1010
1023
|
}
|
|
1011
1024
|
}
|
|
1025
|
+
/** Cross-machine peer messages (ADR 0222) ride the presence fetch: import
|
|
1026
|
+
* whatever mail refs are already local. Reads local refs only, at most once
|
|
1027
|
+
* per import interval; never blocks on the network. */
|
|
1028
|
+
async function receiveRemoteMail(coordRoot) {
|
|
1029
|
+
const { peerInbox } = await import("../inbox/peer-messages.js");
|
|
1030
|
+
importMail(coordRoot, peerInbox(coordRoot), { throttle: true });
|
|
1031
|
+
}
|
|
1012
1032
|
async function handleSessionStarted(run) {
|
|
1013
1033
|
const { coordRoot, adapter, payload, owner, sessionId, data } = run;
|
|
1034
|
+
// Import mail from refs fetched earlier, so a message sent from another
|
|
1035
|
+
// machine while this task was away is in the inbox this context renders.
|
|
1036
|
+
try {
|
|
1037
|
+
await receiveRemoteMail(coordRoot);
|
|
1038
|
+
}
|
|
1039
|
+
catch (err) {
|
|
1040
|
+
logError(coordRoot, err, { phase: "session-start-mail" });
|
|
1041
|
+
}
|
|
1014
1042
|
// A configured backup runs out of process and is freshness-gated per host.
|
|
1015
1043
|
// Startup never waits for restic or a remote provider; the child owns no
|
|
1016
1044
|
// hook stdio, so the harness is not held open until it finishes. A failed
|
|
@@ -1124,6 +1152,7 @@ async function handleTurnStarted(run) {
|
|
|
1124
1152
|
// interval; the systemMessage below reads whatever is locally known).
|
|
1125
1153
|
try {
|
|
1126
1154
|
fetchPresence(coordRoot);
|
|
1155
|
+
await receiveRemoteMail(coordRoot);
|
|
1127
1156
|
}
|
|
1128
1157
|
catch (err) {
|
|
1129
1158
|
logError(coordRoot, err, { phase: "user-prompt-submit-presence" });
|
|
@@ -1187,11 +1216,20 @@ async function handleStop(run) {
|
|
|
1187
1216
|
// its daemon intentionally exits when a machine has no live sessions.
|
|
1188
1217
|
try {
|
|
1189
1218
|
publishPresence(coordRoot);
|
|
1219
|
+
publishMail(coordRoot);
|
|
1190
1220
|
ensureRelayDaemon(coordRoot);
|
|
1191
1221
|
}
|
|
1192
1222
|
catch (err) {
|
|
1193
1223
|
logError(coordRoot, err, { phase: "stop-presence" });
|
|
1194
1224
|
}
|
|
1225
|
+
// Claude Code may move a running foreground command (often the agent's own
|
|
1226
|
+
// commit and push) into the background to deliver a user message. Until it
|
|
1227
|
+
// reports back, finalization cannot pass, so the verdict defers the status
|
|
1228
|
+
// demands instead of bouncing the agent in a loop.
|
|
1229
|
+
const pendingBackgroundHandoffs = adapter === "claude-code"
|
|
1230
|
+
? scanPendingBackgroundHandoffs(payload?.transcript_path ??
|
|
1231
|
+
behavior.discoverTranscript?.(payload?.session_id ?? sessionId))
|
|
1232
|
+
: [];
|
|
1195
1233
|
// Stop verdict (V3 ritual + task/status gate). Direct in-process call: the
|
|
1196
1234
|
// rule lives in Harnery. agent-hook already emitted this turn.completed
|
|
1197
1235
|
// with privacy-safe ritual observations, so the evidence is in the stream.
|
|
@@ -1205,7 +1243,15 @@ async function handleStop(run) {
|
|
|
1205
1243
|
session_name_observation_unavailable: typeof data.session_name_unavailable_reason === "string",
|
|
1206
1244
|
bypass: coordEnv("AGENT_COORD_BYPASS_STOP") === "1",
|
|
1207
1245
|
workflow_child: coordEnv("WORKFLOW_CHILD") === "1",
|
|
1246
|
+
pending_background_handoff: pendingBackgroundHandoffs.length > 0,
|
|
1208
1247
|
});
|
|
1248
|
+
if (verdict.rule === "stop-hook.background_handoff_deferred") {
|
|
1249
|
+
appendDebug(coordRoot, {
|
|
1250
|
+
...debugBase,
|
|
1251
|
+
effect: "stop-deferred-background-handoff",
|
|
1252
|
+
background_task_ids: pendingBackgroundHandoffs,
|
|
1253
|
+
});
|
|
1254
|
+
}
|
|
1209
1255
|
if (!verdict.allow) {
|
|
1210
1256
|
// Backstop for sessions whose evidence can never land (e.g. a headless
|
|
1211
1257
|
// child whose status command resolves to a different owner): after
|
|
@@ -1240,6 +1286,13 @@ async function handleStop(run) {
|
|
|
1240
1286
|
// until the adapter has committed turn.completed above. Reconcile only
|
|
1241
1287
|
// when such a request exists; any later real work cancels it in the
|
|
1242
1288
|
// finalizer instead of being terminated underneath the agent.
|
|
1289
|
+
// A deferred stop proves nothing about finalization; an explicit end must
|
|
1290
|
+
// wait for the turn that reports the background task's result.
|
|
1291
|
+
if (verdict.rule === "stop-hook.background_handoff_deferred") {
|
|
1292
|
+
if (behavior.runtimeContextRetry)
|
|
1293
|
+
scheduleRuntimeContextRetry(coordRoot, adapter, sessionId);
|
|
1294
|
+
return undefined;
|
|
1295
|
+
}
|
|
1243
1296
|
try {
|
|
1244
1297
|
const { hasPendingExplicitSessionEndV3, reconcileSessionFinalizationV3 } = await import("../agents/session-finalizer-v3.js");
|
|
1245
1298
|
if (hasPendingExplicitSessionEndV3(coordRoot)) {
|
|
@@ -1310,6 +1363,12 @@ async function handleToolRequested(run) {
|
|
|
1310
1363
|
emitDeny(adapter, rmReason);
|
|
1311
1364
|
return 0;
|
|
1312
1365
|
}
|
|
1366
|
+
const commitTreeReason = shellCommitTreeReason(payload?.tool_name, payload?.tool_input, resolveBinName(coordRoot));
|
|
1367
|
+
if (commitTreeReason) {
|
|
1368
|
+
const { emitDeny } = await import("./adapter/output.js");
|
|
1369
|
+
emitDeny(adapter, commitTreeReason);
|
|
1370
|
+
return 0;
|
|
1371
|
+
}
|
|
1313
1372
|
// G-guard for ALL adapters. Claude Code previously ran this via a
|
|
1314
1373
|
// pre-tool-use bash adapter (which called `agent-coord verdict --rule=claim`);
|
|
1315
1374
|
// that adapter is now deleted, so agent-hook owns the deny for every adapter.
|
|
@@ -1327,8 +1386,38 @@ async function handleToolRequested(run) {
|
|
|
1327
1386
|
}
|
|
1328
1387
|
if (!guardAllowed)
|
|
1329
1388
|
return 0;
|
|
1389
|
+
// Heavy shell checks queue for a machine-wide admission slot when the
|
|
1390
|
+
// project configures one. Fails open: any error runs the command as written.
|
|
1391
|
+
try {
|
|
1392
|
+
if (await emitAdmissionRewrite(coordRoot, adapter, payload))
|
|
1393
|
+
return 0;
|
|
1394
|
+
}
|
|
1395
|
+
catch (err) {
|
|
1396
|
+
logError(coordRoot, err, { phase: "pre-tool-use-admission" });
|
|
1397
|
+
}
|
|
1330
1398
|
return undefined;
|
|
1331
1399
|
}
|
|
1400
|
+
async function emitAdmissionRewrite(coordRoot, adapter, payload) {
|
|
1401
|
+
const resource = readAdmissionConfig(coordRoot)?.guard?.resource;
|
|
1402
|
+
if (!resource)
|
|
1403
|
+
return false;
|
|
1404
|
+
const { admissionHookOutput } = await import("./shell-admission.js");
|
|
1405
|
+
const output = admissionHookOutput({
|
|
1406
|
+
adapter,
|
|
1407
|
+
resource,
|
|
1408
|
+
bin: resolveBinName(coordRoot),
|
|
1409
|
+
projectRoot: coordRoot,
|
|
1410
|
+
toolName: payload?.tool_name,
|
|
1411
|
+
toolInput: payload?.tool_input,
|
|
1412
|
+
cwd: payload?.cwd,
|
|
1413
|
+
skip: coordEnv("ADMISSION_SKIP") === "1" || Boolean(coordEnv("ADMISSION_HELD")),
|
|
1414
|
+
platform: process.platform,
|
|
1415
|
+
});
|
|
1416
|
+
if (!output)
|
|
1417
|
+
return false;
|
|
1418
|
+
process.stdout.write(`${JSON.stringify(output)}\n`);
|
|
1419
|
+
return true;
|
|
1420
|
+
}
|
|
1332
1421
|
async function handlePostToolUse(run) {
|
|
1333
1422
|
const { coordRoot, adapter, eventName, payload, owner } = run;
|
|
1334
1423
|
// Inject the full instruction only at the successful tool boundary that
|
|
@@ -1348,9 +1437,18 @@ async function handlePostToolUse(run) {
|
|
|
1348
1437
|
// retry response already carries the full instruction and an end-turn
|
|
1349
1438
|
// status is the wrong place to ask.
|
|
1350
1439
|
try {
|
|
1351
|
-
const row = readLiveCoordinationRow(coordRoot, owner.instance_id);
|
|
1352
1440
|
// A workflow child has no user-visible title to set.
|
|
1353
|
-
|
|
1441
|
+
if (coordEnv("WORKFLOW_CHILD") === "1")
|
|
1442
|
+
return;
|
|
1443
|
+
// The live row copies every name-display field from a current heartbeat
|
|
1444
|
+
// cache and leaves them unset otherwise, so a raw cache with nothing
|
|
1445
|
+
// pending proves the row has nothing pending either. That skips a full
|
|
1446
|
+
// ledger read on almost every tool call; only a pending title pays for
|
|
1447
|
+
// the authoritative check below.
|
|
1448
|
+
if (!sessionNameDisplayPending(readHeartbeat(coordRoot, owner.instance_id)))
|
|
1449
|
+
return;
|
|
1450
|
+
const row = readLiveCoordinationRow(coordRoot, owner.instance_id);
|
|
1451
|
+
const name = sessionNameDisplayPending(row);
|
|
1354
1452
|
if (name && toolResponseMintedSessionName(payload?.tool_response, name)) {
|
|
1355
1453
|
// Record the title before asking for it. The suggestion can still
|
|
1356
1454
|
// change afterwards (an assigned-name rewrite, a lifecycle re-mint, a
|
|
@@ -30,17 +30,6 @@ export declare function resolveOwner(opts: {
|
|
|
30
30
|
instance_id: string;
|
|
31
31
|
source: "env" | "payload" | "session_env" | "pidmap-self" | "pidmap-ancestor";
|
|
32
32
|
} | null;
|
|
33
|
-
/**
|
|
34
|
-
* Find the parent owner for a subagent invocation. The per-shell marker at
|
|
35
|
-
* `.harnery/shells/<pid>` is set by `sub-agent-start` and removed by
|
|
36
|
-
* `sub-agent-stop`.
|
|
37
|
-
*
|
|
38
|
-
* Phase 2 stub: the marker file isn't written yet, so we return null in most
|
|
39
|
-
* cases. Phase 2 callers can pass through.
|
|
40
|
-
*/
|
|
41
|
-
export declare function readShellMarker(coordRoot: string, pid: number): string | null;
|
|
42
|
-
/** Read the V3-projected `agent_id` for an owner if it exists. */
|
|
43
|
-
export declare function readAgentIdForOwner(coordRoot: string, instanceId: string): string | null;
|
|
44
33
|
/** Diagnostic: list of pid-map entries (for debugging). */
|
|
45
34
|
export declare function listPidmap(coordRoot: string): Array<{
|
|
46
35
|
pid: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"owner.d.ts","sourceRoot":"","sources":["../../../../src/core/hooks/resolve/owner.ts"],"names":[],"mappings":"AAQA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE;IACjC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACxC,SAAS,EAAE,MAAM,CAAC;CACnB,GAAG;IACF,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,KAAK,GAAG,SAAS,GAAG,aAAa,GAAG,aAAa,GAAG,iBAAiB,CAAC;CAC/E,GAAG,IAAI,CAgFP;AA2BD
|
|
1
|
+
{"version":3,"file":"owner.d.ts","sourceRoot":"","sources":["../../../../src/core/hooks/resolve/owner.ts"],"names":[],"mappings":"AAQA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE;IACjC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACxC,SAAS,EAAE,MAAM,CAAC;CACnB,GAAG;IACF,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,KAAK,GAAG,SAAS,GAAG,aAAa,GAAG,aAAa,GAAG,iBAAiB,CAAC;CAC/E,GAAG,IAAI,CAgFP;AA2BD,2DAA2D;AAC3D,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,KAAK,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAgBnF"}
|
|
@@ -140,29 +140,6 @@ function readPpid(pid) {
|
|
|
140
140
|
}
|
|
141
141
|
return null;
|
|
142
142
|
}
|
|
143
|
-
/**
|
|
144
|
-
* Find the parent owner for a subagent invocation. The per-shell marker at
|
|
145
|
-
* `.harnery/shells/<pid>` is set by `sub-agent-start` and removed by
|
|
146
|
-
* `sub-agent-stop`.
|
|
147
|
-
*
|
|
148
|
-
* Phase 2 stub: the marker file isn't written yet, so we return null in most
|
|
149
|
-
* cases. Phase 2 callers can pass through.
|
|
150
|
-
*/
|
|
151
|
-
export function readShellMarker(coordRoot, pid) {
|
|
152
|
-
const path = join(coordRoot, ".harnery", "shells", String(pid));
|
|
153
|
-
if (!existsSync(path))
|
|
154
|
-
return null;
|
|
155
|
-
try {
|
|
156
|
-
return readFileSync(path, "utf8").trim() || null;
|
|
157
|
-
}
|
|
158
|
-
catch {
|
|
159
|
-
return null;
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
/** Read the V3-projected `agent_id` for an owner if it exists. */
|
|
163
|
-
export function readAgentIdForOwner(coordRoot, instanceId) {
|
|
164
|
-
return readLiveCoordinationRow(coordRoot, instanceId)?.agent_id ?? null;
|
|
165
|
-
}
|
|
166
143
|
/** Diagnostic: list of pid-map entries (for debugging). */
|
|
167
144
|
export function listPidmap(coordRoot) {
|
|
168
145
|
const dir = join(coordRoot, ".harnery", "pid-map");
|
|
@@ -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"}
|
|
@@ -88,6 +88,60 @@ export function scanAssistantStatusBoxPresent(transcriptPath, lastAssistantMessa
|
|
|
88
88
|
return (scanAssistantTextIncludes(transcriptPath, ASSISTANT_STATUS_BOX_PREFIX) ||
|
|
89
89
|
lastAssistantMessage?.includes(ASSISTANT_STATUS_BOX_PREFIX) === true);
|
|
90
90
|
}
|
|
91
|
+
/** A handoff older than this no longer defers Stop, so a lost notification cannot disable the ritual. */
|
|
92
|
+
export const BACKGROUND_HANDOFF_MAX_AGE_MS = 30 * 60 * 1000;
|
|
93
|
+
/**
|
|
94
|
+
* Claude Code interleaves request-capture rows of several hundred KB each, so
|
|
95
|
+
* the 256KB status-box window can lose a handoff written a minute earlier.
|
|
96
|
+
*/
|
|
97
|
+
const BACKGROUND_HANDOFF_TAIL_BYTES = 8 * 1024 * 1024;
|
|
98
|
+
/**
|
|
99
|
+
* Claude Code background tasks it moved off the foreground on its own (to
|
|
100
|
+
* deliver a mid-command user message) that have not yet posted a
|
|
101
|
+
* `<task-notification>`. Only the structured `toolUseResult` fields written by
|
|
102
|
+
* Claude Code open a handoff; the agent cannot forge them through tool output.
|
|
103
|
+
* Any later notification text naming the task closes it, so a spoofed
|
|
104
|
+
* notification can only make Stop stricter. A command the agent chose to
|
|
105
|
+
* background (`run_in_background`) or a Monitor opens nothing.
|
|
106
|
+
*/
|
|
107
|
+
export function scanPendingBackgroundHandoffs(transcriptPath, nowMs = Date.now()) {
|
|
108
|
+
const readablePath = resolveTranscriptPath(transcriptPath);
|
|
109
|
+
if (!readablePath)
|
|
110
|
+
return [];
|
|
111
|
+
let size;
|
|
112
|
+
try {
|
|
113
|
+
size = statSync(readablePath).size;
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
return [];
|
|
117
|
+
}
|
|
118
|
+
const text = readRange(readablePath, Math.max(0, size - BACKGROUND_HANDOFF_TAIL_BYTES), size);
|
|
119
|
+
if (!text)
|
|
120
|
+
return [];
|
|
121
|
+
const opened = new Map();
|
|
122
|
+
for (const line of text.split("\n")) {
|
|
123
|
+
// Request-capture rows echo the same text; the row-type check below keeps
|
|
124
|
+
// only Claude Code's own top-level tool-result rows.
|
|
125
|
+
if (line.includes("backgroundedToDeliverMessage")) {
|
|
126
|
+
const row = parseTranscriptRow(line);
|
|
127
|
+
const result = row?.toolUseResult;
|
|
128
|
+
if (row?.type === "user" &&
|
|
129
|
+
result?.backgroundedToDeliverMessage === true &&
|
|
130
|
+
typeof result.backgroundTaskId === "string" &&
|
|
131
|
+
result.backgroundTaskId) {
|
|
132
|
+
opened.set(result.backgroundTaskId, Date.parse(String(row.timestamp)));
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
if (line.includes("task-notification")) {
|
|
136
|
+
for (const match of line.matchAll(/<task-id>([^<]+)<\/task-id>/g)) {
|
|
137
|
+
opened.delete(match[1]);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return [...opened]
|
|
142
|
+
.filter(([, at]) => Number.isFinite(at) && nowMs - at <= BACKGROUND_HANDOFF_MAX_AGE_MS)
|
|
143
|
+
.map(([id]) => id);
|
|
144
|
+
}
|
|
91
145
|
/** Most recent user-visible assistant text across Claude Code and Codex JSONL. */
|
|
92
146
|
export function scanLatestAssistantText(transcriptPath) {
|
|
93
147
|
const readablePath = resolveTranscriptPath(transcriptPath);
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admission guard for heavy shell checks. A whole-project typecheck, a full
|
|
3
|
+
* test suite, or a production build can each take gigabytes of memory, and
|
|
4
|
+
* several agents starting them at once on one machine can exhaust it. Asking
|
|
5
|
+
* agents in prose to wrap those commands in `admission run` does not work: the
|
|
6
|
+
* rule has to be read and remembered on every call. This guard rewrites the
|
|
7
|
+
* agent's shell command at PreToolUse instead, so each heavy check waits for a
|
|
8
|
+
* slot on a machine-wide admission resource.
|
|
9
|
+
*
|
|
10
|
+
* Enabled only when the project config names a resource
|
|
11
|
+
* (`admission.guard.resource`). It finds each simple command that is a heavy
|
|
12
|
+
* check and inserts `<bin> admission run --resource <name> --label 'agent:
|
|
13
|
+
* ...' --` in front of it, after any leading VAR=value assignments. The rest
|
|
14
|
+
* of the command (cd, pipes, redirects, && chains) is left byte for byte.
|
|
15
|
+
* Heavy means:
|
|
16
|
+
* - tsc, however launched (tsc, npx/bunx/bun x/pnpm exec/yarn tsc,
|
|
17
|
+
* node_modules/.bin/tsc, node .../typescript/bin/tsc)
|
|
18
|
+
* - next build
|
|
19
|
+
* - bun test with no file or directory named (a full suite)
|
|
20
|
+
* - the package scripts test / test:* (with no further positional
|
|
21
|
+
* argument), build, typecheck, type-check, typecheck:*, check-types, tsc,
|
|
22
|
+
* run through bun run, npm, pnpm, or yarn
|
|
23
|
+
* - bash/sh -c '<script>' whose script contains one of the above
|
|
24
|
+
* Watch modes, --help/--version, and named-file test runs are left alone.
|
|
25
|
+
*
|
|
26
|
+
* Passes through untouched: non-shell tools; a command that already runs
|
|
27
|
+
* `admission run` or `heavy-slot`; HARNERY_ADMISSION_SKIP=1 in the command or
|
|
28
|
+
* the hook's environment; HARNERY_ADMISSION_HELD in the hook's environment
|
|
29
|
+
* (the session already holds a slot); text inside quotes, heredocs, and
|
|
30
|
+
* comments. Any parse failure means no rewrite.
|
|
31
|
+
*/
|
|
32
|
+
export declare const ADMISSION_SKIP_PREFIX = "HARNERY_ADMISSION_SKIP=1";
|
|
33
|
+
/** Claude Code's maximum Bash timeout; a queued wait counts against it. */
|
|
34
|
+
export declare const BASH_TIMEOUT_MAX_MS = 600000;
|
|
35
|
+
/** POSIX single-quote a word when it needs quoting (shlex.quote semantics). */
|
|
36
|
+
export declare function shellQuote(value: string): string;
|
|
37
|
+
/**
|
|
38
|
+
* Return the command with each heavy simple command wrapped in `wrapper`
|
|
39
|
+
* (a shell-ready prefix such as `harn admission run --resource build`), or
|
|
40
|
+
* null when nothing changes.
|
|
41
|
+
*/
|
|
42
|
+
export declare function rewriteHeavyCommand(command: string, wrapper: string): string | null;
|
|
43
|
+
/** Normalized shell-tool name, or null for any other tool. */
|
|
44
|
+
export declare function shellToolName(toolName: unknown): string | null;
|
|
45
|
+
export interface AdmissionRewrite {
|
|
46
|
+
updatedInput: Record<string, unknown>;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Rewrite a shell tool's input so its heavy checks queue for admission.
|
|
50
|
+
* Handles `command` or `cmd` as a string, or as an argv such as
|
|
51
|
+
* ["bash", "-lc", "<script>"]. Returns null when nothing changes.
|
|
52
|
+
*/
|
|
53
|
+
export declare function admissionRewriteForTool(toolName: unknown, toolInput: unknown, wrapper: string): AdmissionRewrite | null;
|
|
54
|
+
export interface AdmissionHookInput {
|
|
55
|
+
adapter: string;
|
|
56
|
+
/** Admission resource the project's guard queues on. */
|
|
57
|
+
resource: string;
|
|
58
|
+
/** Host bin name used in the wrapper and the agent-facing note. */
|
|
59
|
+
bin: string;
|
|
60
|
+
/**
|
|
61
|
+
* Project whose admission config `admission run` should read. A nested
|
|
62
|
+
* checkout with its own `.harnery/` would otherwise shadow the host's
|
|
63
|
+
* resource settings for a shell started inside it.
|
|
64
|
+
*/
|
|
65
|
+
projectRoot?: string;
|
|
66
|
+
toolName: unknown;
|
|
67
|
+
toolInput: unknown;
|
|
68
|
+
cwd?: unknown;
|
|
69
|
+
/** True when HARNERY_ADMISSION_SKIP=1 or HARNERY_ADMISSION_HELD is set for the hook. */
|
|
70
|
+
skip?: boolean;
|
|
71
|
+
platform?: string;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* The PreToolUse output that queues a shell command's heavy checks, or null
|
|
75
|
+
* to let the command run as written. Claude Code applies `updatedInput`
|
|
76
|
+
* under the session's own permission rules, so no decision is sent, and its
|
|
77
|
+
* Bash timeout is raised to the maximum because a queued wait counts against
|
|
78
|
+
* it. Codex applies a rewrite only beside `permissionDecision: "allow"`.
|
|
79
|
+
* Cursor and OpenCode have no rewrite channel. Windows-native shells (a
|
|
80
|
+
* drive-letter or UNC workspace) are outside the machine whose queue this
|
|
81
|
+
* guards.
|
|
82
|
+
*/
|
|
83
|
+
export declare function admissionHookOutput(input: AdmissionHookInput): Record<string, unknown> | null;
|
|
84
|
+
//# sourceMappingURL=shell-admission.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shell-admission.d.ts","sourceRoot":"","sources":["../../../src/core/hooks/shell-admission.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAuGH,eAAO,MAAM,qBAAqB,6BAA6B,CAAC;AAChE,2EAA2E;AAC3E,eAAO,MAAM,mBAAmB,SAAU,CAAC;AAgV3C,+EAA+E;AAC/E,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAIhD;AAWD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAsBnF;AAID,8DAA8D;AAC9D,wBAAgB,aAAa,CAAC,QAAQ,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAI9D;AAED,MAAM,WAAW,gBAAgB;IAC/B,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACvC;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,OAAO,EACjB,SAAS,EAAE,OAAO,EAClB,OAAO,EAAE,MAAM,GACd,gBAAgB,GAAG,IAAI,CAmCzB;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,wDAAwD;IACxD,QAAQ,EAAE,MAAM,CAAC;IACjB,mEAAmE;IACnE,GAAG,EAAE,MAAM,CAAC;IACZ;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;IACnB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,wFAAwF;IACxF,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,kBAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CA4B7F"}
|