@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,78 @@
1
+ /** `~9.6k tokens`, `~600 tokens`. */
2
+ export function tokensLabel(n) {
3
+ if (n >= 1000)
4
+ return `~${(n / 1000).toFixed(n >= 10_000 ? 0 : 1).replace(/\.0$/, "")}k tokens`;
5
+ return `~${n} tokens`;
6
+ }
7
+ /** `Anay`, `Anay and Rushil`, `Anay, Rushil and 3 others`. */
8
+ export function namesLabel(names) {
9
+ if (names.length <= 2)
10
+ return names.join(" and ");
11
+ if (names.length === 3)
12
+ return `${names[0]}, ${names[1]} and ${names[2]}`;
13
+ return `${names[0]}, ${names[1]} and ${names.length - 2} others`;
14
+ }
15
+ /** `48k`, `3.8k`, `600`. */
16
+ function tokensShort(n) {
17
+ return tokensLabel(n).replace(/^~/, "").replace(" tokens", "");
18
+ }
19
+ /** What starting from a teammate's learning is worth when its tokens are too few to say: time to a PR. */
20
+ export const PR_SPEEDUP = "3x faster";
21
+ /**
22
+ * Below this many tokens, what a learning saves is too small a number to
23
+ * impress, so trail credits it as a faster PR instead.
24
+ */
25
+ export const TOKEN_CREDIT_FLOOR = 80_000;
26
+ /** Whether a token count is big enough to be the credit. */
27
+ export function tokensWorthSaying(tokens) {
28
+ return (tokens ?? 0) >= TOKEN_CREDIT_FLOOR;
29
+ }
30
+ /**
31
+ * The lines that close a reply after a team learning is saved, one for each
32
+ * way the turn can end, since only the agent knows whether it committed the
33
+ * learning by then. Uncommitted, it makes the case for committing: who else
34
+ * works on the same files, and the head start their agents would get, which
35
+ * is what the learning took to work out, or a faster PR when that's small.
36
+ */
37
+ export function commitLines(note, teammates, where = "files") {
38
+ const tokens = note.cost?.tokens;
39
+ const short = tokensWorthSaying(tokens) ? tokensShort(tokens) : null;
40
+ // "an 80k-token", "an 11k-token": said aloud, they start with a vowel.
41
+ const start = short ? `${/^8|^1[18]k$/.test(short) ? "an" : "a"} ${short}-token head start` : null;
42
+ const place = where === "files" ? "this part of the codebase" : "this repo";
43
+ if (!teammates.length) {
44
+ return start
45
+ ? {
46
+ committed: `📝 Committed · your teammates' agents now get ${start}`,
47
+ uncommitted: `🌱 Commit what you learned and give your teammates' agents ${start}`,
48
+ }
49
+ : {
50
+ committed: `📝 Committed · your teammates' agents now get to a PR ${PR_SPEEDUP}`,
51
+ uncommitted: `🌱 Commit what you learned and your teammates' agents get to a PR ${PR_SPEEDUP}`,
52
+ };
53
+ }
54
+ const who = namesLabel(teammates);
55
+ const work = teammates.length === 1 ? "works" : "work";
56
+ return start
57
+ ? {
58
+ committed: `📝 Committed · ${who} ${work} in ${place}, and their agents now get ${start}`,
59
+ uncommitted: `🌱 ${who} ${work} in ${place}. Commit what you learned and give their agents ${start}`,
60
+ }
61
+ : {
62
+ committed: `📝 Committed · ${who} ${work} in ${place}, and their agents now get to a PR ${PR_SPEEDUP}`,
63
+ uncommitted: `🌱 ${who} ${work} in ${place}. Commit what you learned and their agents get to a PR ${PR_SPEEDUP}`,
64
+ };
65
+ }
66
+ /**
67
+ * The line asking for trail's shared setup to be committed, once: `.trail/`
68
+ * and the SessionStart entry in `.claude/settings.json` are what let a
69
+ * teammate's Claude read the learnings before they install anything.
70
+ */
71
+ export function setupCommitLine(teammates) {
72
+ const ask = "Commit .trail/ and .claude/settings.json once";
73
+ if (!teammates.length)
74
+ return `🌱 ${ask}, and your teammates' Claude starts from your learnings, even before they install trail`;
75
+ const work = teammates.length === 1 ? "works" : "work";
76
+ return `🌱 ${namesLabel(teammates)} ${work} in this repo. ${ask}, and their Claude starts from your learnings, even before they install trail`;
77
+ }
78
+ //# sourceMappingURL=credit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credit.js","sourceRoot":"","sources":["../../src/notes/credit.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import type { Note } from "./notes.js";
2
+ export interface NoteHit {
3
+ note: Note;
4
+ score: number;
5
+ /** Files the note touches that this query's results also point into. */
6
+ shared: string[];
7
+ }
8
+ /**
9
+ * The notes worth showing next to a query's results: ones whose title or body
10
+ * share the query's words, or that touch a file the results point into. At
11
+ * most `limit`, best first. A note has to clear a bar — two of the query's
12
+ * words, or one in its title, or a shared file — so an unrelated note never
13
+ * rides along just because it exists. Only live learnings: never one that was
14
+ * retired, is held for a yes, or that a newer learning replaces.
15
+ */
16
+ export declare function findNotes(notes: Note[], query: string, files?: string[], limit?: number): NoteHit[];
17
+ //# sourceMappingURL=find-notes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"find-notes.d.ts","sourceRoot":"","sources":["../../src/notes/find-notes.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAiBvC,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,IAAI,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,wEAAwE;IACxE,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,GAAE,MAAM,EAAO,EAAE,KAAK,SAAI,GAAG,OAAO,EAAE,CAwBlG"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Which learnings to show next to a query's results.
3
+ */
4
+ import { liveLearnings } from "./learning-fields.js";
5
+ const STOP = new Set("the and for with from that this what when where which into does how why are was were not but you your our out its it's can should would could about after before over under use using used fix find make".split(" "));
6
+ function terms(s) {
7
+ return [...new Set(s.toLowerCase().split(/[^a-z0-9_]+/).filter((t) => t.length >= 3 && !STOP.has(t)))];
8
+ }
9
+ /** The file part of a `file#Symbol` touch. */
10
+ function touchFile(t) {
11
+ return t.split("#")[0];
12
+ }
13
+ /**
14
+ * The notes worth showing next to a query's results: ones whose title or body
15
+ * share the query's words, or that touch a file the results point into. At
16
+ * most `limit`, best first. A note has to clear a bar — two of the query's
17
+ * words, or one in its title, or a shared file — so an unrelated note never
18
+ * rides along just because it exists. Only live learnings: never one that was
19
+ * retired, is held for a yes, or that a newer learning replaces.
20
+ */
21
+ export function findNotes(notes, query, files = [], limit = 2) {
22
+ const q = terms(query);
23
+ const hitFiles = new Set(files);
24
+ const out = [];
25
+ for (const note of liveLearnings(notes)) {
26
+ const title = new Set(terms(note.title));
27
+ const text = new Set(terms(`${note.body} ${note.touches.join(" ")}`));
28
+ let score = 0;
29
+ let matched = 0;
30
+ for (const t of q) {
31
+ if (title.has(t)) {
32
+ score += 3;
33
+ matched++;
34
+ }
35
+ else if (text.has(t)) {
36
+ score += 1;
37
+ matched++;
38
+ }
39
+ }
40
+ const shared = [...new Set(note.touches.map(touchFile))].filter((f) => hitFiles.has(f));
41
+ score += shared.length * 4;
42
+ const clears = shared.length > 0 || matched >= 2 || [...title].some((t) => q.includes(t));
43
+ if (clears && score >= 3)
44
+ out.push({ note, score, shared });
45
+ }
46
+ return out.sort((a, b) => b.score - a.score || b.note.date.localeCompare(a.note.date)).slice(0, limit);
47
+ }
48
+ //# sourceMappingURL=find-notes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"find-notes.js","sourceRoot":"","sources":["../../src/notes/find-notes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * One line of text, for anything a learning carries into what an agent or a
3
+ * person reads.
4
+ *
5
+ * A learning's title, author and section leads come from whoever wrote the
6
+ * file, a teammate's unmerged branch included. A newline in a title used to
7
+ * print as a line of its own, and a line that starts `[trail] ...` reads
8
+ * exactly like trail's own instructions. So every such field goes through
9
+ * `flatLine` on its way out: breaks collapse to spaces, a `[trail]`-style
10
+ * marker at the start or after a collapsed break is dropped, invisible and
11
+ * control characters go (they can hide a marker or rewrite a terminal), and
12
+ * the line is capped.
13
+ *
14
+ * The hooks shim committed into repos runs as plain Node and can't import
15
+ * this, so `FLAT_LINE_JS` is the same function as source text, and a test
16
+ * holds the two to the same output.
17
+ */
18
+ /**
19
+ * `text` as one line of at most `max` characters, ending in "…" when cut.
20
+ * Anything but a string, a number or a boolean reads as "".
21
+ */
22
+ export declare function flatLine(text: unknown, max?: number): string;
23
+ /**
24
+ * The words of `text` as one line, none of them starting with a marker: for
25
+ * text wrapped onto several lines, where any word can start one. A marker in
26
+ * the middle of a word stays, since no line can start there.
27
+ */
28
+ export declare function unmarkedWords(text: unknown): string[];
29
+ /** `flatLine` as plain JS source, for the generated hooks shim. Keep the two in step. */
30
+ export declare const FLAT_LINE_JS = "function flatLine(text, max) {\n if (max === undefined) max = 160;\n const raw = typeof text === 'string' ? text : typeof text === 'number' || typeof text === 'boolean' ? String(text) : '';\n const line = raw\n .replace(/[\\p{Cf}\\ufe00-\\ufe0f\\u{e0100}-\\u{e01ef}]/gu, '')\n .replace(/[\\u0000-\\u0008\\u000e-\\u001f\\u007f-\\u0084\\u0086-\\u009f]/g, '')\n .split(/\\r\\n|[\\n\\r\\u000b\\u000c\\u0085\\u2028\\u2029]/)\n .map((part) => part.replace(/^\\s*(?:\\[(?:trail|graft|trail-code)\\]\\s*)+/i, ''))\n .join(' ')\n .replace(/\\s+/g, ' ')\n .trim();\n const chars = Array.from(line);\n return chars.length > max ? chars.slice(0, Math.max(0, max - 1)).join('').trimEnd() + '\\u2026' : line;\n}";
31
+ //# sourceMappingURL=flatten.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flatten.d.ts","sourceRoot":"","sources":["../../src/notes/flatten.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAeH;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,SAAM,GAAG,MAAM,CAYzD;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,EAAE,CAKrD;AAED,yFAAyF;AACzF,eAAO,MAAM,YAAY,wtBAavB,CAAC"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * One line of text, for anything a learning carries into what an agent or a
3
+ * person reads.
4
+ *
5
+ * A learning's title, author and section leads come from whoever wrote the
6
+ * file, a teammate's unmerged branch included. A newline in a title used to
7
+ * print as a line of its own, and a line that starts `[trail] ...` reads
8
+ * exactly like trail's own instructions. So every such field goes through
9
+ * `flatLine` on its way out: breaks collapse to spaces, a `[trail]`-style
10
+ * marker at the start or after a collapsed break is dropped, invisible and
11
+ * control characters go (they can hide a marker or rewrite a terminal), and
12
+ * the line is capped.
13
+ *
14
+ * The hooks shim committed into repos runs as plain Node and can't import
15
+ * this, so `FLAT_LINE_JS` is the same function as source text, and a test
16
+ * holds the two to the same output.
17
+ */
18
+ /**
19
+ * Characters nobody sees: every Unicode format character (zero-width ones,
20
+ * direction marks and overrides, the soft hyphen, tag characters that can
21
+ * spell out text only an agent reads) and the variation selectors.
22
+ */
23
+ const INVISIBLE = /[\p{Cf}\ufe00-\ufe0f\u{e0100}-\u{e01ef}]/gu;
24
+ /** Control characters other than tab and the line breaks below (ESC, BEL, DEL, C1 but NEL). */
25
+ const CONTROL = /[\u0000-\u0008\u000e-\u001f\u007f-\u0084\u0086-\u009f]/g;
26
+ /** Every line break JavaScript, YAML or a terminal might honour. */
27
+ const BREAK = /\r\n|[\n\r\u000b\u000c\u0085\u2028\u2029]/;
28
+ /** `[trail]`, `[graft]`, `[trail-code]`, any case, once or more, at the start. */
29
+ const MARKER = /^\s*(?:\[(?:trail|graft|trail-code)\]\s*)+/i;
30
+ /**
31
+ * `text` as one line of at most `max` characters, ending in "…" when cut.
32
+ * Anything but a string, a number or a boolean reads as "".
33
+ */
34
+ export function flatLine(text, max = 160) {
35
+ const raw = typeof text === "string" ? text : typeof text === "number" || typeof text === "boolean" ? String(text) : "";
36
+ const line = raw
37
+ .replace(INVISIBLE, "")
38
+ .replace(CONTROL, "")
39
+ .split(BREAK)
40
+ .map((part) => part.replace(MARKER, ""))
41
+ .join(" ")
42
+ .replace(/\s+/g, " ")
43
+ .trim();
44
+ const chars = Array.from(line);
45
+ return chars.length > max ? `${chars.slice(0, Math.max(0, max - 1)).join("").trimEnd()}…` : line;
46
+ }
47
+ /**
48
+ * The words of `text` as one line, none of them starting with a marker: for
49
+ * text wrapped onto several lines, where any word can start one. A marker in
50
+ * the middle of a word stays, since no line can start there.
51
+ */
52
+ export function unmarkedWords(text) {
53
+ return flatLine(text, Number.POSITIVE_INFINITY)
54
+ .split(" ")
55
+ .map((word) => word.replace(MARKER, ""))
56
+ .filter(Boolean);
57
+ }
58
+ /** `flatLine` as plain JS source, for the generated hooks shim. Keep the two in step. */
59
+ export const FLAT_LINE_JS = `function flatLine(text, max) {
60
+ if (max === undefined) max = 160;
61
+ const raw = typeof text === 'string' ? text : typeof text === 'number' || typeof text === 'boolean' ? String(text) : '';
62
+ const line = raw
63
+ .replace(/[\\p{Cf}\\ufe00-\\ufe0f\\u{e0100}-\\u{e01ef}]/gu, '')
64
+ .replace(/[\\u0000-\\u0008\\u000e-\\u001f\\u007f-\\u0084\\u0086-\\u009f]/g, '')
65
+ .split(/\\r\\n|[\\n\\r\\u000b\\u000c\\u0085\\u2028\\u2029]/)
66
+ .map((part) => part.replace(/^\\s*(?:\\[(?:trail|graft|trail-code)\\]\\s*)+/i, ''))
67
+ .join(' ')
68
+ .replace(/\\s+/g, ' ')
69
+ .trim();
70
+ const chars = Array.from(line);
71
+ return chars.length > max ? chars.slice(0, Math.max(0, max - 1)).join('').trimEnd() + '\\u2026' : line;
72
+ }`;
73
+ //# sourceMappingURL=flatten.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flatten.js","sourceRoot":"","sources":["../../src/notes/flatten.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH;;;;GAIG;AACH,MAAM,SAAS,GAAG,4CAA4C,CAAC;AAC/D,+FAA+F;AAC/F,MAAM,OAAO,GAAG,yDAAyD,CAAC;AAC1E,oEAAoE;AACpE,MAAM,KAAK,GAAG,2CAA2C,CAAC;AAC1D,kFAAkF;AAClF,MAAM,MAAM,GAAG,6CAA6C,CAAC;AAE7D;;;GAGG;AACH,MAAM,UAAU,QAAQ,CAAC,IAAa,EAAE,GAAG,GAAG,GAAG;IAC/C,MAAM,GAAG,GAAG,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,IAAI,KAAK,QAAQ,IAAI,OAAO,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACxH,MAAM,IAAI,GAAG,GAAG;SACb,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC;SACtB,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;SACpB,KAAK,CAAC,KAAK,CAAC;SACZ,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;SACvC,IAAI,CAAC,GAAG,CAAC;SACT,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;SACpB,IAAI,EAAE,CAAC;IACV,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC/B,OAAO,KAAK,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;AACnG,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,IAAa;IACzC,OAAO,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,iBAAiB,CAAC;SAC5C,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;SACvC,MAAM,CAAC,OAAO,CAAC,CAAC;AACrB,CAAC;AAED,yFAAyF;AACzF,MAAM,CAAC,MAAM,YAAY,GAAG;;;;;;;;;;;;;EAa1B,CAAC"}
@@ -3,11 +3,17 @@ export declare function noteAuthor(repo: string): string;
3
3
  export declare function currentBranch(repo: string): string | undefined;
