@nanonets/graft 0.23.0 → 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 (287) 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.d.ts +21 -0
  18. package/dist/claude/format.d.ts.map +1 -1
  19. package/dist/claude/format.js +46 -1
  20. package/dist/claude/format.js.map +1 -1
  21. package/dist/claude/hooks.d.ts +5 -9
  22. package/dist/claude/hooks.d.ts.map +1 -1
  23. package/dist/claude/hooks.js +71 -58
  24. package/dist/claude/hooks.js.map +1 -1
  25. package/dist/claude/init.js +3 -3
  26. package/dist/claude/init.js.map +1 -1
  27. package/dist/claude/note-signals.d.ts +28 -0
  28. package/dist/claude/note-signals.d.ts.map +1 -0
  29. package/dist/claude/note-signals.js +325 -0
  30. package/dist/claude/note-signals.js.map +1 -0
  31. package/dist/claude/shim-template.d.ts.map +1 -1
  32. package/dist/claude/shim-template.js +17 -6
  33. package/dist/claude/shim-template.js.map +1 -1
  34. package/dist/claude/skill-template.d.ts.map +1 -1
  35. package/dist/claude/skill-template.js +49 -18
  36. package/dist/claude/skill-template.js.map +1 -1
  37. package/dist/claude/state.d.ts +4 -3
  38. package/dist/claude/state.d.ts.map +1 -1
  39. package/dist/claude/state.js.map +1 -1
  40. package/dist/claude/sync-run.js +1 -1
  41. package/dist/claude/sync-run.js.map +1 -1
  42. package/dist/cli-picker.d.ts +12 -5
  43. package/dist/cli-picker.d.ts.map +1 -1
  44. package/dist/cli-picker.js +24 -8
  45. package/dist/cli-picker.js.map +1 -1
  46. package/dist/cli.d.ts +2 -0
  47. package/dist/cli.d.ts.map +1 -1
  48. package/dist/cli.js +149 -43
  49. package/dist/cli.js.map +1 -1
  50. package/dist/context/batches.d.ts +29 -0
  51. package/dist/context/batches.d.ts.map +1 -0
  52. package/dist/context/batches.js +130 -0
  53. package/dist/context/batches.js.map +1 -0
  54. package/dist/context/build.d.ts +7 -2
  55. package/dist/context/build.d.ts.map +1 -1
  56. package/dist/context/build.js +84 -50
  57. package/dist/context/build.js.map +1 -1
  58. package/dist/context/node-file.d.ts.map +1 -1
  59. package/dist/context/node-file.js +41 -4
  60. package/dist/context/node-file.js.map +1 -1
  61. package/dist/engine.d.ts +2 -0
  62. package/dist/engine.d.ts.map +1 -1
  63. package/dist/engine.js +1 -0
  64. package/dist/engine.js.map +1 -1
  65. package/dist/graph/cards.d.ts.map +1 -1
  66. package/dist/graph/cards.js +9 -4
  67. package/dist/graph/cards.js.map +1 -1
  68. package/dist/graph/enrich.d.ts.map +1 -1
  69. package/dist/graph/enrich.js +8 -3
  70. package/dist/graph/enrich.js.map +1 -1
  71. package/dist/graph/generic.d.ts.map +1 -1
  72. package/dist/graph/generic.js +207 -6
  73. package/dist/graph/generic.js.map +1 -1
  74. package/dist/graph/lsp/client.d.ts +18 -0
  75. package/dist/graph/lsp/client.d.ts.map +1 -1
  76. package/dist/graph/lsp/client.js +40 -2
  77. package/dist/graph/lsp/client.js.map +1 -1
  78. package/dist/graph/lsp/enrich.d.ts.map +1 -1
  79. package/dist/graph/lsp/enrich.js +9 -1
  80. package/dist/graph/lsp/enrich.js.map +1 -1
  81. package/dist/graph/lsp/registry.d.ts +7 -0
  82. package/dist/graph/lsp/registry.d.ts.map +1 -1
  83. package/dist/graph/lsp/registry.js +27 -2
  84. package/dist/graph/lsp/registry.js.map +1 -1
  85. package/dist/graph/queries/gleam.scm +51 -0
  86. package/dist/graph/resolve.d.ts.map +1 -1
  87. package/dist/graph/resolve.js +65 -3
  88. package/dist/graph/resolve.js.map +1 -1
  89. package/dist/graph/workspace-cli.d.ts +2 -0
  90. package/dist/graph/workspace-cli.d.ts.map +1 -1
  91. package/dist/graph/workspace-cli.js +1 -1
  92. package/dist/graph/workspace-cli.js.map +1 -1
  93. package/dist/init-guard.d.ts +11 -0
  94. package/dist/init-guard.d.ts.map +1 -0
  95. package/dist/init-guard.js +21 -0
  96. package/dist/init-guard.js.map +1 -0
  97. package/dist/mcp/tools.d.ts.map +1 -1
  98. package/dist/mcp/tools.js +2 -1
  99. package/dist/mcp/tools.js.map +1 -1
  100. package/dist/notes/branches.d.ts +7 -1
  101. package/dist/notes/branches.d.ts.map +1 -1
  102. package/dist/notes/branches.js +31 -3
  103. package/dist/notes/branches.js.map +1 -1
  104. package/dist/notes/cold-start.d.ts +12 -2
  105. package/dist/notes/cold-start.d.ts.map +1 -1
  106. package/dist/notes/cold-start.js +46 -5
  107. package/dist/notes/cold-start.js.map +1 -1
  108. package/dist/notes/credit.d.ts +37 -0
  109. package/dist/notes/credit.d.ts.map +1 -0
  110. package/dist/notes/credit.js +78 -0
  111. package/dist/notes/credit.js.map +1 -0
  112. package/dist/notes/find-notes.d.ts +17 -0
  113. package/dist/notes/find-notes.d.ts.map +1 -0
  114. package/dist/notes/find-notes.js +48 -0
  115. package/dist/notes/find-notes.js.map +1 -0
  116. package/dist/notes/flatten.d.ts +31 -0
  117. package/dist/notes/flatten.d.ts.map +1 -0
  118. package/dist/notes/flatten.js +73 -0
  119. package/dist/notes/flatten.js.map +1 -0
  120. package/dist/notes/git-facts.d.ts +7 -1
  121. package/dist/notes/git-facts.d.ts.map +1 -1
  122. package/dist/notes/git-facts.js +12 -2
  123. package/dist/notes/git-facts.js.map +1 -1
  124. package/dist/notes/home.d.ts +24 -6
  125. package/dist/notes/home.d.ts.map +1 -1
  126. package/dist/notes/home.js +82 -15
  127. package/dist/notes/home.js.map +1 -1
  128. package/dist/notes/learning-fields.d.ts +102 -0
  129. package/dist/notes/learning-fields.d.ts.map +1 -0
  130. package/dist/notes/learning-fields.js +214 -0
  131. package/dist/notes/learning-fields.js.map +1 -0
  132. package/dist/notes/memory-notes.d.ts +71 -0
  133. package/dist/notes/memory-notes.d.ts.map +1 -0
  134. package/dist/notes/memory-notes.js +239 -0
  135. package/dist/notes/memory-notes.js.map +1 -0
  136. package/dist/notes/note-gate.d.ts +42 -0
  137. package/dist/notes/note-gate.d.ts.map +1 -0
  138. package/dist/notes/note-gate.js +181 -0
  139. package/dist/notes/note-gate.js.map +1 -0
  140. package/dist/notes/notes.d.ts +29 -77
  141. package/dist/notes/notes.d.ts.map +1 -1
  142. package/dist/notes/notes.js +69 -228
  143. package/dist/notes/notes.js.map +1 -1
  144. package/dist/notes/pr-reviews.d.ts +35 -7
  145. package/dist/notes/pr-reviews.d.ts.map +1 -1
  146. package/dist/notes/pr-reviews.js +156 -46
  147. package/dist/notes/pr-reviews.js.map +1 -1
  148. package/dist/notes/secrets.d.ts +28 -0
  149. package/dist/notes/secrets.d.ts.map +1 -0
  150. package/dist/notes/secrets.js +362 -0
  151. package/dist/notes/secrets.js.map +1 -0
  152. package/dist/notes/session-cost.d.ts +2 -0
  153. package/dist/notes/session-cost.d.ts.map +1 -1
  154. package/dist/notes/session-cost.js +8 -3
  155. package/dist/notes/session-cost.js.map +1 -1
  156. package/dist/notes/targets.d.ts +37 -0
  157. package/dist/notes/targets.d.ts.map +1 -0
  158. package/dist/notes/targets.js +108 -0
  159. package/dist/notes/targets.js.map +1 -0
  160. package/dist/notes/team-check.d.ts +22 -0
  161. package/dist/notes/team-check.d.ts.map +1 -0
  162. package/dist/notes/team-check.js +130 -0
  163. package/dist/notes/team-check.js.map +1 -0
  164. package/dist/notes/trail-home.d.ts +3 -0
  165. package/dist/notes/trail-home.d.ts.map +1 -0
  166. package/dist/notes/trail-home.js +12 -0
  167. package/dist/notes/trail-home.js.map +1 -0
  168. package/dist/search/grep-cli.d.ts +5 -2
  169. package/dist/search/grep-cli.d.ts.map +1 -1
  170. package/dist/search/grep-cli.js +11 -4
  171. package/dist/search/grep-cli.js.map +1 -1
  172. package/dist/search/ignored-code.d.ts +9 -0
  173. package/dist/search/ignored-code.d.ts.map +1 -0
  174. package/dist/search/ignored-code.js +73 -0
  175. package/dist/search/ignored-code.js.map +1 -0
  176. package/dist/skills/answers-prompt.d.ts +13 -0
  177. package/dist/skills/answers-prompt.d.ts.map +1 -0
  178. package/dist/skills/answers-prompt.js +83 -0
  179. package/dist/skills/answers-prompt.js.map +1 -0
  180. package/dist/skills/never-save.d.ts +5 -0
  181. package/dist/skills/never-save.d.ts.map +1 -0
  182. package/dist/skills/never-save.js +158 -0
  183. package/dist/skills/never-save.js.map +1 -0
  184. package/dist/skills/params.d.ts +39 -0
  185. package/dist/skills/params.d.ts.map +1 -0
  186. package/dist/skills/params.js +275 -0
  187. package/dist/skills/params.js.map +1 -0
  188. package/dist/skills/ran-less.d.ts +5 -0
  189. package/dist/skills/ran-less.d.ts.map +1 -0
  190. package/dist/skills/ran-less.js +51 -0
  191. package/dist/skills/ran-less.js.map +1 -0
  192. package/dist/skills/risk-delta.d.ts +32 -0
  193. package/dist/skills/risk-delta.d.ts.map +1 -0
  194. package/dist/skills/risk-delta.js +56 -0
  195. package/dist/skills/risk-delta.js.map +1 -0
  196. package/dist/skills/risk.d.ts +73 -0
  197. package/dist/skills/risk.d.ts.map +1 -0
  198. package/dist/skills/risk.js +396 -0
  199. package/dist/skills/risk.js.map +1 -0
  200. package/dist/skills/types.d.ts +422 -0
  201. package/dist/skills/types.d.ts.map +1 -0
  202. package/dist/skills/types.js +2 -0
  203. package/dist/skills/types.js.map +1 -0
  204. package/dist/telemetry/contract.d.ts.map +1 -1
  205. package/dist/telemetry/contract.js +8 -6
  206. package/dist/telemetry/contract.js.map +1 -1
  207. package/dist/telemetry/notice.d.ts.map +1 -1
  208. package/dist/telemetry/notice.js +3 -1
  209. package/dist/telemetry/notice.js.map +1 -1
  210. package/dist/trace/check-reads.d.ts +36 -0
  211. package/dist/trace/check-reads.d.ts.map +1 -0
  212. package/dist/trace/check-reads.js +57 -0
  213. package/dist/trace/check-reads.js.map +1 -0
  214. package/dist/trace/host.d.ts +40 -0
  215. package/dist/trace/host.d.ts.map +1 -0
  216. package/dist/trace/host.js +84 -0
  217. package/dist/trace/host.js.map +1 -0
  218. package/dist/trace/redact.d.ts +8 -0
  219. package/dist/trace/redact.d.ts.map +1 -0
  220. package/dist/trace/redact.js +63 -0
  221. package/dist/trace/redact.js.map +1 -0
  222. package/dist/trace/seen-cache.d.ts +9 -0
  223. package/dist/trace/seen-cache.d.ts.map +1 -0
  224. package/dist/trace/seen-cache.js +46 -0
  225. package/dist/trace/seen-cache.js.map +1 -0
  226. package/dist/trace/shell-scan.d.ts +52 -0
  227. package/dist/trace/shell-scan.d.ts.map +1 -0
  228. package/dist/trace/shell-scan.js +318 -0
  229. package/dist/trace/shell-scan.js.map +1 -0
  230. package/dist/trace/shell-words.d.ts +91 -0
  231. package/dist/trace/shell-words.d.ts.map +1 -0
  232. package/dist/trace/shell-words.js +558 -0
  233. package/dist/trace/shell-words.js.map +1 -0
  234. package/dist/trace/shell.d.ts +91 -0
  235. package/dist/trace/shell.d.ts.map +1 -0
  236. package/dist/trace/shell.js +435 -0
  237. package/dist/trace/shell.js.map +1 -0
  238. package/dist/trace/state.d.ts +27 -0
  239. package/dist/trace/state.d.ts.map +1 -0
  240. package/dist/trace/state.js +98 -0
  241. package/dist/trace/state.js.map +1 -0
  242. package/dist/trace/tamper-code.d.ts +9 -0
  243. package/dist/trace/tamper-code.d.ts.map +1 -0
  244. package/dist/trace/tamper-code.js +174 -0
  245. package/dist/trace/tamper-code.js.map +1 -0
  246. package/dist/trace/tamper-git.d.ts +12 -0
  247. package/dist/trace/tamper-git.d.ts.map +1 -0
  248. package/dist/trace/tamper-git.js +77 -0
  249. package/dist/trace/tamper-git.js.map +1 -0
  250. package/dist/trace/types.d.ts +477 -0
  251. package/dist/trace/types.d.ts.map +1 -0
  252. package/dist/trace/types.js +12 -0
  253. package/dist/trace/types.js.map +1 -0
  254. package/dist/trace/walls-glob.d.ts +11 -0
  255. package/dist/trace/walls-glob.d.ts.map +1 -0
  256. package/dist/trace/walls-glob.js +264 -0
  257. package/dist/trace/walls-glob.js.map +1 -0
  258. package/dist/trace/walls-quoted.d.ts +25 -0
  259. package/dist/trace/walls-quoted.d.ts.map +1 -0
  260. package/dist/trace/walls-quoted.js +81 -0
  261. package/dist/trace/walls-quoted.js.map +1 -0
  262. package/dist/upkeep.d.ts +1 -1
  263. package/dist/upkeep.d.ts.map +1 -1
  264. package/dist/upkeep.js +4 -1
  265. package/dist/upkeep.js.map +1 -1
  266. package/dist/util/actions-folder.d.ts +2 -0
  267. package/dist/util/actions-folder.d.ts.map +1 -0
  268. package/dist/util/actions-folder.js +9 -0
  269. package/dist/util/actions-folder.js.map +1 -0
  270. package/dist/util/front-matter.d.ts +31 -4
  271. package/dist/util/front-matter.d.ts.map +1 -1
  272. package/dist/util/front-matter.js +95 -3
  273. package/dist/util/front-matter.js.map +1 -1
  274. package/dist/util/private-file.d.ts +14 -0
  275. package/dist/util/private-file.d.ts.map +1 -0
  276. package/dist/util/private-file.js +82 -0
  277. package/dist/util/private-file.js.map +1 -0
  278. package/dist/util/private-fs.d.ts +25 -0
  279. package/dist/util/private-fs.d.ts.map +1 -0
  280. package/dist/util/private-fs.js +253 -0
  281. package/dist/util/private-fs.js.map +1 -0
  282. package/dist/util/state.d.ts.map +1 -1
  283. package/dist/util/state.js +3 -0
  284. package/dist/util/state.js.map +1 -1
  285. package/dist/viewer/app.js +2 -2
  286. package/package.json +5 -5
  287. package/scripts/run-tests.mjs +14 -2
