@permission-protocol/mcp-guard 0.1.0 → 0.2.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.
Files changed (88) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/LICENSE +21 -0
  3. package/README.md +101 -59
  4. package/SECURITY.md +40 -0
  5. package/dist/src/approval-server.d.ts +69 -3
  6. package/dist/src/approval-server.js +345 -86
  7. package/dist/src/approval-server.js.map +1 -1
  8. package/dist/src/approval-ui.d.ts +5 -0
  9. package/dist/src/approval-ui.js +120 -81
  10. package/dist/src/approval-ui.js.map +1 -1
  11. package/dist/src/classify.d.ts +29 -0
  12. package/dist/src/classify.js +107 -0
  13. package/dist/src/classify.js.map +1 -0
  14. package/dist/src/cli.js +49 -12
  15. package/dist/src/cli.js.map +1 -1
  16. package/dist/src/config.d.ts +21 -1
  17. package/dist/src/config.js +92 -5
  18. package/dist/src/config.js.map +1 -1
  19. package/dist/src/enforcement/index.d.ts +12 -0
  20. package/dist/src/enforcement/index.js +53 -0
  21. package/dist/src/enforcement/index.js.map +1 -0
  22. package/dist/src/enforcement/policy.d.ts +29 -0
  23. package/dist/src/enforcement/policy.js +60 -0
  24. package/dist/src/enforcement/policy.js.map +1 -0
  25. package/dist/src/enforcement/types.d.ts +19 -0
  26. package/dist/src/enforcement/types.js +3 -0
  27. package/dist/src/enforcement/types.js.map +1 -0
  28. package/dist/src/enforcement/verifier.d.ts +4 -0
  29. package/dist/src/enforcement/verifier.js +110 -0
  30. package/dist/src/enforcement/verifier.js.map +1 -0
  31. package/dist/src/engine.d.ts +11 -2
  32. package/dist/src/engine.js +20 -14
  33. package/dist/src/engine.js.map +1 -1
  34. package/dist/src/frame.d.ts +67 -0
  35. package/dist/src/frame.js +113 -0
  36. package/dist/src/frame.js.map +1 -0
  37. package/dist/src/pending.d.ts +108 -12
  38. package/dist/src/pending.js +174 -24
  39. package/dist/src/pending.js.map +1 -1
  40. package/dist/src/proxy.d.ts +29 -2
  41. package/dist/src/proxy.js +274 -105
  42. package/dist/src/proxy.js.map +1 -1
  43. package/dist/src/receipt-verify.d.ts +36 -0
  44. package/dist/src/receipt-verify.js +88 -0
  45. package/dist/src/receipt-verify.js.map +1 -0
  46. package/dist/src/receipt.d.ts +81 -7
  47. package/dist/src/receipt.js +100 -17
  48. package/dist/src/receipt.js.map +1 -1
  49. package/dist/src/signer.d.ts +38 -0
  50. package/dist/src/signer.js +112 -0
  51. package/dist/src/signer.js.map +1 -0
  52. package/dist/src/verify-cli.d.ts +1 -0
  53. package/dist/src/verify-cli.js +133 -0
  54. package/dist/src/verify-cli.js.map +1 -0
  55. package/dist/src/verify-core.d.ts +22 -0
  56. package/dist/src/verify-core.js +50 -0
  57. package/dist/src/verify-core.js.map +1 -0
  58. package/dist/src/webhook.d.ts +35 -0
  59. package/dist/src/webhook.js +57 -0
  60. package/dist/src/webhook.js.map +1 -0
  61. package/example/test.sh +5 -7
  62. package/package.json +33 -7
  63. package/templates/github-actions/receipt-gate.yml +64 -0
  64. package/assets/demo.gif +0 -0
  65. package/demo/_demo-scenario.sh +0 -43
  66. package/dist/src/tests/config.test.d.ts +0 -1
  67. package/dist/src/tests/config.test.js +0 -63
  68. package/dist/src/tests/config.test.js.map +0 -1
  69. package/dist/src/tests/engine.test.d.ts +0 -1
  70. package/dist/src/tests/engine.test.js +0 -46
  71. package/dist/src/tests/engine.test.js.map +0 -1
  72. package/dist/src/tests/receipt.test.d.ts +0 -1
  73. package/dist/src/tests/receipt.test.js +0 -44
  74. package/dist/src/tests/receipt.test.js.map +0 -1
  75. package/docs/index.html +0 -771
  76. package/permission-protocol-mcp-guard-0.1.0.tgz +0 -0
  77. package/src/approval-server.ts +0 -136
  78. package/src/approval-ui.ts +0 -154
  79. package/src/cli.ts +0 -84
  80. package/src/config.ts +0 -68
  81. package/src/engine.ts +0 -31
  82. package/src/pending.ts +0 -65
  83. package/src/proxy.ts +0 -173
  84. package/src/receipt.ts +0 -52
  85. package/src/tests/config.test.ts +0 -61
  86. package/src/tests/engine.test.ts +0 -47
  87. package/src/tests/receipt.test.ts +0 -44
  88. package/tsconfig.json +0 -16
