@nanonets/graft 0.23.1 → 0.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (266) hide show
  1. package/README.md +4 -4
  2. package/dist/ai/crux.d.ts +31 -3
  3. package/dist/ai/crux.d.ts.map +1 -1
  4. package/dist/ai/crux.js +88 -10
  5. package/dist/ai/crux.js.map +1 -1
  6. package/dist/ai/llm/openai.d.ts +101 -0
  7. package/dist/ai/llm/openai.d.ts.map +1 -1
  8. package/dist/ai/llm/openai.js +396 -6
  9. package/dist/ai/llm/openai.js.map +1 -1
  10. package/dist/ai/llm/recover-tool.d.ts +2 -0
  11. package/dist/ai/llm/recover-tool.d.ts.map +1 -1
  12. package/dist/ai/llm/recover-tool.js +1 -1
  13. package/dist/ai/llm/recover-tool.js.map +1 -1
  14. package/dist/ai/synthesize.d.ts.map +1 -1
  15. package/dist/ai/synthesize.js +100 -1
  16. package/dist/ai/synthesize.js.map +1 -1
  17. package/dist/claude/format.js +1 -1
  18. package/dist/claude/format.js.map +1 -1
  19. package/dist/claude/hooks.d.ts +0 -18
  20. package/dist/claude/hooks.d.ts.map +1 -1
  21. package/dist/claude/hooks.js +24 -77
  22. package/dist/claude/hooks.js.map +1 -1
  23. package/dist/claude/init.js +3 -3
  24. package/dist/claude/init.js.map +1 -1
  25. package/dist/claude/note-signals.d.ts +28 -0
  26. package/dist/claude/note-signals.d.ts.map +1 -0
  27. package/dist/claude/note-signals.js +325 -0
  28. package/dist/claude/note-signals.js.map +1 -0
  29. package/dist/claude/shim-template.d.ts.map +1 -1
  30. package/dist/claude/shim-template.js +10 -4
  31. package/dist/claude/shim-template.js.map +1 -1
  32. package/dist/claude/skill-template.d.ts.map +1 -1
  33. package/dist/claude/skill-template.js +49 -18
  34. package/dist/claude/skill-template.js.map +1 -1
  35. package/dist/claude/state.d.ts +4 -3
  36. package/dist/claude/state.d.ts.map +1 -1
  37. package/dist/claude/state.js.map +1 -1
  38. package/dist/claude/sync-run.js +1 -1
  39. package/dist/claude/sync-run.js.map +1 -1
  40. package/dist/cli-picker.d.ts +12 -5
  41. package/dist/cli-picker.d.ts.map +1 -1
  42. package/dist/cli-picker.js +24 -8
  43. package/dist/cli-picker.js.map +1 -1
  44. package/dist/cli.d.ts +2 -0
  45. package/dist/cli.d.ts.map +1 -1
  46. package/dist/cli.js +131 -38
  47. package/dist/cli.js.map +1 -1
  48. package/dist/context/batches.d.ts +29 -0
  49. package/dist/context/batches.d.ts.map +1 -0
  50. package/dist/context/batches.js +130 -0
  51. package/dist/context/batches.js.map +1 -0
  52. package/dist/context/build.d.ts +7 -2
  53. package/dist/context/build.d.ts.map +1 -1
  54. package/dist/context/build.js +84 -50
  55. package/dist/context/build.js.map +1 -1
  56. package/dist/context/node-file.d.ts.map +1 -1
  57. package/dist/context/node-file.js +41 -4
  58. package/dist/context/node-file.js.map +1 -1
  59. package/dist/engine.d.ts +2 -0
  60. package/dist/engine.d.ts.map +1 -1
  61. package/dist/engine.js +1 -0
  62. package/dist/engine.js.map +1 -1
  63. package/dist/graph/cards.d.ts.map +1 -1
  64. package/dist/graph/cards.js +9 -4
  65. package/dist/graph/cards.js.map +1 -1
  66. package/dist/graph/enrich.d.ts.map +1 -1
  67. package/dist/graph/enrich.js +8 -3
  68. package/dist/graph/enrich.js.map +1 -1
  69. package/dist/graph/generic.d.ts.map +1 -1
  70. package/dist/graph/generic.js +207 -6
  71. package/dist/graph/generic.js.map +1 -1
  72. package/dist/graph/lsp/client.d.ts +18 -0
  73. package/dist/graph/lsp/client.d.ts.map +1 -1
  74. package/dist/graph/lsp/client.js +40 -2
  75. package/dist/graph/lsp/client.js.map +1 -1
  76. package/dist/graph/lsp/enrich.d.ts.map +1 -1
  77. package/dist/graph/lsp/enrich.js +9 -1
  78. package/dist/graph/lsp/enrich.js.map +1 -1
  79. package/dist/graph/lsp/registry.d.ts +7 -0
  80. package/dist/graph/lsp/registry.d.ts.map +1 -1
  81. package/dist/graph/lsp/registry.js +27 -2
  82. package/dist/graph/lsp/registry.js.map +1 -1
  83. package/dist/graph/queries/gleam.scm +51 -0
  84. package/dist/graph/resolve.d.ts.map +1 -1
  85. package/dist/graph/resolve.js +65 -3
  86. package/dist/graph/resolve.js.map +1 -1
  87. package/dist/graph/workspace-cli.d.ts +2 -0
  88. package/dist/graph/workspace-cli.d.ts.map +1 -1
  89. package/dist/graph/workspace-cli.js +1 -1
  90. package/dist/graph/workspace-cli.js.map +1 -1
  91. package/dist/notes/branches.d.ts +7 -1
  92. package/dist/notes/branches.d.ts.map +1 -1
  93. package/dist/notes/branches.js +31 -3
  94. package/dist/notes/branches.js.map +1 -1
  95. package/dist/notes/cold-start.d.ts +12 -2
  96. package/dist/notes/cold-start.d.ts.map +1 -1
  97. package/dist/notes/cold-start.js +46 -5
  98. package/dist/notes/cold-start.js.map +1 -1
  99. package/dist/notes/credit.d.ts +37 -0
  100. package/dist/notes/credit.d.ts.map +1 -0
  101. package/dist/notes/credit.js +78 -0
  102. package/dist/notes/credit.js.map +1 -0
  103. package/dist/notes/find-notes.d.ts +17 -0
  104. package/dist/notes/find-notes.d.ts.map +1 -0
  105. package/dist/notes/find-notes.js +48 -0
  106. package/dist/notes/find-notes.js.map +1 -0
  107. package/dist/notes/flatten.d.ts +31 -0
  108. package/dist/notes/flatten.d.ts.map +1 -0
  109. package/dist/notes/flatten.js +73 -0
  110. package/dist/notes/flatten.js.map +1 -0
  111. package/dist/notes/git-facts.d.ts +2 -0
  112. package/dist/notes/git-facts.d.ts.map +1 -1
  113. package/dist/notes/git-facts.js +6 -0
  114. package/dist/notes/git-facts.js.map +1 -1
  115. package/dist/notes/home.d.ts +24 -6
  116. package/dist/notes/home.d.ts.map +1 -1
  117. package/dist/notes/home.js +82 -15
  118. package/dist/notes/home.js.map +1 -1
  119. package/dist/notes/learning-fields.d.ts +102 -0
  120. package/dist/notes/learning-fields.d.ts.map +1 -0
  121. package/dist/notes/learning-fields.js +214 -0
  122. package/dist/notes/learning-fields.js.map +1 -0
  123. package/dist/notes/memory-notes.d.ts +71 -0
  124. package/dist/notes/memory-notes.d.ts.map +1 -0
  125. package/dist/notes/memory-notes.js +239 -0
  126. package/dist/notes/memory-notes.js.map +1 -0
  127. package/dist/notes/note-gate.d.ts +42 -0
  128. package/dist/notes/note-gate.d.ts.map +1 -0
  129. package/dist/notes/note-gate.js +181 -0
  130. package/dist/notes/note-gate.js.map +1 -0
  131. package/dist/notes/notes.d.ts +29 -85
  132. package/dist/notes/notes.d.ts.map +1 -1
  133. package/dist/notes/notes.js +69 -254
  134. package/dist/notes/notes.js.map +1 -1
  135. package/dist/notes/pr-reviews.d.ts +35 -7
  136. package/dist/notes/pr-reviews.d.ts.map +1 -1
  137. package/dist/notes/pr-reviews.js +156 -46
  138. package/dist/notes/pr-reviews.js.map +1 -1
  139. package/dist/notes/secrets.d.ts +28 -0
  140. package/dist/notes/secrets.d.ts.map +1 -0
  141. package/dist/notes/secrets.js +362 -0
  142. package/dist/notes/secrets.js.map +1 -0
  143. package/dist/notes/targets.d.ts +37 -0
  144. package/dist/notes/targets.d.ts.map +1 -0
  145. package/dist/notes/targets.js +108 -0
  146. package/dist/notes/targets.js.map +1 -0
  147. package/dist/notes/team-check.d.ts +22 -0
  148. package/dist/notes/team-check.d.ts.map +1 -0
  149. package/dist/notes/team-check.js +130 -0
  150. package/dist/notes/team-check.js.map +1 -0
  151. package/dist/notes/trail-home.d.ts +3 -0
  152. package/dist/notes/trail-home.d.ts.map +1 -0
  153. package/dist/notes/trail-home.js +12 -0
  154. package/dist/notes/trail-home.js.map +1 -0
  155. package/dist/skills/answers-prompt.d.ts +13 -0
  156. package/dist/skills/answers-prompt.d.ts.map +1 -0
  157. package/dist/skills/answers-prompt.js +83 -0
  158. package/dist/skills/answers-prompt.js.map +1 -0
  159. package/dist/skills/never-save.d.ts +5 -0
  160. package/dist/skills/never-save.d.ts.map +1 -0
  161. package/dist/skills/never-save.js +158 -0
  162. package/dist/skills/never-save.js.map +1 -0
  163. package/dist/skills/params.d.ts +39 -0
  164. package/dist/skills/params.d.ts.map +1 -0
  165. package/dist/skills/params.js +275 -0
  166. package/dist/skills/params.js.map +1 -0
  167. package/dist/skills/ran-less.d.ts +5 -0
  168. package/dist/skills/ran-less.d.ts.map +1 -0
  169. package/dist/skills/ran-less.js +51 -0
  170. package/dist/skills/ran-less.js.map +1 -0
  171. package/dist/skills/risk-delta.d.ts +32 -0
  172. package/dist/skills/risk-delta.d.ts.map +1 -0
  173. package/dist/skills/risk-delta.js +56 -0
  174. package/dist/skills/risk-delta.js.map +1 -0
  175. package/dist/skills/risk.d.ts +73 -0
  176. package/dist/skills/risk.d.ts.map +1 -0
  177. package/dist/skills/risk.js +396 -0
  178. package/dist/skills/risk.js.map +1 -0
  179. package/dist/skills/types.d.ts +422 -0
  180. package/dist/skills/types.d.ts.map +1 -0
  181. package/dist/skills/types.js +2 -0
  182. package/dist/skills/types.js.map +1 -0
  183. package/dist/telemetry/contract.d.ts.map +1 -1
  184. package/dist/telemetry/contract.js +8 -6
  185. package/dist/telemetry/contract.js.map +1 -1
  186. package/dist/telemetry/notice.d.ts.map +1 -1
  187. package/dist/telemetry/notice.js +3 -1
  188. package/dist/telemetry/notice.js.map +1 -1
  189. package/dist/trace/check-reads.d.ts +36 -0
  190. package/dist/trace/check-reads.d.ts.map +1 -0
  191. package/dist/trace/check-reads.js +57 -0
  192. package/dist/trace/check-reads.js.map +1 -0
  193. package/dist/trace/host.d.ts +40 -0
  194. package/dist/trace/host.d.ts.map +1 -0
  195. package/dist/trace/host.js +84 -0
  196. package/dist/trace/host.js.map +1 -0
  197. package/dist/trace/redact.d.ts +8 -0
  198. package/dist/trace/redact.d.ts.map +1 -0
  199. package/dist/trace/redact.js +63 -0
  200. package/dist/trace/redact.js.map +1 -0
  201. package/dist/trace/seen-cache.d.ts +9 -0
  202. package/dist/trace/seen-cache.d.ts.map +1 -0
  203. package/dist/trace/seen-cache.js +46 -0
  204. package/dist/trace/seen-cache.js.map +1 -0
  205. package/dist/trace/shell-scan.d.ts +52 -0
  206. package/dist/trace/shell-scan.d.ts.map +1 -0
  207. package/dist/trace/shell-scan.js +318 -0
  208. package/dist/trace/shell-scan.js.map +1 -0
  209. package/dist/trace/shell-words.d.ts +91 -0
  210. package/dist/trace/shell-words.d.ts.map +1 -0
  211. package/dist/trace/shell-words.js +558 -0
  212. package/dist/trace/shell-words.js.map +1 -0
  213. package/dist/trace/shell.d.ts +91 -0
  214. package/dist/trace/shell.d.ts.map +1 -0
  215. package/dist/trace/shell.js +435 -0
  216. package/dist/trace/shell.js.map +1 -0
  217. package/dist/trace/state.d.ts +27 -0
  218. package/dist/trace/state.d.ts.map +1 -0
  219. package/dist/trace/state.js +98 -0
  220. package/dist/trace/state.js.map +1 -0
  221. package/dist/trace/tamper-code.d.ts +9 -0
  222. package/dist/trace/tamper-code.d.ts.map +1 -0
  223. package/dist/trace/tamper-code.js +174 -0
  224. package/dist/trace/tamper-code.js.map +1 -0
  225. package/dist/trace/tamper-git.d.ts +12 -0
  226. package/dist/trace/tamper-git.d.ts.map +1 -0
  227. package/dist/trace/tamper-git.js +77 -0
  228. package/dist/trace/tamper-git.js.map +1 -0
  229. package/dist/trace/types.d.ts +477 -0
  230. package/dist/trace/types.d.ts.map +1 -0
  231. package/dist/trace/types.js +12 -0
  232. package/dist/trace/types.js.map +1 -0
  233. package/dist/trace/walls-glob.d.ts +11 -0
  234. package/dist/trace/walls-glob.d.ts.map +1 -0
  235. package/dist/trace/walls-glob.js +264 -0
  236. package/dist/trace/walls-glob.js.map +1 -0
  237. package/dist/trace/walls-quoted.d.ts +25 -0
  238. package/dist/trace/walls-quoted.d.ts.map +1 -0
  239. package/dist/trace/walls-quoted.js +81 -0
  240. package/dist/trace/walls-quoted.js.map +1 -0
  241. package/dist/upkeep.d.ts +1 -1
  242. package/dist/upkeep.d.ts.map +1 -1
  243. package/dist/upkeep.js +4 -1
  244. package/dist/upkeep.js.map +1 -1
  245. package/dist/util/actions-folder.d.ts +2 -0
  246. package/dist/util/actions-folder.d.ts.map +1 -0
  247. package/dist/util/actions-folder.js +9 -0
  248. package/dist/util/actions-folder.js.map +1 -0
  249. package/dist/util/front-matter.d.ts +31 -4
  250. package/dist/util/front-matter.d.ts.map +1 -1
  251. package/dist/util/front-matter.js +95 -3
  252. package/dist/util/front-matter.js.map +1 -1
  253. package/dist/util/private-file.d.ts +14 -0
  254. package/dist/util/private-file.d.ts.map +1 -0
  255. package/dist/util/private-file.js +82 -0
  256. package/dist/util/private-file.js.map +1 -0
  257. package/dist/util/private-fs.d.ts +25 -0
  258. package/dist/util/private-fs.d.ts.map +1 -0
  259. package/dist/util/private-fs.js +253 -0
  260. package/dist/util/private-fs.js.map +1 -0
  261. package/dist/util/state.d.ts.map +1 -1
  262. package/dist/util/state.js +3 -0
  263. package/dist/util/state.js.map +1 -1
  264. package/dist/viewer/app.js +2 -2
  265. package/package.json +5 -5
  266. package/scripts/run-tests.mjs +14 -2
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Where Trail keeps what it knows about one live session on this machine:
3
+ * `~/.trail/sessions/<id>.json` (the transcript offset, the epoch, a pending
4
+ * offer). Only offsets, ids and counts go there, never what anyone typed.
5
+ * Folders are 0700 and files 0600: a session file says what someone was
6
+ * working on.
7
+ */
8
+ import { createHash } from "node:crypto";
9
+ import { chmodSync, closeSync, constants, fchmodSync, lstatSync, mkdirSync, openSync } from "node:fs";
10
+ import { dirname, join } from "node:path";
11
+ import { trailHome } from "../notes/trail-home.js";
12
+ import { writeJsonAtomic } from "../util/state.js";
13
+ const POSIX = process.platform !== "win32";
14
+ /** Opens a folder, and refuses a link (ELOOP) where the platform has O_NOFOLLOW. */
15
+ const DIR_NOFOLLOW = constants.O_RDONLY | (constants.O_DIRECTORY ?? 0) | (constants.O_NOFOLLOW ?? 0);
16
+ /**
17
+ * A folder only its owner can open, made if missing and tightened if it was
18
+ * looser. A link is left as it is: a chmod would follow it and tighten what
19
+ * it points to, which may be a folder that isn't Trail's (a person's dotfiles
20
+ * can link the Trail home; skills/own-folder.ts refuses links in place of
21
+ * Trail's own folders before anything is written). The mode is set through a
22
+ * descriptor that refuses a link, so one swapped in after the check isn't
23
+ * followed either.
24
+ */
25
+ export function ensurePrivateDir(dir) {
26
+ try {
27
+ if (lstatSync(dir).isSymbolicLink())
28
+ return;
29
+ }
30
+ catch {
31
+ /* missing: made below */
32
+ }
33
+ mkdirSync(dir, { recursive: true, mode: 0o700 });
34
+ if (!POSIX || constants.O_NOFOLLOW === undefined)
35
+ return;
36
+ try {
37
+ const fd = openSync(dir, DIR_NOFOLLOW);
38
+ try {
39
+ fchmodSync(fd, 0o700);
40
+ }
41
+ finally {
42
+ closeSync(fd);
43
+ }
44
+ }
45
+ catch (e) {
46
+ // A folder its owner can't read can't be opened, but can still be tightened.
47
+ if (e.code !== "EACCES")
48
+ return;
49
+ try {
50
+ if (!lstatSync(dir).isSymbolicLink())
51
+ chmodSync(dir, 0o700);
52
+ }
53
+ catch {
54
+ /* not ours to change */
55
+ }
56
+ }
57
+ }
58
+ /**
59
+ * JSON only its owner can read, written whole or not at all. Folders it has
60
+ * to make are made private; a folder that already exists is left as it is
61
+ * (a cursor kept beside a caller's own files must not lock them away).
62
+ */
63
+ export function writePrivateJson(path, value) {
64
+ mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
65
+ writeJsonAtomic(path, value, true, 0o600);
66
+ }
67
+ /**
68
+ * A session id as a file name. Hosts send UUIDs; anything else (a path, a
69
+ * dot, a very long string) is hashed, so a payload can never point the file
70
+ * outside the folder.
71
+ */
72
+ function fileId(sessionId) {
73
+ if (/^[A-Za-z0-9_-][A-Za-z0-9._-]{0,127}$/.test(sessionId))
74
+ return sessionId;
75
+ return `h-${createHash("sha256").update(String(sessionId)).digest("hex").slice(0, 16)}`;
76
+ }
77
+ /** `~/.trail/sessions/<id>.json`; the folder exists (0700) once this returns, when it can be made. */
78
+ export function sessionStatePath(sessionId) {
79
+ const dir = join(trailHome(), "sessions");
80
+ try {
81
+ ensurePrivateDir(dir);
82
+ }
83
+ catch {
84
+ /* read-only home: the caller's write fails and it fails open */
85
+ }
86
+ return join(dir, `${fileId(sessionId)}.json`);
87
+ }
88
+ /**
89
+ * `~/.trail/sessions/<id>.hooks.json`: where the turn-end hooks keep their
90
+ * own transcript cursor and what they carry between reads (the reply in
91
+ * progress, the responses already billed). Apart from `<id>.json`, whose
92
+ * cursor belongs to the skills catch-up, so neither reader moves the
93
+ * other's offset.
94
+ */
95
+ export function hookCursorPath(sessionId) {
96
+ return sessionStatePath(sessionId).replace(/\.json$/, ".hooks.json");
97
+ }
98
+ //# sourceMappingURL=state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.js","sourceRoot":"","sources":["../../src/trace/state.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ export declare const SHELLS: RegExp;
2
+ /** Program code that hands a guarded path to a call that writes it. `guardedLiteral`: a string literal names one. */
3
+ export declare function codeWrites(code: string, guardedLiteral: (literal: string) => boolean): boolean;
4
+ /**
5
+ * The code an interpreter or shell runs from its own words (`-c`, `-e`), else from its stdin: a here-string, its
6
+ * heredoc bodies, or what the pipeline's earlier stages hand it (`piped`, g5 review); null when it runs a file.
7
+ */
8
+ export declare function programCode(prog: string, w: string[], bodies: string[], piped?: string | null): string | null;
9
+ //# sourceMappingURL=tamper-code.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tamper-code.d.ts","sourceRoot":"","sources":["../../src/trace/tamper-code.ts"],"names":[],"mappings":"AAUA,eAAO,MAAM,MAAM,QAAqB,CAAC;AAuEzC,qHAAqH;AACrH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,GAAG,OAAO,CAgC9F;AAcD;;;GAGG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,KAAK,GAAE,MAAM,GAAG,IAAW,GAAG,MAAM,GAAG,IAAI,CAqBnH"}
@@ -0,0 +1,174 @@
1
+ /**
2
+ * The tamper check's reading of program code (design 4.1, split from
3
+ * `tamper.ts`): whether code an interpreter runs hands a protected path to a
4
+ * call that writes it, and where that code comes from (`-c`/`-e`, a heredoc,
5
+ * a here-string, or the pipeline feeding its stdin). A literal path is judged
6
+ * by the caller (`guardedLiteral`); a home folder joined with `.trail` or the
7
+ * host's transcripts folder is judged here.
8
+ */
9
+ import { unquote } from './shell-scan.js';
10
+ export const SHELLS = /^(?:ba|z|da)?sh$/;
11
+ const HOME_REF = /\b(?:homedir\(\)|Path\.home\(\)|expanduser\(|environ(?:\.get\(|\[)\s*['"]HOME|process\.env\.HOME\b|getenv\(\s*['"]HOME|ENV\[\s*['"]HOME|Dir\.home\b|ENV\{\s*['"]?HOME)/;
12
+ const TRAIL_PART = /['"`/]\.trail(?![\w.-])/;
13
+ /** The host's transcripts joined onto a home folder, outside a project's memory/ folder (Claude Code's own notes). */
14
+ const PROJECTS_PART = /['"`/]\.claude\/projects\b(?![^'"`\n]*\/memory\/)/;
15
+ const TRAIL_ENV = /\b(?:environ(?:\.get\(|\[)\s*['"]TRAIL_HOME|process\.env\.TRAIL_HOME\b|getenv\(\s*['"]TRAIL_HOME|ENV\[\s*['"]TRAIL_HOME)/;
16
+ const ASSIGNMENT = /^\s*(?:(?:const|let|var|my|local)\s+)?\$?([A-Za-z_]\w*)\s*(?::\s*[\w.[\]]+\s*)?=(?!=)\s*([^\n]+)$/;
17
+ /** Calls that build a path around what they are given: `Path(`, `os.path.expanduser(`, `path.join(`. */
18
+ const WRAPS = String.raw `^\s*(?:(?:[\w.]+\.)?(?:Path|PurePath|expanduser|expandvars|abspath|realpath|join|resolve|expand_path|normpath)\(\s*)*`;
19
+ const PATHY_LITERAL = new RegExp(`${WRAPS}[frbFRB]?(['"\`])((?:(?!\\1)[^\\\\\\n]|\\\\.)*)\\1`);
20
+ /** A path expression that starts from a variable: `os.path.join(base, 'x')`, `root / 'runs'`. */
21
+ const HELD_FROM = new RegExp(`${WRAPS}([A-Za-z_]\\w*)\\b`);
22
+ /** What may follow the path in a path expression: closing parens, joins, more parts; never a read or a parse. */
23
+ const PATH_REST = /^(?:[\s)/+,\w]|\.(?:resolve|expanduser|absolute)\(\)|'[^'\n]*'|"[^"\n]*")*$/;
24
+ /** Calls whose path argument(s) they write: `first` arg, both of the first `two` (copy, move), or a write `mode`. */
25
+ const ARG_CALLS = [
26
+ [/\b(?:open|fopen|openSync)\(/g, 'mode'],
27
+ [/\b(?:writeFile|appendFile|createWriteStream|outputFile|writeJson|truncate|rmSync|rmdir|unlink|mkdir|makedirs|removedirs|remove|rmtree|to_csv|to_json|to_parquet|to_excel)(?:Sync)?\(/g, 'first'],
28
+ [/\b(?:fs|fsp|promises)\.rm\(/g, 'first'],
29
+ [/\bFile\.(?:write|delete|unlink)\(/g, 'first'],
30
+ [/\b(?:rename|renameSync|copyFile|copyFileSync|cpSync|copy|copy2|copyfile|copytree|move|symlink|symlinkSync|link)\(/g, 'two'],
31
+ [/\b(?:fs|fsp|promises)\.cp\(|\bos\.replace\(|\bFileUtils\.\w+\(/g, 'two'],
32
+ ];
33
+ /** Methods that write their receiver: `Path(x).write_text(...)`. */
34
+ const RECEIVER_CALLS = /\.(?:write_text|write_bytes|unlink|touch|mkdir|rmdir|rename|open)\(/g;
35
+ const WRITE_MODE = /^\s*(?:mode\s*=\s*)?[rbuf]?['"][^'"]*[wax+]/;
36
+ /** The arguments of the call whose `(` is at `open`, split at top-level commas (at most 2000 characters read). */
37
+ function callArgs(code, open) {
38
+ const out = [];
39
+ let depth = 0;
40
+ let from = open + 1;
41
+ const end = Math.min(code.length, open + 2000);
42
+ for (let i = open + 1; i < end; i++) {
43
+ const c = code[i];
44
+ if (c === '"' || c === "'" || c === '`') {
45
+ for (i++; i < end && code[i] !== c; i++)
46
+ if (code[i] === '\\')
47
+ i++;
48
+ continue;
49
+ }
50
+ if (c === '(' || c === '[' || c === '{')
51
+ depth++;
52
+ else if (c === ')' || c === ']' || c === '}') {
53
+ if (depth === 0) {
54
+ out.push(code.slice(from, i));
55
+ return out;
56
+ }
57
+ depth--;
58
+ }
59
+ else if (c === ',' && depth === 0) {
60
+ out.push(code.slice(from, i));
61
+ from = i + 1;
62
+ }
63
+ }
64
+ out.push(code.slice(from, end));
65
+ return out;
66
+ }
67
+ /** The expression a method is called on: `Path(x)`, `(home / '.trail')`, `p`. */
68
+ function receiverBefore(code, dot) {
69
+ let j = dot - 1;
70
+ while (j >= 0) {
71
+ const c = code[j];
72
+ if (c === ')' || c === ']') {
73
+ let depth = 0;
74
+ for (; j >= 0; j--) {
75
+ if (code[j] === ')' || code[j] === ']')
76
+ depth++;
77
+ else if ((code[j] === '(' || code[j] === '[') && --depth === 0)
78
+ break;
79
+ }
80
+ j--;
81
+ }
82
+ else if (/[\w.$]/.test(c))
83
+ j--;
84
+ else
85
+ break;
86
+ }
87
+ return code.slice(j + 1, dot);
88
+ }
89
+ /** Program code that hands a guarded path to a call that writes it. `guardedLiteral`: a string literal names one. */
90
+ export function codeWrites(code, guardedLiteral) {
91
+ const pathy = (text) => {
92
+ const m = PATHY_LITERAL.exec(text);
93
+ const v = m?.[2];
94
+ if (v && PATH_REST.test(text.slice(m.index + m[0].length)) && guardedLiteral(v))
95
+ return true;
96
+ return (HOME_REF.test(text) && (TRAIL_PART.test(text) || PROJECTS_PART.test(text))) || TRAIL_ENV.test(text);
97
+ };
98
+ // Variables set to a guarded path, or a path built from one (assignments in order, twice for a late one).
99
+ const held = new Set();
100
+ const statements = code.split(/\n|;/);
101
+ for (let pass = 0; pass < 2; pass++) {
102
+ for (const s of statements) {
103
+ const m = ASSIGNMENT.exec(s);
104
+ if (!m || held.has(m[1]))
105
+ continue;
106
+ const value = m[2];
107
+ const from = HELD_FROM.exec(value);
108
+ if (pathy(value) || (from !== null && held.has(from[1]) && PATH_REST.test(value.slice(from[0].length))))
109
+ held.add(m[1]);
110
+ }
111
+ }
112
+ const mentionsHeld = (arg) => held.size > 0 && (arg.match(/[A-Za-z_]\w*/g) ?? []).some((id) => held.has(id));
113
+ const target = (arg) => arg !== undefined && (pathy(arg) || mentionsHeld(arg));
114
+ for (const [re, which] of ARG_CALLS) {
115
+ for (const m of code.matchAll(re)) {
116
+ const args = callArgs(code, m.index + m[0].length - 1);
117
+ if (which === 'mode' ? args.slice(1).some((a) => WRITE_MODE.test(a)) && target(args[0]) : target(args[0]) || (which === 'two' && target(args[1])))
118
+ return true;
119
+ }
120
+ }
121
+ for (const m of code.matchAll(RECEIVER_CALLS)) {
122
+ if (m[0] === '.open(' && !callArgs(code, m.index + m[0].length - 1).some((a) => WRITE_MODE.test(a)))
123
+ continue;
124
+ if (target(receiverBefore(code, m.index)))
125
+ return true;
126
+ }
127
+ return false;
128
+ }
129
+ /** Flags whose next word is the program, per interpreter family. */
130
+ function codeFlag(prog, a) {
131
+ if (SHELLS.test(prog))
132
+ return /^-[a-z]*c$/.test(a);
133
+ if (/^python/.test(prog))
134
+ return a === '-c';
135
+ if (prog === 'php')
136
+ return a === '-r';
137
+ if (prog === 'ruby' || prog === 'perl')
138
+ return a === '-e' || a === '-E';
139
+ return a === '-e' || a === '--eval' || a === '-p' || a === '--print';
140
+ }
141
+ /** A redirect whose target is the next word (`>`, `2>`, `<<`), not one written onto it (`>out.txt`). */
142
+ const BARE_REDIRECT = /^(?:\d+|&)?(?:>>?|>\||<<?|<>|&>>?)$/;
143
+ /**
144
+ * The code an interpreter or shell runs from its own words (`-c`, `-e`), else from its stdin: a here-string, its
145
+ * heredoc bodies, or what the pipeline's earlier stages hand it (`piped`, g5 review); null when it runs a file.
146
+ */
147
+ export function programCode(prog, w, bodies, piped = null) {
148
+ const parts = [];
149
+ let script = false;
150
+ let here = null;
151
+ for (let i = 1; i < w.length; i++) {
152
+ const a = w[i];
153
+ if (a.startsWith('<<<')) {
154
+ here = unquote(a.length > 3 ? a.slice(3) : (w[++i] ?? ''));
155
+ continue;
156
+ }
157
+ if (/^(?:\d*[<>]|&>)/.test(a)) {
158
+ if (BARE_REDIRECT.test(a))
159
+ i++;
160
+ continue;
161
+ }
162
+ if (codeFlag(prog, a) && w[i + 1] !== undefined)
163
+ parts.push(unquote(w[++i]));
164
+ else if (!a.startsWith('-'))
165
+ script = true;
166
+ }
167
+ if (parts.length)
168
+ return parts.join('\n');
169
+ if (script)
170
+ return null;
171
+ const stdin = [here, ...bodies, piped].filter((x) => !!x);
172
+ return stdin.length ? stdin.join('\n') : null;
173
+ }
174
+ //# sourceMappingURL=tamper-code.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tamper-code.js","sourceRoot":"","sources":["../../src/trace/tamper-code.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Which folders a git command writes, for the tamper check (D59e): `git -C ~/.trail commit`, `--git-dir`,
3
+ * a shell already sitting in Trail's home, a clone into it. Commands that only read (status, log, diff, the
4
+ * list forms of branch, tag, remote, config and stash) write nothing. Pure: words in, folders out.
5
+ */
6
+ /**
7
+ * The folders a git command changes (D59e): the folder its `-C` chain names (or the shell's), its `--git-dir`
8
+ * and `--work-tree`, and the folder a clone or init makes. Empty when the command only reads. `pathOf` turns a
9
+ * word into an absolute path from a folder (null when only the shell could know it).
10
+ */
11
+ export declare function gitWriteTargets(w: string[], folder: string | null, pathOf: (word: string, from: string | null) => string | null): Array<string | null>;
12
+ //# sourceMappingURL=tamper-git.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tamper-git.d.ts","sourceRoot":"","sources":["../../src/trace/tamper-git.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAkCH;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,EAAE,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,KAAK,MAAM,GAAG,IAAI,GAAG,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,CAwBtJ"}
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Which folders a git command writes, for the tamper check (D59e): `git -C ~/.trail commit`, `--git-dir`,
3
+ * a shell already sitting in Trail's home, a clone into it. Commands that only read (status, log, diff, the
4
+ * list forms of branch, tag, remote, config and stash) write nothing. Pure: words in, folders out.
5
+ */
6
+ /** git commands that only read the repository they run in (push and fetch leave its files as they are). */
7
+ const GIT_READS = new Set(['status', 'log', 'diff', 'show', 'rev-parse', 'ls-files', 'ls-tree', 'ls-remote', 'cat-file', 'describe', 'blame',
8
+ 'annotate', 'grep', 'shortlog', 'show-ref', 'for-each-ref', 'rev-list', 'merge-base', 'name-rev', 'whatchanged', 'version', 'help', 'var',
9
+ 'check-ignore', 'check-attr', 'count-objects', 'verify-commit', 'verify-tag', 'cherry', 'range-diff', 'diff-tree', 'diff-files', 'diff-index',
10
+ 'show-branch', 'fetch', 'push']);
11
+ /** git's own options that take the next word. */
12
+ const GIT_VALUE = new Set(['-C', '-c', '--git-dir', '--work-tree', '--namespace', '--exec-path', '--config-env', '--super-prefix']);
13
+ const BRANCH_WRITE = /^(?:-[a-zA-Z]*[dDmMcCfu]|--(?:delete|move|copy|force|set-upstream-to|unset-upstream|edit-description|track|no-track|create-reflog))(?:=|$)/;
14
+ const BRANCH_LIST = /^(?:-l|--list|--contains|--no-contains|--merged|--no-merged|--points-at|--sort|--format)(?:=|$)/;
15
+ const CONFIG_READ = /^(?:-l|--(?:get|get-all|get-regexp|get-urlmatch|list|get-color|get-colorbool))$/;
16
+ const CONFIG_WRITE = /^(?:-e|--(?:unset|unset-all|add|replace-all|remove-section|rename-section|edit))$/;
17
+ /** Whether `git <sub> <args>` changes the repository it runs in; the list forms of branch, tag, remote, config and stash read. */
18
+ function gitSubWrites(sub, args) {
19
+ if (GIT_READS.has(sub))
20
+ return false;
21
+ const pos = args.filter((a) => !a.startsWith('-'));
22
+ const first = args[0] ?? '';
23
+ switch (sub) {
24
+ case 'branch': return args.some((a) => BRANCH_WRITE.test(a)) || (pos.length > 0 && !args.some((a) => BRANCH_LIST.test(a)));
25
+ case 'tag': return !(args.length === 0 || args.includes('-l') || args.includes('--list')) || args.some((a) => /^(?:-[a-zA-Z]*d|--delete)$/.test(a));
26
+ case 'remote': return !(args.length === 0 || ['-v', '--verbose', 'show', 'get-url'].includes(first));
27
+ case 'config':
28
+ if (args.includes('--global') || args.includes('--system'))
29
+ return false; // not this repository's files
30
+ return args.some((a) => CONFIG_WRITE.test(a)) || (!args.some((a) => CONFIG_READ.test(a)) && pos.length >= 2);
31
+ case 'stash': return !['list', 'show'].includes(first);
32
+ case 'worktree': return first !== 'list';
33
+ case 'reflog':
34
+ case 'notes':
35
+ case 'submodule': return !(args.length === 0 || first.startsWith('-') || ['show', 'list', 'status', 'summary'].includes(first));
36
+ case 'archive': return args.some((a) => a === '-o' || a.startsWith('--output'));
37
+ default: return true;
38
+ }
39
+ }
40
+ /**
41
+ * The folders a git command changes (D59e): the folder its `-C` chain names (or the shell's), its `--git-dir`
42
+ * and `--work-tree`, and the folder a clone or init makes. Empty when the command only reads. `pathOf` turns a
43
+ * word into an absolute path from a folder (null when only the shell could know it).
44
+ */
45
+ export function gitWriteTargets(w, folder, pathOf) {
46
+ let dir = folder;
47
+ const dirs = [];
48
+ let i = 1;
49
+ for (; i < w.length; i++) {
50
+ const a = w[i];
51
+ if (!a.startsWith('-'))
52
+ break;
53
+ const eq = a.startsWith('--') ? a.indexOf('=') : -1;
54
+ const name = eq > 0 ? a.slice(0, eq) : a;
55
+ const value = eq > 0 ? a.slice(eq + 1) : GIT_VALUE.has(a) ? w[++i] : undefined;
56
+ if (value === undefined)
57
+ continue;
58
+ if (name === '-C')
59
+ dir = pathOf(value, dir);
60
+ else if (name === '--git-dir' || name === '--work-tree')
61
+ dirs.push(pathOf(value, dir));
62
+ }
63
+ const sub = w[i];
64
+ if (sub === undefined)
65
+ return [];
66
+ const args = w.slice(i + 1);
67
+ if (!gitSubWrites(sub, args))
68
+ return [];
69
+ dirs.push(dir);
70
+ if (sub === 'clone' || sub === 'init') {
71
+ const target = args.filter((a) => !a.startsWith('-'))[sub === 'clone' ? 1 : 0];
72
+ if (target !== undefined)
73
+ dirs.push(pathOf(target, dir));
74
+ }
75
+ return dirs;
76
+ }
77
+ //# sourceMappingURL=tamper-git.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tamper-git.js","sourceRoot":"","sources":["../../src/trace/tamper-git.ts"],"names":[],"mappings":"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"}