spendctl 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/state.js ADDED
@@ -0,0 +1,72 @@
1
+ import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { dirname, join, resolve } from "node:path";
3
+ import { loadConfig, newToken } from "@spendctl/core";
4
+ export function paths(configFlag) {
5
+ const config = resolve(configFlag ?? process.env.SPENDCTL_CONFIG ?? "spendctl.yaml");
6
+ const root = dirname(config);
7
+ const state = join(root, ".spendctl");
8
+ return {
9
+ config,
10
+ root,
11
+ state,
12
+ adminToken: join(state, "admin.token"),
13
+ agentTokens: join(state, "agents.json"),
14
+ sidecar: join(state, "sidecar.json"),
15
+ };
16
+ }
17
+ function writeSecret(path, content) {
18
+ mkdirSync(dirname(path), { recursive: true });
19
+ writeFileSync(path, content, { mode: 0o600 });
20
+ chmodSync(path, 0o600);
21
+ }
22
+ export function ensureAdminToken(p) {
23
+ if (process.env.SPENDCTL_ADMIN_TOKEN)
24
+ return process.env.SPENDCTL_ADMIN_TOKEN;
25
+ if (existsSync(p.adminToken))
26
+ return readFileSync(p.adminToken, "utf8").trim();
27
+ const token = newToken();
28
+ writeSecret(p.adminToken, `${token}\n`);
29
+ return token;
30
+ }
31
+ export function readAdminToken(p) {
32
+ if (process.env.SPENDCTL_ADMIN_TOKEN)
33
+ return process.env.SPENDCTL_ADMIN_TOKEN;
34
+ if (!existsSync(p.adminToken)) {
35
+ throw new Error(`No admin token at ${p.adminToken}. Run \`spendctl init\` (or \`spendctl start\`) in this directory first.`);
36
+ }
37
+ return readFileSync(p.adminToken, "utf8").trim();
38
+ }
39
+ export function readAgentTokens(p) {
40
+ if (!existsSync(p.agentTokens))
41
+ return {};
42
+ return JSON.parse(readFileSync(p.agentTokens, "utf8"));
43
+ }
44
+ export function writeAgentTokens(p, tokens) {
45
+ writeSecret(p.agentTokens, `${JSON.stringify(tokens, null, 2)}\n`);
46
+ }
47
+ export function loadDotenv(root) {
48
+ const file = join(root, ".env");
49
+ if (existsSync(file))
50
+ process.loadEnvFile(file);
51
+ }
52
+ export function tryLoadConfig(p) {
53
+ return existsSync(p.config) ? loadConfig(p.config) : undefined;
54
+ }
55
+ /** Where the running sidecar listens: $SPENDCTL_URL, the pid file, then the config. */
56
+ export function sidecarUrl(p) {
57
+ if (process.env.SPENDCTL_URL)
58
+ return process.env.SPENDCTL_URL;
59
+ if (existsSync(p.sidecar)) {
60
+ try {
61
+ const info = JSON.parse(readFileSync(p.sidecar, "utf8"));
62
+ if (info.url)
63
+ return info.url;
64
+ }
65
+ catch {
66
+ // fall through
67
+ }
68
+ }
69
+ const config = tryLoadConfig(p);
70
+ return `http://${config?.server.host ?? "127.0.0.1"}:${config?.server.port ?? 8402}`;
71
+ }
72
+ //# sourceMappingURL=state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.js","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export type SignerChoice = "mock" | "cdp" | "private-key";
2
+ export declare function policyTemplate(signer: SignerChoice): string;
3
+ export declare const ENV_EXAMPLE = "# Coinbase CDP (default signer for real payments). https://portal.cdp.coinbase.com\nCDP_API_KEY_ID=\nCDP_API_KEY_SECRET=\nCDP_WALLET_SECRET=\nPAYER_ACCOUNT_NAME=spendctl-payer\n\n# Optional: raw key signer (signer.type: private-key). Testnet only.\n# PAYER_PRIVATE_KEY=0x...\n";
4
+ //# sourceMappingURL=templates.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"templates.d.ts","sourceRoot":"","sources":["../src/templates.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,KAAK,GAAG,aAAa,CAAC;AAE1D,wBAAgB,cAAc,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAqD3D;AAED,eAAO,MAAM,WAAW,yRAQvB,CAAC"}
@@ -0,0 +1,63 @@
1
+ export function policyTemplate(signer) {
2
+ const signerBlock = signer === "cdp"
3
+ ? `# Coinbase CDP server wallet: keys stay in CDP, spendctl only asks it to sign.
4
+ # Needs CDP_API_KEY_ID, CDP_API_KEY_SECRET, CDP_WALLET_SECRET and PAYER_ACCOUNT_NAME in .env.
5
+ signer:
6
+ type: cdp`
7
+ : signer === "private-key"
8
+ ? `# Raw private key from $PAYER_PRIVATE_KEY (opt-in; prefer "cdp").
9
+ signer:
10
+ type: private-key`
11
+ : `# "mock" signs with a throwaway key that only the bundled mock facilitator accepts.
12
+ # Switch to "cdp" for real (testnet) payments: \`spendctl init --signer cdp --force\`.
13
+ signer:
14
+ type: mock`;
15
+ return `# spendctl policy — docs: https://spendctl.dev/docs/policy
16
+ # Everything here is enforced by the sidecar, outside the agent's process.
17
+ version: 1
18
+
19
+ ${signerBlock}
20
+
21
+ server:
22
+ host: 127.0.0.1
23
+ port: 8402
24
+
25
+ approvals:
26
+ timeout: 10m # unanswered approvals are denied
27
+ hold: true # keep the agent's request open until a human decides
28
+ holdMax: 4m # ...but answer with a retry-mode 402 after this long (the approval stays open)
29
+ webhooks: []
30
+ # - url: https://hooks.slack.com/services/T000/B000/XXXX
31
+ # format: slack # json | slack | discord
32
+
33
+ defaults:
34
+ networks: ["eip155:84532"] # Base Sepolia only; add "eip155:8453" to allow Base mainnet
35
+ assets: ["USDC"]
36
+ maxChainDepth: 3 # agent -> agent -> agent, then stop
37
+ priceJumpFactor: 3 # a price >3x the last one paid for an endpoint needs a human
38
+ firstPaymentMax: "0.05" # first payment to a new recipient above this needs a human
39
+
40
+ agents:
41
+ researcher:
42
+ description: Research agent that buys weather and search results
43
+ budget:
44
+ perRequest: "0.05"
45
+ daily: "0.03"
46
+ monthly: "20.00"
47
+ onBudgetExceeded: approve # deny | approve
48
+ requireApprovalAbove: "0.50"
49
+ allow:
50
+ - "localhost:4021" # spendctl mock: weather API (x402 v2)
51
+ - "localhost:4022" # spendctl mock: search API (x402 v1)
52
+ `;
53
+ }
54
+ export const ENV_EXAMPLE = `# Coinbase CDP (default signer for real payments). https://portal.cdp.coinbase.com
55
+ CDP_API_KEY_ID=
56
+ CDP_API_KEY_SECRET=
57
+ CDP_WALLET_SECRET=
58
+ PAYER_ACCOUNT_NAME=spendctl-payer
59
+
60
+ # Optional: raw key signer (signer.type: private-key). Testnet only.
61
+ # PAYER_PRIVATE_KEY=0x...
62
+ `;
63
+ //# sourceMappingURL=templates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"templates.js","sourceRoot":"","sources":["../src/templates.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,cAAc,CAAC,MAAoB;IACjD,MAAM,WAAW,GACf,MAAM,KAAK,KAAK;QACd,CAAC,CAAC;;;YAGI;QACN,CAAC,CAAC,MAAM,KAAK,aAAa;YACxB,CAAC,CAAC;;oBAEU;YACZ,CAAC,CAAC;;;aAGG,CAAC;IACZ,OAAO;;;;EAIP,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiCZ,CAAC;AACF,CAAC;AAED,MAAM,CAAC,MAAM,WAAW,GAAG;;;;;;;;CAQ1B,CAAC"}
package/dist/ui.d.ts ADDED
@@ -0,0 +1,15 @@
1
+ export declare const c: {
2
+ bold: (text: string) => string;
3
+ dim: (text: string) => string;
4
+ red: (text: string) => string;
5
+ green: (text: string) => string;
6
+ yellow: (text: string) => string;
7
+ blue: (text: string) => string;
8
+ magenta: (text: string) => string;
9
+ cyan: (text: string) => string;
10
+ gray: (text: string) => string;
11
+ };
12
+ export declare function table(rows: string[][], header?: string[]): string;
13
+ export declare function statusColor(status: string): string;
14
+ export declare function short(text: string | undefined, max?: number): string;
15
+ //# sourceMappingURL=ui.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../src/ui.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,CAAC;IACZ,IAAI,SAH+C,MAAM;IAIzD,GAAG;IACH,GAAG;IACH,KAAK;IACL,MAAM;IACN,IAAI;IACJ,OAAO;IACP,IAAI;IACJ,IAAI;CACL,CAAC;AAMF,wBAAgB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,CAoBjE;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAKlD;AAED,wBAAgB,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE,GAAG,SAAK,GAAG,MAAM,CAGhE"}
package/dist/ui.js ADDED
@@ -0,0 +1,55 @@
1
+ const enabled = process.stdout.isTTY && !process.env.NO_COLOR && process.env.TERM !== "dumb";
2
+ const forced = process.env.FORCE_COLOR && process.env.FORCE_COLOR !== "0";
3
+ const on = Boolean(enabled || forced);
4
+ const wrap = (open, close) => (text) => (on ? `\u001b[${open}m${text}\u001b[${close}m` : text);
5
+ export const c = {
6
+ bold: wrap(1, 22),
7
+ dim: wrap(2, 22),
8
+ red: wrap(31, 39),
9
+ green: wrap(32, 39),
10
+ yellow: wrap(33, 39),
11
+ blue: wrap(34, 39),
12
+ magenta: wrap(35, 39),
13
+ cyan: wrap(36, 39),
14
+ gray: wrap(90, 39),
15
+ };
16
+ // biome-ignore lint/suspicious/noControlCharactersInRegex: strip ANSI escapes for width math
17
+ const ANSI = /\u001b\[[0-9;]*m/g;
18
+ const width = (text) => text.replace(ANSI, "").length;
19
+ export function table(rows, header) {
20
+ const all = header ? [header.map((h) => c.dim(h)), ...rows] : rows;
21
+ const widths = [];
22
+ for (const row of all) {
23
+ row.forEach((cell, i) => {
24
+ widths[i] = Math.max(widths[i] ?? 0, width(cell));
25
+ });
26
+ }
27
+ const columns = process.stdout.columns;
28
+ return all
29
+ .map((row) => {
30
+ const line = row
31
+ .map((cell, i) => (i === row.length - 1 ? cell : cell + " ".repeat((widths[i] ?? 0) - width(cell))))
32
+ .join(" ");
33
+ // Keep tables on one line per row: trim the last (free-text) column to the terminal width.
34
+ if (!columns || width(line) <= columns)
35
+ return line;
36
+ const plain = line.replace(ANSI, "");
37
+ return `${plain.slice(0, Math.max(0, columns - 1))}…`;
38
+ })
39
+ .join("\n");
40
+ }
41
+ export function statusColor(status) {
42
+ if (status === "settled")
43
+ return c.green(status);
44
+ if (status === "pending_approval" || status === "unknown" || status === "dry_run")
45
+ return c.yellow(status);
46
+ if (status === "denied" || status === "failed" || status === "expired")
47
+ return c.red(status);
48
+ return status;
49
+ }
50
+ export function short(text, max = 18) {
51
+ if (!text)
52
+ return "";
53
+ return text.length > max ? `${text.slice(0, max - 1)}…` : text;
54
+ }
55
+ //# sourceMappingURL=ui.js.map
package/dist/ui.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui.js","sourceRoot":"","sources":["../src/ui.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,46 @@
1
1
  {
2
2
  "name": "spendctl",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.1.0",
4
+ "description": "A corporate card and expense policy for AI agents: budgets, approvals and receipts for x402, MPP and any HTTP 402 API.",
5
+ "license": "SEE LICENSE IN LICENSE",
6
+ "type": "module",
7
+ "bin": {
8
+ "spendctl": "./bin/spendctl.js"
9
+ },
10
+ "main": "./dist/index.js",
11
+ "types": "./dist/index.d.ts",
12
+ "exports": {
13
+ ".": {
14
+ "types": "./dist/index.d.ts",
15
+ "import": "./dist/index.js"
16
+ }
17
+ },
18
+ "files": [
19
+ "bin",
20
+ "dist",
21
+ "README.md",
22
+ "THIRD_PARTY_NOTICES"
23
+ ],
24
+ "engines": {
25
+ "node": ">=22.13"
26
+ },
27
+ "keywords": [
28
+ "x402",
29
+ "mpp",
30
+ "ai-agents",
31
+ "payments",
32
+ "budget",
33
+ "mcp",
34
+ "spend-control",
35
+ "http-402"
36
+ ],
37
+ "homepage": "https://spendctl.dev",
38
+ "dependencies": {
39
+ "@spendctl/client": "^0.1.0",
40
+ "@spendctl/core": "0.1.0",
41
+ "@spendctl/mock": "0.1.0",
42
+ "@spendctl/proxy": "0.1.0",
43
+ "@spendctl/mcp-server": "0.1.0"
44
+ },
45
+ "scripts": {}
6
46
  }