human-to-code 0.0.1 → 0.1.2

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 (134) hide show
  1. package/Readme.md +368 -38
  2. package/SECURITY.md +175 -11
  3. package/dist/adapters/general.d.ts +30 -0
  4. package/dist/adapters/general.d.ts.map +1 -0
  5. package/dist/adapters/general.js +77 -0
  6. package/dist/adapters/general.js.map +1 -0
  7. package/dist/adapters/node.d.ts +8 -0
  8. package/dist/adapters/node.d.ts.map +1 -0
  9. package/dist/adapters/node.js +1071 -0
  10. package/dist/adapters/node.js.map +1 -0
  11. package/dist/adapters/python.d.ts +7 -0
  12. package/dist/adapters/python.d.ts.map +1 -0
  13. package/dist/adapters/python.js +540 -0
  14. package/dist/adapters/python.js.map +1 -0
  15. package/dist/adapters/rust.d.ts +7 -0
  16. package/dist/adapters/rust.d.ts.map +1 -0
  17. package/dist/adapters/rust.js +517 -0
  18. package/dist/adapters/rust.js.map +1 -0
  19. package/dist/analyzer-types.d.ts +161 -0
  20. package/dist/analyzer-types.d.ts.map +1 -0
  21. package/dist/analyzer-types.js +8 -0
  22. package/dist/analyzer-types.js.map +1 -0
  23. package/dist/analyzer-utils.d.ts +40 -0
  24. package/dist/analyzer-utils.d.ts.map +1 -0
  25. package/dist/analyzer-utils.js +591 -0
  26. package/dist/analyzer-utils.js.map +1 -0
  27. package/dist/analyzer.d.ts +21 -0
  28. package/dist/analyzer.d.ts.map +1 -0
  29. package/dist/analyzer.js +111 -0
  30. package/dist/analyzer.js.map +1 -0
  31. package/dist/certification.d.ts +102 -0
  32. package/dist/certification.d.ts.map +1 -0
  33. package/dist/certification.js +193 -0
  34. package/dist/certification.js.map +1 -0
  35. package/dist/cli.d.ts +4 -0
  36. package/dist/cli.d.ts.map +1 -0
  37. package/dist/cli.js +566 -0
  38. package/dist/cli.js.map +1 -0
  39. package/dist/compiler-skills.d.ts +25 -0
  40. package/dist/compiler-skills.d.ts.map +1 -0
  41. package/dist/compiler-skills.js +158 -0
  42. package/dist/compiler-skills.js.map +1 -0
  43. package/dist/compiler-tools.d.ts +29 -0
  44. package/dist/compiler-tools.d.ts.map +1 -0
  45. package/dist/compiler-tools.js +337 -0
  46. package/dist/compiler-tools.js.map +1 -0
  47. package/dist/config.d.ts +122 -0
  48. package/dist/config.d.ts.map +1 -0
  49. package/dist/config.js +704 -0
  50. package/dist/config.js.map +1 -0
  51. package/dist/context.d.ts +153 -0
  52. package/dist/context.d.ts.map +1 -0
  53. package/dist/context.js +772 -0
  54. package/dist/context.js.map +1 -0
  55. package/dist/contracts.d.ts +196 -0
  56. package/dist/contracts.d.ts.map +1 -0
  57. package/dist/contracts.js +721 -0
  58. package/dist/contracts.js.map +1 -0
  59. package/dist/discovery.d.ts +34 -0
  60. package/dist/discovery.d.ts.map +1 -0
  61. package/dist/discovery.js +312 -0
  62. package/dist/discovery.js.map +1 -0
  63. package/dist/documentation.d.ts +44 -0
  64. package/dist/documentation.d.ts.map +1 -0
  65. package/dist/documentation.js +418 -0
  66. package/dist/documentation.js.map +1 -0
  67. package/dist/index.d.ts +23 -0
  68. package/dist/index.d.ts.map +1 -0
  69. package/dist/index.js +21 -0
  70. package/dist/index.js.map +1 -0
  71. package/dist/patch.d.ts +71 -0
  72. package/dist/patch.d.ts.map +1 -0
  73. package/dist/patch.js +394 -0
  74. package/dist/patch.js.map +1 -0
  75. package/dist/pinned-http.d.ts +15 -0
  76. package/dist/pinned-http.d.ts.map +1 -0
  77. package/dist/pinned-http.js +170 -0
  78. package/dist/pinned-http.js.map +1 -0
  79. package/dist/planner.d.ts +30 -0
  80. package/dist/planner.d.ts.map +1 -0
  81. package/dist/planner.js +228 -0
  82. package/dist/planner.js.map +1 -0
  83. package/dist/provider.d.ts +168 -0
  84. package/dist/provider.d.ts.map +1 -0
  85. package/dist/provider.js +512 -0
  86. package/dist/provider.js.map +1 -0
  87. package/dist/providers.d.ts +41 -0
  88. package/dist/providers.d.ts.map +1 -0
  89. package/dist/providers.js +954 -0
  90. package/dist/providers.js.map +1 -0
  91. package/dist/run-store.d.ts +24 -0
  92. package/dist/run-store.d.ts.map +1 -0
  93. package/dist/run-store.js +285 -0
  94. package/dist/run-store.js.map +1 -0
  95. package/dist/schemas.d.ts +18 -0
  96. package/dist/schemas.d.ts.map +1 -0
  97. package/dist/schemas.js +228 -0
  98. package/dist/schemas.js.map +1 -0
  99. package/dist/secret-scan.d.ts +30 -0
  100. package/dist/secret-scan.d.ts.map +1 -0
  101. package/dist/secret-scan.js +122 -0
  102. package/dist/secret-scan.js.map +1 -0
  103. package/dist/snapshot.d.ts +33 -0
  104. package/dist/snapshot.d.ts.map +1 -0
  105. package/dist/snapshot.js +136 -0
  106. package/dist/snapshot.js.map +1 -0
  107. package/dist/support-matrix.d.ts +23 -0
  108. package/dist/support-matrix.d.ts.map +1 -0
  109. package/dist/support-matrix.js +199 -0
  110. package/dist/support-matrix.js.map +1 -0
  111. package/dist/types.d.ts +63 -0
  112. package/dist/types.d.ts.map +1 -0
  113. package/dist/types.js +8 -0
  114. package/dist/types.js.map +1 -0
  115. package/dist/validation.d.ts +25 -0
  116. package/dist/validation.d.ts.map +1 -0
  117. package/dist/validation.js +388 -0
  118. package/dist/validation.js.map +1 -0
  119. package/dist/workflow.d.ts +65 -0
  120. package/dist/workflow.d.ts.map +1 -0
  121. package/dist/workflow.js +1636 -0
  122. package/dist/workflow.js.map +1 -0
  123. package/package.json +36 -9
  124. package/.claude/settings.local.json +0 -12
  125. package/.github/workflows/ci.yml +0 -18
  126. package/CONTRIBUTING.md +0 -40
  127. package/src/cli.ts +0 -218
  128. package/src/config.ts +0 -186
  129. package/src/discovery.ts +0 -186
  130. package/src/index.ts +0 -22
  131. package/src/types.ts +0 -74
  132. package/test/config.test.ts +0 -97
  133. package/test/discovery.test.ts +0 -91
  134. package/tsconfig.json +0 -17