@@ -0,0 +1,113 @@
1
+ "use strict";
2
+ /**
3
+ * Inbound JSON-RPC framing for the stdio proxy.
4
+ *
5
+ * The guard only ever forwards a message it parsed and evaluated, re-serialized from
6
+ * the parsed object, so the server cannot read a line differently than the guard did.
7
+ * Anything that is not a single well-formed JSON-RPC 2.0 object is answered with an
8
+ * error and never forwarded. MCP does not use JSON-RPC batching, so arrays are refused.
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.PASSTHROUGH_METHODS = exports.RELEASE_FAILED = exports.EXPIRED = exports.DENIED = exports.HELD = exports.BLOCKED = exports.INVALID_PARAMS = exports.METHOD_NOT_FOUND = exports.INVALID_REQUEST = exports.PARSE_ERROR = void 0;
12
+ exports.isPassthrough = isPassthrough;
13
+ exports.parseFrame = parseFrame;
14
+ exports.errorLine = errorLine;
15
+ exports.toolCallTarget = toolCallTarget;
16
+ exports.stripAgentMetadata = stripAgentMetadata;
17
+ exports.PARSE_ERROR = -32700;
18
+ exports.INVALID_REQUEST = -32600;
19
+ exports.METHOD_NOT_FOUND = -32601;
20
+ exports.INVALID_PARAMS = -32602;
21
+ exports.BLOCKED = -32001;
22
+ exports.HELD = -32002;
23
+ exports.DENIED = -32003;
24
+ exports.EXPIRED = -32004;
25
+ exports.RELEASE_FAILED = -32005;
26
+ /**
27
+ * Methods that carry no action or data access of their own. Everything else — tools/call,
28
+ * resources/read, prompts/get, resources/subscribe and any method the guard does not
29
+ * know — goes through the policy.
30
+ */
31
+ exports.PASSTHROUGH_METHODS = new Set([
32
+ 'initialize',
33
+ 'ping',
34
+ 'tools/list',
35
+ 'resources/list',
36
+ 'resources/templates/list',
37
+ 'resources/unsubscribe',
38
+ 'prompts/list',
39
+ 'logging/setLevel',
40
+ 'completion/complete',
41
+ ]);
42
+ function isPassthrough(method) {
43
+ return exports.PASSTHROUGH_METHODS.has(method) || method.startsWith('notifications/');
44
+ }
45
+ function isPlainObject(v) {
46
+ return typeof v === 'object' && v !== null && !Array.isArray(v);
47
+ }
48
+ function validId(v) {
49
+ return v === null || typeof v === 'string' || (typeof v === 'number' && Number.isFinite(v));
50
+ }
51
+ function parseFrame(line) {
52
+ let parsed;
53
+ try {
54
+ parsed = JSON.parse(line);
55
+ }
56
+ catch {
57
+ return { kind: 'invalid', id: null, code: exports.PARSE_ERROR, message: 'Parse error' };
58
+ }
59
+ if (Array.isArray(parsed)) {
60
+ return { kind: 'invalid', id: null, code: exports.INVALID_REQUEST, message: 'Batch requests are not supported' };
61
+ }
62
+ if (!isPlainObject(parsed)) {
63
+ return { kind: 'invalid', id: null, code: exports.INVALID_REQUEST, message: 'Invalid Request' };
64
+ }
65
+ const id = validId(parsed.id) ? parsed.id : null;
66
+ const invalid = (message) => ({ kind: 'invalid', id, code: exports.INVALID_REQUEST, message });
67
+ if (parsed.jsonrpc !== '2.0')
68
+ return invalid('Invalid Request: jsonrpc must be "2.0"');
69
+ if ('id' in parsed && !validId(parsed.id))
70
+ return invalid('Invalid Request: bad id');
71
+ const msg = parsed;
72
+ if ('method' in parsed) {
73
+ if (typeof parsed.method !== 'string' || !parsed.method)
74
+ return invalid('Invalid Request: method must be a string');
75
+ if ('params' in parsed && !isPlainObject(parsed.params) && !Array.isArray(parsed.params)) {
76
+ return invalid('Invalid Request: params must be an object or array');
77
+ }
78
+ if ('id' in parsed)
79
+ return { kind: 'request', msg: msg };
80
+ return { kind: 'notification', msg: msg };
81
+ }
82
+ if ('id' in parsed && ('result' in parsed || 'error' in parsed))
83
+ return { kind: 'response', msg };
84
+ return invalid('Invalid Request');
85
+ }
86
+ function errorLine(id, code, message) {
87
+ return JSON.stringify({ jsonrpc: '2.0', id, error: { code, message } });
88
+ }
89
+ /**
90
+ * The tools/call target and arguments, validated. Returns an error message when the
91
+ * params are malformed (the call is then refused, never forwarded).
92
+ */
93
+ function toolCallTarget(params) {
94
+ if (!isPlainObject(params))
95
+ return { error: 'Invalid params: tools/call requires an object' };
96
+ if (typeof params.name !== 'string' || !params.name)
97
+ return { error: 'Invalid params: tool name must be a string' };
98
+ if (params.arguments !== undefined && !isPlainObject(params.arguments)) {
99
+ return { error: 'Invalid params: arguments must be an object' };
100
+ }
101
+ return { name: params.name, args: params.arguments };
102
+ }
103
+ /** A copy of the message with Permission Deck agent metadata (`_pp`) removed from tool arguments. */
104
+ function stripAgentMetadata(msg) {
105
+ const params = msg.params;
106
+ if (msg.method !== 'tools/call' || !isPlainObject(params) || !isPlainObject(params.arguments))
107
+ return msg;
108
+ if (!('_pp' in params.arguments))
109
+ return msg;
110
+ const { _pp, ...rest } = params.arguments;
111
+ return { ...msg, params: { ...params, arguments: rest } };
112
+ }
113
+ //# sourceMappingURL=frame.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frame.js","sourceRoot":"","sources":["../../src/frame.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG;;;AA8CH,sCAEC;AAUD,gCA8BC;AAED,8BAEC;AAMD,wCASC;AAGD,gDAMC;AAjGY,QAAA,WAAW,GAAG,CAAC,KAAK,CAAC;AACrB,QAAA,eAAe,GAAG,CAAC,KAAK,CAAC;AACzB,QAAA,gBAAgB,GAAG,CAAC,KAAK,CAAC;AAC1B,QAAA,cAAc,GAAG,CAAC,KAAK,CAAC;AACxB,QAAA,OAAO,GAAG,CAAC,KAAK,CAAC;AACjB,QAAA,IAAI,GAAG,CAAC,KAAK,CAAC;AACd,QAAA,MAAM,GAAG,CAAC,KAAK,CAAC;AAChB,QAAA,OAAO,GAAG,CAAC,KAAK,CAAC;AACjB,QAAA,cAAc,GAAG,CAAC,KAAK,CAAC;AAErC;;;;GAIG;AACU,QAAA,mBAAmB,GAAG,IAAI,GAAG,CAAC;IACzC,YAAY;IACZ,MAAM;IACN,YAAY;IACZ,gBAAgB;IAChB,0BAA0B;IAC1B,uBAAuB;IACvB,cAAc;IACd,kBAAkB;IAClB,qBAAqB;CACtB,CAAC,CAAC;AAEH,SAAgB,aAAa,CAAC,MAAc;IAC1C,OAAO,2BAAmB,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC;AAChF,CAAC;AAED,SAAS,aAAa,CAAC,CAAU;IAC/B,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAClE,CAAC;AAED,SAAS,OAAO,CAAC,CAAU;IACzB,OAAO,CAAC,KAAK,IAAI,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9F,CAAC;AAED,SAAgB,UAAU,CAAC,IAAY;IACrC,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,mBAAW,EAAE,OAAO,EAAE,aAAa,EAAE,CAAC;IAClF,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAC1B,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,uBAAe,EAAE,OAAO,EAAE,kCAAkC,EAAE,CAAC;IAC3G,CAAC;IACD,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC;QAC3B,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,uBAAe,EAAE,OAAO,EAAE,iBAAiB,EAAE,CAAC;IAC1F,CAAC;IACD,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IACjD,MAAM,OAAO,GAAG,CAAC,OAAe,EAAS,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,IAAI,EAAE,uBAAe,EAAE,OAAO,EAAE,CAAC,CAAC;IAEtG,IAAI,MAAM,CAAC,OAAO,KAAK,KAAK;QAAE,OAAO,OAAO,CAAC,wCAAwC,CAAC,CAAC;IACvF,IAAI,IAAI,IAAI,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAAE,OAAO,OAAO,CAAC,yBAAyB,CAAC,CAAC;IAErF,MAAM,GAAG,GAAG,MAAmC,CAAC;IAChD,IAAI,QAAQ,IAAI,MAAM,EAAE,CAAC;QACvB,IAAI,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,MAAM;YAAE,OAAO,OAAO,CAAC,0CAA0C,CAAC,CAAC;QACpH,IAAI,QAAQ,IAAI,MAAM,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;YACzF,OAAO,OAAO,CAAC,oDAAoD,CAAC,CAAC;QACvE,CAAC;QACD,IAAI,IAAI,IAAI,MAAM;YAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,GAAyD,EAAE,CAAC;QAC/G,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,GAAG,EAAE,GAA0C,EAAE,CAAC;IACnF,CAAC;IACD,IAAI,IAAI,IAAI,MAAM,IAAI,CAAC,QAAQ,IAAI,MAAM,IAAI,OAAO,IAAI,MAAM,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC;IAClG,OAAO,OAAO,CAAC,iBAAiB,CAAC,CAAC;AACpC,CAAC;AAED,SAAgB,SAAS,CAAC,EAAa,EAAE,IAAY,EAAE,OAAe;IACpE,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC;AAC1E,CAAC;AAED;;;GAGG;AACH,SAAgB,cAAc,CAC5B,MAAe;IAEf,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC;QAAE,OAAO,EAAE,KAAK,EAAE,+CAA+C,EAAE,CAAC;IAC9F,IAAI,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,IAAI;QAAE,OAAO,EAAE,KAAK,EAAE,4CAA4C,EAAE,CAAC;IACpH,IAAI,MAAM,CAAC,SAAS,KAAK,SAAS,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC;QACvE,OAAO,EAAE,KAAK,EAAE,6CAA6C,EAAE,CAAC;IAClE,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,SAAgD,EAAE,CAAC;AAC9F,CAAC;AAED,qGAAqG;AACrG,SAAgB,kBAAkB,CAAC,GAAmB;IACpD,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC;IAC1B,IAAI,GAAG,CAAC,MAAM,KAAK,YAAY,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,SAAS,CAAC;QAAE,OAAO,GAAG,CAAC;IAC1G,IAAI,CAAC,CAAC,KAAK,IAAI,MAAM,CAAC,SAAS,CAAC;QAAE,OAAO,GAAG,CAAC;IAC7C,MAAM,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,GAAG,MAAM,CAAC,SAAS,CAAC;IAC1C,OAAO,EAAE,GAAG,GAAG,EAAE,MAAM,EAAE,EAAE,GAAG,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,CAAC;AAC5D,CAAC"}
@@ -1,20 +1,116 @@
1
+ import type { Lane } from './engine.js';
2
+ import type { Reversibility } from './config.js';
3
+ import type { JsonRpcId } from './frame.js';
4
+ /**
5
+ * The approval queue and its decision state machine.
6
+ *
7
+ * Every status change goes through `transition()`, driven by one table: an item starts
8
+ * `pending` and moves exactly once to a final state. Final states never change, so a
9
+ * denied item can never be approved, and an approval racing a countdown releases once.
10
+ *
11
+ * Item kinds:
12
+ * - held: a request the proxy is holding; approve/auto-release forwards it.
13
+ * - acted: a Verify-lane action that already ran under a standing rule; it can only
14
+ * be acknowledged (it cannot be denied or undone after the fact).
15
+ * - external: a decision with no MCP request behind it (GitHub webhook); approve
16
+ * issues a scoped receipt.
17
+ */
18
+ export type PendingStatus = 'pending' | 'approved' | 'denied' | 'auto_released' | 'expired' | 'acknowledged';
19
+ export type PendingKind = 'held' | 'acted' | 'external';
20
+ export type PendingEvent = 'approve' | 'deny' | 'auto_release' | 'expire' | 'acknowledge' | 'hold';
21
+ /** Resolved items kept for display before the oldest are dropped. */
22
+ export declare const MAX_RESOLVED = 200;
23
+ export interface PendingEnrichment {
24
+ lane: Lane;
25
+ reversibility: Reversibility;
26
+ countdown_seconds?: number;
27
+ confidence?: number;
28
+ summary: string;
29
+ args_preview: string;
30
+ }
1
31
  export interface PendingAction {
2
32
  id: string;
3
- timestamp: string;
33
+ kind: PendingKind;
34
+ method: string;
4
35
  tool_name: string;
5
- tool_args: any;
36
+ tool_args: Record<string, unknown>;
6
37
  agent_id: string;
7
- rule_id: string;
8
- status: 'pending' | 'approved' | 'denied';
9
- /** The original JSON-RPC line to forward on approval */
10
- originalLine: string;
11
- /** The JSON-RPC request id for matching child responses */
12
- jsonrpcId: string | number | null;
13
- /** Resolver — call with the response line (or error JSON) to unblock the proxy */
38
+ rule_id: string | null;
39
+ status: PendingStatus;
40
+ created_at: string;
41
+ resolved_at?: string;
42
+ /** ISO time after which a pending item expires; absent = no expiry. */
43
+ expires_at?: string;
44
+ /** The JSON-RPC line to forward on release (held items only). */
45
+ forwardLine: string;
46
+ jsonrpcId: JsonRpcId;
47
+ /** Deliver a response line to the waiting client (held items only). */
48
+ resolve: (responseLine: string) => void;
49
+ lane: Lane;
50
+ reversibility: Reversibility;
51
+ countdown_seconds?: number;
52
+ confidence?: number;
53
+ summary: string;
54
+ args_preview: string;
55
+ receipt_id?: string;
56
+ scope?: string;
57
+ scope_ref?: string;
58
+ scope_sha?: string;
59
+ /** epoch ms when the countdown auto-release fires; undefined = no countdown */
60
+ releaseAt?: number;
61
+ countdownTimer?: NodeJS.Timeout;
62
+ expiryTimer?: NodeJS.Timeout;
63
+ }
64
+ export type TransitionResult = {
65
+ ok: true;
66
+ action: PendingAction;
67
+ } | {
68
+ ok: false;
69
+ error: 'not_found' | 'final' | 'not_allowed';
70
+ action?: PendingAction;
71
+ };
72
+ export declare function setAutoReleaseHandler(handler: ((action: PendingAction) => void) | null): void;
73
+ export declare function setExpireHandler(handler: ((action: PendingAction) => void) | null): void;
74
+ /** The only place an item's status changes. */
75
+ export declare function transition(id: string, event: PendingEvent): TransitionResult;
76
+ interface BaseInput {
77
+ toolName: string;
78
+ toolArgs?: Record<string, unknown>;
79
+ agentId: string;
80
+ ruleId: string | null;
81
+ enrichment: PendingEnrichment;
82
+ method?: string;
83
+ }
84
+ export interface HeldInput extends BaseInput {
85
+ /** The scope the release receipt will bind, shown to the approver. */
86
+ scope?: string;
87
+ scope_ref?: string;
88
+ scope_sha?: string;
89
+ forwardLine: string;
90
+ jsonrpcId: JsonRpcId;
14
91
  resolve: (responseLine: string) => void;
92
+ ttlSeconds?: number;
93
+ }
94
+ /** Hold a request for a decision. Reversible holds with a countdown auto-release. */
95
+ export declare function addPending(input: HeldInput): PendingAction;
96
+ export interface ActedInput extends BaseInput {
97
+ receiptId?: string;
98
+ ttlSeconds?: number;
99
+ }
100
+ /** Surface an action that already ran under a standing rule, for acknowledgement. */
101
+ export declare function surfaceActed(input: ActedInput): PendingAction;
102
+ export interface ExternalInput extends BaseInput {
103
+ scope?: string;
104
+ scope_ref?: string;
105
+ scope_sha?: string;
15
106
  }
