@humwick/runner 0.130.4 → 0.130.6
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/LICENSE +661 -167
- package/agent-bin/humwick +2 -2
- package/agent-bin/humwick-browser +4 -0
- package/hooks/fff-search-redirect/fff-search-redirect.cjs +1 -1
- package/hooks/web-tools-redirect/web-tools-redirect.cjs +2 -2
- package/package.json +8 -11
- package/plugins/browser/skills/playwright-cli/SKILL.md +8 -6
- package/plugins/claude/.claude-plugin/plugin.json +3 -3
- package/plugins/claude/claude-statusline-probe.cjs +26 -16
- package/plugins/claude/hooks/gate-run-guard.provisioned.mjs +47 -17
- package/plugins/claude/hooks/gate-run-guard.sh +3 -3
- package/plugins/claude/hooks/gate-run-guard.ts +5 -5
- package/plugins/claude/hooks/kill-guard.provisioned.mjs +1 -1
- package/plugins/claude/hooks/kill-guard.sh +4 -4
- package/plugins/claude/hooks/kill-guard.ts +2 -2
- package/plugins/claude/hooks/permission-request.sh +1 -1
- package/plugins/claude/hooks/post-compact.sh +1 -1
- package/plugins/claude/hooks/post-tool-use.sh +3 -3
- package/plugins/claude/hooks/pre-compact.sh +2 -2
- package/plugins/claude/hooks/read-only-bash-guard.sh +4 -4
- package/plugins/claude/hooks/relay-status.sh +32 -32
- package/plugins/claude/hooks/session-end.sh +2 -2
- package/plugins/claude/hooks/session-start.sh +3 -3
- package/plugins/claude/hooks/shell-trust.ts +1 -1
- package/plugins/claude/hooks/stop-failure.sh +2 -2
- package/plugins/claude/hooks/stop.sh +6 -6
- package/plugins/claude/hooks/subagent-skill-policy.cjs +8 -6
- package/plugins/claude/hooks/subagent-stop.sh +3 -3
- package/plugins/claude/hooks/user-prompt-submit.sh +1 -1
- package/plugins/claude/hooks/wait-loop-guard.ts +3 -3
- package/plugins/claude/monitors/monitors.json +2 -2
- package/plugins/claude/monitors/relay-monitor.provisioned.mjs +96 -62
- package/plugins/claude/monitors/relay-monitor.ts +5 -5
- package/plugins/claude/skills/label/SKILL.md +3 -3
- package/plugins/claude/skills/message/SKILL.md +5 -5
- package/plugins/claude/skills/react/SKILL.md +1 -1
- package/plugins/claude/skills/read-message/SKILL.md +4 -4
- package/plugins/claude/skills/reply/SKILL.md +5 -5
- package/plugins/claude/skills/send-claimable/SKILL.md +5 -5
- package/plugins/claude/skills/slice-first/SKILL.md +5 -3
- package/plugins/claude/skills/slice-first/references/plan-recipe.md +30 -29
- package/plugins/claude/skills/status/SKILL.md +3 -3
- package/plugins/claude/skills/tags/SKILL.md +5 -5
- package/plugins/claude/skills/task/SKILL.md +10 -10
- package/plugins/claude-output-style/.claude-plugin/plugin.json +1 -1
- package/plugins/claude-output-style/output-styles/{agent-relay.md → humwick.md} +1 -1
- package/plugins/codex/skills/guide/SKILL.md +3 -3
- package/plugins/codex/skills/label/SKILL.md +3 -3
- package/plugins/codex/skills/message/SKILL.md +5 -5
- package/plugins/codex/skills/react/SKILL.md +1 -1
- package/plugins/codex/skills/read-message/SKILL.md +4 -4
- package/plugins/codex/skills/reply/SKILL.md +5 -5
- package/plugins/codex/skills/send-claimable/SKILL.md +5 -5
- package/plugins/codex/skills/slice-first/SKILL.md +5 -3
- package/plugins/codex/skills/slice-first/references/plan-recipe.md +30 -29
- package/plugins/codex/skills/status/SKILL.md +3 -3
- package/plugins/codex/skills/tags/SKILL.md +5 -5
- package/plugins/codex/skills/task/SKILL.md +11 -10
- package/src/adapter.ts +95 -92
- package/src/adapters/claude-api.ts +8 -11
- package/src/adapters/claude-context-command.ts +1 -1
- package/src/adapters/claude-credentials.ts +7 -3
- package/src/adapters/claude-delivery-lanes.ts +2 -2
- package/src/adapters/claude-delivery.ts +16 -16
- package/src/adapters/claude-effort.ts +2 -2
- package/src/adapters/claude-exit.ts +2 -2
- package/src/adapters/claude-headless-mirror.ts +18 -2
- package/src/adapters/claude-headless-refusal.ts +3 -3
- package/src/adapters/claude-headless.ts +11 -10
- package/src/adapters/claude-launch-exit.ts +1 -1
- package/src/adapters/claude-monitor-delivery-plan.ts +36 -16
- package/src/adapters/claude-permission.ts +5 -5
- package/src/adapters/claude-prompt-gates.ts +9 -9
- package/src/adapters/claude-prompt-hook.ts +2 -2
- package/src/adapters/claude-session-capture.ts +6 -6
- package/src/adapters/claude-session-probe.ts +25 -25
- package/src/adapters/claude-shutdown.ts +11 -11
- package/src/adapters/claude-status-detectors.ts +31 -31
- package/src/adapters/claude-subagents.ts +7 -7
- package/src/adapters/claude-submit-confirmation.ts +6 -6
- package/src/adapters/claude-tmux.ts +43 -43
- package/src/adapters/claude-token-usage-capture.ts +5 -5
- package/src/adapters/claude-tool-policy.ts +7 -7
- package/src/adapters/claude-transcript.ts +24 -24
- package/src/adapters/claude.ts +100 -100
- package/src/adapters/codex-agent-message-capture.ts +26 -63
- package/src/adapters/codex-app-server.ts +1 -1
- package/src/adapters/codex-client.ts +9 -9
- package/src/adapters/codex-effective-config.ts +1 -1
- package/src/adapters/codex-launch-config.ts +5 -5
- package/src/adapters/codex-rollout-context.ts +2 -2
- package/src/adapters/codex-skill-discovery.ts +1 -1
- package/src/adapters/codex-token-usage-capture.ts +16 -16
- package/src/adapters/codex-tool-output.ts +4 -4
- package/src/adapters/codex-version.ts +3 -3
- package/src/adapters/codex.ts +64 -64
- package/src/adapters/opencode-api.ts +1 -1
- package/src/adapters/opencode-context.ts +20 -22
- package/src/adapters/opencode-model-registry.ts +7 -7
- package/src/adapters/opencode-provider.ts +8 -8
- package/src/adapters/opencode-provisioning.ts +30 -0
- package/src/adapters/opencode-server-retry.ts +1 -1
- package/src/adapters/opencode-soft-steer.ts +5 -5
- package/src/adapters/opencode-spawn.ts +18 -14
- package/src/adapters/opencode-token-usage-capture.ts +12 -12
- package/src/adapters/opencode-tool-events.ts +15 -15
- package/src/adapters/opencode.ts +232 -232
- package/src/adapters/project-shell.ts +11 -11
- package/src/adapters/service-access.ts +6 -6
- package/src/adapters/tmux-offload.ts +9 -9
- package/src/adapters/tool-summary.ts +5 -5
- package/src/agent-redact.ts +1 -1
- package/src/agent-runner/commands/dispatch.ts +10 -10
- package/src/agent-runner/commands/lifecycle.ts +2 -2
- package/src/agent-runner/commands/prompt.ts +19 -19
- package/src/agent-runner/credentials.ts +5 -5
- package/src/agent-runner/inbox.ts +1 -1
- package/src/agent-runner/lifecycle-milestones.ts +3 -3
- package/src/agent-runner/lifecycle-phase.ts +2 -2
- package/src/agent-runner/liveness-exchange.ts +4 -10
- package/src/agent-runner/registration.ts +8 -8
- package/src/agent-runner/runner-context.ts +9 -14
- package/src/agent-runner/session-mirror.ts +12 -12
- package/src/agent-runner/task-claims.ts +2 -2
- package/src/agent-runner/token-usage-coverage.ts +1 -1
- package/src/agent-runner/turn-report.ts +12 -12
- package/src/api-budget-accounting.ts +3 -3
- package/src/area-memory.ts +6 -6
- package/src/artifact-path-materialize.ts +1 -1
- package/src/async-guard.ts +5 -5
- package/src/attachment-cache.ts +17 -22
- package/src/background-script-reconcile.ts +6 -6
- package/src/bounded-log.ts +1 -1
- package/src/busy-reconciler.ts +22 -22
- package/src/claim-tracker.ts +3 -3
- package/src/claude-settings.ts +8 -8
- package/src/claude-system-prompt.ts +1 -1
- package/src/claude-workspace-trust.ts +1 -1
- package/src/config.ts +62 -61
- package/src/context-boundary.ts +5 -5
- package/src/context-command.ts +3 -3
- package/src/control-server.ts +32 -32
- package/src/delivery-result.ts +2 -2
- package/src/effort-command.ts +2 -2
- package/src/empty-turn.ts +22 -14
- package/src/free-port.ts +1 -1
- package/src/gate-run-config.ts +3 -3
- package/src/host-asset-plan.ts +24 -17
- package/src/host-claude-config-worker.ts +2 -2
- package/src/host-sources.ts +2 -2
- package/src/index.ts +16 -16
- package/src/launch-assembly.ts +94 -96
- package/src/liveness.ts +15 -15
- package/src/logger.ts +3 -3
- package/src/mcp-outbox.ts +3 -3
- package/src/mcp-preflight.ts +2 -2
- package/src/mcp-source-selection.ts +2 -2
- package/src/mcp-tool-deferral.ts +1 -1
- package/src/mcp-vault-env.ts +2 -2
- package/src/message-body-config/config.ts +4 -4
- package/src/mid-turn-delivery.ts +2 -2
- package/src/native-memory-lever.ts +8 -8
- package/src/outbox.ts +15 -15
- package/src/pending-permission-store.ts +1 -1
- package/src/profile-home.ts +19 -19
- package/src/profile-projection.ts +26 -24
- package/src/project-instructions.ts +5 -5
- package/src/provider-auth-warning.ts +17 -0
- package/src/provider-double.ts +1 -1
- package/src/provider-hold.ts +3 -3
- package/src/provider-home-marker.ts +1 -1
- package/src/provider-home-tombstone.ts +1 -1
- package/src/provider-input-queue.ts +2 -2
- package/src/provider-integration.ts +15 -13
- package/src/provider-setup.ts +15 -3
- package/src/providers.ts +1 -1
- package/src/provisioning.ts +37 -40
- package/src/question-decision.ts +2 -2
- package/src/quota.ts +0 -6
- package/src/rate-limit.ts +24 -13
- package/src/refused-prompt-store.ts +2 -2
- package/src/relay-injection-events.ts +2 -2
- package/src/relay-instructions.ts +5 -5
- package/src/relay-mcp-proxy.long-turn-e2e.ts +13 -13
- package/src/relay-mcp-proxy.ts +57 -58
- package/src/relay-mcp.ts +55 -69
- package/src/reply-obligation-cache.ts +9 -9
- package/src/response-capture-report.ts +9 -9
- package/src/response-routing.ts +1 -1
- package/src/runner-core.ts +209 -222
- package/src/runner-exit.ts +1 -1
- package/src/runner-helpers.ts +10 -10
- package/src/runner-insights.ts +4 -2
- package/src/runner-mcp-proxy.ts +3 -3
- package/src/runner-spawn-config.ts +3 -3
- package/src/runtime-token-file.ts +1 -1
- package/src/runtime-token-remint.ts +1 -1
- package/src/service-access.ts +2 -2
- package/src/session-destroy.ts +1 -1
- package/src/session-insights.ts +1 -1
- package/src/session-scratch.ts +24 -37
- package/src/spawn-input.ts +6 -6
- package/src/startup-config-fetch.ts +4 -4
- package/src/subreaper.ts +3 -5
- package/src/test-run-dedup.ts +13 -13
- package/src/transcript-context.ts +2 -2
- package/src/transport-errors.ts +1 -1
- package/src/turn-opener.ts +1 -1
- package/src/turn-reconcile-event.ts +2 -2
- package/src/vault-proxy-hop.ts +2 -2
- package/src/web-tools.ts +2 -2
- package/agent-bin/agent-relay-browser +0 -10
- package/plugins/claude/skills/disconnect/SKILL.md +0 -16
- package/plugins/claude/skills/pair/SKILL.md +0 -30
- package/plugins/codex/skills/disconnect/SKILL.md +0 -15
- package/plugins/codex/skills/pair/SKILL.md +0 -29
- package/src/adapters/provider-quota-harvest.ts +0 -76
package/agent-bin/humwick
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/bin/sh
|
|
2
|
-
# Humwick
|
|
2
|
+
# Humwick: `humwick browser` from the release this agent's runner belongs to, never an older
|
|
3
3
|
# install a login shell puts first on PATH. Checkout: <root>/runner/agent-bin -> <root>/src;
|
|
4
4
|
# npm: node_modules/@humwick/runner/agent-bin -> node_modules/@humwick/server/src.
|
|
5
5
|
here=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd -P) || exit 1
|
|
6
6
|
for cli in "$here/../../src/index.ts" "$here/../../server/src/index.ts"; do
|
|
7
|
-
if [ -f "$cli" ]; then exec "${
|
|
7
|
+
if [ -f "$cli" ]; then exec "${HUMWICK_BUN_BIN:-bun}" run --no-env-file "$cli" "$@"; fi
|
|
8
8
|
done
|
|
9
9
|
echo "humwick: no CLI next to $here" >&2
|
|
10
10
|
exit 127
|
|
@@ -110,7 +110,7 @@ function classifyStandaloneSearch(command, cwd, root, words = candidateWords(com
|
|
|
110
110
|
return patterns > 1 ? "mcp__fff__multi_grep" : "mcp__fff__grep";
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
-
function fffBinary(env) { return env.
|
|
113
|
+
function fffBinary(env) { return env.HUMWICK_FFF_MCP_BINARY; }
|
|
114
114
|
|
|
115
115
|
function decide(payload, env = process.env, runGit = spawnSync) {
|
|
116
116
|
try {
|
|
@@ -23,12 +23,12 @@ const REDIRECTS = {
|
|
|
23
23
|
const MAX_REMEMBERED = 100;
|
|
24
24
|
|
|
25
25
|
function enabledTools(env) {
|
|
26
|
-
return new Set(String(env.
|
|
26
|
+
return new Set(String(env.HUMWICK_WEB_TOOLS ?? "").split(",").map((part) => part.trim()).filter(Boolean));
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
function stateFile(env, sessionId) {
|
|
30
30
|
const safe = typeof sessionId !== "string" ? "" : sessionId.replace(/[^A-Za-z0-9_-]/g, "").slice(0, 80);
|
|
31
|
-
return safe ? join(env.
|
|
31
|
+
return safe ? join((env.HUMWICK_SCRATCH_DIR) || tmpdir(), `web-tools-redirect-${safe}.json`) : null;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
function decide(payload, env = process.env) {
|
package/package.json
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@humwick/runner",
|
|
3
|
-
"version": "0.130.
|
|
3
|
+
"version": "0.130.6",
|
|
4
4
|
"description": "Unified provider lifecycle runner for Humwick",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
|
-
"claude-relay": "src/bin/claude.ts",
|
|
8
|
-
"codex-relay": "src/bin/codex.ts",
|
|
9
|
-
"opencode-relay": "src/bin/opencode.ts",
|
|
10
7
|
"claude-humwick": "src/bin/claude.ts",
|
|
11
8
|
"codex-humwick": "src/bin/codex.ts",
|
|
12
9
|
"opencode-humwick": "src/bin/opencode.ts"
|
|
@@ -21,18 +18,18 @@
|
|
|
21
18
|
"!hooks/**/*.test.ts",
|
|
22
19
|
"LICENSE"
|
|
23
20
|
],
|
|
24
|
-
"license": "
|
|
25
|
-
"author": "
|
|
21
|
+
"license": "AGPL-3.0-only",
|
|
22
|
+
"author": "Humwick contributors",
|
|
26
23
|
"repository": {
|
|
27
24
|
"type": "git",
|
|
28
|
-
"url": "git+https://github.com/
|
|
25
|
+
"url": "git+https://github.com/humwick/humwick.git",
|
|
29
26
|
"directory": "runner"
|
|
30
27
|
},
|
|
31
28
|
"dependencies": {
|
|
32
|
-
"@humwick/offload": "0.130.
|
|
33
|
-
"@humwick/providers": "0.104.
|
|
34
|
-
"@humwick/sdk": "0.2.
|
|
35
|
-
"callmux": "0.
|
|
29
|
+
"@humwick/offload": "0.130.6",
|
|
30
|
+
"@humwick/providers": "0.104.12",
|
|
31
|
+
"@humwick/sdk": "0.2.141",
|
|
32
|
+
"callmux": "0.27.0",
|
|
36
33
|
"unbash": "6.0.0"
|
|
37
34
|
},
|
|
38
35
|
"devDependencies": {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: playwright-cli
|
|
3
3
|
description: Drive Relay browsers; live dashboard.
|
|
4
|
-
allowed-tools: Bash(
|
|
4
|
+
allowed-tools: Bash(humwick-browser:*) Bash(playwright-cli:*)
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Browser sessions with playwright-cli
|
|
@@ -13,14 +13,14 @@ Never install a browser or run `playwright-cli open`.
|
|
|
13
13
|
## Start, attach, stop
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
|
-
|
|
16
|
+
humwick-browser start --json # prints sessionId, cdpUrl, viewUrl
|
|
17
17
|
playwright-cli attach --cdp=<cdpUrl> --session=relay
|
|
18
18
|
playwright-cli -s=relay goto http://localhost:3000
|
|
19
19
|
# ... work ...
|
|
20
|
-
|
|
20
|
+
humwick-browser stop # ends the session and deletes its profile
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
-
- One session per agent. `
|
|
23
|
+
- One session per agent. `humwick-browser status` shows yours.
|
|
24
24
|
- Send `viewUrl` to the operator when they should watch ("look at this").
|
|
25
25
|
- The profile is fresh each session: no logins or cookies carry over.
|
|
26
26
|
|
|
@@ -37,13 +37,15 @@ playwright-cli -s=relay hover e4; playwright-cli -s=relay upload ./file.pdf
|
|
|
37
37
|
playwright-cli -s=relay go-back; playwright-cli -s=relay reload
|
|
38
38
|
playwright-cli -s=relay eval "document.title"
|
|
39
39
|
playwright-cli -s=relay eval "el => el.getAttribute('data-testid')" e5
|
|
40
|
-
playwright-cli -s=relay screenshot --filename=page.png
|
|
40
|
+
playwright-cli -s=relay screenshot --filename="$TMPDIR/page.png"
|
|
41
41
|
playwright-cli -s=relay tab-list; playwright-cli -s=relay tab-new http://localhost:3000/b
|
|
42
42
|
playwright-cli -s=relay console; playwright-cli -s=relay requests
|
|
43
43
|
playwright-cli -s=relay resize 1280 800
|
|
44
44
|
```
|
|
45
45
|
|
|
46
|
-
Snapshots go to `.playwright-cli/` in the working directory
|
|
46
|
+
Snapshots go to `.playwright-cli/` in the working directory (locally git-ignored by Relay).
|
|
47
|
+
Write screenshots, traces, downloads and other scratch output under `$TMPDIR`;
|
|
48
|
+
read only what you need.
|
|
47
49
|
Refs change after the page changes: take a new snapshot before acting on old refs.
|
|
48
50
|
|
|
49
51
|
## More
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
|
-
"name": "
|
|
2
|
+
"name": "humwick-runner",
|
|
3
3
|
"description": "Thin Humwick runner bridge for Claude Code",
|
|
4
|
-
"version": "0.130.
|
|
5
|
-
"
|
|
4
|
+
"version": "0.130.6",
|
|
5
|
+
"humwickContracts": {
|
|
6
6
|
"providerPluginProtocol": 1
|
|
7
7
|
}
|
|
8
8
|
}
|
|
@@ -5,24 +5,33 @@ const { mkdirSync, renameSync, writeFileSync } = require("node:fs");
|
|
|
5
5
|
const { tmpdir } = require("node:os");
|
|
6
6
|
const { basename, dirname, join } = require("node:path");
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
process.stdin.
|
|
11
|
-
process.stdin.on("
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
8
|
+
if (require.main === module) {
|
|
9
|
+
let input = "";
|
|
10
|
+
process.stdin.setEncoding("utf8");
|
|
11
|
+
process.stdin.on("data", (chunk) => { input += chunk; });
|
|
12
|
+
process.stdin.on("end", () => {
|
|
13
|
+
process.stdout.write(`${runStatuslineProbe(input).output}\n`);
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function runStatuslineProbe(raw, options) {
|
|
18
|
+
const opts = options || {};
|
|
19
|
+
const metrics = parseClaudeStatusLineInput(raw, opts.now === undefined ? Date.now() : opts.now, opts.agentId);
|
|
20
|
+
if (metrics) writeState(metrics, opts.stateDir || statuslineStateDir());
|
|
21
|
+
return { metrics, output: standaloneOutput(metrics) };
|
|
22
|
+
}
|
|
16
23
|
|
|
17
24
|
function statuslineAgentId() {
|
|
18
|
-
return stringValue(process.env.
|
|
25
|
+
return stringValue(process.env.HUMWICK_AGENT_ID)
|
|
26
|
+
|| stringValue(process.env.HUMWICK_ID);
|
|
19
27
|
}
|
|
20
28
|
|
|
21
29
|
function statuslineStateDir() {
|
|
22
|
-
return process.env.
|
|
30
|
+
return (process.env.HUMWICK_CONTEXT_STATE_DIR)
|
|
31
|
+
|| (process.env.HUMWICK_HOST_TMPDIR) || tmpdir();
|
|
23
32
|
}
|
|
24
33
|
|
|
25
|
-
function parseClaudeStatusLineInput(raw) {
|
|
34
|
+
function parseClaudeStatusLineInput(raw, timestamp, agentId) {
|
|
26
35
|
let data;
|
|
27
36
|
try {
|
|
28
37
|
data = JSON.parse(raw);
|
|
@@ -31,7 +40,6 @@ function parseClaudeStatusLineInput(raw) {
|
|
|
31
40
|
}
|
|
32
41
|
if (!isRecord(data) || !isRecord(data.context_window)) return null;
|
|
33
42
|
const context = data.context_window;
|
|
34
|
-
const timestamp = Date.now();
|
|
35
43
|
const contextPercent = numberValue(context.used_percentage);
|
|
36
44
|
const tokensMax = numberValue(context.context_window_size);
|
|
37
45
|
const usage = isRecord(context.current_usage) ? context.current_usage : undefined;
|
|
@@ -50,7 +58,7 @@ function parseClaudeStatusLineInput(raw) {
|
|
|
50
58
|
const resolvedEffort = effort || stringValue(process.env.CLAUDE_EFFORT) || stringValue(process.env.CLAUDE_CODE_EFFORT_LEVEL);
|
|
51
59
|
|
|
52
60
|
const metrics = {
|
|
53
|
-
agentId: statuslineAgentId() || stringValue(data.session_id) || "unknown",
|
|
61
|
+
agentId: agentId || statuslineAgentId() || stringValue(data.session_id) || "unknown",
|
|
54
62
|
contextPercent: contextPercent !== undefined ? contextPercent : ((tokensUsed || 0) / (tokensMax || 1)) * 100,
|
|
55
63
|
source: "statusline",
|
|
56
64
|
confidence: "exact",
|
|
@@ -69,9 +77,8 @@ function parseClaudeStatusLineInput(raw) {
|
|
|
69
77
|
return metrics;
|
|
70
78
|
}
|
|
71
79
|
|
|
72
|
-
function writeState(metrics) {
|
|
73
|
-
// The runner reads this from the host temp root, not this agent's private TMPDIR
|
|
74
|
-
const dir = statuslineStateDir();
|
|
80
|
+
function writeState(metrics, dir) {
|
|
81
|
+
// The runner reads this from the host temp root, not this agent's private TMPDIR.
|
|
75
82
|
const file = join(dir, `agent-relay-context-${safeStateId(metrics.agentId)}.json`);
|
|
76
83
|
mkdirSync(dirname(file), { recursive: true });
|
|
77
84
|
const tmp = `${file}.${process.pid}.tmp`;
|
|
@@ -79,6 +86,7 @@ function writeState(metrics) {
|
|
|
79
86
|
renameSync(tmp, file);
|
|
80
87
|
}
|
|
81
88
|
|
|
89
|
+
|
|
82
90
|
function quotaWindowsFromRateLimits(rateLimits) {
|
|
83
91
|
const windows = [];
|
|
84
92
|
for (const name of ["five_hour", "seven_day", "seven_day_sonnet", "seven_day_opus"]) {
|
|
@@ -142,3 +150,5 @@ function secondsUntil(epochSeconds, nowMs) {
|
|
|
142
150
|
function epochSecondsToMs(epochSeconds) {
|
|
143
151
|
return epochSeconds === undefined ? undefined : epochSeconds * 1000;
|
|
144
152
|
}
|
|
153
|
+
|
|
154
|
+
module.exports = { runStatuslineProbe };
|
|
@@ -260,19 +260,27 @@ function classifyGateRun(command, commands = {}) {
|
|
|
260
260
|
return null;
|
|
261
261
|
}
|
|
262
262
|
|
|
263
|
-
// sdk/src/
|
|
264
|
-
var
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
263
|
+
// sdk/src/project-config.ts
|
|
264
|
+
var PROJECT_CONFIG_DIR = ".humwick";
|
|
265
|
+
var LEGACY_PROJECT_CONFIG_DIR = ".agent-relay";
|
|
266
|
+
var warnedProjects = new Set;
|
|
267
|
+
function selectProjectConfigDir(project, canonical, legacy) {
|
|
268
|
+
if (project && legacy && !warnedProjects.has(project)) {
|
|
269
|
+
warnedProjects.add(project);
|
|
270
|
+
console.warn(`[project-config] ${project}: ${canonical ? `${PROJECT_CONFIG_DIR}/ wins over deprecated ${LEGACY_PROJECT_CONFIG_DIR}/` : `reading deprecated ${LEGACY_PROJECT_CONFIG_DIR}/`}; migrate with humwick project migrate-config in that checkout`);
|
|
271
|
+
}
|
|
272
|
+
return canonical || !legacy ? PROJECT_CONFIG_DIR : LEGACY_PROJECT_CONFIG_DIR;
|
|
273
|
+
}
|
|
274
|
+
function isProjectConfigPath(path) {
|
|
275
|
+
return [PROJECT_CONFIG_DIR, LEGACY_PROJECT_CONFIG_DIR].some((dir) => path === dir || path.startsWith(`${dir}/`));
|
|
276
|
+
}
|
|
277
|
+
function projectConfigPathIn(path, directory) {
|
|
278
|
+
return isProjectConfigPath(path) ? directory + path.slice(path.indexOf("/") < 0 ? path.length : path.indexOf("/")) : path;
|
|
272
279
|
}
|
|
273
280
|
|
|
274
|
-
// sdk/src/
|
|
275
|
-
|
|
281
|
+
// sdk/src/repo-config-file.ts
|
|
282
|
+
import { dirname, resolve as resolve2 } from "path";
|
|
283
|
+
import { readFileSync, existsSync, mkdirSync, appendFileSync } from "fs";
|
|
276
284
|
|
|
277
285
|
// sdk/src/validation-core.ts
|
|
278
286
|
import { isAbsolute, relative, resolve } from "path";
|
|
@@ -321,9 +329,12 @@ function assertNoControlBytes(text, field) {
|
|
|
321
329
|
throw new ValidationError(`${field} must not contain control bytes (only newline and tab are allowed)`);
|
|
322
330
|
}
|
|
323
331
|
|
|
332
|
+
// sdk/src/types/guards.ts
|
|
333
|
+
function isRecord(value) {
|
|
334
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
335
|
+
}
|
|
336
|
+
|
|
324
337
|
// sdk/src/repo-config-file.ts
|
|
325
|
-
import { dirname, resolve as resolve2 } from "path";
|
|
326
|
-
import { readFileSync } from "fs";
|
|
327
338
|
function absent(err) {
|
|
328
339
|
const code = err.code;
|
|
329
340
|
if (code === "ENOENT" || code === "ENOTDIR")
|
|
@@ -347,7 +358,7 @@ function findRepoConfigFile(startDir, file, clean) {
|
|
|
347
358
|
for (const dir of ancestors(startDir)) {
|
|
348
359
|
let raw;
|
|
349
360
|
try {
|
|
350
|
-
raw = readFileSync(resolve2(dir, file), "utf8");
|
|
361
|
+
raw = readFileSync(resolve2(dir, resolveRepoConfigPath(dir, file)), "utf8");
|
|
351
362
|
} catch (err) {
|
|
352
363
|
raw = absent(err);
|
|
353
364
|
}
|
|
@@ -356,9 +367,28 @@ function findRepoConfigFile(startDir, file, clean) {
|
|
|
356
367
|
}
|
|
357
368
|
return null;
|
|
358
369
|
}
|
|
370
|
+
function resolveRepoConfigPath(root, file) {
|
|
371
|
+
if (!isProjectConfigPath(file))
|
|
372
|
+
return file;
|
|
373
|
+
const canonical = existsSync(resolve2(root, PROJECT_CONFIG_DIR));
|
|
374
|
+
const legacy = existsSync(resolve2(root, LEGACY_PROJECT_CONFIG_DIR));
|
|
375
|
+
const actual = projectConfigPathIn(file, selectProjectConfigDir(undefined, canonical, legacy));
|
|
376
|
+
if (existsSync(resolve2(root, actual)))
|
|
377
|
+
selectProjectConfigDir(resolve2(root), canonical, legacy);
|
|
378
|
+
return actual;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// sdk/src/types/host.ts
|
|
382
|
+
var HOST_GATE_KINDS = ["land", "iterate", "validation"];
|
|
383
|
+
|
|
384
|
+
// sdk/src/land-gates.ts
|
|
385
|
+
import { isAbsolute as isAbsolute2, relative as relative2, resolve as resolve3 } from "path";
|
|
386
|
+
|
|
387
|
+
// sdk/src/types/land-gates.ts
|
|
388
|
+
var LAND_GATE_SCOPES = ["full", "partial"];
|
|
359
389
|
|
|
360
390
|
// sdk/src/land-gates.ts
|
|
361
|
-
var LAND_GATES_FILE = ".
|
|
391
|
+
var LAND_GATES_FILE = ".humwick/land-gates.json";
|
|
362
392
|
var DEFAULT_LAND_GATE_TIMEOUT_MS = 5 * 60 * 1000;
|
|
363
393
|
var LAND_GATE_TIMEOUT_MARGIN_MS = 5 * 60 * 1000;
|
|
364
394
|
function cleanLandGate(value, index, worktreePath) {
|
|
@@ -681,7 +711,7 @@ function waitLoopDenial(command) {
|
|
|
681
711
|
for (let depth = 0;depth <= MAX_UNWRAP_DEPTH && candidate !== undefined; depth += 1) {
|
|
682
712
|
candidate = candidate.replace(TIMEOUT_PREFIX, "");
|
|
683
713
|
if (isForegroundWait(lexCommandLine(candidate))) {
|
|
684
|
-
return "Do not hold the turn on a foreground wait. Run it with the
|
|
714
|
+
return "Do not hold the turn on a foreground wait. Run it with the humwick_run MCP tool (detach: true, waitMs: 0) as ONE poll loop with a deadline " + "(e.g. `end=$((SECONDS+1800)); until <check>; do [ $SECONDS -ge $end ] && exit 1; sleep 30; done`), then end your turn with no text; " + `Relay wakes you once when it finishes. Command: ${command}`;
|
|
685
715
|
}
|
|
686
716
|
candidate = executingShellScript(candidate) ?? unwrapGroupCommand(candidate);
|
|
687
717
|
}
|
|
@@ -922,7 +952,7 @@ function gateDenial(command, flat, cwd) {
|
|
|
922
952
|
return null;
|
|
923
953
|
if (leavesProject(normalized, cwd))
|
|
924
954
|
return null;
|
|
925
|
-
return `This is a project gate: run it with the
|
|
955
|
+
return `This is a project gate: run it with the humwick_run MCP tool (waitMs: 0), then end your turn; Relay wakes you once when it finishes. Command: ${command}`;
|
|
926
956
|
}
|
|
927
957
|
function decide(payload) {
|
|
928
958
|
const input = payload;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
-
# PreToolUse guard
|
|
2
|
+
# PreToolUse guard: steers project gate commands run via Bash/Monitor to humwick_run.
|
|
3
3
|
# FAIL-OPEN: the decision lives in gate-run-guard.ts (shared SDK gate classifier); every
|
|
4
4
|
# precondition miss here (not relay-managed, read-only, no bun) exits 0 with no output.
|
|
5
|
-
[ -n "${
|
|
6
|
-
[ "${
|
|
5
|
+
[ -n "${HUMWICK_RUNNER_PORT:-}" ] || exit 0
|
|
6
|
+
[ "${HUMWICK_APPROVAL:-}" != "read-only" ] || exit 0
|
|
7
7
|
command -v bun >/dev/null 2>&1 || exit 0
|
|
8
8
|
HOOK_DIR="${CLAUDE_PLUGIN_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}/hooks"
|
|
9
9
|
exec bun "${HOOK_DIR}/gate-run-guard.ts" 2>/dev/null || exit 0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
// PreToolUse guard
|
|
1
|
+
// PreToolUse guard: a Bash/Monitor call that runs one of THIS project's own gates
|
|
2
2
|
// (`iterate`, `delivery`, `gates[].command` in the session repo's land-gates.json) is denied with
|
|
3
|
-
// a steer to `
|
|
3
|
+
// a steer to `humwick_run`. FAIL-OPEN: any doubt or error prints nothing and exits 0. Bundled to a
|
|
4
4
|
// dependency-free .mjs for provisioned copies (scripts/build-claude-monitor.ts).
|
|
5
5
|
import { resolve } from "node:path";
|
|
6
6
|
import { classifyGateRun, lexCommandLine, unwrapGroupCommand, unwrapShellCommand } from "@humwick/sdk/gate-run-classify";
|
|
@@ -185,7 +185,7 @@ function dropShellOptionOperands(command: string): string {
|
|
|
185
185
|
return command.slice(0, regionStart) + kept + rest;
|
|
186
186
|
}
|
|
187
187
|
|
|
188
|
-
//
|
|
188
|
+
// fail-opens, hook only: the shared classifier is unchanged (heavy-lease callers keep
|
|
189
189
|
// its conservative join/short-circuit behavior). Each layer is checked, so wrapped forms
|
|
190
190
|
// (`bash -lc 'false && gate'`, `bash -lc 'env --help gate'`) fail open through the wrapper.
|
|
191
191
|
function failOpenForContrivedForm(flat: string): boolean {
|
|
@@ -212,7 +212,7 @@ function gateDenial(command: string, flat: string, cwd: string): string | null {
|
|
|
212
212
|
const category = classifyGateRun(normalized, commands);
|
|
213
213
|
if (!category || category === "heuristic") return null;
|
|
214
214
|
if (leavesProject(normalized, cwd)) return null;
|
|
215
|
-
return `This is a project gate: run it with the
|
|
215
|
+
return `This is a project gate: run it with the humwick_run MCP tool (waitMs: 0), then end your turn; Relay wakes you once when it finishes. Command: ${command}`;
|
|
216
216
|
}
|
|
217
217
|
|
|
218
218
|
function decide(payload: unknown): string | null {
|
|
@@ -223,7 +223,7 @@ function decide(payload: unknown): string | null {
|
|
|
223
223
|
const cwd = typeof input.cwd === "string" && input.cwd ? input.cwd : process.cwd();
|
|
224
224
|
const flat = trustedFlatCommand(command);
|
|
225
225
|
const gate = flat === null ? null : gateDenial(command, flat, cwd);
|
|
226
|
-
// A harness-backgrounded Bash already returns the turn, so only foreground waits are redirected
|
|
226
|
+
// A harness-backgrounded Bash already returns the turn, so only foreground waits are redirected.
|
|
227
227
|
return gate ?? (input.tool_input?.run_in_background === true ? null : waitLoopDenial(command));
|
|
228
228
|
}
|
|
229
229
|
|
|
@@ -6739,7 +6739,7 @@ var DYNAMIC = new Set(["eval", "source", ".", "trap", "python", "python2", "pyth
|
|
|
6739
6739
|
var PLAIN_READERS = new Set(["cat", "tee", "head", "tail", "wc", "tr", "cut", "nl", "rev", "tac", "fold", "base64", "od", "md5sum", "sha256sum", "grep", "egrep", "fgrep", "jq", "echo", "printf", "true"]);
|
|
6740
6740
|
var GIT_BODY_COMMANDS = new Set(["commit", "tag", "notes"]);
|
|
6741
6741
|
var GH_BODY_COMMANDS = new Set(["issue create", "issue comment", "issue edit", "pr create", "pr comment", "pr edit", "pr review", "release create", "release edit", "gist create"]);
|
|
6742
|
-
var RELAY_BODY_COMMANDS = new Set(["message", "/message", "reply", "/reply"
|
|
6742
|
+
var RELAY_BODY_COMMANDS = new Set(["message", "/message", "reply", "/reply"]);
|
|
6743
6743
|
var STDIN_PATHS = new Set(["/dev/stdin", "/dev/fd/0", "/proc/self/fd/0"]);
|
|
6744
6744
|
var REDEFINERS = new Set(["alias", "shopt", "enable", "hash"]);
|
|
6745
6745
|
var ASSIGNMENT = /^[A-Za-z_][A-Za-z0-9_]*=/;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
-
# Shared "fleet fratricide" kill-pattern guard
|
|
2
|
+
# Shared "fleet fratricide" kill-pattern guard.
|
|
3
3
|
#
|
|
4
4
|
# Every managed agent's runner runs as
|
|
5
5
|
# bun run .../agent-relay-runner/src/index.ts <provider> ... (scoped install: .../@humwick/runner/...)
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
# kill "$SERVER_PID") and pkill -f on a token that is unique to the caller's own
|
|
14
14
|
# throwaway server (its exact test port, or "$PWD/public").
|
|
15
15
|
#
|
|
16
|
-
# Layers
|
|
16
|
+
# Layers: when neither the segment matcher below nor a raw kill-verb +
|
|
17
17
|
# fleet-token check fires, the command passes without starting a process.
|
|
18
18
|
# Otherwise kill-guard.ts parses it and answers block (an executed broad kill, e.g.
|
|
19
19
|
# behind sudo or bash -c), static (no dynamic execution, so a kill word in an
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
# the command is a dangerous broad kill, and exits 1 (silent) when it is safe.
|
|
30
30
|
# This lets non-bash callers reuse the SAME matcher as a subprocess.
|
|
31
31
|
#
|
|
32
|
-
# TODO
|
|
32
|
+
# TODO: wire the Codex runner/exec layer to invoke this guard.
|
|
33
33
|
# Codex managed agents have no Claude PreToolUse hook, so the same broad pkill can
|
|
34
34
|
# still fratricide the fleet from a Codex session until that wiring lands. The
|
|
35
35
|
# matcher is intentionally factored here so the Codex side can call it directly
|
|
@@ -41,7 +41,7 @@ shopt -s extglob
|
|
|
41
41
|
case "${BASH_SOURCE[0]}" in */*) KILL_GUARD_PARSER="${BASH_SOURCE[0]%/*}/kill-guard.ts" ;; *) KILL_GUARD_PARSER=kill-guard.ts ;; esac
|
|
42
42
|
|
|
43
43
|
# Guidance returned on a block — tells the caller how to clean up safely instead.
|
|
44
|
-
FRATRICIDE_KILL_GUIDANCE='Blocked a broad process-kill (
|
|
44
|
+
FRATRICIDE_KILL_GUIDANCE='Blocked a broad process-kill (fleet-fratricide guard): this pattern would match sibling agents'\'' runners, because every managed agent runs "bun run.../agent-relay-runner/src/index.ts". Kill only a PID you own — capture it when you spawn the server (SERVER_PID=$!; kill "$SERVER_PID") — or pkill -f a token that is unique to your own process (your exact test port, or "$PWD/public"). Never pkill/killall on bun, node, src/index.ts, agent-relay, humwick, or their runner packages.'
|
|
45
45
|
# The segment matcher reads raw text, so it cannot tell a command from prose.
|
|
46
46
|
FRATRICIDE_PATTERN_GUIDANCE="${FRATRICIDE_KILL_GUIDANCE}"' If this command only MENTIONS a kill in prose (an issue body, a commit message, a heredoc), this guard cannot tell: write the text to a file with the Write tool and pass it by file (gh --body-file, git commit -F), or drop the fleet token from the prose.'
|
|
47
47
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Fleet-fratricide parser
|
|
1
|
+
// Fleet-fratricide parser. stdin: command text. stdout: `block:<command>` for an executed
|
|
2
2
|
// broad kill, `static` when nothing in the command executes text (so a kill word in an argument, heredoc
|
|
3
3
|
// or comment is prose), or `sink` when text may reach a dynamic executor and kill-guard.sh's segment
|
|
4
4
|
// matcher must decide. A non-zero exit means "parser unavailable". Bundled to kill-guard.provisioned.mjs.
|
|
@@ -17,7 +17,7 @@ const PLAIN_READERS = new Set(["cat", "tee", "head", "tail", "wc", "tr", "cut",
|
|
|
17
17
|
// (`git -c alias.x='!sh' x`, a gh alias or extension) may run the text.
|
|
18
18
|
const GIT_BODY_COMMANDS = new Set(["commit", "tag", "notes"]);
|
|
19
19
|
const GH_BODY_COMMANDS = new Set(["issue create", "issue comment", "issue edit", "pr create", "pr comment", "pr edit", "pr review", "release create", "release edit", "gist create"]);
|
|
20
|
-
const RELAY_BODY_COMMANDS = new Set(["message", "/message", "reply", "/reply"
|
|
20
|
+
const RELAY_BODY_COMMANDS = new Set(["message", "/message", "reply", "/reply"]);
|
|
21
21
|
const STDIN_PATHS = new Set(["/dev/stdin", "/dev/fd/0", "/proc/self/fd/0"]);
|
|
22
22
|
// Builtins that change what a later command name runs.
|
|
23
23
|
const REDEFINERS = new Set(["alias", "shopt", "enable", "hash"]);
|
|
@@ -3,7 +3,7 @@ set -euo pipefail
|
|
|
3
3
|
source "${CLAUDE_PLUGIN_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}/hooks/relay-status.sh"
|
|
4
4
|
relay_install_hook_guard permission-request
|
|
5
5
|
|
|
6
|
-
port="${
|
|
6
|
+
port="${HUMWICK_RUNNER_PORT:-}"
|
|
7
7
|
if [[ -z "$port" ]]; then
|
|
8
8
|
exit 0
|
|
9
9
|
fi
|
|
@@ -3,7 +3,7 @@ set -euo pipefail
|
|
|
3
3
|
source "${CLAUDE_PLUGIN_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}/hooks/relay-status.sh"
|
|
4
4
|
relay_install_hook_guard post-compact
|
|
5
5
|
|
|
6
|
-
#
|
|
6
|
+
# the trigger (manual for our /compact, auto for Claude's own) tells the runner which input settled.
|
|
7
7
|
trigger="$(relay_json_string_field trigger "$(cat || true)")"
|
|
8
8
|
metadata=""
|
|
9
9
|
[ -n "$trigger" ] && metadata="{\"compactTrigger\":\"$(relay_json_escape "$trigger")\"}"
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
set -euo pipefail
|
|
3
3
|
source "${CLAUDE_PLUGIN_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}/hooks/relay-status.sh"
|
|
4
4
|
relay_install_hook_guard post-tool-use
|
|
5
|
-
[ -n "${
|
|
6
|
-
#
|
|
7
|
-
context="$(relay_post_json "$
|
|
5
|
+
[ -n "${HUMWICK_RUNNER_PORT:-}" ] || exit 0
|
|
6
|
+
# stdout belongs to this tool result, before Claude can make its next call.
|
|
7
|
+
context="$(relay_post_json "${HUMWICK_RUNNER_PORT-}" /tool-use 4 || true)"
|
|
8
8
|
relay_emit_additional_context PostToolUse "$context"
|
|
@@ -7,6 +7,6 @@ payload="$(cat || true)"
|
|
|
7
7
|
transcript_path="$(relay_json_string_field transcript_path "$payload")"
|
|
8
8
|
|
|
9
9
|
relay_post_timeline_status busy provider-turn "" compacting
|
|
10
|
-
# Pre-destroy seam
|
|
11
|
-
# Insights
|
|
10
|
+
# Pre-destroy seam: compaction is about to discard context — capture this segment's
|
|
11
|
+
# Insights from the full transcript first. The most common boundary in practice.
|
|
12
12
|
relay_post_session_boundary "$transcript_path" compact
|
|
@@ -7,7 +7,7 @@ set -euo pipefail
|
|
|
7
7
|
HOOK_DIR="${CLAUDE_PLUGIN_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}/hooks"
|
|
8
8
|
source "${HOOK_DIR}/relay-status.sh"
|
|
9
9
|
relay_install_hook_guard read-only-bash-guard
|
|
10
|
-
# Shared fleet-fratricide kill-pattern matcher
|
|
10
|
+
# Shared fleet-fratricide kill-pattern matcher: trim_shell_text,
|
|
11
11
|
# split_segments, shell_words and fratricide_deny_reason live here.
|
|
12
12
|
source "${HOOK_DIR}/kill-guard.sh"
|
|
13
13
|
|
|
@@ -32,7 +32,7 @@ if command -v jq >/dev/null 2>&1; then
|
|
|
32
32
|
command_text="$(printf '%s' "$payload" | jq -r '.tool_input.command // empty' 2>/dev/null || true)"
|
|
33
33
|
fi
|
|
34
34
|
|
|
35
|
-
# --- Fleet-fratricide guard: ACTIVE IN ALL APPROVAL MODES
|
|
35
|
+
# --- Fleet-fratricide guard: ACTIVE IN ALL APPROVAL MODES ---
|
|
36
36
|
# A broad pkill/killall/kill can SIGTERM every sibling agent's runner host-wide,
|
|
37
37
|
# so this block runs before (and independent of) the read-only allow-list.
|
|
38
38
|
if (( jq_available )); then
|
|
@@ -51,7 +51,7 @@ else
|
|
|
51
51
|
fi
|
|
52
52
|
|
|
53
53
|
# --- Read-only allow-list: only the read-only approval mode below this point ---
|
|
54
|
-
case "${
|
|
54
|
+
case "${HUMWICK_APPROVAL:-}" in
|
|
55
55
|
open|guarded)
|
|
56
56
|
exit 0
|
|
57
57
|
;;
|
|
@@ -556,7 +556,7 @@ validate_segment() {
|
|
|
556
556
|
validate_bun "$((i + 1))"
|
|
557
557
|
return $?
|
|
558
558
|
;;
|
|
559
|
-
agent-relay)
|
|
559
|
+
humwick|agent-relay)
|
|
560
560
|
validate_agent_relay "$((i + 1))"
|
|
561
561
|
return $?
|
|
562
562
|
;;
|