package/dist/patch.js ADDED
@@ -0,0 +1,394 @@
1
+ /**
2
+ * Constrained patch validation and atomic application.
3
+ *
4
+ * Model output is never applied as a shell patch. Every operation is checked
5
+ * against the repository root, its exact base hash, and an explicit scope.
6
+ */
7
+ import { chmod, copyFile, lstat, mkdir, mkdtemp, readFile, rename, rm, unlink, writeFile, } from "node:fs/promises";
8
+ import { constants as fsConstants } from "node:fs";
9
+ import { tmpdir } from "node:os";
10
+ import { basename, dirname, isAbsolute, join, posix, relative, resolve, sep, win32, } from "node:path";
11
+ import { randomUUID } from "node:crypto";
12
+ import { hashCanonical, sha256Text, validatePatchSetV1 } from "./contracts.js";
13
+ const DEFAULT_MAX_OPERATIONS = 200;
14
+ const DEFAULT_MAX_BYTES = 5 * 1024 * 1024;
15
+ const HARD_PROTECTED_NAMES = new Set([
16
+ ".git",
17
+ ".hg",
18
+ ".svn",
19
+ "node_modules",
20
+ "secrets.human",
21
+ "human-to-code.config.json",
22
+ ".npmrc",
23
+ ".yarnrc",
24
+ ".yarnrc.yml",
25
+ ".pypirc",
26
+ ".netrc",
27
+ ".git-credentials",
28
+ "credentials",
29
+ "credentials.json",
30
+ "service-account.json",
31
+ "kubeconfig",
32
+ ]);
33
+ const HARD_PROTECTED_PREFIXES = [".human-to-code/"];
34
+ export class PatchSafetyError extends Error {
35
+ code;
36
+ details;
37
+ constructor(code, message, details = []) {
38
+ super(message);
39
+ this.name = "PatchSafetyError";
40
+ this.code = code;
41
+ this.details = details;
42
+ }
43
+ }
44
+ function toPosix(value) {
45
+ return value.split(/[\\/]/).join("/");
46
+ }
47
+ export function normalizePatchPath(value) {
48
+ if (typeof value !== "string" || value.length === 0) {
49
+ throw new PatchSafetyError("INVALID_PATH", "Patch paths must be non-empty strings.");
50
+ }
51
+ if (value.includes("\0") || isAbsolute(value) || win32.isAbsolute(value)) {
52
+ throw new PatchSafetyError("PATH_ESCAPE", `Unsafe patch path: ${JSON.stringify(value)}.`);
53
+ }
54
+ const normalized = posix.normalize(toPosix(value));
55
+ if (normalized === "." ||
56
+ normalized === ".." ||
57
+ normalized.startsWith("../") ||
58
+ normalized.includes("/../") ||
59
+ normalized.startsWith("/")) {
60
+ throw new PatchSafetyError("PATH_ESCAPE", `Patch path escapes the root: ${value}.`);
61
+ }
62
+ const segments = normalized.split("/");
63
+ if (segments.some((segment) => segment.length === 0 || segment === "." || segment === "..")) {
64
+ throw new PatchSafetyError("INVALID_PATH", `Patch path is not canonical: ${value}.`);
65
+ }
66
+ return normalized;
67
+ }
68
+ function isPrefixMatch(path, rule) {
69
+ const normalizedRule = normalizePatchPath(rule.endsWith("/") ? rule.slice(0, -1) : rule);
70
+ if (normalizedRule.includes("*")) {
71
+ const escaped = normalizedRule.replace(/[.+^${}()|[\]\\]/gu, "\\$&");
72
+ const expression = escaped.replaceAll("**", "\0").replaceAll("*", "[^/]*").replaceAll("\0", ".*");
73
+ return new RegExp(`^${expression}(?:/.*)?$`, "u").test(path);
74
+ }
75
+ return path === normalizedRule || path.startsWith(`${normalizedRule}/`);
76
+ }
77
+ function assertAllowedPath(path, policy) {
78
+ const parts = path.split("/");
79
+ const sensitiveName = (part) => {
80
+ const lower = part.toLowerCase();
81
+ return HARD_PROTECTED_NAMES.has(lower)
82
+ || /^\.env(?:\..*)?$/iu.test(part)
83
+ || /^(?:id_rsa|id_dsa|id_ecdsa|id_ed25519)(?:\..*)?$/iu.test(part)
84
+ || /\.(?:pem|key|p12|pfx|jks|keystore)$/iu.test(part)
85
+ || /^(?:credentials?|secrets?)(?:\..*)?$/iu.test(part);
86
+ };
87
+ const cargoCredential = parts.some((part, index) => part.toLowerCase() === ".cargo" && /^credentials(?:\.toml)?$/iu.test(parts[index + 1] ?? ""));
88
+ const dockerCredential = parts.some((part, index) => part.toLowerCase() === ".docker" && (parts[index + 1] ?? "").toLowerCase() === "config.json");
89
+ if (parts.some(sensitiveName) || cargoCredential || dockerCredential) {
90
+ throw new PatchSafetyError("PROTECTED_PATH", `Patch targets protected path: ${path}.`);
91
+ }
92
+ if (HARD_PROTECTED_PREFIXES.some((prefix) => path.startsWith(prefix))) {
93
+ throw new PatchSafetyError("PROTECTED_PATH", `Patch targets protected path: ${path}.`);
94
+ }
95
+ if ((policy.protectedPaths ?? []).some((rule) => isPrefixMatch(path, rule))) {
96
+ throw new PatchSafetyError("PROTECTED_PATH", `Patch targets configured protected path: ${path}.`);
97
+ }
98
+ const allowed = policy.allowedPaths;
99
+ if (allowed && allowed.length > 0 && !allowed.some((rule) => isPrefixMatch(path, rule))) {
100
+ throw new PatchSafetyError("OUT_OF_SCOPE", `Patch path is outside the contract scope: ${path}.`);
101
+ }
102
+ }
103
+ function resolveInside(root, path) {
104
+ const abs = resolve(root, ...path.split("/"));
105
+ const rel = relative(root, abs);
106
+ if (rel === "" || rel === ".." || rel.startsWith(`..${sep}`) || isAbsolute(rel)) {
107
+ throw new PatchSafetyError("PATH_ESCAPE", `Resolved path escapes the root: ${path}.`);
108
+ }
109
+ return abs;
110
+ }
111
+ async function assertSafeParents(root, absPath) {
112
+ let cursor = dirname(absPath);
113
+ const rootResolved = resolve(root);
114
+ while (cursor !== rootResolved) {
115
+ const rel = relative(rootResolved, cursor);
116
+ if (rel === ".." || rel.startsWith(`..${sep}`)) {
117
+ throw new PatchSafetyError("PATH_ESCAPE", `Parent directory escapes root: ${absPath}.`);
118
+ }
119
+ try {
120
+ const info = await lstat(cursor);
121
+ if (info.isSymbolicLink()) {
122
+ throw new PatchSafetyError("SYMLINK_ESCAPE", `Patch parent is a symlink: ${toPosix(rel)}.`);
123
+ }
124
+ if (!info.isDirectory()) {
125
+ throw new PatchSafetyError("INVALID_PATH", `Patch parent is not a directory: ${toPosix(rel)}.`);
126
+ }
127
+ }
128
+ catch (error) {
129
+ if (error instanceof PatchSafetyError)
130
+ throw error;
131
+ const code = error.code;
132
+ if (code !== "ENOENT")
133
+ throw error;
134
+ }
135
+ cursor = dirname(cursor);
136
+ }
137
+ }
138
+ async function readSafeRegularFile(absPath, path) {
139
+ let info;
140
+ try {
141
+ info = await lstat(absPath);
142
+ }
143
+ catch (error) {
144
+ if (error.code === "ENOENT") {
145
+ throw new PatchSafetyError("MISSING_BASE", `Patch base file does not exist: ${path}.`);
146
+ }
147
+ throw error;
148
+ }
149
+ if (info.isSymbolicLink()) {
150
+ throw new PatchSafetyError("SYMLINK_ESCAPE", `Patch target is a symlink: ${path}.`);
151
+ }
152
+ if (!info.isFile()) {
153
+ throw new PatchSafetyError("INVALID_TARGET", `Patch target is not a regular file: ${path}.`);
154
+ }
155
+ if (info.nlink > 1) {
156
+ throw new PatchSafetyError("HARDLINK_ESCAPE", `Patch target has multiple hard links: ${path}.`);
157
+ }
158
+ const bytes = await readFile(absPath);
159
+ if (bytes.includes(0)) {
160
+ throw new PatchSafetyError("BINARY_TARGET", `Patch target appears binary: ${path}.`);
161
+ }
162
+ return { text: bytes.toString("utf8"), mode: info.mode & 0o777 };
163
+ }
164
+ function assertBaseHash(path, text, expected) {
165
+ const actual = sha256Text(text);
166
+ if (actual !== expected) {
167
+ throw new PatchSafetyError("STALE_BASE", `Patch base hash does not match ${path}.`, [`expected=${expected}`, `actual=${actual}`]);
168
+ }
169
+ }
170
+ function uniqueOccurrence(haystack, needle) {
171
+ if (needle.length === 0)
172
+ return -1;
173
+ const first = haystack.indexOf(needle);
174
+ if (first < 0)
175
+ return -1;
176
+ return haystack.indexOf(needle, first + 1) < 0 ? first : -2;
177
+ }
178
+ export function computePatchSnapshotHash(operations) {
179
+ const bases = operations
180
+ .map((operation) => {
181
+ if (operation.kind === "create")
182
+ return { path: normalizePatchPath(operation.path), hash: null };
183
+ if (operation.kind === "rename") {
184
+ return {
185
+ path: normalizePatchPath(operation.from),
186
+ destination: normalizePatchPath(operation.path),
187
+ hash: operation.baseHash,
188
+ };
189
+ }
190
+ return { path: normalizePatchPath(operation.path), hash: operation.baseHash };
191
+ })
192
+ .sort((a, b) => a.path.localeCompare(b.path));
193
+ return hashCanonical(bases);
194
+ }
195
+ export async function preparePatch(rootInput, patch, policy = {}) {
196
+ const root = resolve(rootInput);
197
+ const rootInfo = await lstat(root).catch((error) => {
198
+ throw new PatchSafetyError("INVALID_ROOT", `Cannot inspect patch root: ${String(error)}.`);
199
+ });
200
+ if (!rootInfo.isDirectory() || rootInfo.isSymbolicLink()) {
201
+ throw new PatchSafetyError("INVALID_ROOT", "Patch root must be a real directory.");
202
+ }
203
+ if (patch.schemaVersion !== 1 || !Array.isArray(patch.operations)) {
204
+ throw new PatchSafetyError("INVALID_PATCH", "PatchSetV1 schema is invalid.");
205
+ }
206
+ try {
207
+ validatePatchSetV1(patch);
208
+ }
209
+ catch (error) {
210
+ throw new PatchSafetyError("INVALID_PATCH", error instanceof Error ? error.message : String(error));
211
+ }
212
+ const maxOperations = policy.maxOperations ?? DEFAULT_MAX_OPERATIONS;
213
+ if (patch.operations.length === 0 || patch.operations.length > maxOperations) {
214
+ throw new PatchSafetyError("PATCH_SIZE", `Patch must contain between 1 and ${maxOperations} operations.`);
215
+ }
216
+ if (!/^[a-f0-9]{64}$/u.test(patch.snapshotHash)) {
217
+ throw new PatchSafetyError("INVALID_SNAPSHOT", "Patch snapshot hash is not a SHA-256 digest.");
218
+ }
219
+ if (policy.expectedSnapshotHash !== undefined && patch.snapshotHash !== policy.expectedSnapshotHash) {
220
+ throw new PatchSafetyError("INVALID_SNAPSHOT", "Patch is bound to a different workspace snapshot.");
221
+ }
222
+ const normalizedKeys = new Set();
223
+ const claimedPaths = new Set();
224
+ for (const operation of patch.operations) {
225
+ const paths = operation.kind === "rename" ? [operation.from, operation.path] : [operation.path];
226
+ for (const rawPath of paths) {
227
+ const path = normalizePatchPath(rawPath);
228
+ assertAllowedPath(path, policy);
229
+ const key = path.toLocaleLowerCase("en-US");
230
+ if (normalizedKeys.has(key) || claimedPaths.has(path)) {
231
+ throw new PatchSafetyError("PATH_COLLISION", `Patch contains a duplicate or case-colliding path: ${path}.`);
232
+ }
233
+ normalizedKeys.add(key);
234
+ claimedPaths.add(path);
235
+ }
236
+ }
237
+ const prepared = [];
238
+ let changedBytes = 0;
239
+ for (const operation of patch.operations) {
240
+ const path = normalizePatchPath(operation.path);
241
+ const absPath = resolveInside(root, path);
242
+ await assertSafeParents(root, absPath);
243
+ if (operation.kind === "create") {
244
+ try {
245
+ await lstat(absPath);
246
+ throw new PatchSafetyError("TARGET_EXISTS", `Create target already exists: ${path}.`);
247
+ }
248
+ catch (error) {
249
+ if (error instanceof PatchSafetyError)
250
+ throw error;
251
+ if (error.code !== "ENOENT")
252
+ throw error;
253
+ }
254
+ const mode = 0o644;
255
+ changedBytes += Buffer.byteLength(operation.content);
256
+ prepared.push({ kind: "create", path, absPath, content: operation.content, mode });
257
+ continue;
258
+ }
259
+ if (operation.kind === "edit") {
260
+ const current = await readSafeRegularFile(absPath, path);
261
+ assertBaseHash(path, current.text, operation.baseHash);
262
+ const index = uniqueOccurrence(current.text, operation.oldText);
263
+ if (index === -1) {
264
+ throw new PatchSafetyError("EDIT_MISMATCH", `Edit source text was not found in ${path}.`);
265
+ }
266
+ if (index === -2) {
267
+ throw new PatchSafetyError("EDIT_AMBIGUOUS", `Edit source text is not unique in ${path}.`);
268
+ }
269
+ const after = current.text.slice(0, index) +
270
+ operation.newText +
271
+ current.text.slice(index + operation.oldText.length);
272
+ changedBytes += Buffer.byteLength(operation.newText) + Buffer.byteLength(operation.oldText);
273
+ prepared.push({ kind: "edit", path, absPath, before: current.text, after, mode: current.mode });
274
+ continue;
275
+ }
276
+ if (operation.kind === "delete") {
277
+ if (!policy.allowDeletes) {
278
+ throw new PatchSafetyError("DELETE_NOT_ALLOWED", `Delete was not authorized: ${path}.`);
279
+ }
280
+ const current = await readSafeRegularFile(absPath, path);
281
+ assertBaseHash(path, current.text, operation.baseHash);
282
+ changedBytes += Buffer.byteLength(current.text);
283
+ prepared.push({ kind: "delete", path, absPath, before: current.text, mode: current.mode });
284
+ continue;
285
+ }
286
+ if (!policy.allowRenames) {
287
+ throw new PatchSafetyError("RENAME_NOT_ALLOWED", `Rename was not authorized: ${operation.from}.`);
288
+ }
289
+ const from = normalizePatchPath(operation.from);
290
+ const absFrom = resolveInside(root, from);
291
+ await assertSafeParents(root, absFrom);
292
+ const current = await readSafeRegularFile(absFrom, from);
293
+ assertBaseHash(from, current.text, operation.baseHash);
294
+ try {
295
+ await lstat(absPath);
296
+ throw new PatchSafetyError("TARGET_EXISTS", `Rename destination already exists: ${path}.`);
297
+ }
298
+ catch (error) {
299
+ if (error instanceof PatchSafetyError)
300
+ throw error;
301
+ if (error.code !== "ENOENT")
302
+ throw error;
303
+ }
304
+ changedBytes += Buffer.byteLength(current.text);
305
+ prepared.push({ kind: "rename", from, absFrom, path, absPath, before: current.text, mode: current.mode });
306
+ }
307
+ const maxChangedBytes = policy.maxChangedBytes ?? DEFAULT_MAX_BYTES;
308
+ if (changedBytes > maxChangedBytes) {
309
+ throw new PatchSafetyError("PATCH_SIZE", `Patch changes ${changedBytes} bytes, exceeding the ${maxChangedBytes}-byte limit.`);
310
+ }
311
+ return { root, patch, operations: prepared, changedBytes };
312
+ }
313
+ async function writeAtomic(absPath, content, mode) {
314
+ await mkdir(dirname(absPath), { recursive: true });
315
+ const temporary = join(dirname(absPath), `.${basename(absPath)}.h2c-${randomUUID()}.tmp`);
316
+ try {
317
+ await writeFile(temporary, content, { encoding: "utf8", flag: "wx", mode });
318
+ await chmod(temporary, mode);
319
+ await rename(temporary, absPath);
320
+ }
321
+ finally {
322
+ await rm(temporary, { force: true }).catch(() => undefined);
323
+ }
324
+ }
325
+ /**
326
+ * Apply an already constrained PatchSet. On any failure, touched paths are
327
+ * restored to their original content and modes before the error is rethrown.
328
+ */
329
+ export async function applyPatchAtomic(root, patch, policy = {}) {
330
+ const prepared = await preparePatch(root, patch, policy);
331
+ const backupRoot = await mkdtemp(join(tmpdir(), "human-to-code-rollback-"));
332
+ const applied = [];
333
+ const appliedIndexes = [];
334
+ try {
335
+ for (let index = 0; index < prepared.operations.length; index++) {
336
+ const operation = prepared.operations[index];
337
+ const backup = join(backupRoot, String(index));
338
+ if (operation.kind === "create") {
339
+ await writeAtomic(operation.absPath, operation.content, operation.mode);
340
+ applied.push(operation.path);
341
+ appliedIndexes.push(index);
342
+ }
343
+ else if (operation.kind === "edit") {
344
+ await copyFile(operation.absPath, backup, fsConstants.COPYFILE_EXCL);
345
+ await writeAtomic(operation.absPath, operation.after, operation.mode);
346
+ applied.push(operation.path);
347
+ appliedIndexes.push(index);
348
+ }
349
+ else if (operation.kind === "delete") {
350
+ await copyFile(operation.absPath, backup, fsConstants.COPYFILE_EXCL);
351
+ await unlink(operation.absPath);
352
+ applied.push(operation.path);
353
+ appliedIndexes.push(index);
354
+ }
355
+ else {
356
+ await copyFile(operation.absFrom, backup, fsConstants.COPYFILE_EXCL);
357
+ await mkdir(dirname(operation.absPath), { recursive: true });
358
+ await rename(operation.absFrom, operation.absPath);
359
+ applied.push(`${operation.from} -> ${operation.path}`);
360
+ appliedIndexes.push(index);
361
+ }
362
+ }
363
+ }
364
+ catch (error) {
365
+ for (const index of appliedIndexes.reverse()) {
366
+ const operation = prepared.operations[index];
367
+ const backup = join(backupRoot, String(index));
368
+ try {
369
+ if (operation.kind === "create") {
370
+ await rm(operation.absPath, { force: true });
371
+ }
372
+ else if (operation.kind === "edit" || operation.kind === "delete") {
373
+ await copyFile(backup, operation.absPath);
374
+ await chmod(operation.absPath, operation.mode);
375
+ }
376
+ else {
377
+ await rm(operation.absPath, { force: true });
378
+ await copyFile(backup, operation.absFrom);
379
+ await chmod(operation.absFrom, operation.mode);
380
+ }
381
+ }
382
+ catch {
383
+ // Preserve the original failure. Rollback failures are surfaced in the
384
+ // error message instead of risking a second exception hiding it.
385
+ }
386
+ }
387
+ throw new PatchSafetyError("APPLY_FAILED", `Patch application failed and was rolled back: ${String(error)}.`);
388
+ }
389
+ finally {
390
+ await rm(backupRoot, { recursive: true, force: true });
391
+ }
392
+ return { applied, patchHash: hashCanonical(patch) };
393
+ }
394
+ //# sourceMappingURL=patch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"patch.js","sourceRoot":"","sources":["../src/patch.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ /** Dependency-free HTTP(S) transport whose socket is pinned to a vetted IP. */
2
+ export interface PinnedDestination {
3
+ /** Original hostname used for Host and TLS certificate verification. */
4
+ hostname: string;
5
+ /** Exact vetted address used by the socket; no second DNS lookup occurs. */
6
+ address: string;
7
+ family: 4 | 6;
8
+ }
9
+ /**
10
+ * GET or POST using a socket connected to `destination.address`. HTTPS
11
+ * retains the original hostname for SNI and certificate identity checks.
12
+ * Environment proxy variables and the OS resolver are intentionally bypassed.
13
+ */
14
+ export declare function pinnedHttpFetch(rawUrl: string, init: RequestInit, destination: PinnedDestination): Promise<Response>;
15
+ //# sourceMappingURL=pinned-http.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pinned-http.d.ts","sourceRoot":"","sources":["../src/pinned-http.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAc/E,MAAM,WAAW,iBAAiB;IAChC,wEAAwE;IACxE,QAAQ,EAAE,MAAM,CAAC;IACjB,4EAA4E;IAC5E,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC;CACf;AAyED;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,WAAW,EACjB,WAAW,EAAE,iBAAiB,GAC7B,OAAO,CAAC,QAAQ,CAAC,CAwFnB"}
@@ -0,0 +1,170 @@
1
+ /** Dependency-free HTTP(S) transport whose socket is pinned to a vetted IP. */
2
+ import { request as httpRequest, } from "node:http";
3
+ import { request as httpsRequest, } from "node:https";
4
+ import { isIP } from "node:net";
5
+ import { Readable } from "node:stream";
6
+ function abortError() {
7
+ return new DOMException("The provider request was aborted.", "AbortError");
8
+ }
9
+ function requestBody(init, method) {
10
+ if (method === "GET") {
11
+ if (init.body !== undefined && init.body !== null) {
12
+ throw new TypeError("Pinned GET requests must not contain a request body.");
13
+ }
14
+ return Buffer.alloc(0);
15
+ }
16
+ if (typeof init.body === "string")
17
+ return Buffer.from(init.body, "utf8");
18
+ if (init.body instanceof Uint8Array)
19
+ return Buffer.from(init.body);
20
+ if (init.body === undefined || init.body === null)
21
+ return Buffer.alloc(0);
22
+ throw new TypeError("Pinned provider transport accepts only bounded string or byte request bodies.");
23
+ }
24
+ function responseHeaders(message) {
25
+ const headers = new Headers();
26
+ for (let index = 0; index < message.rawHeaders.length; index += 2) {
27
+ const name = message.rawHeaders[index];
28
+ const value = message.rawHeaders[index + 1];
29
+ if (name !== undefined && value !== undefined)
30
+ headers.append(name, value);
31
+ }
32
+ return headers;
33
+ }
34
+ function webResponse(message) {
35
+ const status = message.statusCode;
36
+ if (status === undefined || status < 200 || status > 599) {
37
+ message.destroy();
38
+ throw new Error("Provider returned an unsupported HTTP status.");
39
+ }
40
+ const hasNoBody = status === 204 || status === 205 || status === 304;
41
+ const body = hasNoBody
42
+ ? null
43
+ : Readable.toWeb(message);
44
+ return new Response(body, {
45
+ status,
46
+ statusText: message.statusMessage ?? "",
47
+ headers: responseHeaders(message),
48
+ });
49
+ }
50
+ function normalizedHeaders(url, init, body, method) {
51
+ const source = new Headers(init.headers);
52
+ const headers = {};
53
+ for (const [name, value] of source.entries())
54
+ headers[name] = value;
55
+ for (const name of [
56
+ "proxy-authorization",
57
+ "proxy-connection",
58
+ "te",
59
+ "trailer",
60
+ "transfer-encoding",
61
+ "upgrade",
62
+ ]) {
63
+ delete headers[name];
64
+ }
65
+ // Host is derived from the reviewed URL and cannot be supplied by a caller.
66
+ headers.host = url.host;
67
+ if (method === "POST")
68
+ headers["content-length"] = String(body.byteLength);
69
+ else
70
+ delete headers["content-length"];
71
+ headers.connection = "close";
72
+ return headers;
73
+ }
74
+ /**
75
+ * GET or POST using a socket connected to `destination.address`. HTTPS
76
+ * retains the original hostname for SNI and certificate identity checks.
77
+ * Environment proxy variables and the OS resolver are intentionally bypassed.
78
+ */
79
+ export function pinnedHttpFetch(rawUrl, init, destination) {
80
+ const url = new URL(rawUrl);
81
+ if (url.protocol !== "http:" && url.protocol !== "https:") {
82
+ return Promise.reject(new TypeError("Pinned provider transport supports only HTTP(S)."));
83
+ }
84
+ if (url.username !== "" || url.password !== "" || url.hash !== "") {
85
+ return Promise.reject(new TypeError("Pinned HTTP URLs must not contain credentials or fragments."));
86
+ }
87
+ if (destination.family !== isIP(destination.address)) {
88
+ return Promise.reject(new TypeError("Pinned provider destination address/family is invalid."));
89
+ }
90
+ if (destination.hostname !== url.hostname.replace(/^\[|\]$/gu, "").replace(/\.$/u, "").toLowerCase()) {
91
+ return Promise.reject(new TypeError("Pinned provider hostname does not match its reviewed URL."));
92
+ }
93
+ const method = (init.method ?? "GET").toUpperCase();
94
+ if (method !== "GET" && method !== "POST") {
95
+ return Promise.reject(new TypeError("Pinned HTTP transport permits only GET or POST."));
96
+ }
97
+ let body;
98
+ try {
99
+ body = requestBody(init, method);
100
+ }
101
+ catch (error) {
102
+ return Promise.reject(error);
103
+ }
104
+ const signal = init.signal ?? undefined;
105
+ if (signal?.aborted)
106
+ return Promise.reject(abortError());
107
+ const headers = normalizedHeaders(url, init, body, method);
108
+ const port = url.port === "" ? (url.protocol === "https:" ? 443 : 80) : Number(url.port);
109
+ const common = {
110
+ protocol: url.protocol,
111
+ hostname: destination.address,
112
+ family: destination.family,
113
+ port,
114
+ method,
115
+ path: `${url.pathname}${url.search}`,
116
+ headers,
117
+ agent: false,
118
+ maxHeaderSize: 64 * 1024,
119
+ setHost: false,
120
+ };
121
+ return new Promise((resolveResponse, reject) => {
122
+ let message;
123
+ let settled = false;
124
+ const finishError = (error) => {
125
+ if (settled)
126
+ return;
127
+ settled = true;
128
+ cleanupBeforeResponse();
129
+ reject(error);
130
+ };
131
+ const onAbort = () => {
132
+ const error = abortError();
133
+ message?.destroy(error);
134
+ request.destroy(error);
135
+ };
136
+ const cleanupBeforeResponse = () => {
137
+ signal?.removeEventListener("abort", onAbort);
138
+ };
139
+ const onResponse = (incoming) => {
140
+ message = incoming;
141
+ if (signal?.aborted) {
142
+ onAbort();
143
+ return;
144
+ }
145
+ // Keep the abort listener until the response body closes so timeout and
146
+ // caller cancellation also stop a stalled download.
147
+ incoming.once("close", cleanupBeforeResponse);
148
+ try {
149
+ const result = webResponse(incoming);
150
+ settled = true;
151
+ resolveResponse(result);
152
+ }
153
+ catch (error) {
154
+ finishError(error instanceof Error ? error : new Error(String(error)));
155
+ }
156
+ };
157
+ const request = url.protocol === "https:"
158
+ ? httpsRequest({
159
+ ...common,
160
+ // For DNS names this controls both SNI and certificate hostname
161
+ // validation. IP-literal endpoints are verified against their IP SAN.
162
+ ...(isIP(destination.hostname) === 0 ? { servername: destination.hostname } : {}),
163
+ }, onResponse)
164
+ : httpRequest(common, onResponse);
165
+ request.once("error", finishError);
166
+ signal?.addEventListener("abort", onAbort, { once: true });
167
+ request.end(body);
168
+ });
169
+ }
170
+ //# sourceMappingURL=pinned-http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pinned-http.js","sourceRoot":"","sources":["../src/pinned-http.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /** Deterministic creation and loading of reviewed ChangeContractV1 artifacts. */
2
+ import type { ProjectProfileV1 } from "./analyzer-types.ts";
3
+ import { type ChangeContractV1 } from "./contracts.ts";
4
+ import type { SourceFile } from "./types.ts";
5
+ export declare class PlanningError extends Error {
6
+ readonly code: string;
7
+ constructor(code: string, message: string);
8
+ }
9
+ export interface DraftContractResult {
10
+ contract: ChangeContractV1;
11
+ contractPath: string;
12
+ needsReview: true;
13
+ }
14
+ export declare function contractPathForSource(root: string, source: SourceFile): string;
15
+ /**
16
+ * Create a deliberately unreviewed contract. It is useful as a deterministic
17
+ * starting point, but the material review question prevents generation until
18
+ * a human confirms target, scope, acceptance criteria, and elevated risks.
19
+ */
20
+ export declare function createDraftContract(root: string, source: SourceFile, profile: ProjectProfileV1): Promise<DraftContractResult>;
21
+ export declare function writeDraftContract(result: DraftContractResult): Promise<void>;
22
+ export interface LoadedContract {
23
+ contract: ChangeContractV1;
24
+ contractPath: string;
25
+ hash: string;
26
+ }
27
+ /** Load a reviewed contract and bind it to the current source and analysis. */
28
+ export declare function loadReviewedContract(root: string, contractPathInput: string, profile: ProjectProfileV1): Promise<LoadedContract>;
29
+ export declare function contractRelativeToRoot(root: string, path: string): string;
30
+ //# sourceMappingURL=planner.d.ts.map