16
- export declare function addPending(toolName: string, toolArgs: any, agentId: string, ruleId: string, originalLine: string, jsonrpcId: string | number | null, resolve: (responseLine: string) => void): PendingAction;
107
+ /** Enqueue a decision from an external source (GitHub webhook). Never auto-releases or expires. */
108
+ export declare function addExternalDecision(input: ExternalInput): PendingAction;
17
109
  export declare function getPending(): PendingAction[];
18
110
  export declare function getAction(id: string): PendingAction | undefined;
19
- export declare function resolveAction(id: string, status: 'approved' | 'denied'): PendingAction | undefined;
20
- export declare function recentResolved(limit?: number): PendingAction[];
111
+ export declare function queueSize(): number;
112
+ /** Seconds remaining until auto-release, server-computed. undefined if no countdown. */
113
+ export declare function countdownRemaining(action: PendingAction): number | undefined;
114
+ /** Test/teardown helper: clear the queue and any live timers. */
115
+ export declare function _resetQueue(): void;
116
+ export {};
@@ -1,44 +1,194 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MAX_RESOLVED = void 0;
4
+ exports.setAutoReleaseHandler = setAutoReleaseHandler;
5
+ exports.setExpireHandler = setExpireHandler;
6
+ exports.transition = transition;
3
7
  exports.addPending = addPending;