4
4
  /** Paths that are the code map, agent wiring or the learnings themselves, never what a learning is about. */
5
5
  export declare function ownPath(p: string): boolean;
6
+ /** A repo path that is trail's or the agents' own (`ownPath`, plus AGENTS.md and the like): never what a learning is about. */
7
+ export declare function trailOwnPath(p: string): boolean;
6
8
  /**
7
9
  * Files this session changed: uncommitted changes, plus files in commits made
8
10
  * since `since` (epoch ms). At most `limit`, in the order git lists them.
11
+ * `uncommitted: false` leaves the working tree out, for when the session's own
12
+ * transcript already says which files it changed: uncommitted files from
13
+ * before the session (an untracked token file, a stray AGENTS.md) were
14
+ * otherwise listed on every learning saved there.
9
15
  */
10
- export declare function changedFiles(repo: string, since?: number, limit?: number): string[];
16
+ export declare function changedFiles(repo: string, since?: number, limit?: number, uncommitted?: boolean): string[];
11
17
  /**
12
18
  * The people who changed `files` (the whole repo when empty) in the last six
13
19
  * months, by first name, most commits first: the ones whose agents a learning
@@ -1 +1 @@
1
- {"version":3,"file":"git-facts.d.ts","sourceRoot":"","sources":["../../src/notes/git-facts.ts"],"names":[],"mappings":"AAkBA,yFAAyF;AACzF,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAI/C;AAUD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAG9D;AAED,6GAA6G;AAC7G,wBAAgB,OAAO,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAI1C;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,KAAK,SAAK,GAAG,MAAM,EAAE,CAkB/E;AAKD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,GAAE,MAAM,EAAO,GAAG,MAAM,EAAE,CAqBxE"}
1
+ {"version":3,"file":"git-facts.d.ts","sourceRoot":"","sources":["../../src/notes/git-facts.ts"],"names":[],"mappings":"AAkBA,yFAAyF;AACzF,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAI/C;AAUD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAG9D;AAED,6GAA6G;AAC7G,wBAAgB,OAAO,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAI1C;AAKD,+HAA+H;AAC/H,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAE/C;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,KAAK,SAAK,EAAE,WAAW,UAAO,GAAG,MAAM,EAAE,CAkBnG;AAKD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,GAAE,MAAM,EAAO,GAAG,MAAM,EAAE,CAqBxE"}
@@ -39,18 +39,28 @@ export function ownPath(p) {
39
39
  // to them, which is never what a session's note is about.
40
40
  return /^(graft|\.graft|\.claude|\.cursor|\.codex|\.trail)(\/|$)/.test(p) || p === ".mcp.json" || p === ".gitignore" || p === ".ignore";
41
41
  }
42
+ /** Files the agent instructions live in: trail writes them, so editing them is setting trail up. */
43
+ const AGENT_FILES = new Set(["AGENTS.md", "CLAUDE.md", "GEMINI.md", ".github/copilot-instructions.md"]);
44
+ /** A repo path that is trail's or the agents' own (`ownPath`, plus AGENTS.md and the like): never what a learning is about. */
45
+ export function trailOwnPath(p) {
46
+ return ownPath(p) || AGENT_FILES.has(p);
47
+ }
42
48
  /**
43
49
  * Files this session changed: uncommitted changes, plus files in commits made
44
50
  * since `since` (epoch ms). At most `limit`, in the order git lists them.
51
+ * `uncommitted: false` leaves the working tree out, for when the session's own
52
+ * transcript already says which files it changed: uncommitted files from
53
+ * before the session (an untracked token file, a stray AGENTS.md) were
54
+ * otherwise listed on every learning saved there.
45
55
  */
