@nanonets/graft 0.22.1 → 0.23.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/ask/ask.d.ts +0 -3
- package/dist/ask/ask.d.ts.map +1 -1
- package/dist/ask/ask.js +1 -3
- package/dist/ask/ask.js.map +1 -1
- package/dist/brand.d.ts.map +1 -1
- package/dist/brand.js +4 -1
- package/dist/brand.js.map +1 -1
- package/dist/claude/format.d.ts +1 -9
- package/dist/claude/format.d.ts.map +1 -1
- package/dist/claude/format.js +2 -17
- package/dist/claude/format.js.map +1 -1
- package/dist/claude/hook-layers.d.ts.map +1 -1
- package/dist/claude/hook-layers.js +5 -3
- package/dist/claude/hook-layers.js.map +1 -1
- package/dist/claude/hooks.d.ts +6 -0
- package/dist/claude/hooks.d.ts.map +1 -1
- package/dist/claude/hooks.js +101 -14
- package/dist/claude/hooks.js.map +1 -1
- package/dist/claude/init.d.ts +38 -7
- package/dist/claude/init.d.ts.map +1 -1
- package/dist/claude/init.js +172 -33
- package/dist/claude/init.js.map +1 -1
- package/dist/claude/settings-merge.d.ts +23 -0
- package/dist/claude/settings-merge.d.ts.map +1 -1
- package/dist/claude/settings-merge.js +103 -7
- package/dist/claude/settings-merge.js.map +1 -1
- package/dist/claude/skill-template.d.ts +4 -3
- package/dist/claude/skill-template.d.ts.map +1 -1
- package/dist/claude/skill-template.js +7 -3
- package/dist/claude/skill-template.js.map +1 -1
- package/dist/claude/state.d.ts +1 -1
- package/dist/claude/state.d.ts.map +1 -1
- package/dist/cli.js +43 -35
- package/dist/cli.js.map +1 -1
- package/dist/context/map-dir.d.ts +13 -0
- package/dist/context/map-dir.d.ts.map +1 -0
- package/dist/context/map-dir.js +67 -0
- package/dist/context/map-dir.js.map +1 -0
- package/dist/context/node-file.d.ts +4 -3
- package/dist/context/node-file.d.ts.map +1 -1
- package/dist/context/node-file.js +18 -4
- package/dist/context/node-file.js.map +1 -1
- package/dist/hosts/claude-global.d.ts.map +1 -1
- package/dist/hosts/claude-global.js +31 -11
- package/dist/hosts/claude-global.js.map +1 -1
- package/dist/hosts/config-write.js +1 -1
- package/dist/hosts/config-write.js.map +1 -1
- package/dist/hosts/retract.d.ts.map +1 -1
- package/dist/hosts/retract.js +15 -6
- package/dist/hosts/retract.js.map +1 -1
- package/dist/notes/branches.d.ts +18 -1
- package/dist/notes/branches.d.ts.map +1 -1
- package/dist/notes/branches.js +73 -7
- package/dist/notes/branches.js.map +1 -1
- package/dist/notes/edit-overlap.d.ts +62 -0
- package/dist/notes/edit-overlap.d.ts.map +1 -0
- package/dist/notes/edit-overlap.js +202 -0
- package/dist/notes/edit-overlap.js.map +1 -0
- package/dist/notes/notes.d.ts +6 -0
- package/dist/notes/notes.d.ts.map +1 -1
- package/dist/notes/notes.js +12 -0
- package/dist/notes/notes.js.map +1 -1
- package/dist/notes/repo-trail.d.ts +3 -1
- package/dist/notes/repo-trail.d.ts.map +1 -1
- package/dist/notes/repo-trail.js +40 -3
- package/dist/notes/repo-trail.js.map +1 -1
- package/dist/notes/session-cost.d.ts +16 -4
- package/dist/notes/session-cost.d.ts.map +1 -1
- package/dist/notes/session-cost.js +120 -11
- package/dist/notes/session-cost.js.map +1 -1
- package/dist/upkeep-run.d.ts.map +1 -1
- package/dist/upkeep-run.js +4 -2
- package/dist/upkeep-run.js.map +1 -1
- package/dist/upkeep.js +2 -2
- package/dist/upkeep.js.map +1 -1
- package/dist/util/state.d.ts.map +1 -1
- package/dist/util/state.js +2 -1
- package/dist/util/state.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -48,7 +48,7 @@ import { normalizePathPrefix } from "./util/paths.js";
|
|
|
48
48
|
import { latestSession, formatSessionStats, sessionInputRate } from "./claude/session-metrics.js";
|
|
49
49
|
import { listSessionIds, readSession, sessionDir } from "./claude/state.js";
|
|
50
50
|
import { costLabel, listNotes, noteName, notePlace, noteTargets, readingTokens, savedByNote, commitLines, PERSONAL_SAVED_LINE, PR_SPEEDUP, SECTIONS, tokensWorthSaying, sectionLead, shortDate, tokensLabel, writeNote, mentionedFiles } from "./notes/notes.js";
|
|
51
|
-
import { currentSessionCost } from "./notes/session-cost.js";
|
|
51
|
+
import { aboutTerms, currentSessionCost } from "./notes/session-cost.js";
|
|
52
52
|
import { beginPastRead, finishPastRead } from "./notes/cold-start.js";
|
|
53
53
|
import { beginReviewRead, finishReviewRead } from "./notes/pr-reviews.js";
|
|
54
54
|
import { currentBranch, noteAuthor, teammatesOn } from "./notes/git-facts.js";
|
|
@@ -165,7 +165,7 @@ function queryRoot(dir) {
|
|
|
165
165
|
return resolve(dir);
|
|
166
166
|
const { root, levels } = nearestGraftRoot(process.cwd(), program.opts().dir);
|
|
167
167
|
if (levels > 0)
|
|
168
|
-
console.error(`${tag()} no
|
|
168
|
+
console.error(`${tag()} no code map here — answering from ${contextDirFor(root, program.opts().dir)}`);
|
|
169
169
|
return root;
|
|
170
170
|
}
|
|
171
171
|
/**
|
|
@@ -292,10 +292,10 @@ program
|
|
|
292
292
|
// Hidden: spawned detached by maybeRefreshBranches.
|
|
293
293
|
program
|
|
294
294
|
.command("_trail-branches", { hidden: true })
|
|
295
|
-
.description("internal: fetch, then note which files teammates'
|
|
295
|
+
.description("internal: fetch, then note which files teammates' open branches change and the learnings they carry")
|
|
296
296
|
.argument("[dir]", "target repo directory", ".")
|
|
297
297
|
.action((dir) => {
|
|
298
|
-
refreshBranches(resolve(dir));
|
|
298
|
+
refreshBranches(resolve(dir), { prs: true });
|
|
299
299
|
});
|
|
300
300
|
program
|
|
301
301
|
.command("_trail-claim", { hidden: true })
|
|
@@ -380,7 +380,7 @@ function moveHereToTrail(dir) {
|
|
|
380
380
|
}
|
|
381
381
|
grouped(program.command("build"), GROUP.setup)
|
|
382
382
|
.description(TRAIL
|
|
383
|
-
? "Rebuild the code map in
|
|
383
|
+
? "Rebuild the code map in .trail/cache/ ($0, no key). --check fails if it's stale; --deep adds LLM summaries."
|
|
384
384
|
: "Build graft/ from your code — wiring graph + per-file cards ($0, no key). " +
|
|
385
385
|
"Add --deep for the LLM concept map + per-symbol summaries/crux.")
|
|
386
386
|
.argument("[dir]", "repository root", ".")
|
|
@@ -610,11 +610,11 @@ function pointerFile(pointer) {
|
|
|
610
610
|
return pointer.replace(/:L\d+(-L?\d+)?$/, "");
|
|
611
611
|
}
|
|
612
612
|
/**
|
|
613
|
-
* After `ask`, under trail: which shown learnings are a teammate's,
|
|
614
|
-
* teammates' pushed branches change the files the answer points into, and the
|
|
613
|
+
* After `ask`, under trail: which shown learnings are a teammate's, and the
|
|
615
614
|
* shown learnings recorded as a use, which is what the team page counts as
|
|
616
615
|
* reuse. Then the background upkeep that keeps branches and the workspace
|
|
617
|
-
* current. Spawns no git itself.
|
|
616
|
+
* current. Spawns no git itself. Teammates' branches come up after an edit
|
|
617
|
+
* instead, once there's a function to compare (notes/edit-overlap.ts).
|
|
618
618
|
*/
|
|
619
619
|
function afterAsk(r, repo) {
|
|
620
620
|
if (!r.notesChecked)
|
|
@@ -623,12 +623,6 @@ function afterAsk(r, repo) {
|
|
|
623
623
|
maybeRefreshBranches(repo);
|
|
624
624
|
const me = noteAuthor(repo);
|
|
625
625
|
const files = [...new Set(r.hits.map((h) => pointerFile(h.pointer)))];
|
|
626
|
-
const overlaps = overlapsWith(repo, files, me).slice(0, 2);
|
|
627
|
-
if (overlaps.length) {
|
|
628
|
-
r.overlaps = overlaps.map((o) => formatOverlap(o));
|
|
629
|
-
if (!process.stdout.isTTY)
|
|
630
|
-
r.overlaps.push(`${tag()} Start your reply with the overlap line${overlaps.length === 1 ? "" : "s"} above, word for word, so the user knows.`);
|
|
631
|
-
}
|
|
632
626
|
const shown = r.notes ?? [];
|
|
633
627
|
if (shown.length) {
|
|
634
628
|
for (const h of shown)
|
|
@@ -750,7 +744,7 @@ async function runCheckCommand(dirArg, opts, label) {
|
|
|
750
744
|
console.log(JSON.stringify({ context: r, graph: g.missing ? null : g }, null, 2));
|
|
751
745
|
}
|
|
752
746
|
else if (bothMissing) {
|
|
753
|
-
console.log(`${label}: NO GRAPH\n\nNo
|
|
747
|
+
console.log(`${label}: NO GRAPH\n\nNo code map found. Run \`${cmd("graft build")}\` first.`);
|
|
754
748
|
}
|
|
755
749
|
else {
|
|
756
750
|
if (r.missing) {
|
|
@@ -1192,9 +1186,11 @@ async function runNoteCommand(repo, opts) {
|
|
|
1192
1186
|
};
|
|
1193
1187
|
const minutes = wholeNumber(opts.minutes, "--minutes");
|
|
1194
1188
|
const tokens = wholeNumber(opts.tokens, "--tokens");
|
|
1195
|
-
// What the session spent, from the agent's own transcript when there is one
|
|
1196
|
-
//
|
|
1197
|
-
|
|
1189
|
+
// What the session spent, from the agent's own transcript when there is one,
|
|
1190
|
+
// counted from where the work the note names first came up; the flags win,
|
|
1191
|
+
// since only the agent knows for sure where its task began.
|
|
1192
|
+
const named = [...(opts.touches?.split(",").map((t) => t.trim()).filter(Boolean) ?? []), ...mentionedFiles(repo, body)];
|
|
1193
|
+
const spent = currentSessionCost(repo, undefined, Date.now(), aboutTerms(body, named));
|
|
1198
1194
|
const cost = minutes !== undefined || tokens !== undefined || spent
|
|
1199
1195
|
? { minutes: minutes ?? spent?.minutes, tokens: tokens ?? spent?.tokens }
|
|
1200
1196
|
: undefined;
|
|
@@ -1354,6 +1350,20 @@ async function runInitCommand(dir, opts) {
|
|
|
1354
1350
|
}
|
|
1355
1351
|
const wantClaude = ids.includes("claude");
|
|
1356
1352
|
const cliPath = fileURLToPath(import.meta.url);
|
|
1353
|
+
// Under trail, each repo gets its `.trail/learnings/`, committed with the
|
|
1354
|
+
// code, and its folder in ~/.trail for personal learnings and corrections.
|
|
1355
|
+
// First, before the reads below send their first event: that makes the
|
|
1356
|
+
// repo one on trail, so the event's repo id lands in `.trail/cache/` and
|
|
1357
|
+
// not in a `graft/` that nothing ignores.
|
|
1358
|
+
const notesHome = new Map();
|
|
1359
|
+
if (TRAIL)
|
|
1360
|
+
for (const target of targets) {
|
|
1361
|
+
const { place } = ensureRepoHome(target);
|
|
1362
|
+
const created = place.git ? ensureRepoTrail(place.checkout) : false;
|
|
1363
|
+
notesHome.set(target, { created, dir: place.git ? place.checkout : place.dir });
|
|
1364
|
+
if (place.git)
|
|
1365
|
+
maybeRefreshBranches(place.checkout);
|
|
1366
|
+
}
|
|
1357
1367
|
// Under trail, with Claude Code picked: what the person kept telling Claude
|
|
1358
1368
|
// in this repo's past sessions, and what reviewers kept flagging on its
|
|
1359
1369
|
// merged PRs, read while the rest of init runs and saved as learnings at
|
|
@@ -1369,17 +1379,6 @@ async function runInitCommand(dir, opts) {
|
|
|
1369
1379
|
// Today's output, file by file, behind --verbose. Everything else gets one
|
|
1370
1380
|
// line per step: the graph, then one per agent.
|
|
1371
1381
|
const verbose = opts.verbose === true;
|
|
1372
|
-
// Under trail, each repo gets its `.trail/learnings/`, committed with the
|
|
1373
|
-
// code, and its folder in ~/.trail for personal learnings and corrections.
|
|
1374
|
-
const notesHome = new Map();
|
|
1375
|
-
if (TRAIL)
|
|
1376
|
-
for (const target of targets) {
|
|
1377
|
-
const { place } = ensureRepoHome(target);
|
|
1378
|
-
const created = place.git ? ensureRepoTrail(place.checkout) : false;
|
|
1379
|
-
notesHome.set(target, { created, dir: place.git ? place.checkout : place.dir });
|
|
1380
|
-
if (place.git)
|
|
1381
|
-
maybeRefreshBranches(place.checkout);
|
|
1382
|
-
}
|
|
1383
1382
|
const reports = [];
|
|
1384
1383
|
for (const target of targets) {
|
|
1385
1384
|
if (verbose && target !== repo)
|
|
@@ -1523,8 +1522,12 @@ async function runInitCommand(dir, opts) {
|
|
|
1523
1522
|
for (const w of selectedWrites(plan, ids)) {
|
|
1524
1523
|
if (w.scope !== "repo")
|
|
1525
1524
|
continue;
|
|
1526
|
-
const
|
|
1527
|
-
|
|
1525
|
+
const rel = shown(repo, w.path);
|
|
1526
|
+
// trail's Claude Code setup shares one file in .claude/; the rest there is personal.
|
|
1527
|
+
if (TRAIL && rel.startsWith(".claude/") && rel !== ".claude/settings.json")
|
|
1528
|
+
continue;
|
|
1529
|
+
const parts = rel.split("/");
|
|
1530
|
+
const top = TRAIL && rel === ".claude/settings.json" ? rel : parts.length > 1 ? `${parts[0]}/` : parts[0];
|
|
1528
1531
|
if (!tops.includes(top))
|
|
1529
1532
|
tops.push(top);
|
|
1530
1533
|
}
|
|
@@ -1538,8 +1541,9 @@ async function runInitCommand(dir, opts) {
|
|
|
1538
1541
|
});
|
|
1539
1542
|
tops.splice(0, tops.length, ...changedTops);
|
|
1540
1543
|
if (tops.length)
|
|
1541
|
-
console.error(
|
|
1542
|
-
(
|
|
1544
|
+
console.error(TRAIL
|
|
1545
|
+
? `· commit ${tops.slice(0, 5).join(" and ")}${tops.length > 5 ? ` +${tops.length - 5} more` : ""} once — after that, teammates' Claude reads your learnings even before they install trail`
|
|
1546
|
+
: `· commit ${tops.slice(0, 5).join(" ")}${tops.length > 5 ? ` +${tops.length - 5} more` : ""} to share it — graft/ stays local and git-ignored`);
|
|
1543
1547
|
}
|
|
1544
1548
|
// One epilogue for the whole run. A workspace parent holds no nodes of its
|
|
1545
1549
|
// own, so the totals come from the children — the graph the user actually got.
|
|
@@ -1590,8 +1594,12 @@ function wireTarget(repo, ids, ctx) {
|
|
|
1590
1594
|
say(`✓ wrote ${res.settingsPath}`);
|
|
1591
1595
|
for (const s of res.shims)
|
|
1592
1596
|
say(`✓ wrote ${s}`);
|
|
1593
|
-
|
|
1594
|
-
|
|
1597
|
+
if (res.skill)
|
|
1598
|
+
say(`✓ wrote ${res.skill}`);
|
|
1599
|
+
if (!res.mcp) {
|
|
1600
|
+
// trail registers no server for Claude Code: the hooks and the `trail` command cover it.
|
|
1601
|
+
}
|
|
1602
|
+
else if (res.mcp.action === "skipped-unparseable")
|
|
1595
1603
|
say(`⚠ .mcp.json: ${res.mcp.path} left unchanged (not valid JSON) — add the graft server manually`);
|
|
1596
1604
|
else if (res.mcp.action === "unchanged")
|
|
1597
1605
|
say(`· mcp claude: ${res.mcp.path} (already registered)`);
|