8
+ exports.surfaceActed = surfaceActed;
9
+ exports.addExternalDecision = addExternalDecision;
4
10
  exports.getPending = getPending;
5
11
  exports.getAction = getAction;
6
- exports.resolveAction = resolveAction;
7
- exports.recentResolved = recentResolved;
8
- const uuid_1 = require("uuid");
12
+ exports.queueSize = queueSize;
13
+ exports.countdownRemaining = countdownRemaining;
14
+ exports._resetQueue = _resetQueue;
15
+ const node_crypto_1 = require("node:crypto");
16
+ const ALLOWED_EVENTS = {
17
+ held: new Set(['approve', 'deny', 'auto_release', 'expire', 'hold']),
18
+ acted: new Set(['acknowledge', 'expire']),
19
+ external: new Set(['approve', 'deny']),
20
+ };
21
+ const FINAL_STATUS = {
22
+ approve: 'approved',
23
+ deny: 'denied',
24
+ auto_release: 'auto_released',
25
+ expire: 'expired',
26
+ acknowledge: 'acknowledged',
27
+ };
28
+ /** Resolved items kept for display before the oldest are dropped. */
29
+ exports.MAX_RESOLVED = 200;
9
30
  const queue = new Map();
10
- function addPending(toolName, toolArgs, agentId, ruleId, originalLine, jsonrpcId, resolve) {
11
- const action = {
12
- id: (0, uuid_1.v4)(),
13
- timestamp: new Date().toISOString(),
14
- tool_name: toolName,
15
- tool_args: toolArgs,
16
- agent_id: agentId,
17
- rule_id: ruleId,
31
+ /** Called after a countdown has moved an item to `auto_released`; the proxy releases it. */
32
+ let autoReleaseHandler = null;
33
+ function setAutoReleaseHandler(handler) {
34
+ autoReleaseHandler = handler;
35
+ }
36
+ /** Called after a TTL has moved an item to `expired`; the proxy answers the client. */
37
+ let expireHandler = null;
38
+ function setExpireHandler(handler) {
39
+ expireHandler = handler;
40
+ }
41
+ function clearTimers(action, which) {
42
+ if (action.countdownTimer)
43
+ clearTimeout(action.countdownTimer);
44
+ action.countdownTimer = undefined;
45
+ if (which === 'all') {
46
+ if (action.expiryTimer)
47
+ clearTimeout(action.expiryTimer);
48
+ action.expiryTimer = undefined;
49
+ }
50
+ }
51
+ function prune() {
52
+ let resolved = 0;
53
+ for (const a of queue.values())
54
+ if (a.status !== 'pending')
55
+ resolved++;
56
+ if (resolved <= exports.MAX_RESOLVED)
57
+ return;
58
+ for (const [id, a] of queue) {
59
+ if (resolved <= exports.MAX_RESOLVED)
60
+ break;
61
+ if (a.status !== 'pending') {
62
+ queue.delete(id);
63
+ resolved--;
64
+ }
65
+ }
66
+ }
67
+ /** The only place an item's status changes. */
68
+ function transition(id, event) {
69
+ const action = queue.get(id);
70
+ if (!action)
71
+ return { ok: false, error: 'not_found' };
72
+ if (action.status !== 'pending')
73
+ return { ok: false, error: 'final', action };
74
+ if (!ALLOWED_EVENTS[action.kind].has(event))
75
+ return { ok: false, error: 'not_allowed', action };
76
+ if ((event === 'auto_release' || event === 'hold') && action.releaseAt === undefined) {
77
+ return { ok: false, error: 'not_allowed', action };
78
+ }
79
+ if (event === 'hold') {
80
+ clearTimers(action, 'countdown');
81
+ action.releaseAt = undefined;
82
+ return { ok: true, action };
83
+ }
84
+ clearTimers(action, 'all');
85
+ action.releaseAt = undefined;
86
+ action.status = FINAL_STATUS[event];
87
+ action.resolved_at = new Date().toISOString();
88
+ prune();
89
+ return { ok: true, action };
90
+ }
91
+ function startExpiry(action, ttlSeconds) {
92
+ if (!ttlSeconds || ttlSeconds <= 0)
93
+ return;
94
+ action.expires_at = new Date(Date.now() + ttlSeconds * 1000).toISOString();
95
+ action.expiryTimer = setTimeout(() => {
96
+ const r = transition(action.id, 'expire');
97
+ if (r.ok && expireHandler)
98
+ expireHandler(r.action);
99
+ }, ttlSeconds * 1000);
100
+ action.expiryTimer.unref?.();
101
+ }
102
+ function baseAction(kind, input) {
103
+ return {
104
+ id: (0, node_crypto_1.randomUUID)(),
105
+ kind,
106
+ method: input.method ?? 'tools/call',
107
+ tool_name: input.toolName,
108
+ tool_args: input.toolArgs ?? {},
109
+ agent_id: input.agentId,
110
+ rule_id: input.ruleId,
18
111
  status: 'pending',
19
- originalLine,
20
- jsonrpcId,
21
- resolve,
112
+ created_at: new Date().toISOString(),
113
+ forwardLine: '',
114
+ jsonrpcId: null,
115
+ resolve: () => { },
116
+ lane: input.enrichment.lane,
117
+ reversibility: input.enrichment.reversibility,
118
+ ...(input.enrichment.confidence !== undefined ? { confidence: input.enrichment.confidence } : {}),
119
+ summary: input.enrichment.summary,
120
+ args_preview: input.enrichment.args_preview,
22
121
  };
122
+ }
123
+ /** Hold a request for a decision. Reversible holds with a countdown auto-release. */
124
+ function addPending(input) {
125
+ const action = baseAction('held', input);
126
+ action.forwardLine = input.forwardLine;
127
+ action.jsonrpcId = input.jsonrpcId;
128
+ action.resolve = input.resolve;
129
+ if (input.scope)
130
+ action.scope = input.scope;
131
+ if (input.scope_ref)
132
+ action.scope_ref = input.scope_ref;
133
+ if (input.scope_sha)
134
+ action.scope_sha = input.scope_sha;
135
+ const countdown = input.enrichment.countdown_seconds;
136
+ if (countdown !== undefined)
137
+ action.countdown_seconds = countdown;
138
+ // Irreversible (or no countdown) NEVER auto-releases; it waits for a decision or expiry.
139
+ if (action.reversibility === 'reversible' && countdown !== undefined && countdown > 0) {
140
+ action.releaseAt = Date.now() + countdown * 1000;
141
+ action.countdownTimer = setTimeout(() => {
142
+ const r = transition(action.id, 'auto_release');
143
+ if (r.ok && autoReleaseHandler)
144
+ autoReleaseHandler(r.action);
145
+ }, countdown * 1000);
146
+ action.countdownTimer.unref?.();
147
+ }
148
+ startExpiry(action, input.ttlSeconds);
149
+ queue.set(action.id, action);
150
+ return action;
151
+ }
152
+ /** Surface an action that already ran under a standing rule, for acknowledgement. */
153
+ function surfaceActed(input) {
154
+ const action = baseAction('acted', input);
155
+ if (input.receiptId !== undefined)
156
+ action.receipt_id = input.receiptId;
157
+ startExpiry(action, input.ttlSeconds);
158
+ queue.set(action.id, action);
159
+ return action;
160
+ }
161
+ /** Enqueue a decision from an external source (GitHub webhook). Never auto-releases or expires. */
162
+ function addExternalDecision(input) {
163
+ const action = baseAction('external', input);
164
+ if (input.scope)
165
+ action.scope = input.scope;
166
+ if (input.scope_ref)
167
+ action.scope_ref = input.scope_ref;
168
+ if (input.scope_sha)
169
+ action.scope_sha = input.scope_sha;
23
170
  queue.set(action.id, action);
24
171
  return action;
25
172
  }
26
173
  function getPending() {
27
- return Array.from(queue.values()).filter(a => a.status === 'pending');
174
+ return Array.from(queue.values()).filter((a) => a.status === 'pending');
28
175
  }
29
176
  function getAction(id) {
30
177
  return queue.get(id);
31
178
  }
32
- function resolveAction(id, status) {
33
- const action = queue.get(id);
34
- if (!action || action.status !== 'pending')
179
+ function queueSize() {
180
+ return queue.size;
181
+ }
182
+ /** Seconds remaining until auto-release, server-computed. undefined if no countdown. */
183
+ function countdownRemaining(action) {
184
+ if (action.releaseAt === undefined || action.status !== 'pending')
35
185
  return undefined;
36
- action.status = status;
37
- return action;
186
+ return Math.max(0, Math.ceil((action.releaseAt - Date.now()) / 1000));
38
187
  }
39
- function recentResolved(limit = 50) {
40
- return Array.from(queue.values())
41
- .filter(a => a.status !== 'pending')
42
- .slice(-limit);
188
+ /** Test/teardown helper: clear the queue and any live timers. */
189
+ function _resetQueue() {
190
+ for (const action of queue.values())
191
+ clearTimers(action, 'all');
192
+ queue.clear();
43
193
  }
44
194
  //# sourceMappingURL=pending.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"pending.js","sourceRoot":"","sources":["../../src/pending.ts"],"names":[],"mappings":";;AAoBA,gCAuBC;AAED,gCAEC;AAED,8BAEC;AAED,sCAKC;AAED,wCAIC;AAhED,+BAAoC;AAkBpC,MAAM,KAAK,GAA+B,IAAI,GAAG,EAAE,CAAC;AAEpD,SAAgB,UAAU,CACxB,QAAgB,EAChB,QAAa,EACb,OAAe,EACf,MAAc,EACd,YAAoB,EACpB,SAAiC,EACjC,OAAuC;IAEvC,MAAM,MAAM,GAAkB;QAC5B,EAAE,EAAE,IAAA,SAAM,GAAE;QACZ,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,SAAS,EAAE,QAAQ;QACnB,SAAS,EAAE,QAAQ;QACnB,QAAQ,EAAE,OAAO;QACjB,OAAO,EAAE,MAAM;QACf,MAAM,EAAE,SAAS;QACjB,YAAY;QACZ,SAAS;QACT,OAAO;KACR,CAAC;IACF,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;IAC7B,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAgB,UAAU;IACxB,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC;AACxE,CAAC;AAED,SAAgB,SAAS,CAAC,EAAU;IAClC,OAAO,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AACvB,CAAC;AAED,SAAgB,aAAa,CAAC,EAAU,EAAE,MAA6B;IACrE,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC7B,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC7D,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAgB,cAAc,CAAC,QAAgB,EAAE;IAC/C,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;SAC9B,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,SAAS,CAAC;SACnC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC;AACnB,CAAC"}
1
+ {"version":3,"file":"pending.js","sourceRoot":"","sources":["../../src/pending.ts"],"names":[],"mappings":"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"}
@@ -1,2 +1,29 @@
1
- import type { Config } from './config.js';
2
- export declare function startProxy(config: Config, agentId: string, serverCommand: string[], approvalPort?: number): void;
1
+ import { type Config, type Rule } from './config.js';
2
+ import { type Decision } from './engine.js';
3
+ import { type ScopeBinding } from './receipt.js';
4
+ import { type PendingEnrichment } from './pending.js';
5
+ /**
6
+ * Derive a one-line summary + the literal artifact preview from the tool name and args,
7
+ * so the console can render a human-readable card. For capped spends the amount shown is
8
+ * the argument the rule caps (`amountArg`), the same one the classifier read.
9
+ */
10
+ export declare function derivePreview(toolName: string, toolArgs: Record<string, unknown> | undefined, amountArg?: string): {
11
+ summary: string;
12
+ args_preview: string;
13
+ };
14
+ /** Build the enrichment record for the queue from a classified Decision + args. */
15
+ export declare function buildEnrichment(decision: Decision, toolName: string, toolArgs: Record<string, unknown> | undefined, rule?: Rule | null): PendingEnrichment;
16
+ /**
17
+ * Derive a receipt scope binding from the tool + args, for the code/infra tools the
18
+ * offline receipt gate verifies:
19
+ * - merge_pr -> `github:merge`, ref `refs/pull/<n>/merge`
20
+ * - run_sql_migration -> `sql:migrate:<env>`
21
+ * - deploy -> `deploy:<env>`
22
+ * Other tools carry no scope.
23
+ */
24
+ export declare function deriveScope(toolName: string, toolArgs: Record<string, unknown> | undefined): ScopeBinding | undefined;
25
+ export interface ProxyOptions {
26
+ approvalPort?: number;
27
+ operator?: string;
28
+ }
29
+ export declare function startProxy(config: Config, agentId: string, serverCommand: string[], opts?: ProxyOptions): void;