46
- export function changedFiles(repo, since, limit = 10) {
56
+ export function changedFiles(repo, since, limit = 10, uncommitted = true) {
47
57
  const out = [];
48
58
  const add = (p) => {
49
59
  const f = p.trim();
50
60
  if (f && !ownPath(f) && !out.includes(f))
51
61
  out.push(f);
52
62
  };
53
- const status = git(repo, ["status", "--porcelain", "--untracked-files=all"], true);
63
+ const status = uncommitted ? git(repo, ["status", "--porcelain", "--untracked-files=all"], true) : null;
54
64
  for (const line of (status ?? "").split("\n")) {
55
65
  if (!line.trim())
56
66
  continue;
@@ -1 +1 @@
1
- {"version":3,"file":"git-facts.js","sourceRoot":"","sources":["../../src/notes/git-facts.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"git-facts.js","sourceRoot":"","sources":["../../src/notes/git-facts.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
- /** `~/.trail`, or `$TRAIL_HOME`. */
2
- export declare function trailHome(env?: NodeJS.ProcessEnv, home?: string): string;
1
+ import { trailHome } from "./trail-home.js";
2
+ export { trailHome };
3
3
  /** A path as people read it: `~/.trail/…` under the home folder, absolute otherwise. */
4
4
  export declare function shownPath(p: string): string;
5
5
  /** The nearest folder at or above `start` holding a `.git` (folder or file), or null outside git. */
@@ -12,6 +12,16 @@ export declare function remoteUrl(config: string): string | null;
12
12
  * Null for a remote that is a path on this machine: those are keyed by path.
13
13
  */
14
14
  export declare function keyFromRemote(url: string): string | null;
15
+ /**
16
+ * The checkout at or above `start` and its remote's key (`github.com/nanonets/assign`),
17
+ * as written in its git config, before any `insteadOf`: a clone whose fetches go
18
+ * somewhere else still names the same repo. Null outside git or without a remote.
19
+ * Reads only; spawns nothing.
20
+ */
21
+ export declare function remoteKey(start: string): {
22
+ checkout: string;
23
+ key: string;
24
+ } | null;
15
25
  export interface RepoPlace {
16
26
  /** The top of the checkout the folder is in (a worktree's own top), or the folder itself outside git. */
17
27
  checkout: string;
@@ -30,7 +40,7 @@ export declare function repoPlace(start: string, env?: NodeJS.ProcessEnv): RepoP
30
40
  * statusline); a machine with no notes anywhere never spawns it.
31
41
  */
32
42
  export declare function findRepoPlace(start: string, env?: NodeJS.ProcessEnv): RepoPlace;
33
- export declare const HOME_README = "# ~/.trail\n\nWhat Trail keeps on this machine. Learnings about the code are in each\nrepo's own .trail/learnings/, committed with the code; this folder holds\nthe rest, and none of it leaves this machine unless you share it.\n\n- repos/<repo>/notes/ personal learnings: about your setup or habits,\n not the code\n- repos/<repo>/skills/ corrections you taught your agent, per skill\n- repos/known.json the repos Trail has run in, which is the list a\n workspace's repo picker shows\n- cloud.json your Trail workspace, once you've connected one\n\n<repo> is the repo's remote (github.com/owner/name), so every clone and\nworktree of one repo shares its notes. Repos without a remote are under\nlocal/, by path.\n";
43
+ export declare const HOME_README = "# ~/.trail\n\nWhat Trail keeps on this machine. Learnings about the code are in each\nrepo's own .trail/learnings/, committed with the code; this folder holds\nthe rest, and none of it leaves this machine unless you share it.\n\n- repos/<repo>/notes/ personal learnings: about your setup or habits,\n not the code\n- repos/<repo>/skills/ corrections you taught your agent, per skill\n- repos/known.json the repos Trail has run in, which is the list a\n workspace's repo picker shows\n- cloud.json your Trail workspace, once you've connected one\n\n<repo> is the repo's remote (github.com/owner/name), so every clone and\nworktree of one repo shares its learnings. Repos without a remote are under\nlocal/, by path.\n";
34
44
  /**
35
45
  * Make the folder for `start`'s repo, and return where it is. A repo seen for
36
46
  * the first time under this key, whose first commit already has a folder (a
@@ -57,11 +67,19 @@ export declare function notePlaces(dir: string, env?: NodeJS.ProcessEnv): RepoPl
57
67
  /** This repo keeps learnings: it has a committed `.trail/`, or `trail init` or a first learning made its folder in ~/.trail. */
58
68
  export declare function keepsNotes(dir: string, env?: NodeJS.ProcessEnv): boolean;
59
69
  /**
60
- * How many learnings bear on `dir`, counted without reading them: the repo's
61
- * `.trail/learnings/`, this machine's own, and the ones on teammates' pushed
62
- * branches, one per file name. Spawns nothing: the statusline calls it.
70
+ * How many live learnings bear on `dir`: the repo's `.trail/learnings/`, this
71
+ * machine's own, and the ones on teammates' pushed branches, one per file
72
+ * name, leaving out what is retired, held or replaced (`liveLearnings`).
73
+ * Spawns nothing and prints nothing: the statusline calls it.
63
74
  */
64
75
  export declare function noteCount(dir: string, env?: NodeJS.ProcessEnv): number;
76
+ /** The live learnings bearing on `dir` by where they live: the repo's (`.trail/learnings/`, teammates' branches) and the person's own in the Trail home. */
77
+ export interface NoteCounts {
78
+ repo: number;
79
+ personal: number;
80
+ }
81
+ /** `noteCount`, split by place, so the session start names each where it is. */
82
+ export declare function noteCounts(dir: string, env?: NodeJS.ProcessEnv): NoteCounts;
65
83
  export interface KnownRepo {
66
84
  /** `github.com/hashicorp/go-retryablehttp`: the key notes are kept under. */
67
85
  key: string;
@@ -1 +1 @@
1
- {"version":3,"file":"home.d.ts","sourceRoot":"","sources":["../../src/notes/home.ts"],"names":[],"mappings":"AAwCA,oCAAoC;AACpC,wBAAgB,SAAS,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,EAAE,IAAI,GAAE,MAAkB,GAAG,MAAM,CAEhG;AAED,wFAAwF;AACxF,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAK3C;AAMD,qGAAqG;AACrG,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAQzD;AA8CD,sFAAsF;AACtF,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAkBvD;AAQD;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CA2BxD;AAWD,MAAM,WAAW,SAAS;IACxB,yGAAyG;IACzG,QAAQ,EAAE,MAAM,CAAC;IACjB,6BAA6B;IAC7B,GAAG,EAAE,OAAO,CAAC;IACb,kDAAkD;IAClD,GAAG,EAAE,MAAM,CAAC;IACZ,6EAA6E;IAC7E,GAAG,EAAE,MAAM,CAAC;CACb;AAsBD,+EAA+E;AAC/E,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,SAAS,CAgBxF;AA+BD;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,SAAS,CAS5F;AAED,eAAO,MAAM,WAAW,oxBAgBvB,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG;IAAE,KAAK,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAe1H;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAYvE;AASD,sFAAsF;AACtF,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAcpD;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,SAAS,EAAE,CAKzF;AAED,gIAAgI;AAChI,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAErF;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAYnF;AAMD,MAAM,WAAW,SAAS;IACxB,6EAA6E;IAC7E,GAAG,EAAE,MAAM,CAAC;IACZ,wDAAwD;IACxD,IAAI,EAAE,MAAM,CAAC;IACb,yDAAyD;IACzD,IAAI,EAAE,MAAM,CAAC;IACb,sBAAsB;IACtB,MAAM,EAAE,MAAM,CAAC;CAChB;AAMD,+GAA+G;AAC/G,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAI/D;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,SAAS,EAAE,CAK5E;AAKD;;;GAGG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,GAAE,MAAM,CAAC,UAAwB,EAAE,GAAG,SAAa,GAAG,IAAI,CAatG"}
1
+ {"version":3,"file":"home.d.ts","sourceRoot":"","sources":["../../src/notes/home.ts"],"names":[],"mappings":"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"}
@@ -36,11 +36,11 @@ import { homedir } from "node:os";
36
36
  import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
37
37
  import { readJson, writeJsonAtomic } from "../util/state.js";
38
38
  import { readBranchCache } from "./branches.js";
39
- import { hasRepoTrail, learningFiles } from "./repo-trail.js";
40
- /** `~/.trail`, or `$TRAIL_HOME`. */
41
- export function trailHome(env = process.env, home = homedir()) {
42
- return env.TRAIL_HOME ? resolve(env.TRAIL_HOME) : join(home, ".trail");
43
- }
39
+ import { hasRepoTrail, learningFiles, learningsDir } from "./repo-trail.js";
40
+ import { liveLearnings, readLearningFields } from "./learning-fields.js";
41
+ import { matter } from "../util/front-matter.js";
42
+ import { trailHome } from "./trail-home.js";
43
+ export { trailHome };
44
44
  /** A path as people read it: `~/.trail/…` under the home folder, absolute otherwise. */
45
45
  export function shownPath(p) {
46
46
  if (!isAbsolute(p))
@@ -131,7 +131,15 @@ export function remoteUrl(config) {
131
131
  }
132
132
  /** One path segment of a key: lowercase, safe as a folder name, never `.` or `..`. */
133
133
  function segment(s) {
134
- const out = s.toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
134
+ const dashed = s.toLowerCase().replace(/[^a-z0-9._-]+/g, "-");
135
+ // Trim the dashes by hand: `/-+$/` rescans every run of dashes, quadratic on a long one.
136
+ let a = 0;
137
+ let b = dashed.length;
138
+ while (a < b && dashed[a] === "-")
139
+ a++;
140
+ while (b > a && dashed[b - 1] === "-")
141
+ b--;
142
+ const out = dashed.slice(a, b);
135
143
  return /^\.+$/.test(out) ? "" : out;
136
144
  }
137
145
  /**
@@ -172,6 +180,26 @@ export function keyFromRemote(url) {
172
180
  return null;
173
181
  return [host, ...parts].join("/");
174
182
  }
183
+ /**
184
+ * The checkout at or above `start` and its remote's key (`github.com/nanonets/assign`),
185
+ * as written in its git config, before any `insteadOf`: a clone whose fetches go
186
+ * somewhere else still names the same repo. Null outside git or without a remote.
187
+ * Reads only; spawns nothing.
188
+ */
189
+ export function remoteKey(start) {
190
+ const top = checkoutRoot(start);
191
+ const dirs = top ? gitDirs(top) : null;
192
+ if (!top || !dirs)
193
+ return null;
194
+ try {
195
+ const url = remoteUrl(readFileSync(join(dirs.commonDir, "config"), "utf8"));
196
+ const key = url ? keyFromRemote(url) : null;
197
+ return key ? { checkout: top, key } : null;
198
+ }
199
+ catch {
200
+ return null;
201
+ }
202
+ }
175
203
  /** `local/Users-priya-src-extract`: the key for a repo with no remote, or a folder outside git. */
176
204
  function pathKey(dir) {
177
205
  return `local/${segment(resolve(dir)) || "root"}`;
@@ -267,7 +295,7 @@ the rest, and none of it leaves this machine unless you share it.
267
295
  - cloud.json your Trail workspace, once you've connected one
268
296
 
269
297
  <repo> is the repo's remote (github.com/owner/name), so every clone and
270
- worktree of one repo shares its notes. Repos without a remote are under
298
+ worktree of one repo shares its learnings. Repos without a remote are under
271
299
  local/, by path.
272
300
  `;
273
301
  /**
@@ -351,21 +379,58 @@ export function notePlaces(dir, env = process.env) {
351
379
  export function keepsNotes(dir, env = process.env) {
352
380
  return notePlaces(dir, env).some((p) => existsSync(p.dir) || (p.git && hasRepoTrail(p.checkout)));
353
381
  }
382
+ function counted(text, name, scope, ref) {
383
+ try {
384
+ const parsed = matter(text);
385
+ const d = parsed.data;
386
+ if (parsed.refused || typeof d.title !== "string" || !d.title.trim())
387
+ return null;
388
+ const date = d.date instanceof Date ? d.date.toISOString().slice(0, 10) : String(d.date ?? "");
389
+ return { ...readLearningFields(d, name), scope, date, path: name, ...(ref ? { ref } : {}) };
390
+ }
391
+ catch {
392
+ return null;
393
+ }
394
+ }
395
+ function readText(path) {
396
+ try {
397
+ return readFileSync(path, "utf8");
398
+ }
399
+ catch {
400
+ return null;
401
+ }
402
+ }
354
403
  /**
355
- * How many learnings bear on `dir`, counted without reading them: the repo's
356
- * `.trail/learnings/`, this machine's own, and the ones on teammates' pushed
357
- * branches, one per file name. Spawns nothing: the statusline calls it.
404
+ * How many live learnings bear on `dir`: the repo's `.trail/learnings/`, this
405
+ * machine's own, and the ones on teammates' pushed branches, one per file
406
+ * name, leaving out what is retired, held or replaced (`liveLearnings`).
407
+ * Spawns nothing and prints nothing: the statusline calls it.
358
408
  */
359
409
  export function noteCount(dir, env = process.env) {
360
- const names = new Set();
410
+ const c = noteCounts(dir, env);
411
+ return c.repo + c.personal;
412
+ }
413
+ /** `noteCount`, split by place, so the session start names each where it is. */
414
+ export function noteCounts(dir, env = process.env) {
415
+ const all = [];
416
+ const seen = new Set();
417
+ const add = (name, text, scope, ref) => {
418
+ if (seen.has(name) || text === null)
419
+ return;
420
+ const c = counted(text, name, scope, ref);
421
+ if (!c)
422
+ return;
423
+ seen.add(name);
424
+ all.push(c);
425
+ };
361
426
  for (const p of notePlaces(dir, env)) {
362
427
  if (p.git)
363
428
  for (const f of learningFiles(p.checkout))
364
- names.add(f);
429
+ add(f, readText(join(learningsDir(p.checkout), f)), "repo");
365
430
  try {
366
431
  for (const f of readdirSync(join(p.dir, "notes")))
367
432
  if (f.endsWith(".md"))
368
- names.add(f);
433
+ add(f, readText(join(p.dir, "notes", f)), "personal");
369
434
  }
370
435
  catch {
371
436
  /* none */
@@ -373,9 +438,11 @@ export function noteCount(dir, env = process.env) {
373
438
  if (p.git)
374
439
  for (const b of readBranchCache(p.checkout)?.branches ?? [])
375
440
  for (const l of b.learnings)
376
- names.add(l.name);
441
+ add(l.name, l.text, "repo", b.ref);
377
442
  }
378
- return names.size;
443
+ const live = liveLearnings(all);
444
+ const personal = live.filter((c) => c.scope === "personal").length;
445
+ return { repo: live.length - personal, personal };
379
446
  }
380
447
  function knownPath(home) {
381
448
  return join(home, "repos", "known.json");