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,99 @@
1
+ /**
2
+ * Structured errors. READ-ONLY after Stage 1.
3
+ *
4
+ * Every error carries a machine-readable `detail` so the *calling agent* can
5
+ * repair itself without another round trip: which job holds the lock, which rule
6
+ * string to add, which enum values exist.
7
+ */
8
+ /** Base for everything in this module. `instanceof` works across all subclasses. */
9
+ export class AgyWorkerError extends Error {
10
+ detail;
11
+ remedy;
12
+ constructor(message, detail, remedy) {
13
+ super(message);
14
+ this.name = new.target.name;
15
+ this.detail = detail;
16
+ this.remedy = remedy;
17
+ Error.captureStackTrace?.(this, new.target);
18
+ }
19
+ toJSON() {
20
+ return {
21
+ error: this.code,
22
+ message: this.message,
23
+ detail: this.detail,
24
+ remedy: this.remedy,
25
+ };
26
+ }
27
+ }
28
+ export function isAgyWorkerError(e) {
29
+ return e instanceof AgyWorkerError;
30
+ }
31
+ /** Normalizes anything thrown into an envelope so a tool handler never leaks a stack. */
32
+ export function toErrorEnvelope(e) {
33
+ if (isAgyWorkerError(e))
34
+ return e.toJSON();
35
+ const message = e instanceof Error ? e.message : String(e);
36
+ return {
37
+ error: 'VALIDATION',
38
+ message,
39
+ detail: { unexpected: true },
40
+ remedy: 'This is an internal failure, not a usable input error. Retry once; if it repeats, report it.',
41
+ };
42
+ }
43
+ /**
44
+ * Losing a lock race is an error, never a silent serialization.
45
+ * The caller decides whether to wait on the holder or pick a different cwd.
46
+ */
47
+ export class LockConflictError extends AgyWorkerError {
48
+ code = 'LOCK_CONFLICT';
49
+ constructor(detail, message) {
50
+ const holder = detail.holder_job_id;
51
+ super(message ??
52
+ (detail.reason === 'limit'
53
+ ? `project concurrency limit reached (${detail.limit} running)`
54
+ : `${detail.scope} lock on "${detail.key}" is held by job ${holder}`), detail, detail.reason === 'limit'
55
+ ? 'Wait for a running job to finish (agy_wait on one of running_job_ids), or cancel one with agy_cancel.'
56
+ : detail.scope === 'cwd_write'
57
+ ? `One writing job per cwd at a time; holder is job ${holder}. For parallel work start each job in its own git worktree inside the project root (cwd), or agy_wait on the holder.`
58
+ : `Call agy_wait({ job_id: "${holder}" }) to take over the holder, agy_cancel to stop it, or start this job in a different cwd.`);
59
+ }
60
+ }
61
+ /** A policy refusal, whether reported by the gate or replayed by the broker. */
62
+ export class PolicyDeniedError extends AgyWorkerError {
63
+ code = 'POLICY_DENIED';
64
+ constructor(detail, message) {
65
+ super(message ??
66
+ `${detail.tool}${detail.command ? ` (${detail.command})` : ''} denied by ${detail.policy} under profile "${detail.profile}"`, detail, detail.immutable
67
+ ? `This rule cannot be lifted by a client request. Use a different approach, or a profile that permits it.`
68
+ : detail.required_rule
69
+ ? `Retry with permissions.allow including ${JSON.stringify(detail.required_rule)}.`
70
+ : 'Narrow the requested action, or choose a profile whose ceiling covers it.');
71
+ }
72
+ }
73
+ /** Containment failure. Checked *after* realpath, never before (see docs/permissions.md). */
74
+ export class PathEscapeError extends AgyWorkerError {
75
+ code = 'PATH_ESCAPE';
76
+ constructor(detail, message) {
77
+ super(message ??
78
+ `path "${detail.input_path}" resolves to "${detail.resolved_path}", outside the allowed ${detail.kind} roots`, detail, `Use a path inside one of: ${detail.roots.join(', ')}. Symlinks are resolved before the check, so linking out does not work.`);
79
+ }
80
+ }
81
+ export class JobNotFoundError extends AgyWorkerError {
82
+ code = 'JOB_NOT_FOUND';
83
+ constructor(detail, message) {
84
+ super(message ?? `no job "${detail.job_id}" in project ${detail.project_root}`, detail, detail.known_recent.length
85
+ ? `Recent job ids: ${detail.known_recent.join(', ')}. Use agy_list_jobs for the full list.`
86
+ : 'Use agy_list_jobs to see what exists in this project. Jobs are per-project and never visible across projects.');
87
+ }
88
+ }
89
+ export class ValidationError extends AgyWorkerError {
90
+ code = 'VALIDATION';
91
+ constructor(detail, message) {
92
+ super(message ?? `invalid ${detail.field}: expected ${detail.expected}`, detail, detail.allowed
93
+ ? `Allowed values: ${detail.allowed.join(' | ')}.`
94
+ : detail.allowed_verbs
95
+ ? `A rule looks like verb(pattern). Verbs: ${detail.allowed_verbs.join(' | ')}. Prefix the pattern with "regex:" to opt into regular expressions.`
96
+ : `Correct ${detail.field} and call again.`);
97
+ }
98
+ }
99
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/contract/errors.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * The frozen contract. Every other module imports from here (or from the three
3
+ * files directly); nothing else in `src/` may redefine these shapes.
4
+ *
5
+ * READ-ONLY after Stage 1 — see `contract_change_requests`.
6
+ */
7
+ export * from './types.js';
8
+ export * from './errors.js';
9
+ export * from './paths.js';
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/contract/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,cAAc,YAAY,CAAA;AAC1B,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * The frozen contract. Every other module imports from here (or from the three
3
+ * files directly); nothing else in `src/` may redefine these shapes.
4
+ *
5
+ * READ-ONLY after Stage 1 — see `contract_change_requests`.
6
+ */
7
+ export * from './types.js';
8
+ export * from './errors.js';
9
+ export * from './paths.js';
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/contract/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,cAAc,YAAY,CAAA;AAC1B,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA"}
@@ -0,0 +1,139 @@
1
+ /**
2
+ * Project discovery, on-disk layout, and path containment. READ-ONLY after Stage 1.
3
+ *
4
+ * Layout — deliberately outside the repo so nothing has to be
5
+ * gitignored (see docs/operations.md):
6
+ *
7
+ * ```
8
+ * ~/.agy-worker/projects/<sha256(canonical_root)[:16]>/
9
+ * project.json index.db
10
+ * jobs/<job-id>/{request,effective-config,state}.json
11
+ * events.ndjson stderr.log exit_code
12
+ * inbox.jsonl policy.json gate-log.jsonl
13
+ * agent-result.json broker-result.json verification.json
14
+ * verify.log verify.json
15
+ * ```
16
+ */
17
+ export type ProjectRootSource = 'env' | 'git' | 'cwd';
18
+ export interface ProjectRootResolution {
19
+ root: string;
20
+ source: ProjectRootSource;
21
+ }
22
+ /**
23
+ * Resolve the project root.
24
+ *
25
+ * Precedence: `AGY_WORKER_PROJECT` (documented as an *override* in `docs/operations.md`) →
26
+ * nearest ancestor containing `.git` → the starting directory itself. The last
27
+ * branch ensures non-git directories are fully supported.
28
+ *
29
+ * The returned path is always canonical (symlinks resolved).
30
+ */
31
+ export declare function resolveProjectRoot(startCwd?: string): ProjectRootResolution;
32
+ /** Convenience wrapper when the caller does not care where the root came from. */
33
+ export declare function projectRoot(startCwd?: string): string;
34
+ /** Walks up looking for `.git` (a directory *or* a worktree/submodule file). */
35
+ export declare function findGitRoot(startCanonical: string): string | null;
36
+ /** `~/.agy-worker`, or `AGY_WORKER_HOME` when set (tests always set it). */
37
+ export declare function stateHome(): string;
38
+ /** `sha256(canonical_root)` truncated to 16 hex chars — the per-project directory name. */
39
+ export declare function projectKey(canonicalRoot: string): string;
40
+ export interface ProjectPaths {
41
+ /** Canonical project root inside the user's filesystem. */
42
+ root: string;
43
+ key: string;
44
+ /** `<stateHome>/projects/<key>` */
45
+ dir: string;
46
+ projectJson: string;
47
+ db: string;
48
+ jobsDir: string;
49
+ }
50
+ export declare function projectPaths(canonicalRoot: string): ProjectPaths;
51
+ /** Chmod SQLite db and WAL/SHM files to 0o600. */
52
+ export declare function chmodDbFiles(dbPath: string): void;
53
+ /**
54
+ * Creates the project directory tree and writes `project.json` (the reverse
55
+ * lookup from hash back to path). Idempotent and safe to race.
56
+ */
57
+ export declare function ensureProjectDirs(paths: ProjectPaths): ProjectPaths;
58
+ export interface JobPaths {
59
+ jobId: string;
60
+ dir: string;
61
+ request: string;
62
+ effectiveConfig: string;
63
+ state: string;
64
+ /** agy stdout, redirected straight to this fd. Cursors are byte offsets into it. */
65
+ events: string;
66
+ stderr: string;
67
+ /** Written by the runner on exit. Its presence is what makes a job finalizable. */
68
+ exitCode: string;
69
+ inbox: string;
70
+ policy: string;
71
+ gateLog: string;
72
+ agentResult: string;
73
+ brokerResult: string;
74
+ verification: string;
75
+ /** stdout+stderr of `verify_command`, capped at 1 MiB (PR6 §6.2). */
76
+ verifyLog: string;
77
+ /** `VerifyRecord`, written once after `verify_command` exits (PR6 §6.2). */
78
+ verifyJson: string;
79
+ }
80
+ export declare function jobPaths(project: ProjectPaths, jobId: string): JobPaths;
81
+ export declare function ensureJobDirs(paths: JobPaths): JobPaths;
82
+ /** Sortable id: `<base36 ms>-<8 hex>`. Lexical order matches creation order. */
83
+ export declare function newJobId(now?: number): string;
84
+ /** Session ids are opaque; they never appear in a filesystem path. */
85
+ export declare function newSessionId(): string;
86
+ /**
87
+ * The DDL text. Resolved next to this module (`dist/contract/schema.sql` after a
88
+ * build, `src/contract/schema.sql` under vitest), with the source tree as fallback.
89
+ */
90
+ export declare function loadSchemaSql(): string;
91
+ /** Installed package root (the directory holding `package.json`). */
92
+ export declare function packageRoot(): string;
93
+ /**
94
+ * Absolute path to one of the three entry points. The gate path is written into
95
+ * generated `hooks.json` files, so it must be stable and absolute.
96
+ *
97
+ * `ENV.GATE_BIN` overrides the `'gate'` case only — a test-only escape hatch
98
+ * (`ENV.GATE_BIN`'s own comment) so a test can point `agy_start` at a
99
+ * nonexistent gate binary and exercise its `existsSync` failure path without
100
+ * disturbing the real `dist/gate.js` every other test also depends on.
101
+ */
102
+ export declare function binPath(which: 'server' | 'runner' | 'gate'): string;
103
+ /**
104
+ * Absolute, `..`-free, symlink-resolved path.
105
+ *
106
+ * When the path does not exist yet (a file the job is about to write) the deepest
107
+ * existing ancestor is resolved and the remaining segments are appended. That is
108
+ * what makes containment checks meaningful for not-yet-created files: the
109
+ * *directory* they would land in is what actually decides the answer.
110
+ */
111
+ export declare function canonicalize(input: string): string;
112
+ /** True when `candidate` is `root` itself or lives beneath it. Both must be canonical. */
113
+ export declare function isWithin(candidate: string, root: string): boolean;
114
+ /** True when the path traverses a symlink anywhere below `root`. */
115
+ export declare function traversesSymlink(input: string): boolean;
116
+ /**
117
+ * Canonicalize then check containment; throw {@link PathEscapeError} on escape.
118
+ *
119
+ * ⚠ Order matters and is the whole point: resolving *after* the check would let a
120
+ * symlink inside the workspace point anywhere (see docs/permissions.md). Returns the
121
+ * canonical path so callers use the resolved form from here on.
122
+ */
123
+ export declare function assertContained(input: string, roots: string[], kind: 'read' | 'write'): string;
124
+ /** Non-throwing form of {@link assertContained}. */
125
+ export declare function containedOrNull(input: string, roots: string[]): string | null;
126
+ /**
127
+ * Write via a sibling temp file plus `rename`, so a concurrent reader either sees
128
+ * the previous complete version or the new one — never a torn file. Several
129
+ * processes read `state.json` and `broker-result.json` without coordination.
130
+ */
131
+ export declare function writeFileAtomic(target: string, data: string | Uint8Array): void;
132
+ export declare function writeJsonAtomic(target: string, value: unknown): void;
133
+ /** Returns null for a missing *or* unparsable file; a torn read is not fatal. */
134
+ export declare function readJsonIfExists<T>(target: string): T | null;
135
+ /** Appends one NDJSON line with a single `O_APPEND` write, which is atomic for small lines. */
136
+ export declare function appendJsonLine(target: string, value: unknown): void;
137
+ /** Current byte length, or 0 when the file does not exist yet. */
138
+ export declare function fileSize(target: string): number;
139
+ //# sourceMappingURL=paths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/contract/paths.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,359 @@
1
+ /**
2
+ * Project discovery, on-disk layout, and path containment. READ-ONLY after Stage 1.
3
+ *
4
+ * Layout — deliberately outside the repo so nothing has to be
5
+ * gitignored (see docs/operations.md):
6
+ *
7
+ * ```
8
+ * ~/.agy-worker/projects/<sha256(canonical_root)[:16]>/
9
+ * project.json index.db
10
+ * jobs/<job-id>/{request,effective-config,state}.json
11
+ * events.ndjson stderr.log exit_code
12
+ * inbox.jsonl policy.json gate-log.jsonl
13
+ * agent-result.json broker-result.json verification.json
14
+ * verify.log verify.json
15
+ * ```
16
+ */
17
+ import { createHash, randomUUID } from 'node:crypto';
18
+ import { chmodSync, closeSync, existsSync, fsyncSync, mkdirSync, openSync, readFileSync, realpathSync, renameSync, statSync, writeFileSync, writeSync, } from 'node:fs';
19
+ import { homedir } from 'node:os';
20
+ import { dirname, isAbsolute, join, parse as parsePath, relative, resolve, sep } from 'node:path';
21
+ import { fileURLToPath } from 'node:url';
22
+ import { PathEscapeError } from './errors.js';
23
+ import { ENV } from './types.js';
24
+ /**
25
+ * Resolve the project root.
26
+ *
27
+ * Precedence: `AGY_WORKER_PROJECT` (documented as an *override* in `docs/operations.md`) →
28
+ * nearest ancestor containing `.git` → the starting directory itself. The last
29
+ * branch ensures non-git directories are fully supported.
30
+ *
31
+ * The returned path is always canonical (symlinks resolved).
32
+ */
33
+ export function resolveProjectRoot(startCwd = process.cwd()) {
34
+ const override = process.env[ENV.PROJECT_ROOT];
35
+ if (override && override.trim()) {
36
+ return { root: canonicalize(resolve(override.trim())), source: 'env' };
37
+ }
38
+ const start = canonicalize(resolve(startCwd));
39
+ const gitRoot = findGitRoot(start);
40
+ if (gitRoot)
41
+ return { root: gitRoot, source: 'git' };
42
+ return { root: start, source: 'cwd' };
43
+ }
44
+ /** Convenience wrapper when the caller does not care where the root came from. */
45
+ export function projectRoot(startCwd) {
46
+ return resolveProjectRoot(startCwd).root;
47
+ }
48
+ /** Walks up looking for `.git` (a directory *or* a worktree/submodule file). */
49
+ export function findGitRoot(startCanonical) {
50
+ let dir = startCanonical;
51
+ for (;;) {
52
+ if (existsSync(join(dir, '.git')))
53
+ return dir;
54
+ const parent = dirname(dir);
55
+ if (parent === dir)
56
+ return null;
57
+ dir = parent;
58
+ }
59
+ }
60
+ // ─────────────────────────────────────────────────────────────────────────────
61
+ // State home and per-project directories
62
+ // ─────────────────────────────────────────────────────────────────────────────
63
+ /** `~/.agy-worker`, or `AGY_WORKER_HOME` when set (tests always set it). */
64
+ export function stateHome() {
65
+ const override = process.env[ENV.STATE_HOME];
66
+ if (override && override.trim())
67
+ return resolve(override.trim());
68
+ return join(homedir(), '.agy-worker');
69
+ }
70
+ /** `sha256(canonical_root)` truncated to 16 hex chars — the per-project directory name. */
71
+ export function projectKey(canonicalRoot) {
72
+ return createHash('sha256').update(canonicalRoot).digest('hex').slice(0, 16);
73
+ }
74
+ export function projectPaths(canonicalRoot) {
75
+ const key = projectKey(canonicalRoot);
76
+ const dir = join(stateHome(), 'projects', key);
77
+ return {
78
+ root: canonicalRoot,
79
+ key,
80
+ dir,
81
+ projectJson: join(dir, 'project.json'),
82
+ db: join(dir, 'index.db'),
83
+ jobsDir: join(dir, 'jobs'),
84
+ };
85
+ }
86
+ /** Chmod SQLite db and WAL/SHM files to 0o600. */
87
+ export function chmodDbFiles(dbPath) {
88
+ for (const suffix of ['', '-wal', '-shm']) {
89
+ const p = `${dbPath}${suffix}`;
90
+ if (existsSync(p)) {
91
+ try {
92
+ chmodSync(p, 0o600);
93
+ }
94
+ catch {
95
+ // best-effort
96
+ }
97
+ }
98
+ }
99
+ }
100
+ /**
101
+ * Creates the project directory tree and writes `project.json` (the reverse
102
+ * lookup from hash back to path). Idempotent and safe to race.
103
+ */
104
+ export function ensureProjectDirs(paths) {
105
+ mkdirSync(paths.jobsDir, { recursive: true, mode: 0o700 });
106
+ try {
107
+ chmodSync(paths.dir, 0o700);
108
+ chmodSync(paths.jobsDir, 0o700);
109
+ }
110
+ catch {
111
+ // best-effort
112
+ }
113
+ if (!existsSync(paths.projectJson)) {
114
+ writeJsonAtomic(paths.projectJson, { root: paths.root, key: paths.key });
115
+ }
116
+ chmodDbFiles(paths.db);
117
+ return paths;
118
+ }
119
+ export function jobPaths(project, jobId) {
120
+ const dir = join(project.jobsDir, jobId);
121
+ return {
122
+ jobId,
123
+ dir,
124
+ request: join(dir, 'request.json'),
125
+ effectiveConfig: join(dir, 'effective-config.json'),
126
+ state: join(dir, 'state.json'),
127
+ events: join(dir, 'events.ndjson'),
128
+ stderr: join(dir, 'stderr.log'),
129
+ exitCode: join(dir, 'exit_code'),
130
+ inbox: join(dir, 'inbox.jsonl'),
131
+ policy: join(dir, 'policy.json'),
132
+ gateLog: join(dir, 'gate-log.jsonl'),
133
+ agentResult: join(dir, 'agent-result.json'),
134
+ brokerResult: join(dir, 'broker-result.json'),
135
+ verification: join(dir, 'verification.json'),
136
+ verifyLog: join(dir, 'verify.log'),
137
+ verifyJson: join(dir, 'verify.json'),
138
+ };
139
+ }
140
+ export function ensureJobDirs(paths) {
141
+ mkdirSync(paths.dir, { recursive: true, mode: 0o700 });
142
+ try {
143
+ chmodSync(paths.dir, 0o700);
144
+ }
145
+ catch {
146
+ // best-effort
147
+ }
148
+ chmodDbFiles(join(paths.dir, '..', '..', 'index.db'));
149
+ return paths;
150
+ }
151
+ /** Sortable id: `<base36 ms>-<8 hex>`. Lexical order matches creation order. */
152
+ export function newJobId(now = Date.now()) {
153
+ return `${now.toString(36)}-${randomUUID().replace(/-/g, '').slice(0, 8)}`;
154
+ }
155
+ /** Session ids are opaque; they never appear in a filesystem path. */
156
+ export function newSessionId() {
157
+ return randomUUID();
158
+ }
159
+ // ─────────────────────────────────────────────────────────────────────────────
160
+ // Package-relative resources
161
+ // ─────────────────────────────────────────────────────────────────────────────
162
+ const HERE = dirname(fileURLToPath(import.meta.url));
163
+ /**
164
+ * The DDL text. Resolved next to this module (`dist/contract/schema.sql` after a
165
+ * build, `src/contract/schema.sql` under vitest), with the source tree as fallback.
166
+ */
167
+ export function loadSchemaSql() {
168
+ const candidates = [
169
+ join(HERE, 'schema.sql'),
170
+ join(HERE, '..', '..', 'src', 'contract', 'schema.sql'),
171
+ ];
172
+ for (const c of candidates) {
173
+ if (existsSync(c))
174
+ return readFileSync(c, 'utf8');
175
+ }
176
+ throw new Error(`schema.sql not found; looked in: ${candidates.join(', ')}`);
177
+ }
178
+ /** Installed package root (the directory holding `package.json`). */
179
+ export function packageRoot() {
180
+ let dir = HERE;
181
+ for (;;) {
182
+ if (existsSync(join(dir, 'package.json')))
183
+ return dir;
184
+ const parent = dirname(dir);
185
+ if (parent === dir)
186
+ return HERE;
187
+ dir = parent;
188
+ }
189
+ }
190
+ /**
191
+ * Absolute path to one of the three entry points. The gate path is written into
192
+ * generated `hooks.json` files, so it must be stable and absolute.
193
+ *
194
+ * `ENV.GATE_BIN` overrides the `'gate'` case only — a test-only escape hatch
195
+ * (`ENV.GATE_BIN`'s own comment) so a test can point `agy_start` at a
196
+ * nonexistent gate binary and exercise its `existsSync` failure path without
197
+ * disturbing the real `dist/gate.js` every other test also depends on.
198
+ */
199
+ export function binPath(which) {
200
+ if (which === 'gate') {
201
+ const override = process.env[ENV.GATE_BIN];
202
+ if (override && override.trim())
203
+ return override.trim();
204
+ }
205
+ const root = packageRoot();
206
+ const dist = join(root, 'dist', `${which}.js`);
207
+ if (existsSync(dist))
208
+ return dist;
209
+ return join(root, 'src', `${which}.ts`);
210
+ }
211
+ // ─────────────────────────────────────────────────────────────────────────────
212
+ // Canonicalization and containment
213
+ // ─────────────────────────────────────────────────────────────────────────────
214
+ /**
215
+ * Absolute, `..`-free, symlink-resolved path.
216
+ *
217
+ * When the path does not exist yet (a file the job is about to write) the deepest
218
+ * existing ancestor is resolved and the remaining segments are appended. That is
219
+ * what makes containment checks meaningful for not-yet-created files: the
220
+ * *directory* they would land in is what actually decides the answer.
221
+ */
222
+ export function canonicalize(input) {
223
+ const abs = isAbsolute(input) ? resolve(input) : resolve(process.cwd(), input);
224
+ try {
225
+ return realpathSync.native(abs);
226
+ }
227
+ catch {
228
+ // fall through to the partial-resolution path
229
+ }
230
+ const rootOf = parsePath(abs).root;
231
+ const tail = [];
232
+ let dir = abs;
233
+ for (;;) {
234
+ const parent = dirname(dir);
235
+ tail.unshift(dir.slice(parent === rootOf ? parent.length : parent.length + 1));
236
+ dir = parent;
237
+ if (dir === rootOf)
238
+ break;
239
+ try {
240
+ return join(realpathSync.native(dir), ...tail);
241
+ }
242
+ catch {
243
+ continue;
244
+ }
245
+ }
246
+ try {
247
+ return join(realpathSync.native(rootOf), ...tail);
248
+ }
249
+ catch {
250
+ return abs;
251
+ }
252
+ }
253
+ /** True when `candidate` is `root` itself or lives beneath it. Both must be canonical. */
254
+ export function isWithin(candidate, root) {
255
+ if (candidate === root)
256
+ return true;
257
+ const rel = relative(root, candidate);
258
+ return rel !== '' && !rel.startsWith('..' + sep) && rel !== '..' && !isAbsolute(rel);
259
+ }
260
+ /** True when the path traverses a symlink anywhere below `root`. */
261
+ export function traversesSymlink(input) {
262
+ const abs = isAbsolute(input) ? resolve(input) : resolve(process.cwd(), input);
263
+ return canonicalize(abs) !== abs;
264
+ }
265
+ /**
266
+ * Canonicalize then check containment; throw {@link PathEscapeError} on escape.
267
+ *
268
+ * ⚠ Order matters and is the whole point: resolving *after* the check would let a
269
+ * symlink inside the workspace point anywhere (see docs/permissions.md). Returns the
270
+ * canonical path so callers use the resolved form from here on.
271
+ */
272
+ export function assertContained(input, roots, kind) {
273
+ const resolved = canonicalize(input);
274
+ const canonicalRoots = roots.map(canonicalize);
275
+ for (const root of canonicalRoots) {
276
+ if (isWithin(resolved, root))
277
+ return resolved;
278
+ }
279
+ const abs = isAbsolute(input) ? resolve(input) : resolve(process.cwd(), input);
280
+ throw new PathEscapeError({
281
+ input_path: input,
282
+ resolved_path: resolved,
283
+ kind,
284
+ roots: canonicalRoots,
285
+ via_symlink: resolved !== abs,
286
+ });
287
+ }
288
+ /** Non-throwing form of {@link assertContained}. */
289
+ export function containedOrNull(input, roots) {
290
+ const resolved = canonicalize(input);
291
+ for (const root of roots) {
292
+ if (isWithin(resolved, canonicalize(root)))
293
+ return resolved;
294
+ }
295
+ return null;
296
+ }
297
+ // ─────────────────────────────────────────────────────────────────────────────
298
+ // Atomic file helpers
299
+ // ─────────────────────────────────────────────────────────────────────────────
300
+ /**
301
+ * Write via a sibling temp file plus `rename`, so a concurrent reader either sees
302
+ * the previous complete version or the new one — never a torn file. Several
303
+ * processes read `state.json` and `broker-result.json` without coordination.
304
+ */
305
+ export function writeFileAtomic(target, data) {
306
+ mkdirSync(dirname(target), { recursive: true });
307
+ const tmp = `${target}.${process.pid}.${Date.now().toString(36)}.tmp`;
308
+ const fd = openSync(tmp, 'wx', 0o600);
309
+ try {
310
+ if (typeof data === 'string')
311
+ writeSync(fd, data);
312
+ else
313
+ writeSync(fd, data);
314
+ fsyncSync(fd);
315
+ }
316
+ finally {
317
+ closeSync(fd);
318
+ }
319
+ try {
320
+ chmodSync(tmp, 0o600);
321
+ }
322
+ catch {
323
+ // best-effort
324
+ }
325
+ renameSync(tmp, target);
326
+ }
327
+ export function writeJsonAtomic(target, value) {
328
+ writeFileAtomic(target, JSON.stringify(value, null, 2) + '\n');
329
+ }
330
+ /** Returns null for a missing *or* unparsable file; a torn read is not fatal. */
331
+ export function readJsonIfExists(target) {
332
+ try {
333
+ return JSON.parse(readFileSync(target, 'utf8'));
334
+ }
335
+ catch {
336
+ return null;
337
+ }
338
+ }
339
+ /** Appends one NDJSON line with a single `O_APPEND` write, which is atomic for small lines. */
340
+ export function appendJsonLine(target, value) {
341
+ mkdirSync(dirname(target), { recursive: true });
342
+ writeFileSync(target, JSON.stringify(value) + '\n', { flag: 'a', mode: 0o600 });
343
+ try {
344
+ chmodSync(target, 0o600);
345
+ }
346
+ catch {
347
+ // best-effort
348
+ }
349
+ }
350
+ /** Current byte length, or 0 when the file does not exist yet. */
351
+ export function fileSize(target) {
352
+ try {
353
+ return statSync(target).size;
354
+ }
355
+ catch {
356
+ return 0;
357
+ }
358
+ }
359
+ //# sourceMappingURL=paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/contract/paths.ts"],"names":[],"mappings":"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"}