@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 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. The hook stops waiting after 9 minutes by default, under Claude Code's 600-second hook timeout, because a hook that times out does not block.
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 MAX_WAIT_MS = 57e4;
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(env.GUARDIAN_HOOK_APPROVAL_TIMEOUT_MS ?? 54e4);
351
- const approvalTimeoutMs = Number.isFinite(requested) ? Math.min(Math.max(requested, 0), MAX_WAIT_MS) : 54e4;
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.0",
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.0"
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": "^3.2.4"
31
+ "vitest": "^5.1.0"
32
32
  },
33
33
  "publishConfig": {
34
34
  "access": "public"