@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.
- package/README.md +4 -4
- package/dist/ai/crux.d.ts +31 -3
- package/dist/ai/crux.d.ts.map +1 -1
- package/dist/ai/crux.js +88 -10
- package/dist/ai/crux.js.map +1 -1
- package/dist/ai/llm/openai.d.ts +101 -0
- package/dist/ai/llm/openai.d.ts.map +1 -1
- package/dist/ai/llm/openai.js +396 -6
- package/dist/ai/llm/openai.js.map +1 -1
- package/dist/ai/llm/recover-tool.d.ts +2 -0
- package/dist/ai/llm/recover-tool.d.ts.map +1 -1
- package/dist/ai/llm/recover-tool.js +1 -1
- package/dist/ai/llm/recover-tool.js.map +1 -1
- package/dist/ai/synthesize.d.ts.map +1 -1
- package/dist/ai/synthesize.js +100 -1
- package/dist/ai/synthesize.js.map +1 -1
- package/dist/claude/format.d.ts +21 -0
- package/dist/claude/format.d.ts.map +1 -1
- package/dist/claude/format.js +46 -1
- package/dist/claude/format.js.map +1 -1
- package/dist/claude/hooks.d.ts +5 -9
- package/dist/claude/hooks.d.ts.map +1 -1
- package/dist/claude/hooks.js +71 -58
- package/dist/claude/hooks.js.map +1 -1
- package/dist/claude/init.js +3 -3
- package/dist/claude/init.js.map +1 -1
- package/dist/claude/note-signals.d.ts +28 -0
- package/dist/claude/note-signals.d.ts.map +1 -0
- package/dist/claude/note-signals.js +325 -0
- package/dist/claude/note-signals.js.map +1 -0
- package/dist/claude/shim-template.d.ts.map +1 -1
- package/dist/claude/shim-template.js +17 -6
- package/dist/claude/shim-template.js.map +1 -1
- package/dist/claude/skill-template.d.ts.map +1 -1
- package/dist/claude/skill-template.js +49 -18
- package/dist/claude/skill-template.js.map +1 -1
- package/dist/claude/state.d.ts +4 -3
- package/dist/claude/state.d.ts.map +1 -1
- package/dist/claude/state.js.map +1 -1
- package/dist/claude/sync-run.js +1 -1
- package/dist/claude/sync-run.js.map +1 -1
- package/dist/cli-picker.d.ts +12 -5
- package/dist/cli-picker.d.ts.map +1 -1
- package/dist/cli-picker.js +24 -8
- package/dist/cli-picker.js.map +1 -1
- package/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +149 -43
- package/dist/cli.js.map +1 -1
- package/dist/context/batches.d.ts +29 -0
- package/dist/context/batches.d.ts.map +1 -0
- package/dist/context/batches.js +130 -0
- package/dist/context/batches.js.map +1 -0
- package/dist/context/build.d.ts +7 -2
- package/dist/context/build.d.ts.map +1 -1
- package/dist/context/build.js +84 -50
- package/dist/context/build.js.map +1 -1
- package/dist/context/node-file.d.ts.map +1 -1
- package/dist/context/node-file.js +41 -4
- package/dist/context/node-file.js.map +1 -1
- package/dist/engine.d.ts +2 -0
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +1 -0
- package/dist/engine.js.map +1 -1
- package/dist/graph/cards.d.ts.map +1 -1
- package/dist/graph/cards.js +9 -4
- package/dist/graph/cards.js.map +1 -1
- package/dist/graph/enrich.d.ts.map +1 -1
- package/dist/graph/enrich.js +8 -3
- package/dist/graph/enrich.js.map +1 -1
- package/dist/graph/generic.d.ts.map +1 -1
- package/dist/graph/generic.js +207 -6
- package/dist/graph/generic.js.map +1 -1
- package/dist/graph/lsp/client.d.ts +18 -0
- package/dist/graph/lsp/client.d.ts.map +1 -1
- package/dist/graph/lsp/client.js +40 -2
- package/dist/graph/lsp/client.js.map +1 -1
- package/dist/graph/lsp/enrich.d.ts.map +1 -1
- package/dist/graph/lsp/enrich.js +9 -1
- package/dist/graph/lsp/enrich.js.map +1 -1
- package/dist/graph/lsp/registry.d.ts +7 -0
- package/dist/graph/lsp/registry.d.ts.map +1 -1
- package/dist/graph/lsp/registry.js +27 -2
- package/dist/graph/lsp/registry.js.map +1 -1
- package/dist/graph/queries/gleam.scm +51 -0
- package/dist/graph/resolve.d.ts.map +1 -1
- package/dist/graph/resolve.js +65 -3
- package/dist/graph/resolve.js.map +1 -1
- package/dist/graph/workspace-cli.d.ts +2 -0
- package/dist/graph/workspace-cli.d.ts.map +1 -1
- package/dist/graph/workspace-cli.js +1 -1
- package/dist/graph/workspace-cli.js.map +1 -1
- package/dist/init-guard.d.ts +11 -0
- package/dist/init-guard.d.ts.map +1 -0
- package/dist/init-guard.js +21 -0
- package/dist/init-guard.js.map +1 -0
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +2 -1
- package/dist/mcp/tools.js.map +1 -1
- package/dist/notes/branches.d.ts +7 -1
- package/dist/notes/branches.d.ts.map +1 -1
- package/dist/notes/branches.js +31 -3
- package/dist/notes/branches.js.map +1 -1
- package/dist/notes/cold-start.d.ts +12 -2
- package/dist/notes/cold-start.d.ts.map +1 -1
- package/dist/notes/cold-start.js +46 -5
- package/dist/notes/cold-start.js.map +1 -1
- package/dist/notes/credit.d.ts +37 -0
- package/dist/notes/credit.d.ts.map +1 -0
- package/dist/notes/credit.js +78 -0
- package/dist/notes/credit.js.map +1 -0
- package/dist/notes/find-notes.d.ts +17 -0
- package/dist/notes/find-notes.d.ts.map +1 -0
- package/dist/notes/find-notes.js +48 -0
- package/dist/notes/find-notes.js.map +1 -0
- package/dist/notes/flatten.d.ts +31 -0
- package/dist/notes/flatten.d.ts.map +1 -0
- package/dist/notes/flatten.js +73 -0
- package/dist/notes/flatten.js.map +1 -0
- package/dist/notes/git-facts.d.ts +7 -1
- package/dist/notes/git-facts.d.ts.map +1 -1
- package/dist/notes/git-facts.js +12 -2
- package/dist/notes/git-facts.js.map +1 -1
- package/dist/notes/home.d.ts +24 -6
- package/dist/notes/home.d.ts.map +1 -1
- package/dist/notes/home.js +82 -15
- package/dist/notes/home.js.map +1 -1
- package/dist/notes/learning-fields.d.ts +102 -0
- package/dist/notes/learning-fields.d.ts.map +1 -0
- package/dist/notes/learning-fields.js +214 -0
- package/dist/notes/learning-fields.js.map +1 -0
- package/dist/notes/memory-notes.d.ts +71 -0
- package/dist/notes/memory-notes.d.ts.map +1 -0
- package/dist/notes/memory-notes.js +239 -0
- package/dist/notes/memory-notes.js.map +1 -0
- package/dist/notes/note-gate.d.ts +42 -0
- package/dist/notes/note-gate.d.ts.map +1 -0
- package/dist/notes/note-gate.js +181 -0
- package/dist/notes/note-gate.js.map +1 -0
- package/dist/notes/notes.d.ts +29 -77
- package/dist/notes/notes.d.ts.map +1 -1
- package/dist/notes/notes.js +69 -228
- package/dist/notes/notes.js.map +1 -1
- package/dist/notes/pr-reviews.d.ts +35 -7
- package/dist/notes/pr-reviews.d.ts.map +1 -1
- package/dist/notes/pr-reviews.js +156 -46
- package/dist/notes/pr-reviews.js.map +1 -1
- package/dist/notes/secrets.d.ts +28 -0
- package/dist/notes/secrets.d.ts.map +1 -0
- package/dist/notes/secrets.js +362 -0
- package/dist/notes/secrets.js.map +1 -0
- package/dist/notes/session-cost.d.ts +2 -0
- package/dist/notes/session-cost.d.ts.map +1 -1
- package/dist/notes/session-cost.js +8 -3
- package/dist/notes/session-cost.js.map +1 -1
- package/dist/notes/targets.d.ts +37 -0
- package/dist/notes/targets.d.ts.map +1 -0
- package/dist/notes/targets.js +108 -0
- package/dist/notes/targets.js.map +1 -0
- package/dist/notes/team-check.d.ts +22 -0
- package/dist/notes/team-check.d.ts.map +1 -0
- package/dist/notes/team-check.js +130 -0
- package/dist/notes/team-check.js.map +1 -0
- package/dist/notes/trail-home.d.ts +3 -0
- package/dist/notes/trail-home.d.ts.map +1 -0
- package/dist/notes/trail-home.js +12 -0
- package/dist/notes/trail-home.js.map +1 -0
- package/dist/search/grep-cli.d.ts +5 -2
- package/dist/search/grep-cli.d.ts.map +1 -1
- package/dist/search/grep-cli.js +11 -4
- package/dist/search/grep-cli.js.map +1 -1
- package/dist/search/ignored-code.d.ts +9 -0
- package/dist/search/ignored-code.d.ts.map +1 -0
- package/dist/search/ignored-code.js +73 -0
- package/dist/search/ignored-code.js.map +1 -0
- package/dist/skills/answers-prompt.d.ts +13 -0
- package/dist/skills/answers-prompt.d.ts.map +1 -0
- package/dist/skills/answers-prompt.js +83 -0
- package/dist/skills/answers-prompt.js.map +1 -0
- package/dist/skills/never-save.d.ts +5 -0
- package/dist/skills/never-save.d.ts.map +1 -0
- package/dist/skills/never-save.js +158 -0
- package/dist/skills/never-save.js.map +1 -0
- package/dist/skills/params.d.ts +39 -0
- package/dist/skills/params.d.ts.map +1 -0
- package/dist/skills/params.js +275 -0
- package/dist/skills/params.js.map +1 -0
- package/dist/skills/ran-less.d.ts +5 -0
- package/dist/skills/ran-less.d.ts.map +1 -0
- package/dist/skills/ran-less.js +51 -0
- package/dist/skills/ran-less.js.map +1 -0
- package/dist/skills/risk-delta.d.ts +32 -0
- package/dist/skills/risk-delta.d.ts.map +1 -0
- package/dist/skills/risk-delta.js +56 -0
- package/dist/skills/risk-delta.js.map +1 -0
- package/dist/skills/risk.d.ts +73 -0
- package/dist/skills/risk.d.ts.map +1 -0
- package/dist/skills/risk.js +396 -0
- package/dist/skills/risk.js.map +1 -0
- package/dist/skills/types.d.ts +422 -0
- package/dist/skills/types.d.ts.map +1 -0
- package/dist/skills/types.js +2 -0
- package/dist/skills/types.js.map +1 -0
- package/dist/telemetry/contract.d.ts.map +1 -1
- package/dist/telemetry/contract.js +8 -6
- package/dist/telemetry/contract.js.map +1 -1
- package/dist/telemetry/notice.d.ts.map +1 -1
- package/dist/telemetry/notice.js +3 -1
- package/dist/telemetry/notice.js.map +1 -1
- package/dist/trace/check-reads.d.ts +36 -0
- package/dist/trace/check-reads.d.ts.map +1 -0
- package/dist/trace/check-reads.js +57 -0
- package/dist/trace/check-reads.js.map +1 -0
- package/dist/trace/host.d.ts +40 -0
- package/dist/trace/host.d.ts.map +1 -0
- package/dist/trace/host.js +84 -0
- package/dist/trace/host.js.map +1 -0
- package/dist/trace/redact.d.ts +8 -0
- package/dist/trace/redact.d.ts.map +1 -0
- package/dist/trace/redact.js +63 -0
- package/dist/trace/redact.js.map +1 -0
- package/dist/trace/seen-cache.d.ts +9 -0
- package/dist/trace/seen-cache.d.ts.map +1 -0
- package/dist/trace/seen-cache.js +46 -0
- package/dist/trace/seen-cache.js.map +1 -0
- package/dist/trace/shell-scan.d.ts +52 -0
- package/dist/trace/shell-scan.d.ts.map +1 -0
- package/dist/trace/shell-scan.js +318 -0
- package/dist/trace/shell-scan.js.map +1 -0
- package/dist/trace/shell-words.d.ts +91 -0
- package/dist/trace/shell-words.d.ts.map +1 -0
- package/dist/trace/shell-words.js +558 -0
- package/dist/trace/shell-words.js.map +1 -0
- package/dist/trace/shell.d.ts +91 -0
- package/dist/trace/shell.d.ts.map +1 -0
- package/dist/trace/shell.js +435 -0
- package/dist/trace/shell.js.map +1 -0
- package/dist/trace/state.d.ts +27 -0
- package/dist/trace/state.d.ts.map +1 -0
- package/dist/trace/state.js +98 -0
- package/dist/trace/state.js.map +1 -0
- package/dist/trace/tamper-code.d.ts +9 -0
- package/dist/trace/tamper-code.d.ts.map +1 -0
- package/dist/trace/tamper-code.js +174 -0
- package/dist/trace/tamper-code.js.map +1 -0
- package/dist/trace/tamper-git.d.ts +12 -0
- package/dist/trace/tamper-git.d.ts.map +1 -0
- package/dist/trace/tamper-git.js +77 -0
- package/dist/trace/tamper-git.js.map +1 -0
- package/dist/trace/types.d.ts +477 -0
- package/dist/trace/types.d.ts.map +1 -0
- package/dist/trace/types.js +12 -0
- package/dist/trace/types.js.map +1 -0
- package/dist/trace/walls-glob.d.ts +11 -0
- package/dist/trace/walls-glob.d.ts.map +1 -0
- package/dist/trace/walls-glob.js +264 -0
- package/dist/trace/walls-glob.js.map +1 -0
- package/dist/trace/walls-quoted.d.ts +25 -0
- package/dist/trace/walls-quoted.d.ts.map +1 -0
- package/dist/trace/walls-quoted.js +81 -0
- package/dist/trace/walls-quoted.js.map +1 -0
- package/dist/upkeep.d.ts +1 -1
- package/dist/upkeep.d.ts.map +1 -1
- package/dist/upkeep.js +4 -1
- package/dist/upkeep.js.map +1 -1
- package/dist/util/actions-folder.d.ts +2 -0
- package/dist/util/actions-folder.d.ts.map +1 -0
- package/dist/util/actions-folder.js +9 -0
- package/dist/util/actions-folder.js.map +1 -0
- package/dist/util/front-matter.d.ts +31 -4
- package/dist/util/front-matter.d.ts.map +1 -1
- package/dist/util/front-matter.js +95 -3
- package/dist/util/front-matter.js.map +1 -1
- package/dist/util/private-file.d.ts +14 -0
- package/dist/util/private-file.d.ts.map +1 -0
- package/dist/util/private-file.js +82 -0
- package/dist/util/private-file.js.map +1 -0
- package/dist/util/private-fs.d.ts +25 -0
- package/dist/util/private-fs.d.ts.map +1 -0
- package/dist/util/private-fs.js +253 -0
- package/dist/util/private-fs.js.map +1 -0
- package/dist/util/state.d.ts.map +1 -1
- package/dist/util/state.js +3 -0
- package/dist/util/state.js.map +1 -1
- package/dist/viewer/app.js +2 -2
- package/package.json +5 -5
- package/scripts/run-tests.mjs +14 -2
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Learnings from the notes Claude Code keeps for this repo on this machine
|
|
3
|
+
* (`~/.claude/projects/<folder>/memory/*.md`), for `trail init` to offer on
|
|
4
|
+
* day one. Those notes are Claude's own memory of the repo: what it was told
|
|
5
|
+
* about the project, where things are, how the person likes to work. They
|
|
6
|
+
* never leave this machine, so a teammate's Claude starts without them.
|
|
7
|
+
*
|
|
8
|
+
* No model reads them: each note is already short and written for Claude.
|
|
9
|
+
* trail keeps a project or reference note as a team learning only when it
|
|
10
|
+
* names code that exists now and the repo doesn't already say it; the rest,
|
|
11
|
+
* and the person's feedback notes, are offered as their own. Notes about the
|
|
12
|
+
* person (`user`) are never offered. Anything that looks like a secret is
|
|
13
|
+
* scrubbed, and a note that still looks like one is skipped.
|
|
14
|
+
*/
|
|
15
|
+
import { readdirSync, readFileSync, statSync } from "node:fs";
|
|
16
|
+
import { homedir } from "node:os";
|
|
17
|
+
import { basename, join } from "node:path";
|
|
18
|
+
import { countBucket } from "../telemetry/contract.js";
|
|
19
|
+
import { track } from "../telemetry/track.js";
|
|
20
|
+
import { readJson, writeJsonAtomic } from "../util/state.js";
|
|
21
|
+
import { sameRepoRoots, scrub } from "./cold-start.js";
|
|
22
|
+
import { noteAuthor } from "./git-facts.js";
|
|
23
|
+
import { ensureRepoHome } from "./home.js";
|
|
24
|
+
import { shortDate, writeNote } from "./notes.js";
|
|
25
|
+
import { claudeProjectDir } from "./session-cost.js";
|
|
26
|
+
import { alreadySaid, codeAnchors, knownText } from "./team-check.js";
|
|
27
|
+
const BODY_CHARS = 1500;
|
|
28
|
+
/* -------------------------------------------------------------------------- */
|
|
29
|
+
/* Reading the notes */
|
|
30
|
+
/* -------------------------------------------------------------------------- */
|
|
31
|
+
/** The memory folders of this repo's checkouts on this machine: its own, its worktrees', and other clones'. */
|
|
32
|
+
export function memoryDirs(repo, home = homedir()) {
|
|
33
|
+
return [...new Set(sameRepoRoots(repo, home).map((r) => join(claudeProjectDir(r, home), "memory")))];
|
|
34
|
+
}
|
|
35
|
+
/** The value of `key:` in a frontmatter block, top level or under `metadata:`, unquoted. */
|
|
36
|
+
function field(front, key) {
|
|
37
|
+
const m = new RegExp(`^\\s*${key}:\\s*(.*)$`, "m").exec(front);
|
|
38
|
+
if (!m)
|
|
39
|
+
return "";
|
|
40
|
+
const v = m[1].trim();
|
|
41
|
+
if ((v.startsWith('"') && v.endsWith('"')) || (v.startsWith("'") && v.endsWith("'"))) {
|
|
42
|
+
try {
|
|
43
|
+
return v.startsWith('"') ? JSON.parse(v) : v.slice(1, -1);
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return v.slice(1, -1);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return v;
|
|
50
|
+
}
|
|
51
|
+
const TYPES = ["project", "reference", "feedback", "user"];
|
|
52
|
+
/** One memory note, or null when it isn't one (no frontmatter, empty, the MEMORY.md index). */
|
|
53
|
+
export function readMemoryNote(path) {
|
|
54
|
+
if (basename(path) === "MEMORY.md")
|
|
55
|
+
return null;
|
|
56
|
+
let text;
|
|
57
|
+
let updated;
|
|
58
|
+
try {
|
|
59
|
+
text = readFileSync(path, "utf8");
|
|
60
|
+
updated = statSync(path).mtime.toISOString().slice(0, 10);
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
const m = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/.exec(text);
|
|
66
|
+
if (!m)
|
|
67
|
+
return null;
|
|
68
|
+
const front = m[1];
|
|
69
|
+
const body = m[2].trim();
|
|
70
|
+
if (!body)
|
|
71
|
+
return null;
|
|
72
|
+
const raw = field(front, "type").toLowerCase();
|
|
73
|
+
const modified = /^\d{4}-\d{2}-\d{2}/.exec(field(front, "modified"))?.[0];
|
|
74
|
+
return {
|
|
75
|
+
path,
|
|
76
|
+
name: field(front, "name") || basename(path, ".md"),
|
|
77
|
+
description: field(front, "description"),
|
|
78
|
+
type: TYPES.includes(raw) ? raw : "other",
|
|
79
|
+
body,
|
|
80
|
+
updated: modified ?? updated,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
/** Every memory note of the repo's checkouts on this machine, newest first. */
|
|
84
|
+
export function memoryNotes(repo, home = homedir()) {
|
|
85
|
+
const out = [];
|
|
86
|
+
for (const dir of memoryDirs(repo, home)) {
|
|
87
|
+
let files;
|
|
88
|
+
try {
|
|
89
|
+
files = readdirSync(dir).filter((f) => f.endsWith(".md"));
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
for (const f of files) {
|
|
95
|
+
const note = readMemoryNote(join(dir, f));
|
|
96
|
+
if (note)
|
|
97
|
+
out.push(note);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return out.sort((a, b) => b.updated.localeCompare(a.updated));
|
|
101
|
+
}
|
|
102
|
+
/* -------------------------------------------------------------------------- */
|
|
103
|
+
/* As learnings */
|
|
104
|
+
/* -------------------------------------------------------------------------- */
|
|
105
|
+
/** A title a person reads: the note's name when it's words, else its description's first clause. */
|
|
106
|
+
export function memoryTitle(note) {
|
|
107
|
+
const words = /\s/.test(note.name.trim()) ? note.name.trim() : "";
|
|
108
|
+
const first = note.description.split(/(?<=[a-z0-9)`])\.\s|;\s| — | -- /)[0].trim();
|
|
109
|
+
let t = words || first || note.name.replace(/[-_]+/g, " ");
|
|
110
|
+
t = t.replace(/\.$/, "");
|
|
111
|
+
if (t.length > 90)
|
|
112
|
+
t = `${t.slice(0, 89).replace(/\s+\S*$/, "")}…`;
|
|
113
|
+
return t.charAt(0).toUpperCase() + t.slice(1);
|
|
114
|
+
}
|
|
115
|
+
/** `[[name]]` links to other memory notes read as plain words outside Claude's memory. */
|
|
116
|
+
function unlink(s) {
|
|
117
|
+
return s.replace(/\[\[([^\]]+)\]\]/g, "$1");
|
|
118
|
+
}
|
|
119
|
+
/** At most `max` characters, cut at a paragraph or line break when there is one. */
|
|
120
|
+
function clip(s, max) {
|
|
121
|
+
if (s.length <= max)
|
|
122
|
+
return s;
|
|
123
|
+
const cut = s.slice(0, max);
|
|
124
|
+
const at = Math.max(cut.lastIndexOf("\n\n"), cut.lastIndexOf("\n"));
|
|
125
|
+
return `${(at > max / 2 ? cut.slice(0, at) : cut).trimEnd()}\n…`;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* A memory note's body as a learning's: what it says, with its **Why:**,
|
|
129
|
+
* under `## Decided`; its **How to apply:** under `## Watch out`. Its own
|
|
130
|
+
* headings become bold lines so they don't break the learning's sections.
|
|
131
|
+
*/
|
|
132
|
+
export function memoryBody(note) {
|
|
133
|
+
const text = unlink(note.body).replace(/^#{1,6}\s+(.+)$/gm, "**$1**");
|
|
134
|
+
const split = /\*\*How to apply:?\*\*:?/i.exec(text);
|
|
135
|
+
const decided = (split ? text.slice(0, split.index) : text).trim();
|
|
136
|
+
const apply = split ? text.slice(split.index + split[0].length).trim() : "";
|
|
137
|
+
let out = `## Decided\n${clip(decided, BODY_CHARS)}`;
|
|
138
|
+
if (apply)
|
|
139
|
+
out += `\n\n## Watch out\n${clip(apply, 600)}`;
|
|
140
|
+
return scrub(out);
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* A short fact with its reason, not a work log. Status write-ups, and long
|
|
144
|
+
* notes with no **Why:**, stay in Claude's memory: as a learning they'd read
|
|
145
|
+
* as a diary, and be wrong by next week.
|
|
146
|
+
*/
|
|
147
|
+
export function readsAsLearning(body) {
|
|
148
|
+
if (/\*\*Status\b|^Status:|Shipped on branch|SLA breach|\bnot merged yet\b/im.test(body))
|
|
149
|
+
return false;
|
|
150
|
+
return body.split(/\s+/).filter(Boolean).length <= 150 || /\*\*Why:?\*\*/i.test(body);
|
|
151
|
+
}
|
|
152
|
+
/** Still looks like a credential after scrubbing, or names where one lives: not worth the risk of committing. */
|
|
153
|
+
const SECRETISH = /\b(?:AWS_SECRET_ACCESS_KEY|PRIVATE KEY|client_secret|BEGIN OPENSSH)\b|\[redacted\]/;
|
|
154
|
+
/**
|
|
155
|
+
* What `trail init` offers from Claude Code's memory of this repo, for the
|
|
156
|
+
* team: project and reference notes that read as a learning, are tied to code
|
|
157
|
+
* that exists now, and aren't already said. Notes offered before and
|
|
158
|
+
* unchanged since are left out.
|
|
159
|
+
*/
|
|
160
|
+
export function memoryCandidates(repo, opts = {}) {
|
|
161
|
+
const known = knownText(repo);
|
|
162
|
+
const team = [];
|
|
163
|
+
const titles = new Set();
|
|
164
|
+
for (const note of memoryNotes(repo, opts.home)) {
|
|
165
|
+
// Only what the team can use: Claude already reads the rest of its memory
|
|
166
|
+
// on this machine, so offering it again as a personal learning repeats it.
|
|
167
|
+
if (note.type !== "project" && note.type !== "reference")
|
|
168
|
+
continue;
|
|
169
|
+
if (opts.offered?.has(offerKey(note)))
|
|
170
|
+
continue;
|
|
171
|
+
if (!readsAsLearning(note.body))
|
|
172
|
+
continue;
|
|
173
|
+
const title = memoryTitle(note);
|
|
174
|
+
const key = title.toLowerCase();
|
|
175
|
+
if (titles.has(key))
|
|
176
|
+
continue;
|
|
177
|
+
const body = memoryBody(note);
|
|
178
|
+
if (SECRETISH.test(body))
|
|
179
|
+
continue;
|
|
180
|
+
if (alreadySaid(known, title, body))
|
|
181
|
+
continue;
|
|
182
|
+
titles.add(key);
|
|
183
|
+
const touches = codeAnchors(repo, `${note.description}\n${note.body}`);
|
|
184
|
+
if (!touches.length)
|
|
185
|
+
continue;
|
|
186
|
+
team.push({ title, body, forTeam: true, touches, path: note.path, updated: note.updated });
|
|
187
|
+
}
|
|
188
|
+
return team;
|
|
189
|
+
}
|
|
190
|
+
/** A note is offered again only once it changes. */
|
|
191
|
+
function offerKey(note) {
|
|
192
|
+
return `${note.path}@${note.updated}`;
|
|
193
|
+
}
|
|
194
|
+
/** Where a repo remembers which memory notes init offered, on this machine. */
|
|
195
|
+
function offeredMark(repo) {
|
|
196
|
+
return join(ensureRepoHome(repo).place.dir, "memory-notes.json");
|
|
197
|
+
}
|
|
198
|
+
/** The memory notes init offered in this repo before, unchanged since. */
|
|
199
|
+
export function offeredBefore(repo) {
|
|
200
|
+
return new Set(readJson(offeredMark(repo))?.offered ?? []);
|
|
201
|
+
}
|
|
202
|
+
/** Each kept candidate as a learning: the team's in `.trail/learnings/`, the person's own in ~/.trail. */
|
|
203
|
+
export function saveMemoryCandidates(repo, kept, author = noteAuthor(repo), date = new Date().toISOString().slice(0, 10)) {
|
|
204
|
+
return kept.map((c) => writeNote(repo, {
|
|
205
|
+
title: c.title,
|
|
206
|
+
author,
|
|
207
|
+
date,
|
|
208
|
+
body: `${c.body.trim()}\n\n_From Claude Code's memory of this repo, last updated ${shortDate(c.updated)}._`,
|
|
209
|
+
touches: c.touches,
|
|
210
|
+
}, c.forTeam ? "repo" : "personal"));
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Save the candidates the person keeps and remember every one was offered.
|
|
214
|
+
* Without `keep` (no terminal to ask on), the team ones are kept: the
|
|
215
|
+
* person's own are already in their Claude's memory. `keep` resolving null
|
|
216
|
+
* means they cancelled: nothing is saved or marked, and the next init asks again.
|
|
217
|
+
*/
|
|
218
|
+
export async function finishMemoryRead(repo, candidates, keep) {
|
|
219
|
+
const chosen = candidates.length && keep ? await keep(candidates) : candidates.filter((c) => c.forTeam);
|
|
220
|
+
const kept = chosen ?? [];
|
|
221
|
+
const saved = kept.length ? saveMemoryCandidates(repo, kept) : [];
|
|
222
|
+
if (chosen !== null && candidates.length) {
|
|
223
|
+
const offered = offeredBefore(repo);
|
|
224
|
+
for (const c of candidates)
|
|
225
|
+
offered.add(offerKey(c));
|
|
226
|
+
writeJsonAtomic(offeredMark(repo), { at: Date.now(), offered: [...offered] }, true);
|
|
227
|
+
}
|
|
228
|
+
const team = candidates.filter((c) => c.forTeam);
|
|
229
|
+
track("cold_start", {
|
|
230
|
+
source: "memory",
|
|
231
|
+
outcome: chosen === null ? "cancelled" : candidates.length ? "found" : "none_found",
|
|
232
|
+
offered_bucket: countBucket(candidates.length),
|
|
233
|
+
picked_bucket: countBucket(saved.length),
|
|
234
|
+
team_offered_bucket: countBucket(team.length),
|
|
235
|
+
team_picked_bucket: countBucket(kept.filter((c) => c.forTeam).length),
|
|
236
|
+
}, { repo });
|
|
237
|
+
return { saved, kept, cancelled: chosen === null };
|
|
238
|
+
}
|
|
239
|
+
//# sourceMappingURL=memory-notes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-notes.js","sourceRoot":"","sources":["../../src/notes/memory-notes.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { type Note } from "./notes.js";
|
|
2
|
+
/** Past this many words a learning gets skimmed: a warning, never a refusal. */
|
|
3
|
+
export declare const LONG_NOTE_WORDS = 250;
|
|
4
|
+
export interface GateInput {
|
|
5
|
+
title: string;
|
|
6
|
+
body: string;
|
|
7
|
+
/** Kept in ~/.trail for this person, not the team: only the status and repeat checks apply. */
|
|
8
|
+
personal: boolean;
|
|
9
|
+
/** Repo files the note names that exist (from `mentionedFiles`), relative to the checkout. */
|
|
10
|
+
files: string[];
|
|
11
|
+
/** Whether the note names a function, type or other symbol that's in the repo's code. */
|
|
12
|
+
namesSymbol: boolean;
|
|
13
|
+
/** What it will touch, for the repeat check. */
|
|
14
|
+
touches: string[];
|
|
15
|
+
/** The id of the learning it says it replaces (`--replaces`). */
|
|
16
|
+
replaces?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface GateResult {
|
|
19
|
+
/** Why it can't be saved as it is, each with how to fix it. Empty: it passes. */
|
|
20
|
+
problems: string[];
|
|
21
|
+
warnings: string[];
|
|
22
|
+
}
|
|
23
|
+
/** The learning this one repeats: same files, and much the same title or text. */
|
|
24
|
+
export declare function repeatOf(input: Pick<GateInput, "title" | "body" | "touches" | "replaces" | "personal">, existing: Note[]): Note | null;
|
|
25
|
+
/** The checks, on a learning about to be saved. `existing`: the learnings already there. */
|
|
26
|
+
export declare function gateNote(input: GateInput, existing: Note[]): GateResult;
|
|
27
|
+
/** The names a note uses that might be symbols, most likely first: backticked, then code-shaped. At most `limit`. */
|
|
28
|
+
export declare function symbolCandidates(text: string, limit?: number): string[];
|
|
29
|
+
/**
|
|
30
|
+
* Whether any of `names` is in the repo's code: a whole-word `git grep` over
|
|
31
|
+
* tracked files, leaving out trail's own files and markdown, which would find
|
|
32
|
+
* the note's own words. Outside git, false: the files it names still count.
|
|
33
|
+
*/
|
|
34
|
+
export declare function namesRepoSymbol(repo: string, names: string[]): boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Of `files` (relative to the checkout at `repo`), the ones git tracks. A
|
|
37
|
+
* learning's `touches:` lists these, plus files the session itself edited:
|
|
38
|
+
* an untracked file that was already lying around (a token, a scratch file)
|
|
39
|
+
* is never what a learning is about. Outside git, every file that exists.
|
|
40
|
+
*/
|
|
41
|
+
export declare function trackedFiles(repo: string, files: string[]): Set<string>;
|
|
42
|
+
//# sourceMappingURL=note-gate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"note-gate.d.ts","sourceRoot":"","sources":["../../src/notes/note-gate.ts"],"names":[],"mappings":"AAgBA,OAAO,EAA4C,KAAK,IAAI,EAAE,MAAM,YAAY,CAAC;AAEjF,gFAAgF;AAChF,eAAO,MAAM,eAAe,MAAM,CAAC;AAEnC,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,+FAA+F;IAC/F,QAAQ,EAAE,OAAO,CAAC;IAClB,8FAA8F;IAC9F,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,yFAAyF;IACzF,WAAW,EAAE,OAAO,CAAC;IACrB,gDAAgD;IAChD,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,iEAAiE;IACjE,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,UAAU;IACzB,iFAAiF;IACjF,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAiED,kFAAkF;AAClF,wBAAgB,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC,SAAS,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,GAAG,UAAU,GAAG,UAAU,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,IAAI,GAAG,IAAI,CAYtI;AAED,4FAA4F;AAC5F,wBAAgB,QAAQ,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,UAAU,CAsCvE;AAMD,qHAAqH;AACrH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,SAAI,GAAG,MAAM,EAAE,CAUlE;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CActE;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC,MAAM,CAAC,CAQvE"}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What `trail note` checks before it saves a learning for the team: that a
|
|
3
|
+
* teammate's Claude would act differently for reading it. A learning that
|
|
4
|
+
* names no code never reaches anyone (learnings arrive when Claude opens the
|
|
5
|
+
* files they name), one about setting trail up isn't about the repo, status
|
|
6
|
+
* ("PR is open") is wrong by next week, a decision without its reason can't be
|
|
7
|
+
* weighed, and a second copy of a learning buries the first.
|
|
8
|
+
*
|
|
9
|
+
* Each check that fails says how to fix it, and the agent saves again. A long
|
|
10
|
+
* learning only gets a warning. `--anyway` saves past the checks, for when
|
|
11
|
+
* one of them is wrong.
|
|
12
|
+
*/
|
|
13
|
+
import { execFileSync } from "node:child_process";
|
|
14
|
+
import { existsSync } from "node:fs";
|
|
15
|
+
import { join } from "node:path";
|
|
16
|
+
import { trailOwnPath } from "./git-facts.js";
|
|
17
|
+
import { noteName, notePlace, SECTIONS, shortDate } from "./notes.js";
|
|
18
|
+
/** Past this many words a learning gets skimmed: a warning, never a refusal. */
|
|
19
|
+
export const LONG_NOTE_WORDS = 250;
|
|
20
|
+
/** Setting trail (or graft) up, said in a title or body. */
|
|
21
|
+
const SETUP_TALK = /\b(?:trail|graft)\b[^.\n]{0,40}\b(?:init|setup|set up|install(?:ed|ing)?|hooks?|wiring|wired)\b|\b(?:setting up|set up|install(?:ed|ing)?|wiring)\b[^.\n]{0,20}\b(?:trail|graft)\b/i;
|
|
22
|
+
/** Status: true when written, wrong a week later. */
|
|
23
|
+
const STATUS = [
|
|
24
|
+
/\b(?:PR|pull request|MR)\s*#?\d*\s+(?:is|was|got|has been|now)\s+(?:open|opened|merged|closed|approved|up|green|fixed|pushed)\b/i,
|
|
25
|
+
/\bnot (?:merged|pushed|released|published|deployed|reviewed) yet\b/i,
|
|
26
|
+
/\bpushed and not merged\b/i,
|
|
27
|
+
/\b(?:today|tomorrow|yesterday|tonight|this (?:morning|afternoon|evening|week))\b/i,
|
|
28
|
+
/\b(?:waiting on|blocked on|still open|awaiting review|in review)\b/i,
|
|
29
|
+
];
|
|
30
|
+
/** A reason: a cause, an error, a number, or a word that brings one. */
|
|
31
|
+
const WHY = /\b(?:because|since|so that|so|otherwise|or else|else|due to|caused?|causes|causing|means|meant|breaks?|broke|broken|fails?|failed|failing|errors?|exceptions?|crash(?:es|ed)?|hangs?|leaks?|slow(?:er)?|faster|cheaper|costs?|instead|to avoid|to keep|to stop|to prevent|in order to|unless|only if|rejects?|refuses?|blocks?|loses?|lost|drops?|wipes?|overwrites?|but|though|doubles?|twice|half|latency|memory|wrong|incorrect|missing|stale|races?|timeouts?|times out|deadlocks?|conflicts?|regress(?:es|ion)?|can't|cannot|won't|doesn't|don't|isn't|aren't|never)\b|\d|["“][^"”]{4,}["”]|→|=>/i;
|
|
32
|
+
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(" "));
|
|
33
|
+
function words(s) {
|
|
34
|
+
return new Set(s.toLowerCase().split(/[^a-z0-9_]+/).filter((t) => t.length >= 3 && !STOP.has(t)));
|
|
35
|
+
}
|
|
36
|
+
function jaccard(a, b) {
|
|
37
|
+
if (!a.size || !b.size)
|
|
38
|
+
return 0;
|
|
39
|
+
let both = 0;
|
|
40
|
+
for (const t of a)
|
|
41
|
+
if (b.has(t))
|
|
42
|
+
both++;
|
|
43
|
+
return both / (a.size + b.size - both);
|
|
44
|
+
}
|
|
45
|
+
/** The body without fenced code, which quotes errors and commands rather than saying status. */
|
|
46
|
+
function prose(body) {
|
|
47
|
+
return body.replace(/```[\s\S]*?```/g, "");
|
|
48
|
+
}
|
|
49
|
+
/** The lines a reason belongs on: under Decided and Tried and ruled out, or the whole body when it has neither. */
|
|
50
|
+
function decisionLines(body) {
|
|
51
|
+
const lines = prose(body).split(/\r?\n/);
|
|
52
|
+
const wanted = new Set([SECTIONS[0].heading.toLowerCase(), SECTIONS[1].heading.toLowerCase()]);
|
|
53
|
+
const out = [];
|
|
54
|
+
let section = null;
|
|
55
|
+
let sawSection = false;
|
|
56
|
+
for (const raw of lines) {
|
|
57
|
+
const l = raw.trim();
|
|
58
|
+
const h = /^#{1,6}\s+(.*)$/.exec(l);
|
|
59
|
+
if (h) {
|
|
60
|
+
section = h[1].trim().toLowerCase();
|
|
61
|
+
if (wanted.has(section))
|
|
62
|
+
sawSection = true;
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
if (l && section && wanted.has(section))
|
|
66
|
+
out.push(l);
|
|
67
|
+
}
|
|
68
|
+
if (sawSection)
|
|
69
|
+
return out;
|
|
70
|
+
return lines.map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
|
|
71
|
+
}
|
|
72
|
+
function clip(s, n = 70) {
|
|
73
|
+
const t = s.trim().replace(/^[-*]\s+/, "");
|
|
74
|
+
return t.length > n ? `${t.slice(0, n - 1).trimEnd()}…` : t;
|
|
75
|
+
}
|
|
76
|
+
/** The learning this one repeats: same files, and much the same title or text. */
|
|
77
|
+
export function repeatOf(input, existing) {
|
|
78
|
+
const files = new Set(input.touches.map((t) => t.split("#")[0]));
|
|
79
|
+
const title = words(input.title);
|
|
80
|
+
const body = words(input.body);
|
|
81
|
+
for (const n of existing) {
|
|
82
|
+
if (input.replaces && n.id === input.replaces)
|
|
83
|
+
continue;
|
|
84
|
+
const shared = n.touches.some((t) => files.has(t.split("#")[0]));
|
|
85
|
+
const sameTitle = jaccard(title, words(n.title));
|
|
86
|
+
const sameBody = jaccard(body, words(n.body));
|
|
87
|
+
if (shared ? sameTitle >= 0.5 || sameBody >= 0.5 : (input.personal || !files.size) && sameTitle >= 0.6)
|
|
88
|
+
return n;
|
|
89
|
+
}
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
/** The checks, on a learning about to be saved. `existing`: the learnings already there. */
|
|
93
|
+
export function gateNote(input, existing) {
|
|
94
|
+
const problems = [];
|
|
95
|
+
const warnings = [];
|
|
96
|
+
const text = `${input.title}\n${prose(input.body)}`;
|
|
97
|
+
if (!input.personal) {
|
|
98
|
+
const code = input.files.filter((f) => !trailOwnPath(f));
|
|
99
|
+
const onlyTrail = input.files.length > 0 && code.length === 0;
|
|
100
|
+
if (!code.length && !input.namesSymbol) {
|
|
101
|
+
problems.push(SETUP_TALK.test(text) || onlyTrail
|
|
102
|
+
? "It reads as a note about setting trail up, not this repo's code. Skip it, or keep it with --personal if it's about your machine."
|
|
103
|
+
: "It names no file or function in this repo. Name what it's about (`src/x.ts`, `parseConfig`), so a teammate's Claude gets it when it opens that file.");
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
for (const line of text.split(/\r?\n/)) {
|
|
107
|
+
if (STATUS.some((re) => re.test(line))) {
|
|
108
|
+
problems.push(`"${clip(line)}" is status: true today, wrong next week. Keep what stays true (the cause, the rule, the why) and put status in the PR.`);
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
if (!input.personal && !decisionLines(input.body).some((l) => WHY.test(l))) {
|
|
113
|
+
problems.push('No line says why. Give each decision its reason: the cause, the error it hit, or the number that settled it ("because…", "otherwise…", "fails with…").');
|
|
114
|
+
}
|
|
115
|
+
const twin = repeatOf(input, existing);
|
|
116
|
+
if (twin) {
|
|
117
|
+
problems.push(`It repeats ${notePlace(twin)} ("${clip(twin.title, 50)}"${twin.author ? `, ${twin.author}` : ""}, ${shortDate(twin.date)}). If it updates that one, add --replaces ${noteName(twin)}: the old file stays as the record and yours is read instead. If it's different, say how in the title.`);
|
|
118
|
+
}
|
|
119
|
+
const count = input.body.split(/\s+/).filter(Boolean).length;
|
|
120
|
+
if (count > LONG_NOTE_WORDS)
|
|
121
|
+
warnings.push(`long: ${count} words. Long learnings get skimmed; cut it to the fact and the why.`);
|
|
122
|
+
return { problems, warnings };
|
|
123
|
+
}
|
|
124
|
+
/** `parseConfig`, `Client.Do`, `default_retry_max`, `retry()`: words in a note shaped like code. */
|
|
125
|
+
const BACKTICKED = /`([A-Za-z_$][\w$]*(?:(?:\.|::|#)[A-Za-z_$][\w$]*)*)(?:\(\))?`/g;
|
|
126
|
+
const CODE_SHAPED = /\b([a-z]+[A-Z][\w]*|[A-Z][a-z0-9]+[A-Z][\w]*|[a-z][a-z0-9]*_[a-z0-9_]+|[A-Za-z_]\w*(?=\(\)))\b/g;
|
|
127
|
+
/** The names a note uses that might be symbols, most likely first: backticked, then code-shaped. At most `limit`. */
|
|
128
|
+
export function symbolCandidates(text, limit = 8) {
|
|
129
|
+
const out = [];
|
|
130
|
+
const add = (s) => {
|
|
131
|
+
const name = s.split(/\.|::|#/).pop();
|
|
132
|
+
if (name.length < 3 || /\.[A-Za-z]{1,5}$/.test(s) || out.includes(name))
|
|
133
|
+
return;
|
|
134
|
+
out.push(name);
|
|
135
|
+
};
|
|
136
|
+
for (const m of text.matchAll(BACKTICKED))
|
|
137
|
+
add(m[1]);
|
|
138
|
+
for (const m of text.matchAll(CODE_SHAPED))
|
|
139
|
+
add(m[1]);
|
|
140
|
+
return out.slice(0, limit);
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Whether any of `names` is in the repo's code: a whole-word `git grep` over
|
|
144
|
+
* tracked files, leaving out trail's own files and markdown, which would find
|
|
145
|
+
* the note's own words. Outside git, false: the files it names still count.
|
|
146
|
+
*/
|
|
147
|
+
export function namesRepoSymbol(repo, names) {
|
|
148
|
+
if (!names.length)
|
|
149
|
+
return false;
|
|
150
|
+
for (const name of names) {
|
|
151
|
+
try {
|
|
152
|
+
execFileSync("git", ["grep", "-q", "-w", "-F", "-e", name, "--", ".", ":(exclude).trail", ":(exclude).claude", ":(exclude)*.md"], {
|
|
153
|
+
cwd: repo,
|
|
154
|
+
stdio: "ignore",
|
|
155
|
+
});
|
|
156
|
+
return true;
|
|
157
|
+
}
|
|
158
|
+
catch {
|
|
159
|
+
/* not found, or not a repo */
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Of `files` (relative to the checkout at `repo`), the ones git tracks. A
|
|
166
|
+
* learning's `touches:` lists these, plus files the session itself edited:
|
|
167
|
+
* an untracked file that was already lying around (a token, a scratch file)
|
|
168
|
+
* is never what a learning is about. Outside git, every file that exists.
|
|
169
|
+
*/
|
|
170
|
+
export function trackedFiles(repo, files) {
|
|
171
|
+
if (!files.length)
|
|
172
|
+
return new Set();
|
|
173
|
+
try {
|
|
174
|
+
const out = execFileSync("git", ["ls-files", "-z", "--", ...files], { cwd: repo, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
|
|
175
|
+
return new Set(out.split("\0").filter(Boolean));
|
|
176
|
+
}
|
|
177
|
+
catch {
|
|
178
|
+
return new Set(files.filter((f) => existsSync(join(repo, f))));
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
//# sourceMappingURL=note-gate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"note-gate.js","sourceRoot":"","sources":["../../src/notes/note-gate.ts"],"names":[],"mappings":"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"}
|