@agentwares/agentguard 0.1.6 → 0.1.9
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/CHANGELOG.md +89 -0
- package/README.md +223 -16
- package/dist/audit-2YCMHMCP.js +17 -0
- package/dist/audit-2YCMHMCP.js.map +1 -0
- package/dist/chunk-3O6KWT3E.js +345 -0
- package/dist/chunk-3O6KWT3E.js.map +1 -0
- package/dist/chunk-5WRI5ZAA.js +31 -0
- package/dist/chunk-5WRI5ZAA.js.map +1 -0
- package/dist/chunk-6S7LYVOC.js +1033 -0
- package/dist/chunk-6S7LYVOC.js.map +1 -0
- package/dist/chunk-6TUQD666.js +828 -0
- package/dist/chunk-6TUQD666.js.map +1 -0
- package/dist/chunk-BKXXTWIS.js +119 -0
- package/dist/chunk-BKXXTWIS.js.map +1 -0
- package/dist/chunk-D66U3PVB.js +529 -0
- package/dist/chunk-D66U3PVB.js.map +1 -0
- package/dist/chunk-HPYZ3JDX.js +206 -0
- package/dist/chunk-HPYZ3JDX.js.map +1 -0
- package/dist/chunk-KRKZGAJ3.js +769 -0
- package/dist/chunk-KRKZGAJ3.js.map +1 -0
- package/dist/chunk-SUXQTT3X.js +1268 -0
- package/dist/chunk-SUXQTT3X.js.map +1 -0
- package/dist/chunk-TW5KJREH.js +190 -0
- package/dist/chunk-TW5KJREH.js.map +1 -0
- package/dist/chunk-VQWQ5TOM.js +113 -0
- package/dist/chunk-VQWQ5TOM.js.map +1 -0
- package/dist/chunk-X4M7YWQA.js +270 -0
- package/dist/chunk-X4M7YWQA.js.map +1 -0
- package/dist/chunk-ZSLWPKXI.js +1144 -0
- package/dist/chunk-ZSLWPKXI.js.map +1 -0
- package/dist/cli.js +8 -4725
- package/dist/cli.js.map +1 -1
- package/dist/fixtures/crm-server.js +6 -1272
- package/dist/fixtures/crm-server.js.map +1 -1
- package/dist/fixtures/demo-agent.js +4 -115
- package/dist/fixtures/demo-agent.js.map +1 -1
- package/dist/index.d.ts +76 -10
- package/dist/index.js +246 -5087
- package/dist/index.js.map +1 -1
- package/dist/init-CWROGV5I.js +15 -0
- package/dist/init-CWROGV5I.js.map +1 -0
- package/dist/proxy-3Z5YEZ4R.js +154 -0
- package/dist/proxy-3Z5YEZ4R.js.map +1 -0
- package/dist/tools-3LLDG3XQ.js +15 -0
- package/dist/tools-3LLDG3XQ.js.map +1 -0
- package/llms.txt +4 -0
- package/package.json +9 -3
- package/server.json +2 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/connect.ts","../src/commands/control.ts","../src/commands/hook.ts","../src/hooks/transcript-file.ts","../src/commands/keys.ts","../src/commands/permission-diff.ts","../src/commands/report.ts","../src/cli.ts"],"sourcesContent":["/**\n * `agentguard connect <key>` — point this machine's MCP client at a hosted agentguard proxy.\n *\n * The OSS CLI enforces policy locally and needs no account. The hosted tiers move that\n * enforcement server-side, so \"connecting\" is not an install: it is resolving a key to the\n * customer's own proxy URL and writing one remote MCP server into the client config.\n *\n * Everything the command prints comes from the server, so the CLI never has to know the\n * shape of a proxy id, a band, or the URL scheme — it stays correct when those change.\n */\nimport { existsSync } from \"node:fs\";\nimport { relative } from \"node:path\";\nimport { flagBool, flagString, type ParsedArgs } from \"../args.js\";\nimport {\n describeConfigPath,\n detectClientConfigs,\n isGeminiConfig,\n mergeServerIntoConfig,\n PROXY_SERVER_NAME,\n type ClientConfigFile,\n type ServerEntry,\n} from \"../configs.js\";\nimport { homeFrom, type Io } from \"../context.js\";\n\nexport const DEFAULT_PROXY_URL = \"https://agentwares-agentguard-proxy.vercel.app\";\n\n/** What POST /connect answers with. Optional fields are tolerated so an older CLI still works. */\ninterface ConnectResponse {\n proxyId: string;\n slug: string;\n mode: string;\n mcpUrl: string;\n headers: Record<string, string>;\n upstreams?: string[];\n band?: { tier: string; quantity: number };\n dashboardUrl?: string;\n mcpServers: Record<string, ServerEntry>;\n claudeCode?: string;\n}\n\ninterface StructuredError {\n code: string;\n cause: string;\n fix?: string;\n retryable?: boolean;\n}\n\nfunction fail(e: StructuredError): never {\n throw e;\n}\n\nexport async function connectCommand(\n args: ParsedArgs,\n io: Io,\n fetchImpl: typeof fetch = fetch,\n): Promise<number> {\n const key = args.positionals[0] ?? io.env.AGENTGUARD_KEY;\n if (!key) {\n io.err(\"usage: agentguard connect <key> [--write] [--client <path>] [--url <proxy-url>]\");\n io.err(\" the key is on your dashboard; it starts with agk_\");\n return 2;\n }\n\n const base = (\n flagString(args, \"url\") ??\n io.env.AGENTGUARD_PROXY_URL ??\n DEFAULT_PROXY_URL\n ).replace(/\\/+$/, \"\");\n\n let res: Response;\n try {\n res = await fetchImpl(`${base}/connect`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({ key }),\n });\n } catch (err) {\n // A network failure is the one retryable case here; everything else is a bad key or a bad URL.\n fail({\n code: \"PROXY_UNREACHABLE\",\n cause: `could not reach ${base}: ${err instanceof Error ? err.message : String(err)}`,\n fix: \"check the network, or pass --url if you run your own proxy\",\n retryable: true,\n });\n }\n\n const text = await res.text();\n let body: unknown;\n try {\n body = JSON.parse(text);\n } catch {\n fail({\n code: \"PROXY_BAD_RESPONSE\",\n cause: `${base}/connect returned ${res.status} that was not JSON: ${text.slice(0, 200)}`,\n fix: \"check --url points at an agentguard proxy, not at the dashboard\",\n retryable: false,\n });\n }\n if (!res.ok) {\n const e = body as Partial<StructuredError>;\n fail({\n code: e.code ?? \"CONNECT_REFUSED\",\n cause: e.cause ?? `${base}/connect returned ${res.status}`,\n fix: e.fix ?? \"check the key on your dashboard; revoked keys stop working immediately\",\n retryable: e.retryable ?? false,\n });\n }\n const conn = body as ConnectResponse;\n\n if (flagBool(args, \"json\")) {\n io.out(JSON.stringify(conn, null, 2));\n return 0;\n }\n\n const rel = (p: string) => (p.startsWith(io.cwd + \"/\") ? relative(io.cwd, p) : p);\n const entry = conn.mcpServers[PROXY_SERVER_NAME] ?? {\n type: \"http\",\n url: conn.mcpUrl,\n headers: conn.headers,\n };\n\n if (!flagBool(args, \"write\")) {\n io.out(JSON.stringify({ mcpServers: { [PROXY_SERVER_NAME]: entry } }, null, 2));\n } else {\n const explicit = flagString(args, \"client\");\n const configs = explicit\n ? [describeConfigPath(explicit)]\n : detectClientConfigs(io.cwd, homeFrom(io), io.env);\n // Same rule as `init`: a user-level config affects every project on the machine, so it is\n // only written when named explicitly.\n const projectLevel = configs.filter((c) => c.path.startsWith(io.cwd + \"/\"));\n let chosen: ClientConfigFile[];\n if (explicit || flagBool(args, \"all\")) chosen = configs;\n else chosen = projectLevel.slice(0, 1);\n\n if (chosen.length === 0) {\n io.err(\n \"no MCP config found here (.mcp.json, .cursor/mcp.json, .vscode/mcp.json). Create one, or paste this into your client:\",\n );\n io.out(JSON.stringify({ mcpServers: { [PROXY_SERVER_NAME]: entry } }, null, 2));\n return 1;\n }\n for (const c of chosen) {\n if (!existsSync(c.path)) {\n io.err(`no MCP config at ${c.path}`);\n return 1;\n }\n // Gemini CLI takes Streamable HTTP as `httpUrl`; its `url` would be dialled as SSE.\n const forClient: ServerEntry = isGeminiConfig(c)\n ? { httpUrl: entry.url, ...(entry.headers ? { headers: entry.headers } : {}) }\n : entry;\n const { backup, replaced } = mergeServerIntoConfig(c, PROXY_SERVER_NAME, forClient);\n io.out(\n `${replaced ? \"updated\" : \"wrote \"} ${rel(c.path)} (${c.label}) → ${PROXY_SERVER_NAME} = ${conn.mcpUrl}`,\n );\n io.out(`backup ${rel(backup)}`);\n }\n for (const c of configs.filter((c) => !chosen.includes(c)))\n io.out(\n `found ${c.path} (${c.label}, user-level) — not touched; pass --client ${JSON.stringify(c.path)} to write it too`,\n );\n }\n\n const band = conn.band ? ` band=${conn.band.tier} (${conn.band.quantity} calls/mo)` : \"\";\n io.out(`\\nproxy ${conn.slug} (${conn.proxyId}) mode=${conn.mode}${band}`);\n if (conn.upstreams?.length) io.out(`upstreams: ${conn.upstreams.join(\", \")}`);\n if (conn.dashboardUrl) io.out(`dashboard: ${conn.dashboardUrl}`);\n if (conn.claudeCode) io.out(`claude code: ${conn.claudeCode}`);\n if (!flagBool(args, \"write\"))\n io.out(`\\nrun again with --write to add this to your MCP client config`);\n return 0;\n}\n","/**\n * `agentguard kill|resume|approve|deny|approvals` — the human side of the loop.\n */\nimport { flagBool, flagString, type ParsedArgs } from \"../args.js\";\nimport { createFileGuard, loadPolicyFor, readRegistration, type Io } from \"../context.js\";\n\nasync function pokeHttp(\n io: Io,\n reg: ReturnType<typeof readRegistration>,\n path: string,\n body?: unknown,\n): Promise<void> {\n if (!reg) return;\n try {\n const res = await fetch(`${reg.baseUrl}${path}`, {\n method: \"POST\",\n headers: { Authorization: `Bearer ${reg.token}`, \"Content-Type\": \"application/json\" },\n body: body === undefined ? undefined : JSON.stringify(body),\n signal: AbortSignal.timeout(2000),\n });\n if (!res.ok)\n io.err(\n `running proxy at ${reg.baseUrl} answered ${res.status} (the file switch still applies)`,\n );\n } catch {\n io.err(\n `no proxy answering at ${reg.baseUrl} (stale ${reg.pid}?) — the file switch still applies`,\n );\n }\n}\n\nexport async function killCommand(args: ParsedArgs, io: Io): Promise<number> {\n const loaded = loadPolicyFor(args, io, { allowMissingEnv: true });\n const { kill } = createFileGuard(loaded, { alerts: false, env: io.env });\n const reason =\n args.positionals.join(\" \") ||\n flagString(args, \"reason\") ||\n `agentguard kill by ${io.env.USER ?? \"operator\"}`;\n kill.kill(reason);\n await pokeHttp(io, readRegistration(loaded), \"/kill\", { reason });\n io.out(\n `KILLED: ${kill.path} written — every tool call through this policy now returns KILLED. Clear with: agentguard resume`,\n );\n return 0;\n}\n\nexport async function resumeCommand(args: ParsedArgs, io: Io): Promise<number> {\n const loaded = loadPolicyFor(args, io, { allowMissingEnv: true });\n const { kill } = createFileGuard(loaded, { alerts: false, env: io.env });\n kill.resume();\n await pokeHttp(io, readRegistration(loaded), \"/resume\");\n io.out(`resumed: ${kill.path} removed`);\n if (io.env[loaded.policy.kill.env])\n io.err(\n `note: ${loaded.policy.kill.env} is set in this shell's environment; proxies started from it stay killed`,\n );\n return 0;\n}\n\nexport async function decideCommand(\n decision: \"approved\" | \"denied\",\n args: ParsedArgs,\n io: Io,\n): Promise<number> {\n const id = args.positionals[0];\n if (!id) {\n io.err(\n `usage: agentguard ${decision === \"approved\" ? \"approve\" : \"deny\"} <approval-id> [--by name] [--note text]`,\n );\n return 1;\n }\n const loaded = loadPolicyFor(args, io, { allowMissingEnv: true });\n const { guard } = createFileGuard(loaded, { alerts: false, env: io.env });\n const record = await guard.decide(\n id,\n decision,\n flagString(args, \"by\") ?? io.env.USER ?? \"cli\",\n flagString(args, \"note\"),\n );\n if (!record) {\n io.err(`no approval ${id} — pending ones: agentguard approvals`);\n return 1;\n }\n io.out(\n `${record.status}: ${record.tool} (${record.id}, run ${record.run_id})${record.status === \"approved\" ? \" — the agent may now retry the identical call once\" : \"\"}`,\n );\n return 0;\n}\n\nexport async function approvalsCommand(args: ParsedArgs, io: Io): Promise<number> {\n const loaded = loadPolicyFor(args, io, { allowMissingEnv: true });\n const { guard } = createFileGuard(loaded, { alerts: false, env: io.env });\n const list = await guard.approvals.list(flagBool(args, \"all\") ? undefined : \"pending\");\n if (flagBool(args, \"json\")) {\n io.out(JSON.stringify(list, null, 2));\n return 0;\n }\n if (list.length === 0) {\n io.out(flagBool(args, \"all\") ? \"no approvals recorded\" : \"no pending approvals\");\n return 0;\n }\n for (const r of list) {\n io.out(\n `${r.id} ${r.status.padEnd(9)} ${r.tool} run ${r.run_id}${r.agent ? ` agent ${r.agent}` : \"\"} expires ${r.expires_at}`,\n );\n io.out(` args: ${JSON.stringify(r.args).slice(0, 300)}`);\n if (r.status === \"pending\")\n io.out(` → agentguard approve ${r.id} | agentguard deny ${r.id}`);\n }\n return 0;\n}\n","/**\n * `agentguard hook pre-tool-use` — what a coding agent's pre-execution hook runs for each shell\n * command, file edit and MCP tool call: Claude Code `PreToolUse`, Codex `PreToolUse`, Gemini CLI\n * `BeforeTool`. Reads the harness's JSON on stdin and answers in that harness's format on\n * stdout (nothing else may go to stdout).\n *\n * - allow: no output, exit 0. The harness's own permission flow still applies; agentguard never\n * answers \"allow\", so it can only take permissions away.\n * - deny: Claude Code / Codex `hookSpecificOutput.permissionDecision: \"deny\"`, Gemini CLI\n * `decision: \"deny\"`, with the agentguard error body (`code`, `cause`, `fix`, `retryable`) as\n * the reason the model reads, and a one-line `systemMessage` for the person.\n * - dry-run would-have-stopped: a `systemMessage` only; the call runs.\n * - an error inside agentguard: a `systemMessage` saying the call was NOT checked, exit 0. A\n * broken policy file must not stop the agent; it must not pass silently either.\n */\nimport { existsSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { dirname, join, resolve } from \"node:path\";\nimport {\n assessHookAction,\n detectHookClient,\n hookActionFromInput,\n type HookClient,\n type PreflightResult,\n} from \"@agentwares/agentguard-core\";\nimport { flagString, type ParsedArgs } from \"../args.js\";\nimport {\n approvalUrlFor,\n createFileGuard,\n describeError,\n homeFrom,\n readRegistration,\n DEFAULT_POLICY_FILE,\n type Io,\n} from \"../context.js\";\nimport { CLIENT_ALIASES, hookSettingsFiles } from \"../hooks/clients.js\";\nimport { humanTurnFromTranscript } from \"../hooks/transcript-file.js\";\nimport { loadPolicyFile } from \"@agentwares/agentguard-core/node\";\n\nconst RUN_PREFIX: Record<HookClient, string> = {\n \"claude-code\": \"cc\",\n codex: \"codex\",\n \"gemini-cli\": \"gemini\",\n};\n\n/** Walk up from `start` to the filesystem root looking for agentguard.yaml. */\nfunction findPolicyUpwards(start: string): string | undefined {\n let dir = resolve(start);\n for (let i = 0; i < 64; i += 1) {\n const candidate = join(dir, DEFAULT_POLICY_FILE);\n if (existsSync(candidate)) return candidate;\n const parent = dirname(dir);\n if (parent === dir) return undefined;\n dir = parent;\n }\n return undefined;\n}\n\nfunction projectDir(io: Io, inputCwd: string | undefined): string | undefined {\n return io.env.CLAUDE_PROJECT_DIR || io.env.GEMINI_PROJECT_DIR || inputCwd || undefined;\n}\n\n/** --config → AGENTGUARD_CONFIG → agentguard.yaml at or above the project → --fallback-config. */\nexport function resolveHookPolicy(\n args: ParsedArgs,\n io: Io,\n inputCwd: string | undefined,\n): { path: string; found: \"flag\" | \"env\" | \"project\" | \"fallback\" } | undefined {\n const flag = flagString(args, \"config\");\n if (flag) return { path: resolve(io.cwd, flag), found: \"flag\" };\n if (io.env.AGENTGUARD_CONFIG)\n return { path: resolve(io.cwd, io.env.AGENTGUARD_CONFIG), found: \"env\" };\n const start = projectDir(io, inputCwd) ?? io.cwd;\n const near = findPolicyUpwards(start);\n if (near) return { path: near, found: \"project\" };\n const fallback = flagString(args, \"fallback-config\");\n if (fallback && existsSync(resolve(io.cwd, fallback)))\n return { path: resolve(io.cwd, fallback), found: \"fallback\" };\n return undefined;\n}\n\nfunction out(io: Io, value: unknown): void {\n io.out(JSON.stringify(value));\n}\n\n/** A systemMessage reaches the person in all three harnesses and changes no decision. */\nfunction warn(io: Io, message: string): void {\n out(io, { systemMessage: message });\n}\n\nfunction respond(\n io: Io,\n client: HookClient,\n result: PreflightResult,\n summary: string,\n approveCommand: (id: string) => string,\n): void {\n if (result.decision === \"deny\" && result.error) {\n const e = result.error;\n const reason = JSON.stringify(e);\n const id = result.approvalId ? `, approval ${result.approvalId}` : \"\";\n const approve =\n e.code === \"APPROVAL_REQUIRED\" && result.approvalId\n ? ` To let this exact command run once: ${approveCommand(result.approvalId)}`\n : \"\";\n const systemMessage = `agentguard refused \"${summary.slice(0, 120)}\" (${e.code}${id}): ${e.cause}${approve}`;\n if (client === \"gemini-cli\") out(io, { decision: \"deny\", reason, systemMessage });\n else\n out(io, {\n hookSpecificOutput: {\n hookEventName: \"PreToolUse\",\n permissionDecision: \"deny\",\n permissionDecisionReason: reason,\n },\n systemMessage,\n });\n return;\n }\n if (result.would) {\n out(io, {\n systemMessage: `agentguard (hooks.mode: dry-run) would have stopped \"${summary.slice(0, 120)}\" with ${result.would.code}: ${result.would.cause} — it ran; nothing is blocked until hooks.mode is enforce`,\n });\n }\n}\n\nexport async function hookCommand(args: ParsedArgs, io: Io): Promise<number> {\n const event = args.positionals[0];\n if (event !== \"pre-tool-use\") {\n io.err(\n \"usage: agentguard hook pre-tool-use [--client claude|codex|gemini] [--config agentguard.yaml] [--fallback-config path]\\n\" +\n \" run by a coding agent's pre-execution hook, with the hook's JSON on stdin; `agentguard hooks install` sets it up\",\n );\n return 1;\n }\n const flagClient = flagString(args, \"client\");\n let client: HookClient = (flagClient && CLIENT_ALIASES[flagClient]) || \"claude-code\";\n try {\n const raw = (await io.stdin?.()) ?? \"\";\n const input = JSON.parse(raw) as Record<string, unknown>;\n if (!flagClient) client = detectHookClient(input);\n const inputCwd = typeof input.cwd === \"string\" ? input.cwd : undefined;\n const policyRef = resolveHookPolicy(args, io, inputCwd);\n if (!policyRef) return 0; // no agentguard.yaml for this project: nothing to enforce\n const loaded = loadPolicyFile(policyRef.path, { env: io.env, allowMissingEnv: true });\n const action = hookActionFromInput(client, input, inputCwd ?? io.cwd);\n if (!action) return 0;\n const home = homeFrom(io);\n const workspace =\n projectDir(io, undefined) ??\n (policyRef.found === \"project\" ? dirname(policyRef.path) : undefined) ??\n action.cwd;\n const tmpDirs = [\n tmpdir(),\n io.env.TMPDIR,\n typeof input.scratchpad_dir === \"string\" ? input.scratchpad_dir : undefined,\n \"/tmp\",\n \"/private/tmp\",\n \"/var/folders\",\n \"/private/var/folders\",\n ].filter((d): d is string => Boolean(d));\n const ctx = {\n workspace: resolve(workspace),\n home,\n tmpDirs,\n stateDir: loaded.stateDir,\n guardFiles: [loaded.path, ...hookSettingsFiles({ cwd: resolve(workspace), home })],\n };\n const assessment = assessHookAction(loaded.policy, action, ctx);\n const reg = readRegistration(loaded);\n const { guard } = createFileGuard(loaded, {\n env: io.env,\n approvalUrl: approvalUrlFor(reg),\n log: (line) => io.err(line),\n });\n const configHint =\n policyRef.found === \"project\" && dirname(policyRef.path) === resolve(workspace)\n ? \"\"\n : ` --config ${JSON.stringify(policyRef.path)}`;\n const approveCommand = (id: string): string =>\n `npx @agentwares/agentguard approve ${id}${configHint}`;\n const result = await guard.preflight({\n action,\n assessment,\n runId: `${RUN_PREFIX[client]}_${action.sessionId}`,\n humanTurn: () =>\n client === \"claude-code\"\n ? humanTurnFromTranscript(action.transcriptPath, {\n requireOrigin: loaded.policy.hooks.irreversible.require_origin,\n })\n : {\n missing: `${client} transcripts are not a verified format for this check, so an irreversible command needs \\`agentguard approve\\``,\n },\n approveCommand,\n });\n respond(io, client, result, assessment.summary, approveCommand);\n return 0;\n } catch (err) {\n warn(\n io,\n `agentguard hook error — this call was NOT checked: ${describeError(err).replace(/\\s+/g, \" \").slice(0, 400)}`,\n );\n return 0;\n }\n}\n","/**\n * Read the end of a coding agent's transcript and find the latest turn a person typed. Long\n * sessions write tens of megabytes; the latest human turn is almost always near the end, so read\n * the last 1 MB first and widen only when it holds none.\n */\nimport { closeSync, existsSync, openSync, readSync, statSync } from \"node:fs\";\nimport { scanTranscript, type HumanTurn, type TranscriptScan } from \"@agentwares/agentguard-core\";\n\nconst STEPS = [1 << 20, 8 << 20, 64 << 20];\n\nexport interface TranscriptEvidence {\n turn?: HumanTurn;\n /** why there is no turn */\n missing?: string;\n scan?: TranscriptScan;\n}\n\nfunction readTail(path: string, bytes: number, size: number): string {\n const length = Math.min(bytes, size);\n const fd = openSync(path, \"r\");\n try {\n const buf = Buffer.alloc(length);\n readSync(fd, buf, 0, length, size - length);\n return buf.toString(\"utf8\");\n } finally {\n closeSync(fd);\n }\n}\n\nexport function humanTurnFromTranscript(\n path: string | undefined,\n opts: { requireOrigin?: boolean } = {},\n): TranscriptEvidence {\n if (!path) return { missing: \"the hook input carried no transcript_path\" };\n if (!existsSync(path)) return { missing: `no transcript at ${path}` };\n let size: number;\n try {\n size = statSync(path).size;\n } catch (err) {\n return {\n missing: `transcript unreadable: ${err instanceof Error ? err.message : String(err)}`,\n };\n }\n let scan: TranscriptScan | undefined;\n for (const step of STEPS) {\n try {\n scan = scanTranscript(readTail(path, step, size), opts);\n } catch (err) {\n return {\n missing: `transcript unreadable: ${err instanceof Error ? err.message : String(err)}`,\n };\n }\n if (scan.turn || step >= size) break;\n }\n if (scan?.turn) return { turn: scan.turn, scan };\n return {\n missing:\n size > STEPS[STEPS.length - 1]! ? \"none in the last 64 MB of the transcript\" : undefined,\n scan,\n };\n}\n","/**\n * `agentguard key create|list|revoke` — scoped agent credentials. The proxy holds upstream tokens;\n * each agent gets its own `agk_…` key whose hash and scope live in agentguard.yaml.\n */\nimport { readFileSync, writeFileSync } from \"node:fs\";\nimport YAML, { isMap, isSeq, YAMLSeq, type YAMLMap } from \"yaml\";\nimport { generateAgentKey, hashAgentKey } from \"@agentwares/agentguard-core\";\nimport { flagList, flagNumber, flagString, type ParsedArgs } from \"../args.js\";\nimport { policyPathFrom, type Io } from \"../context.js\";\n\nexport async function keyCommand(args: ParsedArgs, io: Io): Promise<number> {\n const [sub, name] = args.positionals;\n const path = policyPathFrom(args, io);\n const doc = YAML.parseDocument(readFileSync(path, \"utf8\"));\n let agents = doc.get(\"agents\");\n if (!isSeq(agents)) {\n agents = new YAMLSeq();\n doc.set(\"agents\", agents);\n }\n const seq = agents as YAMLSeq;\n const items = seq.items.filter(isMap) as YAMLMap[];\n\n if (sub === \"list\" || sub === undefined) {\n if (items.length === 0)\n io.out(\n \"no agents in agentguard.yaml — create one: agentguard key create <name> --allow 'crm_get_*'\",\n );\n for (const a of items) {\n const allow = a.get(\"allow\");\n io.out(\n `${String(a.get(\"name\")).padEnd(20)} key: ${a.get(\"key_hash\") ? \"set\" : \"none (stdio --agent only)\"} allow: ${isSeq(allow) ? allow.items.map(String).join(\", \") : \"all\"}`,\n );\n }\n return 0;\n }\n if (!name) {\n io.err(\n \"usage: agentguard key create <agent> [--allow pattern]... [--deny pattern]... [--writes n] [--spend n] [--deletes n] [--emails n] [--tool-calls n] [--mode dry-run|enforce] [--upstream name]...\",\n );\n return 1;\n }\n if (sub === \"revoke\") {\n const idx = items.findIndex((a) => a.get(\"name\") === name);\n if (idx < 0) {\n io.err(`no agent \"${name}\"`);\n return 1;\n }\n seq.items.splice(seq.items.indexOf(items[idx]!), 1);\n writeFileSync(path, doc.toString());\n io.out(`revoked ${name}: removed from agentguard.yaml (running proxies pick it up on restart)`);\n return 0;\n }\n if (sub !== \"create\") {\n io.err(`unknown subcommand \"${sub}\" — use create, list or revoke`);\n return 1;\n }\n const key = generateAgentKey();\n const keyHash = await hashAgentKey(key);\n const existing = items.find((a) => a.get(\"name\") === name);\n const entry: Record<string, unknown> = { name, key_hash: keyHash };\n const allow = flagList(args, \"allow\");\n const deny = flagList(args, \"deny\");\n if (allow.length) entry.allow = allow;\n if (deny.length) entry.deny = deny;\n const upstreams = flagList(args, \"upstream\");\n if (upstreams.length) entry.upstreams = upstreams;\n const mode = flagString(args, \"mode\");\n if (mode) entry.mode = mode;\n const perRun: Record<string, number> = {};\n for (const [flag, counter] of [\n [\"writes\", \"writes\"],\n [\"spend\", \"spend_usd\"],\n [\"deletes\", \"deletes\"],\n [\"emails\", \"emails\"],\n [\"tool-calls\", \"tool_calls\"],\n ] as const) {\n const n = flagNumber(args, flag);\n if (n !== undefined) perRun[counter] = n;\n }\n if (Object.keys(perRun).length) entry.caps = { per_run: perRun };\n if (existing) {\n for (const [k, v] of Object.entries(entry)) existing.set(k, v);\n } else {\n seq.add(doc.createNode(entry));\n }\n writeFileSync(path, doc.toString());\n io.err(\n `${existing ? \"rotated\" : \"created\"} agent \"${name}\" in ${path}${allow.length ? ` (allow: ${allow.join(\", \")})` : \" (allow: all tools)\"}`,\n );\n io.err(\n \"the key is shown once; give it to the agent as `Authorization: Bearer <key>` (HTTP) — over stdio use `agentguard proxy --agent \" +\n name +\n \"`\",\n );\n io.out(key);\n return 0;\n}\n","/**\n * `agentguard permission-diff` — which changes between two git refs widen what an agent may do\n * (agentguard.yaml, .claude/settings.json, mcp.json). The GitHub Action posts the markdown.\n */\nimport { execFileSync } from \"node:child_process\";\nimport {\n diffPermissionFile,\n renderPermissionDiffMarkdown,\n type Finding,\n} from \"@agentwares/agentguard-core\";\nimport { flagBool, flagList, flagString, type ParsedArgs } from \"../args.js\";\nimport type { Io } from \"../context.js\";\n\nexport const DEFAULT_PERMISSION_PATHS = [\n \"agentguard.yaml\",\n \"agentguard.yml\",\n \".claude/settings.json\",\n \".claude/settings.local.json\",\n \".mcp.json\",\n \"mcp.json\",\n \".cursor/mcp.json\",\n \".vscode/mcp.json\",\n];\n\nconst PERMISSION_FILE =\n /(^|\\/)(agentguard[^/]*\\.ya?ml|\\.claude\\/settings(\\.local)?\\.json|[^/]*mcp[^/]*\\.json|claude_desktop_config\\.json)$/;\n\nfunction git(cwd: string, argv: string[]): string | undefined {\n try {\n return execFileSync(\"git\", argv, {\n cwd,\n encoding: \"utf8\",\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n });\n } catch {\n return undefined;\n }\n}\n\nexport function showAt(cwd: string, ref: string, path: string): string | undefined {\n return git(cwd, [\"show\", `${ref}:${path}`]);\n}\n\nexport function changedPermissionFiles(cwd: string, base: string, head: string): string[] {\n const out = git(cwd, [\"diff\", \"--name-only\", base, head]) ?? \"\";\n return out\n .split(\"\\n\")\n .map((l) => l.trim())\n .filter((l) => l && PERMISSION_FILE.test(l));\n}\n\nexport function resolveBase(cwd: string, explicit: string | undefined): string {\n if (explicit) return explicit;\n for (const candidate of [\"origin/main\", \"main\", \"origin/master\", \"master\"]) {\n if (git(cwd, [\"rev-parse\", \"--verify\", \"--quiet\", candidate]) !== undefined) return candidate;\n }\n return \"HEAD~1\";\n}\n\nexport interface PermissionDiffResult {\n base: string;\n head: string;\n files: string[];\n findings: Finding[];\n markdown: string;\n}\n\nexport function runPermissionDiff(\n cwd: string,\n opts: { base?: string; head?: string; paths?: string[]; title?: string },\n): PermissionDiffResult {\n const base = resolveBase(cwd, opts.base);\n const head = opts.head ?? \"HEAD\";\n const files = [\n ...new Set([\n ...(opts.paths ?? DEFAULT_PERMISSION_PATHS),\n ...changedPermissionFiles(cwd, base, head),\n ]),\n ];\n const findings: Finding[] = [];\n const touched: string[] = [];\n for (const file of files) {\n const before = showAt(cwd, base, file);\n const after = showAt(cwd, head, file);\n if (before === undefined && after === undefined) continue;\n if (before === after) continue;\n touched.push(file);\n findings.push(...diffPermissionFile(file, before, after));\n }\n return {\n base,\n head,\n files: touched,\n findings,\n markdown: renderPermissionDiffMarkdown(findings, { title: opts.title }),\n };\n}\n\nexport async function permissionDiffCommand(args: ParsedArgs, io: Io): Promise<number> {\n const paths = flagList(args, \"paths\");\n const result = runPermissionDiff(io.cwd, {\n base: flagString(args, \"base\"),\n head: flagString(args, \"head\"),\n paths: paths.length ? paths : undefined,\n });\n const format = flagString(args, \"format\") ?? (flagBool(args, \"json\") ? \"json\" : \"markdown\");\n if (format === \"json\") io.out(JSON.stringify(result, null, 2));\n else io.out(result.markdown);\n const widen = result.findings.filter((f) => f.severity === \"widen\").length;\n if (flagBool(args, \"fail-on-widen\") && widen > 0) return 1;\n return 0;\n}\n","/**\n * `agentguard report` (the incident-shaped summary), `diff` (mutation diff), `verify` (audit\n * chain), `status` (counters and remaining budget).\n */\nimport { resolve } from \"node:path\";\nimport {\n buildReport,\n latestRunId,\n listRuns,\n renderMutationDiff,\n renderReportMarkdown,\n} from \"@agentwares/agentguard-core\";\nimport { readAuditFile, verifyAuditFile } from \"@agentwares/agentguard-core/node\";\nimport { flagBool, flagString, type ParsedArgs } from \"../args.js\";\nimport { createFileGuard, loadPolicyFor, readRegistration, type Io } from \"../context.js\";\n\nfunction pickRun(args: ParsedArgs, entries: ReturnType<typeof readAuditFile>): string | undefined {\n if (flagBool(args, \"all\")) return undefined;\n return flagString(args, \"run\") ?? latestRunId(entries);\n}\n\nexport async function reportCommand(args: ParsedArgs, io: Io): Promise<number> {\n const loaded = loadPolicyFor(args, io, { allowMissingEnv: true });\n const entries = readAuditFile(loaded.auditPath);\n const runId = pickRun(args, entries);\n const report = buildReport(entries, { runId });\n if (flagBool(args, \"json\")) {\n io.out(\n JSON.stringify(\n {\n ...report,\n mutations: report.mutations.map((m) => ({\n seq: m.seq,\n ts: m.ts,\n tool: m.tool,\n mutation: m.mutation,\n })),\n },\n null,\n 2,\n ),\n );\n return 0;\n }\n io.out(renderReportMarkdown(report));\n const chain = await verifyAuditFile(loaded.auditPath);\n io.out(\n chain.ok\n ? `Audit chain: ${chain.entries} entries, verified (${loaded.auditPath}).`\n : `Audit chain BROKEN at entry ${chain.brokenAt}: ${chain.reason}`,\n );\n if (runId && listRuns(entries).length > 1) io.out(`Other runs: agentguard report --all`);\n return 0;\n}\n\nexport async function diffCommand(args: ParsedArgs, io: Io): Promise<number> {\n const loaded = loadPolicyFor(args, io, { allowMissingEnv: true });\n const entries = readAuditFile(loaded.auditPath);\n const runId = pickRun(args, entries);\n io.out(renderMutationDiff(entries, { runId }).trimEnd());\n return 0;\n}\n\nexport async function verifyCommand(args: ParsedArgs, io: Io): Promise<number> {\n let path = args.positionals[0];\n if (!path) path = loadPolicyFor(args, io, { allowMissingEnv: true }).auditPath;\n path = resolve(io.cwd, path);\n const result = await verifyAuditFile(path);\n if (flagBool(args, \"json\")) io.out(JSON.stringify({ path, ...result }));\n else if (result.ok)\n io.out(\n `ok: ${result.entries} entries, chain intact, head ${result.head?.slice(0, 16)}… (${path})`,\n );\n else io.out(`BROKEN at entry ${result.brokenAt}: ${result.reason} (${path})`);\n return result.ok ? 0 : 1;\n}\n\nexport async function statusCommand(args: ParsedArgs, io: Io): Promise<number> {\n const loaded = loadPolicyFor(args, io, { allowMissingEnv: true });\n const { guard, kill } = createFileGuard(loaded, { alerts: false, env: io.env });\n const entries = readAuditFile(loaded.auditPath);\n const runId = flagString(args, \"run\") ?? latestRunId(entries) ?? \"(none yet)\";\n const status = await guard.status(runId);\n const killed = kill.check();\n const reg = readRegistration(loaded);\n const pending = await guard.approvals.list(\"pending\");\n if (flagBool(args, \"json\")) {\n io.out(\n JSON.stringify(\n {\n policy: loaded.path,\n mode: loaded.policy.mode,\n runId,\n ...status,\n killed,\n pendingApprovals: pending.length,\n http: reg ? { url: reg.url, pid: reg.pid } : undefined,\n },\n null,\n 2,\n ),\n );\n return 0;\n }\n io.out(\n `policy ${loaded.path} (mode: ${loaded.policy.mode}, ${loaded.policy.upstreams.length} upstreams)`,\n );\n io.out(\n `kill ${killed.killed ? `ON — ${killed.reason} (agentguard resume to clear)` : \"off\"}`,\n );\n io.out(\n `http ${reg ? `${reg.url} (pid ${reg.pid})` : \"not running (agentguard proxy --http)\"}`,\n );\n io.out(`audit ${entries.length} entries in ${loaded.auditPath}`);\n io.out(\n `pending ${pending.length} approval${pending.length === 1 ? \"\" : \"s\"}${pending.length ? ` — agentguard approvals` : \"\"}`,\n );\n io.out(`run ${runId}`);\n const fmt = (scope: \"per_run\" | \"per_day\"): string =>\n Object.entries(status.caps[scope])\n .map(([k, limit]) => `${k} ${status.usage[scope][k] ?? 0}/${limit}`)\n .join(\" \") || \"no caps\";\n io.out(` per_run ${fmt(\"per_run\")}`);\n io.out(` per_day ${fmt(\"per_day\")}`);\n return 0;\n}\n","#!/usr/bin/env node\n/**\n * `agentguard` — MCP policy proxy: hard spend limits, destructive-action gating with approvals,\n * a kill switch, scoped credentials, dry-run writes, a loop breaker, blast-radius caps and a\n * hash-chained audit log. No LLM calls, no phone-home, no account.\n */\nimport { parseArgs, type ParsedArgs } from \"./args.js\";\nimport { version } from \"./version.js\";\n\nexport { version };\nimport { defaultIo, describeError, type Io } from \"./context.js\";\nimport { connectCommand } from \"./commands/connect.js\";\nimport { approvalsCommand, decideCommand, killCommand, resumeCommand } from \"./commands/control.js\";\nimport { hookCommand } from \"./commands/hook.js\";\nimport { hooksCommand } from \"./commands/hooks.js\";\nimport { keyCommand } from \"./commands/keys.js\";\nimport { permissionDiffCommand } from \"./commands/permission-diff.js\";\nimport { diffCommand, reportCommand, statusCommand, verifyCommand } from \"./commands/report.js\";\n\n// The MCP SDK costs ~110 ms to load. `agentguard hook pre-tool-use` runs before every guarded\n// tool call of a coding agent and never needs it, so the commands that do load it on demand.\nconst proxyCommand = async (args: ParsedArgs, io: Io): Promise<number> =>\n (await import(\"./commands/proxy.js\")).proxyCommand(args, io);\nconst initCommand = async (args: ParsedArgs, io: Io): Promise<number> =>\n (await import(\"./commands/init.js\")).initCommand(args, io);\nconst toolsCommand = async (args: ParsedArgs, io: Io): Promise<number> =>\n (await import(\"./commands/tools.js\")).toolsCommand(args, io);\nconst auditCommand = async (args: ParsedArgs, io: Io): Promise<number> =>\n (await import(\"./commands/audit.js\")).auditCommand(args, io);\n\nexport const HELP = `agentguard — MCP policy proxy for agents that touch production\n\n npx @agentwares/agentguard init read your MCP config, write agentguard.yaml (dry-run), route every server through the proxy\n agentguard report [--run id|--all] what this run did / would have destroyed / spent, where it was halted\n agentguard diff [--run id] record-by-record mutation diff from a dry run\n agentguard verify [audit.jsonl] prove the hash-chained audit log was not edited\n agentguard connect <key> [--write] point this machine at your hosted proxy (paid tiers)\n\n agentguard hooks install [--project|--user] [--client claude|codex|gemini|all]\n check a coding agent's own shell commands and file edits against agentguard.yaml (dry-run first);\n irreversible commands (push, merge, publish, send, rm outside the repo) only on a turn a person typed\n agentguard hooks uninstall | status\n agentguard hook pre-tool-use what the installed hook runs (reads the harness's JSON on stdin)\n\n agentguard audit [--since 7d|30d|all] [--client claude|codex|all] [--json]\n which rules in CLAUDE.md / AGENTS.md / GEMINI.md / .cursor/rules your coding agents broke,\n from this machine's Claude Code and Codex sessions in this repo (nothing is sent anywhere)\n agentguard audit --enforce [--preview]\n write the checkable rules into agentguard.yaml as hook rules, in dry-run, and install the hook\n\n agentguard proxy [--http --port 8788] [--agent name] [--run-id id] [--mode dry-run|enforce]\n agentguard tools [--json] the tools your agent will see, with class and why\n agentguard status [--run id] counters vs caps, kill state, pending approvals\n\n agentguard kill [reason] halt every run now (file + running HTTP proxy); agentguard resume\n agentguard approvals [--all] pending approvals; agentguard approve <id> | deny <id> [--note text]\n agentguard key create <agent> [--allow 'crm_get_*']... [--deny p] [--writes n] [--spend n] [--mode m]\n agentguard key list | revoke <agent>\n agentguard permission-diff [--base ref] [--head ref] [--paths a,b] [--format markdown|json] [--fail-on-widen]\n\nOptions: --config <agentguard.yaml> (or AGENTGUARD_CONFIG), --json, --help, --version\nDocs: https://github.com/agentwares/agentguard/tree/main/apps/agentguard-cli`;\n\nexport async function main(argv: readonly string[], io: Io = defaultIo()): Promise<number> {\n const args: ParsedArgs = parseArgs(argv);\n if (args.flags.version) {\n io.out(version());\n return 0;\n }\n if (args.command === undefined && !args.flags.help && io.tty === false) {\n // An MCP client spawned bare `npx @agentwares/agentguard` — that is what server.json registers — and is\n // waiting for JSON-RPC on stdout. Serve the proxy instead of printing help into the stream.\n try {\n return await proxyCommand(args, io);\n } catch (err) {\n io.err(describeError(err));\n return 1;\n }\n }\n if (args.flags.help || args.command === undefined || args.command === \"help\") {\n io.out(HELP);\n return args.command === undefined && !args.flags.help ? 1 : 0;\n }\n try {\n switch (args.command) {\n case \"init\":\n return await initCommand(args, io);\n case \"proxy\":\n case \"serve\":\n return await proxyCommand(args, io);\n case \"report\":\n return await reportCommand(args, io);\n case \"diff\":\n return await diffCommand(args, io);\n case \"verify\":\n return await verifyCommand(args, io);\n case \"connect\":\n return await connectCommand(args, io);\n case \"status\":\n return await statusCommand(args, io);\n case \"tools\":\n return await toolsCommand(args, io);\n case \"kill\":\n return await killCommand(args, io);\n case \"resume\":\n return await resumeCommand(args, io);\n case \"approve\":\n return await decideCommand(\"approved\", args, io);\n case \"deny\":\n return await decideCommand(\"denied\", args, io);\n case \"approvals\":\n return await approvalsCommand(args, io);\n case \"key\":\n case \"keys\":\n return await keyCommand(args, io);\n case \"permission-diff\":\n return await permissionDiffCommand(args, io);\n case \"hook\":\n return await hookCommand(args, io);\n case \"hooks\":\n return await hooksCommand(args, io);\n case \"audit\":\n return await auditCommand(args, io);\n default:\n io.err(`unknown command \"${args.command}\"\\n`);\n io.err(HELP);\n return 1;\n }\n } catch (err) {\n io.err(describeError(err));\n return 1;\n }\n}\n\nconst isMain =\n process.argv[1] !== undefined && /(^|\\/)(cli\\.[cm]?[jt]s|agentguard)$/.test(process.argv[1]);\nif (isMain) {\n main(process.argv.slice(2)).then(\n (code) => {\n if (code !== 0) process.exitCode = code;\n },\n (err: unknown) => {\n process.stderr.write(`${describeError(err)}\\n`);\n process.exitCode = 1;\n },\n );\n}\n"],"mappings":"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","names":["c","existsSync","existsSync","existsSync","allow","out","resolve","resolve"]}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
// src/fixtures/demo-agent.ts
|
|
2
|
+
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
3
|
+
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
4
|
+
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
5
|
+
import { fileURLToPath } from "url";
|
|
6
|
+
import path from "path";
|
|
7
|
+
function summarize(result) {
|
|
8
|
+
const text = result.content.find((c) => c.type === "text")?.text;
|
|
9
|
+
const meta = result._meta?.agentguard;
|
|
10
|
+
if (result.isError) {
|
|
11
|
+
let code;
|
|
12
|
+
try {
|
|
13
|
+
code = JSON.parse(text ?? "{}").code;
|
|
14
|
+
} catch {
|
|
15
|
+
}
|
|
16
|
+
return { ok: false, code, text };
|
|
17
|
+
}
|
|
18
|
+
return { ok: true, dryRun: meta?.dryRun, text };
|
|
19
|
+
}
|
|
20
|
+
async function runDemoAgent(client, opts = {}) {
|
|
21
|
+
const steps = [];
|
|
22
|
+
const log = opts.log ?? (() => void 0);
|
|
23
|
+
const meta = opts.runId ? { runId: opts.runId } : void 0;
|
|
24
|
+
const call = async (step, tool, args) => {
|
|
25
|
+
const result = await client.callTool({
|
|
26
|
+
name: tool,
|
|
27
|
+
arguments: args,
|
|
28
|
+
_meta: meta
|
|
29
|
+
});
|
|
30
|
+
const s = { step, tool, ...summarize(result) };
|
|
31
|
+
steps.push(s);
|
|
32
|
+
log(
|
|
33
|
+
`${s.ok ? s.dryRun ? "faked " : "ok " : `${s.code ?? "error"}`.padEnd(6)} ${step}: ${tool}`
|
|
34
|
+
);
|
|
35
|
+
return s;
|
|
36
|
+
};
|
|
37
|
+
await call("read: list contacts", "crm_list_contacts", { limit: 10 });
|
|
38
|
+
await call("read: get one", "crm_get_contact", { id: "c_1" });
|
|
39
|
+
await call("write: create", "crm_create_contact", {
|
|
40
|
+
name: "Demo Person",
|
|
41
|
+
email: "demo@example.com"
|
|
42
|
+
});
|
|
43
|
+
await call("write: update", "crm_update_contact", { id: "c_1", fields: { name: "Ada L." } });
|
|
44
|
+
await call("write: delete (destructive)", "crm_delete_contact", { id: "c_2" });
|
|
45
|
+
await call("write: send email", "crm_send_email", {
|
|
46
|
+
to: "ada@example.com",
|
|
47
|
+
subject: "Hi",
|
|
48
|
+
body: "Hello from the demo agent"
|
|
49
|
+
});
|
|
50
|
+
await call("spend: charge $12", "crm_charge_card", {
|
|
51
|
+
customer_id: "c_1",
|
|
52
|
+
amount_cents: 1200,
|
|
53
|
+
currency: "usd"
|
|
54
|
+
});
|
|
55
|
+
const loops = opts.loop ?? 5;
|
|
56
|
+
for (let i = 0; i < loops; i += 1) {
|
|
57
|
+
const s = await call(`loop ${i + 1}/${loops}: identical update`, "crm_update_contact", {
|
|
58
|
+
id: "c_3",
|
|
59
|
+
fields: { name: "Same Thing" }
|
|
60
|
+
});
|
|
61
|
+
if (s.code === "LOOP_DETECTED") break;
|
|
62
|
+
}
|
|
63
|
+
const burst = opts.burst ?? 60;
|
|
64
|
+
for (let i = 0; i < burst; i += 1) {
|
|
65
|
+
const s = await call(`burst ${i + 1}/${burst}: create`, "crm_create_contact", {
|
|
66
|
+
name: `Bulk ${i}`,
|
|
67
|
+
email: `bulk${i}@example.com`
|
|
68
|
+
});
|
|
69
|
+
if (s.code === "CAP_EXCEEDED") break;
|
|
70
|
+
}
|
|
71
|
+
return steps;
|
|
72
|
+
}
|
|
73
|
+
var isMain = process.argv[1] !== void 0 && /demo-agent\.[cm]?[jt]s$/.test(process.argv[1]);
|
|
74
|
+
if (isMain) {
|
|
75
|
+
const argv = process.argv.slice(2);
|
|
76
|
+
const arg = (name) => {
|
|
77
|
+
const i = argv.indexOf(name);
|
|
78
|
+
return i >= 0 ? argv[i + 1] : void 0;
|
|
79
|
+
};
|
|
80
|
+
const url = arg("--url");
|
|
81
|
+
const config = arg("--config") ?? "agentguard.yaml";
|
|
82
|
+
const client = new Client({ name: "agentguard-demo-agent", version: "0.1.0" });
|
|
83
|
+
if (url) {
|
|
84
|
+
await client.connect(
|
|
85
|
+
new StreamableHTTPClientTransport(new URL(url), {
|
|
86
|
+
requestInit: {
|
|
87
|
+
headers: { "X-Run-Id": arg("--run-id") ?? `demo_${Date.now().toString(36)}` }
|
|
88
|
+
}
|
|
89
|
+
})
|
|
90
|
+
);
|
|
91
|
+
} else {
|
|
92
|
+
const cli = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../cli.js");
|
|
93
|
+
await client.connect(
|
|
94
|
+
new StdioClientTransport({
|
|
95
|
+
command: process.execPath,
|
|
96
|
+
args: [cli, "proxy", "--config", config],
|
|
97
|
+
stderr: "inherit"
|
|
98
|
+
})
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
try {
|
|
102
|
+
const steps = await runDemoAgent(client, {
|
|
103
|
+
log: (l) => console.log(l),
|
|
104
|
+
runId: arg("--run-id")
|
|
105
|
+
});
|
|
106
|
+
const halts = steps.filter((s) => !s.ok).map((s) => s.code);
|
|
107
|
+
console.log(
|
|
108
|
+
`
|
|
109
|
+
${steps.length} calls; halts: ${halts.join(", ") || "none"}. Now run: agentguard report`
|
|
110
|
+
);
|
|
111
|
+
} finally {
|
|
112
|
+
await client.close();
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export {
|
|
117
|
+
runDemoAgent
|
|
118
|
+
};
|
|
119
|
+
//# sourceMappingURL=chunk-BKXXTWIS.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/fixtures/demo-agent.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * A scripted \"agent\" that misbehaves on purpose: reads, then writes, then loops, then bursts\n * writes past the cap. Run it against the proxy to see dry-run diffs, LOOP_DETECTED and\n * CAP_EXCEEDED in `agentguard report`.\n *\n * node dist/fixtures/demo-agent.js --config agentguard.yaml # spawns `agentguard proxy` over stdio\n */\nimport { Client } from \"@modelcontextprotocol/sdk/client/index.js\";\nimport { StdioClientTransport } from \"@modelcontextprotocol/sdk/client/stdio.js\";\nimport { StreamableHTTPClientTransport } from \"@modelcontextprotocol/sdk/client/streamableHttp.js\";\nimport type { CallToolResult } from \"@modelcontextprotocol/sdk/types.js\";\nimport { fileURLToPath } from \"node:url\";\nimport path from \"node:path\";\n\nexport interface DemoStep {\n step: string;\n tool: string;\n ok: boolean;\n code?: string;\n dryRun?: boolean;\n text?: string;\n}\n\nexport interface DemoOptions {\n /** how many writes to burst at the end (default 60 — past a `writes: 50` cap) */\n burst?: number;\n /** how many times to repeat the identical update (default 5 — past `max_repeats: 3`) */\n loop?: number;\n runId?: string;\n log?: (line: string) => void;\n}\n\nfunction summarize(result: CallToolResult): {\n ok: boolean;\n code?: string;\n dryRun?: boolean;\n text?: string;\n} {\n const text = result.content.find((c) => c.type === \"text\")?.text;\n const meta = (result._meta as { agentguard?: { dryRun?: boolean } } | undefined)?.agentguard;\n if (result.isError) {\n let code: string | undefined;\n try {\n code = (JSON.parse(text ?? \"{}\") as { code?: string }).code;\n } catch {\n // not JSON\n }\n return { ok: false, code, text };\n }\n return { ok: true, dryRun: meta?.dryRun, text };\n}\n\n/** Drive a connected client through the scripted scenario. Returns every step's outcome. */\nexport async function runDemoAgent(client: Client, opts: DemoOptions = {}): Promise<DemoStep[]> {\n const steps: DemoStep[] = [];\n const log = opts.log ?? (() => undefined);\n const meta = opts.runId ? { runId: opts.runId } : undefined;\n const call = async (\n step: string,\n tool: string,\n args: Record<string, unknown>,\n ): Promise<DemoStep> => {\n const result = (await client.callTool({\n name: tool,\n arguments: args,\n _meta: meta,\n })) as CallToolResult;\n const s = { step, tool, ...summarize(result) };\n steps.push(s);\n log(\n `${s.ok ? (s.dryRun ? \"faked \" : \"ok \") : `${s.code ?? \"error\"}`.padEnd(6)} ${step}: ${tool}`,\n );\n return s;\n };\n\n await call(\"read: list contacts\", \"crm_list_contacts\", { limit: 10 });\n await call(\"read: get one\", \"crm_get_contact\", { id: \"c_1\" });\n await call(\"write: create\", \"crm_create_contact\", {\n name: \"Demo Person\",\n email: \"demo@example.com\",\n });\n await call(\"write: update\", \"crm_update_contact\", { id: \"c_1\", fields: { name: \"Ada L.\" } });\n await call(\"write: delete (destructive)\", \"crm_delete_contact\", { id: \"c_2\" });\n await call(\"write: send email\", \"crm_send_email\", {\n to: \"ada@example.com\",\n subject: \"Hi\",\n body: \"Hello from the demo agent\",\n });\n await call(\"spend: charge $12\", \"crm_charge_card\", {\n customer_id: \"c_1\",\n amount_cents: 1200,\n currency: \"usd\",\n });\n\n const loops = opts.loop ?? 5;\n for (let i = 0; i < loops; i += 1) {\n const s = await call(`loop ${i + 1}/${loops}: identical update`, \"crm_update_contact\", {\n id: \"c_3\",\n fields: { name: \"Same Thing\" },\n });\n if (s.code === \"LOOP_DETECTED\") break;\n }\n\n const burst = opts.burst ?? 60;\n for (let i = 0; i < burst; i += 1) {\n const s = await call(`burst ${i + 1}/${burst}: create`, \"crm_create_contact\", {\n name: `Bulk ${i}`,\n email: `bulk${i}@example.com`,\n });\n if (s.code === \"CAP_EXCEEDED\") break;\n }\n return steps;\n}\n\nconst isMain = process.argv[1] !== undefined && /demo-agent\\.[cm]?[jt]s$/.test(process.argv[1]);\nif (isMain) {\n const argv = process.argv.slice(2);\n const arg = (name: string): string | undefined => {\n const i = argv.indexOf(name);\n return i >= 0 ? argv[i + 1] : undefined;\n };\n const url = arg(\"--url\");\n const config = arg(\"--config\") ?? \"agentguard.yaml\";\n const client = new Client({ name: \"agentguard-demo-agent\", version: \"0.1.0\" });\n if (url) {\n await client.connect(\n new StreamableHTTPClientTransport(new URL(url), {\n requestInit: {\n headers: { \"X-Run-Id\": arg(\"--run-id\") ?? `demo_${Date.now().toString(36)}` },\n },\n }),\n );\n } else {\n const cli = path.resolve(path.dirname(fileURLToPath(import.meta.url)), \"../cli.js\");\n await client.connect(\n new StdioClientTransport({\n command: process.execPath,\n args: [cli, \"proxy\", \"--config\", config],\n stderr: \"inherit\",\n }),\n );\n }\n try {\n const steps = await runDemoAgent(client, {\n log: (l) => console.log(l),\n runId: arg(\"--run-id\"),\n });\n const halts = steps.filter((s) => !s.ok).map((s) => s.code);\n console.log(\n `\\n${steps.length} calls; halts: ${halts.join(\", \") || \"none\"}. Now run: agentguard report`,\n );\n } finally {\n await client.close();\n }\n}\n"],"mappings":"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","names":[]}
|