agy-worker-mcp 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (227) hide show
  1. package/CHANGELOG.md +141 -0
  2. package/LICENSE +21 -0
  3. package/README.md +309 -0
  4. package/commands/agy-ceiling.md +31 -0
  5. package/dist/broker/blockers.d.ts +86 -0
  6. package/dist/broker/blockers.d.ts.map +1 -0
  7. package/dist/broker/blockers.js +390 -0
  8. package/dist/broker/blockers.js.map +1 -0
  9. package/dist/broker/outcome.d.ts +85 -0
  10. package/dist/broker/outcome.d.ts.map +1 -0
  11. package/dist/broker/outcome.js +147 -0
  12. package/dist/broker/outcome.js.map +1 -0
  13. package/dist/broker/reconcile.d.ts +74 -0
  14. package/dist/broker/reconcile.d.ts.map +1 -0
  15. package/dist/broker/reconcile.js +415 -0
  16. package/dist/broker/reconcile.js.map +1 -0
  17. package/dist/broker/result.d.ts +88 -0
  18. package/dist/broker/result.d.ts.map +1 -0
  19. package/dist/broker/result.js +234 -0
  20. package/dist/broker/result.js.map +1 -0
  21. package/dist/broker/verify.d.ts +52 -0
  22. package/dist/broker/verify.d.ts.map +1 -0
  23. package/dist/broker/verify.js +174 -0
  24. package/dist/broker/verify.js.map +1 -0
  25. package/dist/contract/errors.d.ts +119 -0
  26. package/dist/contract/errors.d.ts.map +1 -0
  27. package/dist/contract/errors.js +99 -0
  28. package/dist/contract/errors.js.map +1 -0
  29. package/dist/contract/index.d.ts +10 -0
  30. package/dist/contract/index.d.ts.map +1 -0
  31. package/dist/contract/index.js +10 -0
  32. package/dist/contract/index.js.map +1 -0
  33. package/dist/contract/paths.d.ts +139 -0
  34. package/dist/contract/paths.d.ts.map +1 -0
  35. package/dist/contract/paths.js +359 -0
  36. package/dist/contract/paths.js.map +1 -0
  37. package/dist/contract/schema.sql +64 -0
  38. package/dist/contract/types.d.ts +1113 -0
  39. package/dist/contract/types.d.ts.map +1 -0
  40. package/dist/contract/types.js +114 -0
  41. package/dist/contract/types.js.map +1 -0
  42. package/dist/events/cursor.d.ts +65 -0
  43. package/dist/events/cursor.d.ts.map +1 -0
  44. package/dist/events/cursor.js +286 -0
  45. package/dist/events/cursor.js.map +1 -0
  46. package/dist/events/detect.d.ts +58 -0
  47. package/dist/events/detect.d.ts.map +1 -0
  48. package/dist/events/detect.js +183 -0
  49. package/dist/events/detect.js.map +1 -0
  50. package/dist/events/normalize.d.ts +30 -0
  51. package/dist/events/normalize.d.ts.map +1 -0
  52. package/dist/events/normalize.js +158 -0
  53. package/dist/events/normalize.js.map +1 -0
  54. package/dist/events/parse.d.ts +41 -0
  55. package/dist/events/parse.d.ts.map +1 -0
  56. package/dist/events/parse.js +89 -0
  57. package/dist/events/parse.js.map +1 -0
  58. package/dist/gate/bind.d.ts +28 -0
  59. package/dist/gate/bind.d.ts.map +1 -0
  60. package/dist/gate/bind.js +154 -0
  61. package/dist/gate/bind.js.map +1 -0
  62. package/dist/gate/gate.d.ts +139 -0
  63. package/dist/gate/gate.d.ts.map +1 -0
  64. package/dist/gate/gate.js +488 -0
  65. package/dist/gate/gate.js.map +1 -0
  66. package/dist/gate/hooks-file.d.ts +55 -0
  67. package/dist/gate/hooks-file.d.ts.map +1 -0
  68. package/dist/gate/hooks-file.js +104 -0
  69. package/dist/gate/hooks-file.js.map +1 -0
  70. package/dist/gate.d.ts +3 -0
  71. package/dist/gate.d.ts.map +1 -0
  72. package/dist/gate.js +20 -0
  73. package/dist/gate.js.map +1 -0
  74. package/dist/policy/ceiling-review.d.ts +22 -0
  75. package/dist/policy/ceiling-review.d.ts.map +1 -0
  76. package/dist/policy/ceiling-review.js +170 -0
  77. package/dist/policy/ceiling-review.js.map +1 -0
  78. package/dist/policy/ceiling.d.ts +128 -0
  79. package/dist/policy/ceiling.d.ts.map +1 -0
  80. package/dist/policy/ceiling.js +273 -0
  81. package/dist/policy/ceiling.js.map +1 -0
  82. package/dist/policy/containment.d.ts +100 -0
  83. package/dist/policy/containment.d.ts.map +1 -0
  84. package/dist/policy/containment.js +1071 -0
  85. package/dist/policy/containment.js.map +1 -0
  86. package/dist/policy/hard-deny.d.ts +28 -0
  87. package/dist/policy/hard-deny.d.ts.map +1 -0
  88. package/dist/policy/hard-deny.js +78 -0
  89. package/dist/policy/hard-deny.js.map +1 -0
  90. package/dist/policy/profiles.d.ts +82 -0
  91. package/dist/policy/profiles.d.ts.map +1 -0
  92. package/dist/policy/profiles.js +317 -0
  93. package/dist/policy/profiles.js.map +1 -0
  94. package/dist/policy/rules.d.ts +138 -0
  95. package/dist/policy/rules.d.ts.map +1 -0
  96. package/dist/policy/rules.js +1180 -0
  97. package/dist/policy/rules.js.map +1 -0
  98. package/dist/policy/seatbelt.d.ts +32 -0
  99. package/dist/policy/seatbelt.d.ts.map +1 -0
  100. package/dist/policy/seatbelt.js +59 -0
  101. package/dist/policy/seatbelt.js.map +1 -0
  102. package/dist/policy/tools.d.ts +36 -0
  103. package/dist/policy/tools.d.ts.map +1 -0
  104. package/dist/policy/tools.js +94 -0
  105. package/dist/policy/tools.js.map +1 -0
  106. package/dist/runner/gate-watchdog.d.ts +93 -0
  107. package/dist/runner/gate-watchdog.d.ts.map +1 -0
  108. package/dist/runner/gate-watchdog.js +153 -0
  109. package/dist/runner/gate-watchdog.js.map +1 -0
  110. package/dist/runner/idle.d.ts +51 -0
  111. package/dist/runner/idle.d.ts.map +1 -0
  112. package/dist/runner/idle.js +81 -0
  113. package/dist/runner/idle.js.map +1 -0
  114. package/dist/runner/inbox.d.ts +56 -0
  115. package/dist/runner/inbox.d.ts.map +1 -0
  116. package/dist/runner/inbox.js +134 -0
  117. package/dist/runner/inbox.js.map +1 -0
  118. package/dist/runner/reap.d.ts +65 -0
  119. package/dist/runner/reap.d.ts.map +1 -0
  120. package/dist/runner/reap.js +168 -0
  121. package/dist/runner/reap.js.map +1 -0
  122. package/dist/runner/runner.d.ts +51 -0
  123. package/dist/runner/runner.d.ts.map +1 -0
  124. package/dist/runner/runner.js +289 -0
  125. package/dist/runner/runner.js.map +1 -0
  126. package/dist/runner/spawn.d.ts +98 -0
  127. package/dist/runner/spawn.d.ts.map +1 -0
  128. package/dist/runner/spawn.js +230 -0
  129. package/dist/runner/spawn.js.map +1 -0
  130. package/dist/runner/verify.d.ts +24 -0
  131. package/dist/runner/verify.d.ts.map +1 -0
  132. package/dist/runner/verify.js +108 -0
  133. package/dist/runner/verify.js.map +1 -0
  134. package/dist/runner.d.ts +3 -0
  135. package/dist/runner.d.ts.map +1 -0
  136. package/dist/runner.js +15 -0
  137. package/dist/runner.js.map +1 -0
  138. package/dist/server/context.d.ts +41 -0
  139. package/dist/server/context.d.ts.map +1 -0
  140. package/dist/server/context.js +59 -0
  141. package/dist/server/context.js.map +1 -0
  142. package/dist/server/instructions.d.ts +13 -0
  143. package/dist/server/instructions.d.ts.map +1 -0
  144. package/dist/server/instructions.js +121 -0
  145. package/dist/server/instructions.js.map +1 -0
  146. package/dist/server/server.d.ts +20 -0
  147. package/dist/server/server.d.ts.map +1 -0
  148. package/dist/server/server.js +55 -0
  149. package/dist/server/server.js.map +1 -0
  150. package/dist/server/tools/cancel.d.ts +24 -0
  151. package/dist/server/tools/cancel.d.ts.map +1 -0
  152. package/dist/server/tools/cancel.js +59 -0
  153. package/dist/server/tools/cancel.js.map +1 -0
  154. package/dist/server/tools/capabilities.d.ts +36 -0
  155. package/dist/server/tools/capabilities.d.ts.map +1 -0
  156. package/dist/server/tools/capabilities.js +116 -0
  157. package/dist/server/tools/capabilities.js.map +1 -0
  158. package/dist/server/tools/ceiling.d.ts +31 -0
  159. package/dist/server/tools/ceiling.d.ts.map +1 -0
  160. package/dist/server/tools/ceiling.js +121 -0
  161. package/dist/server/tools/ceiling.js.map +1 -0
  162. package/dist/server/tools/index.d.ts +38 -0
  163. package/dist/server/tools/index.d.ts.map +1 -0
  164. package/dist/server/tools/index.js +115 -0
  165. package/dist/server/tools/index.js.map +1 -0
  166. package/dist/server/tools/listJobs.d.ts +30 -0
  167. package/dist/server/tools/listJobs.d.ts.map +1 -0
  168. package/dist/server/tools/listJobs.js +37 -0
  169. package/dist/server/tools/listJobs.js.map +1 -0
  170. package/dist/server/tools/logs.d.ts +31 -0
  171. package/dist/server/tools/logs.d.ts.map +1 -0
  172. package/dist/server/tools/logs.js +96 -0
  173. package/dist/server/tools/logs.js.map +1 -0
  174. package/dist/server/tools/result.d.ts +32 -0
  175. package/dist/server/tools/result.d.ts.map +1 -0
  176. package/dist/server/tools/result.js +95 -0
  177. package/dist/server/tools/result.js.map +1 -0
  178. package/dist/server/tools/send.d.ts +37 -0
  179. package/dist/server/tools/send.d.ts.map +1 -0
  180. package/dist/server/tools/send.js +71 -0
  181. package/dist/server/tools/send.js.map +1 -0
  182. package/dist/server/tools/sessions.d.ts +28 -0
  183. package/dist/server/tools/sessions.d.ts.map +1 -0
  184. package/dist/server/tools/sessions.js +54 -0
  185. package/dist/server/tools/sessions.js.map +1 -0
  186. package/dist/server/tools/start.d.ts +107 -0
  187. package/dist/server/tools/start.d.ts.map +1 -0
  188. package/dist/server/tools/start.js +482 -0
  189. package/dist/server/tools/start.js.map +1 -0
  190. package/dist/server/tools/wait.d.ts +29 -0
  191. package/dist/server/tools/wait.d.ts.map +1 -0
  192. package/dist/server/tools/wait.js +120 -0
  193. package/dist/server/tools/wait.js.map +1 -0
  194. package/dist/server.d.ts +3 -0
  195. package/dist/server.d.ts.map +1 -0
  196. package/dist/server.js +17 -0
  197. package/dist/server.js.map +1 -0
  198. package/dist/setup/install.d.ts +52 -0
  199. package/dist/setup/install.d.ts.map +1 -0
  200. package/dist/setup/install.js +108 -0
  201. package/dist/setup/install.js.map +1 -0
  202. package/dist/setup.d.ts +3 -0
  203. package/dist/setup.d.ts.map +1 -0
  204. package/dist/setup.js +24 -0
  205. package/dist/setup.js.map +1 -0
  206. package/dist/store/db.d.ts +49 -0
  207. package/dist/store/db.d.ts.map +1 -0
  208. package/dist/store/db.js +101 -0
  209. package/dist/store/db.js.map +1 -0
  210. package/dist/store/jobs.d.ts +45 -0
  211. package/dist/store/jobs.d.ts.map +1 -0
  212. package/dist/store/jobs.js +150 -0
  213. package/dist/store/jobs.js.map +1 -0
  214. package/dist/store/locks.d.ts +60 -0
  215. package/dist/store/locks.d.ts.map +1 -0
  216. package/dist/store/locks.js +172 -0
  217. package/dist/store/locks.js.map +1 -0
  218. package/dist/store/sessions.d.ts +37 -0
  219. package/dist/store/sessions.d.ts.map +1 -0
  220. package/dist/store/sessions.js +117 -0
  221. package/dist/store/sessions.js.map +1 -0
  222. package/dist/trace/digest.d.ts +77 -0
  223. package/dist/trace/digest.d.ts.map +1 -0
  224. package/dist/trace/digest.js +481 -0
  225. package/dist/trace/digest.js.map +1 -0
  226. package/package.json +68 -0
  227. package/skills/agy-ceiling/SKILL.md +72 -0