@@ -0,0 +1,22 @@
1
+ /**
2
+ * The code `text` is about, as `touches:` entries: files it names that exist
3
+ * in the checkout, `paths` that exist (an inline review comment's file), and
4
+ * `file#Symbol` for a backticked name the graph knows in one to three places.
5
+ * Empty when it names no code that exists now.
6
+ */
7
+ export declare function codeAnchors(repo: string, text: string, paths?: string[]): string[];
8
+ /** The words that carry meaning: four letters or more, not filler. */
9
+ export declare function contentWords(s: string): Set<string>;
10
+ /** What the repo already tells Claude: CLAUDE.md, AGENTS.md, and the learnings here, team and personal. */
11
+ export interface KnownText {
12
+ chunks: Set<string>[];
13
+ titles: Set<string>[];
14
+ }
15
+ export declare function knownText(repo: string): KnownText;
16
+ /**
17
+ * Whether the repo already says what a candidate says: most of its title's
18
+ * and lead's words in one paragraph of CLAUDE.md, AGENTS.md or a learning, or
19
+ * a learning with nearly the same title.
20
+ */
21
+ export declare function alreadySaid(known: KnownText, title: string, body: string): boolean;
22
+ //# sourceMappingURL=team-check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"team-check.d.ts","sourceRoot":"","sources":["../../src/notes/team-check.ts"],"names":[],"mappings":"AAwBA;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,GAAE,MAAM,EAAO,GAAG,MAAM,EAAE,CA8BtF;AAMD,sEAAsE;AACtE,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAOnD;AAkBD,2GAA2G;AAC3G,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;IACtB,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;CACvB;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAYjD;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAOlF"}
@@ -0,0 +1,130 @@
1
+ /**
2
+ * Whether something `trail init` found is fit to offer as a team learning:
3
+ * it is tied to code that exists now, and the repo doesn't already say it.
4
+ *
5
+ * A learning a teammate's Claude acts on names the file or function it is
6
+ * about; that is also what lets trail hand it to Claude when Claude opens
7
+ * that file. One that names no code is a habit or a status line, and stays
8
+ * the person's own. One that CLAUDE.md, AGENTS.md or an existing learning
9
+ * already says adds nothing but noise.
10
+ */
11
+ import { existsSync, readFileSync } from "node:fs";
12
+ import { join } from "node:path";
13
+ import { contextDirFor } from "../context/node-file.js";
14
+ import { loadGraphCached } from "../graph/load.js";
15
+ import { listNotes, mentionedFiles } from "./notes.js";
16
+ const TOUCH_LIMIT = 10;
17
+ /** `foo_test.go`, `foo.test.ts`, `test/…`, `__tests__/…`, `spec/…`. */
18
+ const TEST_PATH = /(?:^|\/)(?:tests?|__tests__|spec)\/|[._-](?:test|spec)\.[A-Za-z]+$|_test\.go$/;
19
+ /** `Foo`, `Foo.bar`, `foo_bar()` in backticks: names a note can give a symbol by. */
20
+ const TICKED = /`([A-Za-z_$][\w$]*(?:(?:\.|::|#)[A-Za-z_$][\w$]*)*)(?:\(\))?`/g;
21
+ /**
22
+ * The code `text` is about, as `touches:` entries: files it names that exist
23
+ * in the checkout, `paths` that exist (an inline review comment's file), and
24
+ * `file#Symbol` for a backticked name the graph knows in one to three places.
25
+ * Empty when it names no code that exists now.
26
+ */
27
+ export function codeAnchors(repo, text, paths = []) {
28
+ const out = [];
29
+ const add = (t) => {
30
+ if (out.length < TOUCH_LIMIT && !out.includes(t))
31
+ out.push(t);
32
+ };
33
+ for (const f of mentionedFiles(repo, text))
34
+ add(f);
35
+ for (const p of paths)
36
+ if (p && !p.startsWith("..") && existsSync(join(repo, p)))
37
+ add(p);
38
+ const graph = loadGraphCached(contextDirFor(repo));
39
+ if (!graph)
40
+ return out;
41
+ const names = new Set();
42
+ for (const m of text.matchAll(TICKED)) {
43
+ const last = m[1].split(/\.|::|#/).pop();
44
+ // Short or generic words (`id`, `run`) match too much to mean anything.
45
+ if (last.length >= 4)
46
+ names.add(last);
47
+ }
48
+ if (!names.size)
49
+ return out;
50
+ const byName = new Map();
51
+ for (const n of graph.nodes) {
52
+ if (n.kind === "file" || !names.has(n.name))
53
+ continue;
54
+ const list = byName.get(n.name) ?? [];
55
+ list.push(n.id);
56
+ byName.set(n.name, list);
57
+ }
58
+ for (const ids of byName.values()) {
59
+ // A test's fake of a function isn't what the note is about, when the real one is there.
60
+ const real = ids.filter((id) => !TEST_PATH.test(id.split("#")[0]));
61
+ const pick = real.length ? real : ids;
62
+ if (pick.length <= 3)
63
+ for (const id of pick)
64
+ add(id);
65
+ }
66
+ return out;
67
+ }
68
+ const STOP = new Set("the and for with from that this what when where which into does have has had been being they them their there then than also only just more most some such very will would should could must about after before over under using used make makes made keep keeps kept your yours ours here every each other".split(" "));
69
+ /** The words that carry meaning: four letters or more, not filler. */
70
+ export function contentWords(s) {
71
+ return new Set(s
72
+ .toLowerCase()
73
+ .split(/[^a-z0-9_]+/)
74
+ .filter((w) => w.length >= 4 && !STOP.has(w)));
75
+ }
76
+ /** Paragraphs and list items of a markdown text, each as its content words. */
77
+ function chunks(text) {
78
+ return text
79
+ .split(/\n\s*\n|\n(?=\s*(?:[-*+]|\d+\.)\s)/)
80
+ .map(contentWords)
81
+ .filter((w) => w.size >= 3);
82
+ }
83
+ function readText(path) {
84
+ try {
85
+ return readFileSync(path, "utf8");
86
+ }
87
+ catch {
88
+ return "";
89
+ }
90
+ }
91
+ export function knownText(repo) {
92
+ const docs = ["CLAUDE.md", "AGENTS.md", ".claude/CLAUDE.md"].map((f) => readText(join(repo, f)));
93
+ let notes = [];
94
+ try {
95
+ notes = listNotes(repo, { branches: false });
96
+ }
97
+ catch {
98
+ /* no learnings yet */
99
+ }
100
+ return {
101
+ chunks: [...docs.flatMap(chunks), ...notes.flatMap((n) => chunks(n.body))],
102
+ titles: notes.map((n) => contentWords(n.title)).filter((w) => w.size > 0),
103
+ };
104
+ }
105
+ /**
106
+ * Whether the repo already says what a candidate says: most of its title's
107
+ * and lead's words in one paragraph of CLAUDE.md, AGENTS.md or a learning, or
108
+ * a learning with nearly the same title.
109
+ */
110
+ export function alreadySaid(known, title, body) {
111
+ const t = contentWords(title);
112
+ if (t.size && known.titles.some((k) => overlap(t, k) >= 0.8 && overlap(k, t) >= 0.8))
113
+ return true;
114
+ const lead = body.replace(/^#+ .*$/gm, "").trim().slice(0, 400);
115
+ const words = contentWords(`${title} ${lead}`);
116
+ if (words.size < 5)
117
+ return false;
118
+ return known.chunks.some((c) => overlap(words, c) >= 0.6);
119
+ }
120
+ /** The share of `a`'s words that are in `b`. */
121
+ function overlap(a, b) {
122
+ if (!a.size)
123
+ return 0;
124
+ let n = 0;
125
+ for (const w of a)
126
+ if (b.has(w))
127
+ n++;
128
+ return n / a.size;
129
+ }
130
+ //# sourceMappingURL=team-check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"team-check.js","sourceRoot":"","sources":["../../src/notes/team-check.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ /** `~/.trail`, or `$TRAIL_HOME`. */
2
+ export declare function trailHome(env?: NodeJS.ProcessEnv, home?: string): string;
3
+ //# sourceMappingURL=trail-home.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trail-home.d.ts","sourceRoot":"","sources":["../../src/notes/trail-home.ts"],"names":[],"mappings":"AAQA,oCAAoC;AACpC,wBAAgB,SAAS,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,EAAE,IAAI,GAAE,MAAkB,GAAG,MAAM,CAEhG"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * `~/.trail` on its own, so a hook's fast path (the trace layer, `trail keep`'s
3
+ * check before a shell command) can find it without loading notes/home.ts and
4
+ * the front-matter parser that file needs to count learnings.
5
+ */
6
+ import { homedir } from "node:os";
7
+ import { join, resolve } from "node:path";
8
+ /** `~/.trail`, or `$TRAIL_HOME`. */
9
+ export function trailHome(env = process.env, home = homedir()) {
10
+ return env.TRAIL_HOME ? resolve(env.TRAIL_HOME) : join(home, ".trail");
11
+ }
12
+ //# sourceMappingURL=trail-home.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trail-home.js","sourceRoot":"","sources":["../../src/notes/trail-home.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE1C,oCAAoC;AACpC,MAAM,UAAU,SAAS,CAAC,MAAyB,OAAO,CAAC,GAAG,EAAE,OAAe,OAAO,EAAE;IACtF,OAAO,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AACzE,CAAC"}
@@ -19,8 +19,11 @@ export declare function formatGrepResult(result: GrepResult): string;
19
19
  * Truncation is never silent, even on the zero-hit path: if some indexed
20
20
  * files couldn't be read (`truncated.files > 0`), that's called out too —
21
21
  * otherwise a zero-hit result on a stale graph or wrong root reads as "no
22
- * matches" when really some files were never searched at all. */
23
- export declare function zeroHitNote(result: GrepResult): string;
22
+ * matches" when really some files were never searched at all.
23
+ *
24
+ * `ignored`: git-ignored code under the root (see `ignoredCode`). When there
25
+ * is some, the note names it instead of saying all the code was searched. */
26
+ export declare function zeroHitNote(result: GrepResult, ignored?: string[]): string;
24
27
  /**
25
28
  * Resolve the graph at `dir` (respecting `--dir`), run `grepGraph`, and print
26
29
  * either the human report or `--json`. Exits the process (code 1) when
@@ -1 +1 @@
1
- {"version":3,"file":"grep-cli.d.ts","sourceRoot":"","sources":["../../src/search/grep-cli.ts"],"names":[],"mappings":"AAaA,OAAO,EAA6B,KAAK,UAAU,EAAE,MAAM,WAAW,CAAC;AAGvE,MAAM,WAAW,cAAc;IAC7B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,oFAAoF;IACpF,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAaD,oFAAoF;AACpF,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAG3D;AAYD;gEACgE;AAChE,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAS3D;AAED;;;;;;;iEAOiE;AACjE,wBAAgB,WAAW,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAKtD;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,GAAG,IAAI,CAgCvF"}
1
+ {"version":3,"file":"grep-cli.d.ts","sourceRoot":"","sources":["../../src/search/grep-cli.ts"],"names":[],"mappings":"AAaA,OAAO,EAA6B,KAAK,UAAU,EAAE,MAAM,WAAW,CAAC;AAIvE,MAAM,WAAW,cAAc;IAC7B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,oFAAoF;IACpF,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAaD,oFAAoF;AACpF,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAG3D;AAYD;gEACgE;AAChE,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAS3D;AAED;;;;;;;;;;6EAU6E;AAC7E,wBAAgB,WAAW,CAAC,MAAM,EAAE,UAAU,EAAE,OAAO,GAAE,MAAM,EAAO,GAAG,MAAM,CAQ9E;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,GAAG,IAAI,CAgCvF"}
@@ -13,6 +13,7 @@ import { withSavings } from "../context/savings.js";
13
13
  import { loadGraphCached } from "../graph/load.js";
14
14
  import { grepGraph } from "./grep.js";
15
15
  import { cmd } from "../brand.js";
16
+ import { ignoredCode, ignoredLabel } from "./ignored-code.js";
16
17
  function groupHeader(g) {
17
18
  if (g.symbol)
18
19
  return `${g.symbol.name} · ${g.symbol.kind} · ${g.symbol.path}:${g.symbol.span} · ${g.inDegree} in-edges`;
@@ -60,9 +61,15 @@ export function formatGrepResult(result) {
60
61
  * Truncation is never silent, even on the zero-hit path: if some indexed
61
62
  * files couldn't be read (`truncated.files > 0`), that's called out too —
62
63
  * otherwise a zero-hit result on a stale graph or wrong root reads as "no
63
- * matches" when really some files were never searched at all. */
64
- export function zeroHitNote(result) {
65
- const base = `no hits for "${result.pattern}" in ${result.filesSearched} indexed files. The pattern may be too specific — retry ${cmd("graft grep")} with a bare symbol name or short substring (drop the receiver, full signature, and regex anchors). All indexed code was searched; use raw grep -rn only for genuinely unindexed files (docs, configs, brand-new files)`;
64
+ * matches" when really some files were never searched at all.
65
+ *
66
+ * `ignored`: git-ignored code under the root (see `ignoredCode`). When there
67
+ * is some, the note names it instead of saying all the code was searched. */
68
+ export function zeroHitNote(result, ignored = []) {
69
+ const retry = `no hits for "${result.pattern}" in ${result.filesSearched} indexed files. The pattern may be too specific — retry ${cmd("graft grep")} with a bare symbol name or short substring (drop the receiver, full signature, and regex anchors).`;
70
+ const base = ignored.length
71
+ ? `${retry} Git-ignored code isn't indexed and wasn't searched: ${ignoredLabel(ignored)}. Run grep -rn there, and on docs and configs`
72
+ : `${retry} All indexed code was searched; use raw grep -rn only for genuinely unindexed files (docs, configs, brand-new files)`;
66
73
  const { files } = result.truncated;
67
74
  if (files === 0)
68
75
  return base;
@@ -100,7 +107,7 @@ export function runGrepCommand(pattern, dir, opts) {
100
107
  return;
101
108
  }
102
109
  if (result.totalHits === 0) {
103
- console.error(zeroHitNote(result));
110
+ console.error(zeroHitNote(result, ignoredCode(root)));
104
111
  return;
105
112
  }
106
113
  process.stdout.write(formatGrepResult(result));
@@ -1 +1 @@
1
- {"version":3,"file":"grep-cli.js","sourceRoot":"","sources":["../../src/search/grep-cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"grep-cli.js","sourceRoot":"","sources":["../../src/search/grep-cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Git-ignored folders and files under `root` holding code the map would
3
+ * otherwise index, repo-relative, folders ending in `/`. Dependency, build and
4
+ * dot folders are left out. Empty outside git, or when git can't say.
5
+ */
6
+ export declare function ignoredCode(root: string, limit?: number): string[];
7
+ /** `a/, b/ and 3 more`. */
8
+ export declare function ignoredLabel(paths: string[], shown?: number): string;
9
+ //# sourceMappingURL=ignored-code.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ignored-code.d.ts","sourceRoot":"","sources":["../../src/search/ignored-code.ts"],"names":[],"mappings":"AAqCA;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,SAAK,GAAG,MAAM,EAAE,CAiB9D;AAED,2BAA2B;AAC3B,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,KAAK,SAAI,GAAG,MAAM,CAG/D"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Code the map leaves out because git ignores it, named when a search comes up
3
+ * empty. A migration repo kept the old app's code in git-ignored dumps (they
4
+ * held credentials); `trail grep` found nothing, said all indexed code was
5
+ * searched, and the agent's own grep then found the file. After that the agent
6
+ * stopped trusting trail for the session.
7
+ */
8
+ import { spawnSync } from "node:child_process";
9
+ import { readdirSync } from "node:fs";
10
+ import { extname, join } from "node:path";
11
+ import { supportedExtensions } from "../graph/source-files.js";
12
+ import { shouldSkipDir } from "../ingest/fs.js";
13
+ /** Most entries one ignored folder's walk looks at before giving up on it. */
14
+ const WALK_CAP = 2000;
15
+ function holdsCode(dir, exts) {
16
+ const stack = [dir];
17
+ let seen = 0;
18
+ while (stack.length && seen < WALK_CAP) {
19
+ const at = stack.pop();
20
+ let entries;
21
+ try {
22
+ entries = readdirSync(at, { withFileTypes: true });
23
+ }
24
+ catch {
25
+ continue;
26
+ }
27
+ for (const e of entries) {
28
+ if (++seen > WALK_CAP)
29
+ break;
30
+ if (e.isDirectory()) {
31
+ if (!shouldSkipDir(e.name))
32
+ stack.push(join(at, e.name));
33
+ }
34
+ else if (exts.has(extname(e.name).toLowerCase()))
35
+ return true;
36
+ }
37
+ }
38
+ return false;
39
+ }
40
+ /**
41
+ * Git-ignored folders and files under `root` holding code the map would
42
+ * otherwise index, repo-relative, folders ending in `/`. Dependency, build and
43
+ * dot folders are left out. Empty outside git, or when git can't say.
44
+ */
45
+ export function ignoredCode(root, limit = 20) {
46
+ const r = spawnSync("git", ["ls-files", "--others", "--ignored", "--exclude-standard", "--directory", "--no-empty-directory"], {
47
+ cwd: root,
48
+ encoding: "utf8",
49
+ timeout: 3000,
50
+ });
51
+ if (r.status !== 0 || typeof r.stdout !== "string")
52
+ return [];
53
+ const exts = new Set(supportedExtensions());
54
+ const out = [];
55
+ for (const entry of r.stdout.split("\n")) {
56
+ if (!entry)
57
+ continue;
58
+ if (entry.replace(/\/$/, "").split("/").some((p) => shouldSkipDir(p)))
59
+ continue;
60
+ const code = entry.endsWith("/") ? holdsCode(join(root, entry), exts) : exts.has(extname(entry).toLowerCase());
61
+ if (code)
62
+ out.push(entry);
63
+ if (out.length >= limit)
64
+ break;
65
+ }
66
+ return out;
67
+ }
68
+ /** `a/, b/ and 3 more`. */
69
+ export function ignoredLabel(paths, shown = 3) {
70
+ const head = paths.slice(0, shown).join(", ");
71
+ return paths.length > shown ? `${head} and ${paths.length - shown} more` : head;
72
+ }
73
+ //# sourceMappingURL=ignored-code.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ignored-code.js","sourceRoot":"","sources":["../../src/search/ignored-code.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /** The command, a whole Bash call, answers a login or confirmation prompt for the person. */
2
+ export declare function answersPrompt(cmd: string): boolean;
3
+ /**
4
+ * D116 item 5: the whole call only feeds keystrokes into a login (`(sleep 15; printf '\n'; sleep 300) | script -q
5
+ * /dev/null npm login`, `yes | npx vercel login`, `npm login <<< ...`): the login and its service, else null. Such a
6
+ * step is dropped from a skill and the login becomes a "Before you start" line for the person; what was fed is never
7
+ * kept. A feed into a publish, `expect`, or a login inside a longer call is not one (still `answersPrompt`).
8
+ */
9
+ export declare function loginFeed(cmd: string): {
10
+ service: string;
11
+ login: string;
12
+ } | null;
13
+ //# sourceMappingURL=answers-prompt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"answers-prompt.d.ts","sourceRoot":"","sources":["../../src/skills/answers-prompt.ts"],"names":[],"mappings":"AAwBA,6FAA6F;AAC7F,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAElD;AAgCD;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAWhF"}
@@ -0,0 +1,83 @@
1
+ /**
2
+ * A step that answers a login or confirmation prompt for the person (D101
3
+ * item 4): keystrokes piped or fed into `script`, `expect` or a login or
4
+ * publish (`(sleep 15; printf '\n'; sleep 300) | script -q /dev/null npm
5
+ * login`, `yes | npm publish`, `printf 'y\n' | npm login`, `npm login <<<
6
+ * ...`), or `expect` run at all. Such a step is never kept: the prompt it
7
+ * answers is the person's, and an agent rightly reads a kept one as a way
8
+ * round their confirmation.
9
+ *
10
+ * Linear: one top-level split per level, groups `( … )` and `{ …; }` read
11
+ * at most 3 levels deep, and patterns with no nested repetition.
12
+ */
13
+ import { bareCommand, splitTop } from '../trace/shell.js';
14
+ import { gatedKind, loginOf } from './risk.js';
15
+ const MAX_DEPTH = 3;
16
+ /** A program that writes keystrokes: `printf`, `echo` or `yes` at a command's start. */
17
+ const FEEDER = /(?:^|[;&|({]\s*)(?:printf|echo|yes)(?![\w.-])/;
18
+ /** Programs that drive another program's terminal prompt. */
19
+ const PROMPT_DRIVER = /^(?:script|expect|unbuffer)(?![\w.-])/;
20
+ const EXPECT = /^expect(?![\w.-])/;
21
+ const HERE_STRING = /<<</;
22
+ const STDIN_FLAG = /\s--(?:password-stdin|with-token|stdin)(?![\w-])/;
23
+ /** The command, a whole Bash call, answers a login or confirmation prompt for the person. */
24
+ export function answersPrompt(cmd) {
25
+ return within(String(cmd ?? ''), 0);
26
+ }
27
+ function within(text, depth) {
28
+ const segs = splitTop(text);
29
+ for (let i = 0; i < segs.length; i++) {
30
+ const seg = segs[i];
31
+ const t = seg.text.trim();
32
+ if (EXPECT.test(bareCommand(t)))
33
+ return true;
34
+ if (depth < MAX_DEPTH && (t.startsWith('(') || t.startsWith('{'))) {
35
+ const inner = t.replace(/^[({]/, '').replace(/[)}]$/, '');
36
+ if (within(inner, depth + 1))
37
+ return true;
38
+ }
39
+ if (HERE_STRING.test(t) && promptTarget(t))
40
+ return true;
41
+ const next = segs[i + 1];
42
+ if (seg.sep === '|' && next && FEEDER.test(t) && promptTarget(next.text))
43
+ return true;
44
+ }
45
+ return false;
46
+ }
47
+ /** What a fed keystroke would answer: a prompt driver, or a login or publish (through its wrappers, risk.ts). */
48
+ function promptTarget(text) {
49
+ const t = text.trim();
50
+ if (PROMPT_DRIVER.test(bareCommand(t)))
51
+ return true;
52
+ // A flag made to read stdin (`docker login --password-stdin`, `gh auth login --with-token`) is input, not a prompt.
53
+ if (STDIN_FLAG.test(t))
54
+ return false;
55
+ const kind = gatedKind(t);
56
+ return kind === 'login' || kind === 'publish';
57
+ }
58
+ /** A group or a command that only waits and types: `(sleep 15; printf '\n'; sleep 300)`, `printf 'y\n'`, `yes`. */
59
+ const KEYSTROKES = /^(?:[({]\s*)?(?:(?:sleep\s+[\d.]+|printf\s+(?:'[^']*'|"[^"]*"|[^\s;&|()'"])+|echo(?:\s+(?:'[^']*'|"[^"]*"|[^\s;&|()'"])+)*|yes)\s*(?:;\s*|$|(?=[)}])))+(?:[)}]\s*)?$/;
60
+ /**
61
+ * D116 item 5: the whole call only feeds keystrokes into a login (`(sleep 15; printf '\n'; sleep 300) | script -q
62
+ * /dev/null npm login`, `yes | npx vercel login`, `npm login <<< ...`): the login and its service, else null. Such a
63
+ * step is dropped from a skill and the login becomes a "Before you start" line for the person; what was fed is never
64
+ * kept. A feed into a publish, `expect`, or a login inside a longer call is not one (still `answersPrompt`).
65
+ */
66
+ export function loginFeed(cmd) {
67
+ const text = String(cmd ?? '').trim();
68
+ if (!answersPrompt(text))
69
+ return null;
70
+ const segs = splitTop(text);
71
+ let target;
72
+ if (segs.length === 1 && HERE_STRING.test(text))
73
+ target = text.slice(0, text.search(HERE_STRING));
74
+ else if (segs.length === 2 && segs[0].sep === '|' && segs[0].text.length <= 4096 && KEYSTROKES.test(segs[0].text.trim()))
75
+ target = segs[1].text;
76
+ else
77
+ return null;
78
+ const bare = bareCommand(target.trim());
79
+ if (EXPECT.test(bare) || gatedKind(bare) !== 'login')
80
+ return null;
81
+ return loginOf(bare);
82
+ }
83
+ //# sourceMappingURL=answers-prompt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"answers-prompt.js","sourceRoot":"","sources":["../../src/skills/answers-prompt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE/C,MAAM,SAAS,GAAG,CAAC,CAAC;AACpB,wFAAwF;AACxF,MAAM,MAAM,GAAG,+CAA+C,CAAC;AAC/D,6DAA6D;AAC7D,MAAM,aAAa,GAAG,uCAAuC,CAAC;AAC9D,MAAM,MAAM,GAAG,mBAAmB,CAAC;AACnC,MAAM,WAAW,GAAG,KAAK,CAAC;AAC1B,MAAM,UAAU,GAAG,kDAAkD,CAAC;AAEtE,6FAA6F;AAC7F,MAAM,UAAU,aAAa,CAAC,GAAW;IACvC,OAAO,MAAM,CAAC,MAAM,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;AACtC,CAAC;AAED,SAAS,MAAM,CAAC,IAAY,EAAE,KAAa;IACzC,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC5B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAE,CAAC;QACrB,MAAM,CAAC,GAAG,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QAC1B,IAAI,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;YAAE,OAAO,IAAI,CAAC;QAC7C,IAAI,KAAK,GAAG,SAAS,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;YAClE,MAAM,KAAK,GAAG,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;YAC1D,IAAI,MAAM,CAAC,KAAK,EAAE,KAAK,GAAG,CAAC,CAAC;gBAAE,OAAO,IAAI,CAAC;QAC5C,CAAC;QACD,IAAI,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,YAAY,CAAC,CAAC,CAAC;YAAE,OAAO,IAAI,CAAC;QACxD,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QACzB,IAAI,GAAG,CAAC,GAAG,KAAK,GAAG,IAAI,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;IACxF,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,iHAAiH;AACjH,SAAS,YAAY,CAAC,IAAY;IAChC,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IACtB,IAAI,aAAa,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACpD,oHAAoH;IACpH,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IACrC,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;IAC1B,OAAO,IAAI,KAAK,OAAO,IAAI,IAAI,KAAK,SAAS,CAAC;AAChD,CAAC;AAED,mHAAmH;AACnH,MAAM,UAAU,GAAG,sKAAsK,CAAC;AAE1L;;;;;GAKG;AACH,MAAM,UAAU,SAAS,CAAC,GAAW;IACnC,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACtC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACtC,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC5B,IAAI,MAAc,CAAC;IACnB,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC;SAC7F,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,CAAC,CAAE,CAAC,GAAG,KAAK,GAAG,IAAI,IAAI,CAAC,CAAC,CAAE,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QAAE,MAAM,GAAG,IAAI,CAAC,CAAC,CAAE,CAAC,IAAI,CAAC;;QAC/I,OAAO,IAAI,CAAC;IACjB,MAAM,IAAI,GAAG,WAAW,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;IACxC,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,SAAS,CAAC,IAAI,CAAC,KAAK,OAAO;QAAE,OAAO,IAAI,CAAC;IAClE,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC;AACvB,CAAC"}
@@ -0,0 +1,5 @@
1
+ /** Reason a command can never be in a skill (4.11), or null. */
2
+ export declare function neverSave(cmd: string): string | null;
3
+ /** 4.10 backstop: a password written out after a flag that takes one. The fold names most secrets; these it can't tell from a word. */
4
+ export declare function literalPassword(cmd: string): boolean;
5
+ //# sourceMappingURL=never-save.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"never-save.d.ts","sourceRoot":"","sources":["../../src/skills/never-save.ts"],"names":[],"mappings":"AA2HA,gEAAgE;AAChE,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAWpD;AAaD,uIAAuI;AACvI,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAGpD"}