@odingard/guardian-hook 0.1.0 → 0.1.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/README.md +1 -1
- package/dist/index.js +10 -4
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -16,7 +16,7 @@ There is no model in the decision: Guardian decides ALLOW / ASK / DENY determini
|
|
|
16
16
|
| **ASK** | The agent waits. You get the request on your phone or in the console. On approval the hook claims and redeems the capability, then the call runs. It is never auto-approved. |
|
|
17
17
|
| **DENY** | The agent is told no, with the reason. Nothing runs. |
|
|
18
18
|
|
|
19
|
-
**Fail closed.** If Guardian can't be reached, the configuration is wrong, approval times out or redemption fails, the call is denied.
|
|
19
|
+
**Fail closed.** If Guardian can't be reached, the configuration is wrong, approval times out or redemption fails, the call is denied. Each request stays open for 5 minutes (Guardian's limit), and the hook waits that long for an approval, under Claude Code's 600-second hook timeout, because a hook that times out does not block. An ASK not approved within 5 minutes expires; the call is denied and the agent can ask again.
|
|
20
20
|
|
|
21
21
|
## Tools the hook proposes
|
|
22
22
|
|
package/dist/index.js
CHANGED
|
@@ -179,7 +179,8 @@ async function decide(call, options) {
|
|
|
179
179
|
connectionId: options.connectionId,
|
|
180
180
|
toolName: call.toolName,
|
|
181
181
|
arguments: call.arguments,
|
|
182
|
-
purpose: `${options.agentName}: ${call.summary}
|
|
182
|
+
purpose: `${options.agentName}: ${call.summary}`,
|
|
183
|
+
...options.requestTtlMs !== void 0 ? { ttlMs: options.requestTtlMs } : {}
|
|
183
184
|
});
|
|
184
185
|
} catch {
|
|
185
186
|
return denied(call, "SERVICE_UNAVAILABLE");
|
|
@@ -255,7 +256,8 @@ async function decide(call, options) {
|
|
|
255
256
|
|
|
256
257
|
// src/index.ts
|
|
257
258
|
var DEFAULT_BASE_URL = "https://guardian-api.odingard.com";
|
|
258
|
-
var
|
|
259
|
+
var REQUEST_TTL_MS = 3e5;
|
|
260
|
+
var MAX_WAIT_MS = REQUEST_TTL_MS;
|
|
259
261
|
function claudeCodeOutput(verdict) {
|
|
260
262
|
return JSON.stringify({
|
|
261
263
|
hookSpecificOutput: {
|
|
@@ -347,8 +349,10 @@ async function runHook(stdin, env, deps = {}) {
|
|
|
347
349
|
if (!deps.client && !baseUrl.startsWith("https://")) {
|
|
348
350
|
return failClosed("GUARDIAN_BASE_URL must be https. Nothing ran.");
|
|
349
351
|
}
|
|
350
|
-
const requested = Number(
|
|
351
|
-
|
|
352
|
+
const requested = Number(
|
|
353
|
+
env.GUARDIAN_HOOK_APPROVAL_TIMEOUT_MS ?? MAX_WAIT_MS
|
|
354
|
+
);
|
|
355
|
+
const approvalTimeoutMs = Number.isFinite(requested) ? Math.min(Math.max(requested, 0), MAX_WAIT_MS) : MAX_WAIT_MS;
|
|
352
356
|
const verdict = await decide(call, {
|
|
353
357
|
client: deps.client ?? createGuardianClient({
|
|
354
358
|
baseUrl,
|
|
@@ -358,6 +362,7 @@ async function runHook(stdin, env, deps = {}) {
|
|
|
358
362
|
connectionId: connectionId ?? "",
|
|
359
363
|
agentName: env.GUARDIAN_HOOK_AGENT_NAME?.trim() || "Claude Code",
|
|
360
364
|
approvalTimeoutMs,
|
|
365
|
+
requestTtlMs: REQUEST_TTL_MS,
|
|
361
366
|
pollIntervalMs: 2e3,
|
|
362
367
|
...deps.wait ? { wait: deps.wait } : {},
|
|
363
368
|
...deps.now ? { now: deps.now } : {},
|
|
@@ -405,6 +410,7 @@ if (invokedDirectly) {
|
|
|
405
410
|
export {
|
|
406
411
|
DEFAULT_BASE_URL,
|
|
407
412
|
MAX_WAIT_MS,
|
|
413
|
+
REQUEST_TTL_MS,
|
|
408
414
|
SETTINGS_SNIPPET,
|
|
409
415
|
claudeCodeOutput,
|
|
410
416
|
connectionFor,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@odingard/guardian-hook",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Guardian for coding agents: a Claude Code PreToolUse hook that sends shell commands, file writes and MCP calls to Guardian for a deterministic ALLOW/ASK/DENY decision. Deploys and destructive commands wait for a human approval on your phone; every allowed call carries a verifiable receipt.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -22,13 +22,13 @@
|
|
|
22
22
|
"prepublishOnly": "npm run build && npm test"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@odingard/guardian-sdk": "^0.3.
|
|
25
|
+
"@odingard/guardian-sdk": "^0.3.5"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"@types/node": "^22",
|
|
29
29
|
"esbuild": "^0.28.2",
|
|
30
30
|
"typescript": "^5.9.3",
|
|
31
|
-
"vitest": "^
|
|
31
|
+
"vitest": "^5.1.0"
|
|
32
32
|
},
|
|
33
33
|
"publishConfig": {
|
|
34
34
|
"access": "public"
|