@@ -0,0 +1,488 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { appendJsonLine, chmodDbFiles, jobPaths } from '../contract/paths.js';
4
+ import { GATE_DENIAL_MARKER } from '../contract/types.js';
5
+ import { evaluateCommandPolicy, firstMatch, firstMatchForDenial, parseRulesLenient, requiredRuleFor } from '../policy/rules.js';
6
+ import { seatbeltCommandLine } from '../policy/seatbelt.js';
7
+ import { ALLOWED_DEV_READS, assignmentReadPaths, extractCommandContainment, isAgentsPath, isContainedForKind } from '../policy/containment.js';
8
+ import { isCredentialPath } from '../policy/hard-deny.js';
9
+ import { classifyToolCall } from '../policy/tools.js';
10
+ import { bindConversation } from './bind.js';
11
+ import { openStore } from '../store/db.js';
12
+ import { updateJob } from '../store/jobs.js';
13
+ /**
14
+ * The PreToolUse hook. Spawned fresh for every single tool call, so it must stay
15
+ * cheap — no warm caches, no heavy imports, no network.
16
+ *
17
+ * ⚠⚠ The one absolute rule of this file: **something with a `decision` field must
18
+ * reach stdout on every path.** `{}` and empty output are denials (§9). A crash,
19
+ * a JSON parse failure, a locked database, a missing job — all of them must still
20
+ * print a `decision`. This is the only code in the package that can affect
21
+ * anything outside our own jobs; getting it wrong breaks the user's interactive
22
+ * agy sessions machine-wide.
23
+ *
24
+ * That decision is not always `ask` any more (0.2.0, I1/I3). A *bound* job's gate never answers
25
+ * `ask` — every tool call is either allowed or denied, and any failure once we
26
+ * know a call is ours becomes `deny`, not a silent pass-through. `ask` survives
27
+ * only for the two cases where we genuinely cannot tell whose call this is: a
28
+ * payload we could not parse at all, and a `conversationId` that binds to none
29
+ * of our jobs (someone's own interactive agy session, which this package must
30
+ * never touch). Failing `ask` there is still correct because agy itself fails
31
+ * closed on anything else a hook can produce — a non-zero exit or output that
32
+ * does not parse as JSON is a *denial*, not a pass-through (measured against
33
+ * 1.1.23, §9) — so `ask` in print mode is the one output that reliably reaches
34
+ * agy's own built-in engine and, for a job we cannot identify, that engine's
35
+ * ordinary confirmation-under-`--dangerously-skip-permissions` behaviour is
36
+ * exactly what the user asked for by running their own session (M3-C:
37
+ * with no `overwrite.BypassSandbox`, the model's own value wins).
38
+ */
39
+ /** The safe pass-through. Delegates to agy's built-in engine. Never `{}`. */
40
+ export const PASSTHROUGH = { decision: 'ask' };
41
+ /**
42
+ * `<guidance sentence> [agy-worker-denial:{"required_rule":...}]` — agy passes
43
+ * `reason` to the model verbatim (measured, §10), so the human sentence goes
44
+ * first and the machine payload our own `events/detect.ts` parses trails it.
45
+ */
46
+ function composeDenialReason(guidance, onDenial, payload) {
47
+ const abortNote = onDenial === 'abort'
48
+ ? ' This job is configured with on_denial: "abort" and will be terminated immediately due to this denial.'
49
+ : '';
50
+ return `${guidance}${abortNote} [${GATE_DENIAL_MARKER}${JSON.stringify(payload)}]`;
51
+ }
52
+ /**
53
+ * Pure decision function — no I/O, so it is exhaustively testable.
54
+ *
55
+ * Order is fixed (see docs/permissions.md) and each step matters:
56
+ *
57
+ * 1. `bound === null` → `ask`, return immediately. Not our job (§1.3 step 1).
58
+ * 2. `unsupported` (unclassifiable tool, or a subagent tool — M2) → `deny`,
59
+ * `required_rule: null`.
60
+ * 3. `control` (`manage_task`) → `allow`, no overwrite.
61
+ * 4. containment (write outside `write_roots` or into `{workspace}/.agents`
62
+ * — I6; read outside `read_roots`) → `deny`, ahead of every rule list.
63
+ * 5. deny list matches → `deny`.
64
+ * 6. allow list matches → `allow`; `run_command` additionally pins
65
+ * `overwrite.Cwd` and sets `overwrite.BypassSandbox` from `policy.bypass_sandbox`
66
+ * (I2) — every allow explicitly decides sandboxing, never leaves it to the
67
+ * model (M3 variant C: an unset overwrite lets the model's own value win).
68
+ * 7. otherwise → `deny`, `required_rule` filled in. I1: a bound job's gate
69
+ * never answers `ask` — `default_decision` is gone.
70
+ *
71
+ * A `deny` reason is an instruction channel, not an explanation: agy hands the
72
+ * string to the model verbatim (§10), so it should name the permitted alternative
73
+ * and carry a parsable `GATE_DENIAL_MARKER` payload for the broker.
74
+ */
75
+ export function decide(input) {
76
+ const { payload, bound } = input;
77
+ if (!bound) {
78
+ return { decision: PASSTHROUGH, log: null, requestsAbort: false };
79
+ }
80
+ const { job, policy, conversationId } = bound;
81
+ const toolName = payload.toolCall?.name ?? 'unknown';
82
+ const args = payload.toolCall?.args ?? {};
83
+ const stepIdx = typeof payload.stepIdx === 'number' ? payload.stepIdx : null;
84
+ const toolClass = classifyToolCall(toolName, args, policy.workspace);
85
+ const command = toolClass.kind === 'subject' && toolClass.subject.verb === 'command' ? toolClass.subject.value : null;
86
+ const makeLog = (decision, policyStage, matchedRule, reason) => ({
87
+ ts: Date.now(),
88
+ job_id: job.job_id,
89
+ conversation_id: conversationId,
90
+ step_idx: stepIdx,
91
+ tool: toolName,
92
+ command,
93
+ decision,
94
+ policy: policyStage,
95
+ matched_rule: matchedRule,
96
+ reason,
97
+ });
98
+ /** Every `deny` in this function goes through here so the payload/log/reason stay in lockstep. */
99
+ const denyWith = (policyStage, requiredRule, guidance, options) => {
100
+ const denialPayload = {
101
+ job_id: job.job_id,
102
+ tool: toolName,
103
+ required_rule: requiredRule,
104
+ policy: policyStage,
105
+ on_denial: policy.on_denial,
106
+ };
107
+ const reason = composeDenialReason(guidance, policy.on_denial, denialPayload);
108
+ return {
109
+ decision: { decision: 'deny', reason },
110
+ log: makeLog('deny', policyStage, options?.matchedRule ?? null, reason),
111
+ requestsAbort: options?.requestsAbort ?? (policy.on_denial === 'abort'),
112
+ };
113
+ };
114
+ // Step 2 (§2.2): unclassifiable or subagent tool.
115
+ // 0.3.0 PR5: an unsupported tool call sets requestsAbort: false, EXCEPT when
116
+ // it is a subagent tool (M2). Subagents attempt to bypass policy by running
117
+ // under an unbound conversationId, so they must abort when on_denial === 'abort'.
118
+ // But a single call to an unclassified tool such as schedule is not a policy
119
+ // violation, and a flaky tool retry should not cost the whole job.
120
+ if (toolClass.kind === 'unsupported') {
121
+ const requestsAbort = toolClass.subagent && policy.on_denial === 'abort';
122
+ return denyWith('unsupported', null, toolClass.reason, { requestsAbort });
123
+ }
124
+ // Step 3: `manage_task` — conversation-scoped bookkeeping, not a rule subject.
125
+ if (toolClass.kind === 'control') {
126
+ return {
127
+ decision: { decision: 'allow' },
128
+ log: makeLog('allow', 'control', null, null),
129
+ requestsAbort: false,
130
+ };
131
+ }
132
+ // toolClass.kind === 'subject' from here.
133
+ const { subject } = toolClass;
134
+ const roots = { read: policy.read_roots, write: policy.write_roots };
135
+ // Step 4: containment & credential HARD_DENY, ahead of every rule list.
136
+ const commandLine = toolName === 'run_command' && typeof args.CommandLine === 'string' ? args.CommandLine : null;
137
+ if (toolName === 'run_command' && commandLine !== null) {
138
+ const analysis = extractCommandContainment(commandLine, policy.workspace);
139
+ // Item 1: Unexpanded shell expansions in path positions
140
+ if (analysis.unexpandedPath) {
141
+ return denyWith('containment', null, `unexpanded_path: Path argument (${analysis.unexpandedPath}) contains unexpanded shell expansions ($VAR, backticks, or non-leading ~) and cannot be verified. Expand the path to an absolute path or a workspace-relative path and retry (globs *, ?, and [ are evaluated against literal directories, so they may be used as-is).`);
142
+ }
143
+ // Item 3: Credential HARD_DENY for commands
144
+ for (const p of analysis.candidatePaths) {
145
+ if (isCredentialPath(p)) {
146
+ return denyWith('deny_list', null, `hard_deny: credential path protected: ${p}`, { matchedRule: 'hard_deny' });
147
+ }
148
+ }
149
+ // Item 4 & 5: Write containment (resolved against policy.workspace, never args.Cwd)
150
+ const allWrite = analysis.writePaths;
151
+ for (const w of allWrite) {
152
+ if (isAgentsPath(w, policy.workspace)) {
153
+ return denyWith('containment', null, `This action attempts to write inside ${policy.workspace}/.agents (${w}). This directory contains the gate's own hook configuration and is always write-protected against all modifications including shell redirection (I6). Use a different path.`);
154
+ }
155
+ if (!isContainedForKind(w, roots, 'write')) {
156
+ return denyWith('containment', null, `This action attempts to write outside the workspace (${w}). Writes are permitted only within the workspace. Retry with a path inside the workspace.`);
157
+ }
158
+ }
159
+ // Item 2: Read-side containment for shell commands
160
+ const allRead = [...new Set([...analysis.readPaths, ...assignmentReadPaths(commandLine)])];
161
+ for (const r of allRead) {
162
+ if (ALLOWED_DEV_READS.has(r))
163
+ continue;
164
+ if (!isContainedForKind(r, roots, 'read')) {
165
+ return denyWith('containment', null, `read_outside_workspace: This action attempts to read outside the workspace (${r}). Reads are permitted only within the workspace.`);
166
+ }
167
+ }
168
+ }
169
+ else {
170
+ for (const w of toolClass.write) {
171
+ if (isAgentsPath(w, policy.workspace)) {
172
+ return denyWith('containment', null, `This action attempts to write inside ${policy.workspace}/.agents (${w}). This directory contains the gate's own hook configuration and is always write-protected against all modifications including shell redirection (I6). Use a different path.`);
173
+ }
174
+ if (!isContainedForKind(w, roots, 'write')) {
175
+ return denyWith('containment', null, `This action attempts to write outside the workspace (${w}). Writes are permitted only within the workspace. Retry with a path inside the workspace.`);
176
+ }
177
+ }
178
+ for (const r of toolClass.read) {
179
+ if (!isContainedForKind(r, roots, 'read')) {
180
+ return denyWith('containment', null, `This action attempts to read outside the workspace (${r}). Reads are permitted only within the workspace.`);
181
+ }
182
+ }
183
+ }
184
+ // Step 5: deny list.
185
+ const denyHit = firstMatchForDenial(parseRulesLenient(policy.deny), subject);
186
+ if (denyHit) {
187
+ return denyWith('deny_list', null, `This action (${denyHit.raw}) is denied by this job's policy. Do not attempt to bypass this constraint with another tool; report this restriction directly in your final response.`);
188
+ }
189
+ // Step 6 & 7 for command:
190
+ if (subject.verb === 'command') {
191
+ const cmdEval = evaluateCommandPolicy(subject.value, parseRulesLenient(policy.allow), parseRulesLenient(policy.deny));
192
+ if (cmdEval.allowed) {
193
+ const overwrite = commandOverwrite(policy, subject.value);
194
+ return {
195
+ decision: { decision: 'allow', overwrite },
196
+ log: makeLog('allow', 'profile_allowlist', cmdEval.matchedRule, null),
197
+ requestsAbort: false,
198
+ };
199
+ }
200
+ if (cmdEval.stage === 'deny_list') {
201
+ const guidance = cmdEval.reason === 'env_assignment_denied'
202
+ ? 'env_assignment_denied'
203
+ : `This action is denied by this job's policy. Do not attempt to bypass this constraint with another tool; report this restriction directly in your final response.`;
204
+ return denyWith('deny_list', null, guidance);
205
+ }
206
+ // stage === 'default'
207
+ if (policy.command_policy === 'denylist') {
208
+ const overwrite = commandOverwrite(policy, subject.value);
209
+ return {
210
+ decision: { decision: 'allow', overwrite },
211
+ log: makeLog('allow', 'denylist_default', null, null),
212
+ requestsAbort: false,
213
+ };
214
+ }
215
+ return denyWith('default', cmdEval.requiredRule, `This action is not in the allowlist for profile "${policy.profile}". If it remains necessary, stop execution and report in your final response that the following rule is required: ${cmdEval.requiredRule}`);
216
+ }
217
+ // Step 6: allow list (for non-command subjects).
218
+ const allowHit = firstMatch(parseRulesLenient(policy.allow), subject);
219
+ if (allowHit) {
220
+ return {
221
+ decision: { decision: 'allow' },
222
+ log: makeLog('allow', 'profile_allowlist', allowHit.raw, null),
223
+ requestsAbort: false,
224
+ };
225
+ }
226
+ // Step 7: nothing matched. I1 — a bound job's gate never answers `ask`;
227
+ // `default_decision` is gone, so this is always `deny`.
228
+ const requiredRule = requiredRuleFor(subject);
229
+ return denyWith('default', requiredRule, `This action is not in the allowlist for profile "${policy.profile}". If it remains necessary, stop execution and report in your final response that the following rule is required: ${requiredRule}`);
230
+ }
231
+ /**
232
+ * The `overwrite` every allowed `run_command` carries. `Cwd` is pinned to the
233
+ * workspace and `BypassSandbox` is always explicit (I2, M3 variant C). Under
234
+ * `sandbox: 'seatbelt'` the command itself is rewritten to run inside our own
235
+ * write-only profile (M9: `overwrite.CommandLine` is honoured by agy; the
236
+ * model and the event stream still see the original) with agy's sandbox off.
237
+ */
238
+ export function commandOverwrite(policy, commandLine) {
239
+ if (policy.sandbox === 'seatbelt') {
240
+ return {
241
+ Cwd: policy.workspace,
242
+ BypassSandbox: true,
243
+ CommandLine: seatbeltCommandLine(commandLine, policy.seatbelt_write_roots),
244
+ };
245
+ }
246
+ return { Cwd: policy.workspace, BypassSandbox: policy.bypass_sandbox };
247
+ }
248
+ /**
249
+ * Count the number of 'deny' decisions in a gate-log.jsonl content string.
250
+ * Tolerates empty strings, trailing newlines, and malformed lines.
251
+ */
252
+ export function countDeniesInGateLog(text) {
253
+ if (!text)
254
+ return 0;
255
+ let count = 0;
256
+ const lines = text.split('\n');
257
+ for (const line of lines) {
258
+ const trimmed = line.trim();
259
+ if (!trimmed)
260
+ continue;
261
+ try {
262
+ const parsed = JSON.parse(trimmed);
263
+ if (parsed && typeof parsed === 'object' && parsed.decision === 'deny') {
264
+ count++;
265
+ }
266
+ }
267
+ catch {
268
+ // ignore malformed lines
269
+ }
270
+ }
271
+ return count;
272
+ }
273
+ /** Read stdin to EOF. Returns null on any failure — the caller then passes through. */
274
+ export function readStdin() {
275
+ try {
276
+ return readFileSync(0, 'utf8');
277
+ }
278
+ catch {
279
+ return null;
280
+ }
281
+ }
282
+ /** Tolerant payload parse. Null when the shape is unusable; never throws. */
283
+ export function parsePayload(raw) {
284
+ if (!raw || !raw.trim())
285
+ return null;
286
+ try {
287
+ const parsed = JSON.parse(raw);
288
+ if (!parsed || typeof parsed !== 'object')
289
+ return null;
290
+ const p = parsed;
291
+ if (typeof p.conversationId !== 'string' || p.conversationId.length === 0)
292
+ return null;
293
+ const toolCallRaw = p.toolCall;
294
+ if (!toolCallRaw || typeof toolCallRaw !== 'object')
295
+ return null;
296
+ const toolCall = toolCallRaw;
297
+ if (typeof toolCall.name !== 'string' || toolCall.name.length === 0)
298
+ return null;
299
+ const args = toolCall.args && typeof toolCall.args === 'object'
300
+ ? toolCall.args
301
+ : undefined;
302
+ return {
303
+ conversationId: p.conversationId,
304
+ stepIdx: typeof p.stepIdx === 'number' ? p.stepIdx : undefined,
305
+ modelName: typeof p.modelName === 'string' ? p.modelName : undefined,
306
+ toolCall: { name: toolCall.name, args },
307
+ workspacePaths: Array.isArray(p.workspacePaths)
308
+ ? (p.workspacePaths.filter((x) => typeof x === 'string'))
309
+ : undefined,
310
+ transcriptPath: typeof p.transcriptPath === 'string' ? p.transcriptPath : undefined,
311
+ artifactDirectoryPath: typeof p.artifactDirectoryPath === 'string' ? p.artifactDirectoryPath : undefined,
312
+ };
313
+ }
314
+ catch {
315
+ return null;
316
+ }
317
+ }
318
+ /** Write the decision to stdout as one line. The only place that writes stdout. */
319
+ /**
320
+ * Captured before {@link guardStdout} neuters the public one, so this stays the
321
+ * only path to the real file descriptor.
322
+ */
323
+ const realStdoutWrite = process.stdout.write.bind(process.stdout);
324
+ let emitted = false;
325
+ /**
326
+ * Make stdout write-once and pollution-proof.
327
+ *
328
+ * Measured against agy 1.1.23: a hook that exits 0 but whose stdout does not
329
+ * parse is a DENIAL, not a passthrough —
330
+ * failed to unmarshal result from hook ... via protojson: not json at all
331
+ * and this process always exits 0 (see `src/gate.ts`), so the
332
+ * `|| printf '{"decision":"ask"}'` fallback in `hooks.json` — which only fires
333
+ * on a non-zero exit — cannot cover it. One stray `console.log` from anywhere
334
+ * in the import graph would therefore deny every tool call in the workspace,
335
+ * including the user's own interactive agy sessions.
336
+ *
337
+ * So: everything except {@link emit} is swallowed, and only the first decision
338
+ * is written.
339
+ */
340
+ export function guardStdout() {
341
+ process.stdout.write = ((_chunk, encoding, cb) => {
342
+ const done = typeof encoding === 'function' ? encoding : cb;
343
+ if (typeof done === 'function')
344
+ done();
345
+ return true;
346
+ });
347
+ }
348
+ export function emit(decision) {
349
+ if (emitted)
350
+ return;
351
+ emitted = true;
352
+ realStdoutWrite(JSON.stringify(decision));
353
+ }
354
+ /** Test seam: `emitted` is module state and every test needs a clean one. */
355
+ export function resetEmitForTests() {
356
+ emitted = false;
357
+ }
358
+ /** Append to `gate-log.jsonl`. Every verdict is recorded, allows included (§1.8). */
359
+ export function logDecision(jobDir, entry) {
360
+ appendJsonLine(join(jobDir, 'gate-log.jsonl'), entry);
361
+ }
362
+ /** `deny` reason used when the store cannot even be opened (§2.3). No job to log against. */
363
+ const STATE_UNAVAILABLE = { decision: 'deny', reason: 'agy-worker gate: state unavailable' };
364
+ /** `deny` reason for any failure once we are past "open the store" (§2.3). */
365
+ const INTERNAL_ERROR = { decision: 'deny', reason: 'agy-worker gate: internal error' };
366
+ /**
367
+ * `dist/gate.js` entry point.
368
+ *
369
+ * Always resolves 0 — a non-zero exit from a hook is not a documented signal,
370
+ * and we must not find out what agy does with one. Emits exactly once: the
371
+ * decision is computed and everything that can fail (DB access, binding,
372
+ * logging, the `on_denial: 'abort'` mark) is contained in a try/catch that
373
+ * runs *before* `emit`, and everything after `emit` is itself wrapped so a
374
+ * failure there can never produce a second line on stdout.
375
+ *
376
+ * Failure paths (not all of them are
377
+ * `ask` any more, since I1 only protects a *bound* job's decision, not the
378
+ * gate process's own health):
379
+ * - unparsable payload → `ask` (we cannot even tell whose call this is —
380
+ * handled above, before this function's own try/catch begins).
381
+ * - the store cannot be opened at all → `deny`, `state unavailable`. A
382
+ * broken `AGY_WORKER_HOME`/project dir means we cannot tell bound from
383
+ * unbound either, but unlike a parse failure this is *our* infrastructure
384
+ * breaking, not a payload shape we cannot read — failing open here would
385
+ * mean every tool call in every workspace runs unguarded the moment our
386
+ * own state directory has a problem.
387
+ * - `bindConversation` resolves and the conversation is not one of ours →
388
+ * `ask` (unchanged; `decide()` returns `PASSTHROUGH` for `bound === null`
389
+ * without throwing, so this falls out of the ordinary call below).
390
+ * - the store opened and anything after that throws → `deny`, `internal
391
+ * error`. By this point we hold a real, open connection; failing closed
392
+ * is strictly safer than guessing `ask` and letting agy's own engine (or
393
+ * the model, per M3-C) decide unsupervised.
394
+ */
395
+ export async function main() {
396
+ const raw = readStdin();
397
+ const payload = parsePayload(raw);
398
+ if (!payload) {
399
+ emit(PASSTHROUGH);
400
+ return 0;
401
+ }
402
+ let outcome = { decision: INTERNAL_ERROR, log: null, requestsAbort: false };
403
+ let jobDir = null;
404
+ let store;
405
+ try {
406
+ store = openStore({ readOnly: true });
407
+ chmodDbFiles(store.paths.db);
408
+ }
409
+ catch {
410
+ emit(STATE_UNAVAILABLE);
411
+ return 0;
412
+ }
413
+ try {
414
+ try {
415
+ const bound = bindConversation(store, payload.conversationId);
416
+ outcome = decide({ payload, bound });
417
+ if (bound) {
418
+ jobDir = jobPaths(store.paths, bound.job.job_id).dir;
419
+ let reachedMaxDenials = false;
420
+ if (outcome.log?.decision === 'deny' &&
421
+ typeof bound.policy.max_denials === 'number' &&
422
+ bound.job.lifecycle !== 'canceling' &&
423
+ bound.job.lifecycle !== 'finished') {
424
+ const gateLogFile = jobPaths(store.paths, bound.job.job_id).gateLog;
425
+ let existingDenies = 0;
426
+ try {
427
+ if (existsSync(gateLogFile)) {
428
+ existingDenies = countDeniesInGateLog(readFileSync(gateLogFile, 'utf8'));
429
+ }
430
+ }
431
+ catch {
432
+ // Best effort; tolerate missing or unreadable gate-log.
433
+ }
434
+ reachedMaxDenials = existingDenies + 1 >= bound.policy.max_denials;
435
+ }
436
+ const shouldAbort = (outcome.requestsAbort || reachedMaxDenials) &&
437
+ bound.job.lifecycle !== 'canceling' &&
438
+ bound.job.lifecycle !== 'finished';
439
+ if (shouldAbort) {
440
+ const abortReason = outcome.requestsAbort
441
+ ? 'on_denial'
442
+ : 'max_denials';
443
+ if (outcome.log) {
444
+ outcome.log.abort_reason = abortReason;
445
+ }
446
+ // The store above is now genuinely read-only (finding 19), so this
447
+ // one write opens its own short-lived read-write connection rather
448
+ // than widening the hot path everyone else pays for.
449
+ try {
450
+ const writeStore = openStore({ readOnly: false });
451
+ chmodDbFiles(writeStore.paths.db);
452
+ try {
453
+ // Mark only — the actual killpg is handled by the broker's
454
+ // reconcile loop, not by the gate.
455
+ updateJob(writeStore, bound.job.job_id, { lifecycle: 'canceling' });
456
+ }
457
+ finally {
458
+ writeStore.close();
459
+ }
460
+ }
461
+ catch {
462
+ // Best effort; the deadline / next reconcile still catches it.
463
+ }
464
+ }
465
+ }
466
+ }
467
+ finally {
468
+ store.close();
469
+ }
470
+ }
471
+ catch {
472
+ // Past this point we had a real store connection open — fail closed
473
+ // rather than passing through (§2.3's "bound, later exception" row).
474
+ outcome = { decision: INTERNAL_ERROR, log: null, requestsAbort: false };
475
+ jobDir = null;
476
+ }
477
+ emit(outcome.decision);
478
+ if (jobDir && outcome.log) {
479
+ try {
480
+ logDecision(jobDir, outcome.log);
481
+ }
482
+ catch {
483
+ // Logging is best-effort; the decision already reached stdout.
484
+ }
485
+ }
486
+ return 0;
487
+ }
488
+ //# sourceMappingURL=gate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gate.js","sourceRoot":"","sources":["../../src/gate/gate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Single owner of `<workspace>/.agents/hooks.json`'s lifecycle: `start.ts` writes
3
+ * our entry when a job spawns, `reconcile.ts` removes it once no live job on that
4
+ * `cwd` needs it any more. Kept in one module — with the key constant — so the two
5
+ * call sites can never drift on what "our entry" means.
6
+ */
7
+ /** The one key this package ever writes into `hooks.json`. Never touch any other key. */
8
+ export declare const GATE_HOOK_KEY = "agy-worker-gate";
9
+ export declare function hooksFilePath(workspace: string): string;
10
+ /**
11
+ * Write (merging, never clobbering unrelated keys) `<workspace>/.agents/hooks.json`
12
+ * so the PreToolUse gate loads for this workspace. `--add-dir` is what makes agy
13
+ * load it at all (see docs/permissions.md) — this is the piece that puts the
14
+ * file there in the first place, since nothing else in the package owns it.
15
+ *
16
+ * The command is just `node '<gatePath>'` — quoted (an unquoted absolute path
17
+ * breaks on any install path containing a space). There used to be a
18
+ * `|| printf '{"decision":"ask"}'` fallback here; it is gone. agy already fails closed on its own —
19
+ * empty/non-JSON stdout or a non-zero exit is a *denial*, not a pass-through
20
+ * (measured against 1.1.23, `src/gate/gate.ts`'s own header comment) — so the
21
+ * fallback never protected anything: its only effect was to convert that
22
+ * already-safe failure into `{"decision":"ask"}`, which in print mode reaches
23
+ * agy's built-in engine and lets a `run_command` call proceed with whatever
24
+ * `BypassSandbox` value the model itself asked for (M3-C) — the exact hole I2 exists to close.
25
+ * Losing the fallback also means `ensureGateHook` must only ever be called once
26
+ * `gatePath` is confirmed to exist (`agy_start`'s own `existsSync` check).
27
+ *
28
+ * Our key is written **first** in the object, ahead of every pre-existing key.
29
+ * Measured (M6): agy evaluates
30
+ * `hooks.json`'s PreToolUse groups in declaration order and a `deny` from an
31
+ * earlier group short-circuits the rest — a group installed ahead of ours that
32
+ * denies would mean our gate never runs at all for that call, and the runtime
33
+ * watchdog (`src/runner/gate-watchdog.ts`) would misread the resulting silence
34
+ * in `gate-log.jsonl` as "hooks never loaded". Writing ours first guarantees it
35
+ * runs on every tool call regardless of what else is declared in this file.
36
+ * (A hook group installed *outside* this file entirely — e.g. a user's global
37
+ * `~/.gemini/config/hooks.json` — that denies ahead of ours is the one case
38
+ * this cannot cover; the watchdog still reports it correctly if bluntly, as
39
+ * "gate never fired", which is safe — fail closed — just imprecise about why.
40
+ * Not handled here, by design.)
41
+ */
42
+ export declare function ensureGateHook(workspace: string, gatePath: string): void;
43
+ /**
44
+ * Remove only {@link GATE_HOOK_KEY} from `<workspace>/.agents/hooks.json`,
45
+ * preserving every other key untouched. Deletes the file when it held nothing
46
+ * else, and the `.agents` directory when that leaves it empty. A no-op when the
47
+ * file does not exist or never carried our key.
48
+ *
49
+ * Best effort by design: called from
50
+ * `reconcile`, which must never fail a tool call over hook-file housekeeping. A
51
+ * stale entry left behind by a failure here is harmless until the next
52
+ * `agy_start` on the same workspace, which overwrites it unconditionally.
53
+ */
54
+ export declare function removeGateHook(workspace: string): void;
55
+ //# sourceMappingURL=hooks-file.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks-file.d.ts","sourceRoot":"","sources":["../../src/gate/hooks-file.ts"],"names":[],"mappings":"AAKA;;;;;GAKG;AAEH,yFAAyF;AACzF,eAAO,MAAM,aAAa,oBAAoB,CAAA;AAE9C,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEvD;AAOD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAexE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAyBtD"}