@nanonets/graft 0.8.0 → 0.8.1
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 +38 -8
- package/dist/claude/hooks.d.ts +15 -0
- package/dist/claude/hooks.d.ts.map +1 -1
- package/dist/claude/hooks.js +52 -3
- package/dist/claude/hooks.js.map +1 -1
- package/dist/claude/init.d.ts +17 -0
- package/dist/claude/init.d.ts.map +1 -1
- package/dist/claude/init.js +45 -19
- package/dist/claude/init.js.map +1 -1
- package/dist/claude/settings-merge.d.ts.map +1 -1
- package/dist/claude/settings-merge.js +9 -1
- package/dist/claude/settings-merge.js.map +1 -1
- package/dist/claude/skill-template.d.ts.map +1 -1
- package/dist/claude/skill-template.js +11 -3
- package/dist/claude/skill-template.js.map +1 -1
- package/dist/claude/state.d.ts +2 -20
- package/dist/claude/state.d.ts.map +1 -1
- package/dist/claude/state.js +9 -72
- package/dist/claude/state.js.map +1 -1
- package/dist/cli-picker.d.ts +60 -0
- package/dist/cli-picker.d.ts.map +1 -0
- package/dist/cli-picker.js +268 -0
- package/dist/cli-picker.js.map +1 -0
- package/dist/cli.js +99 -10
- package/dist/cli.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/build.d.ts +13 -2
- package/dist/graph/build.d.ts.map +1 -1
- package/dist/graph/build.js +93 -19
- package/dist/graph/build.js.map +1 -1
- package/dist/graph/extract-cache.d.ts +96 -0
- package/dist/graph/extract-cache.d.ts.map +1 -0
- package/dist/graph/extract-cache.js +199 -0
- package/dist/graph/extract-cache.js.map +1 -0
- package/dist/graph/fingerprint.d.ts +70 -0
- package/dist/graph/fingerprint.d.ts.map +1 -0
- package/dist/graph/fingerprint.js +147 -0
- package/dist/graph/fingerprint.js.map +1 -0
- package/dist/graph/load.d.ts +11 -0
- package/dist/graph/load.d.ts.map +1 -1
- package/dist/graph/load.js +14 -0
- package/dist/graph/load.js.map +1 -1
- package/dist/graph/refresh.d.ts +49 -0
- package/dist/graph/refresh.d.ts.map +1 -0
- package/dist/graph/refresh.js +202 -0
- package/dist/graph/refresh.js.map +1 -0
- package/dist/graph/source-files.d.ts +18 -0
- package/dist/graph/source-files.d.ts.map +1 -0
- package/dist/graph/source-files.js +36 -0
- package/dist/graph/source-files.js.map +1 -0
- package/dist/hosts/codex-hooks.d.ts +8 -0
- package/dist/hosts/codex-hooks.d.ts.map +1 -1
- package/dist/hosts/codex-hooks.js +27 -4
- package/dist/hosts/codex-hooks.js.map +1 -1
- package/dist/hosts/init.d.ts +2 -0
- package/dist/hosts/init.d.ts.map +1 -1
- package/dist/hosts/init.js +5 -2
- package/dist/hosts/init.js.map +1 -1
- package/dist/hosts/mcp-config.d.ts +18 -0
- package/dist/hosts/mcp-config.d.ts.map +1 -1
- package/dist/hosts/mcp-config.js +31 -7
- package/dist/hosts/mcp-config.js.map +1 -1
- package/dist/hosts/plan.d.ts +32 -0
- package/dist/hosts/plan.d.ts.map +1 -0
- package/dist/hosts/plan.js +67 -0
- package/dist/hosts/plan.js.map +1 -0
- package/dist/hosts/registry.d.ts.map +1 -1
- package/dist/hosts/registry.js +9 -0
- package/dist/hosts/registry.js.map +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +5 -2
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tools.d.ts +2 -2
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +106 -90
- package/dist/mcp/tools.js.map +1 -1
- package/dist/util/state.d.ts +45 -0
- package/dist/util/state.d.ts.map +1 -0
- package/dist/util/state.js +121 -0
- package/dist/util/state.js.map +1 -0
- package/package.json +1 -1
package/dist/claude/state.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"state.js","sourceRoot":"","sources":["../../src/claude/state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"state.js","sourceRoot":"","sources":["../../src/claude/state.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEvE,OAAO,EACL,aAAa,EACb,WAAW,EACX,aAAa,EACb,aAAa,EACb,QAAQ,EACR,UAAU,EACV,UAAU,EACV,SAAS,EACT,WAAW,EACX,eAAe,EACf,UAAU,GACX,MAAM,kBAAkB,CAAC;AAe1B,SAAS,YAAY;IACnB,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,aAAa,EAAE,EAAE,EAAE,UAAU,EAAE,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,gBAAgB,EAAE,EAAE,EAAE,CAAC;AACrH,CAAC;AAED,SAAS,WAAW,CAAC,CAAS,EAAE,EAAU,IAAY,OAAO,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;AAE1G,MAAM,UAAU,WAAW,CAAC,CAAS,EAAE,EAAU;IAC/C,OAAO,QAAQ,CAAe,WAAW,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,YAAY,EAAE,CAAC;AACtE,CAAC;AACD,MAAM,UAAU,YAAY,CAAC,CAAS,EAAE,EAAU,EAAE,CAAe;IACjE,eAAe,CAAC,WAAW,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;AACzC,CAAC"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { HostPlan, PlannedWrite } from './hosts/plan.js';
|
|
2
|
+
/** `/Users/me/.codex/x` → `~/.codex/x`, for display only. */
|
|
3
|
+
export declare function tilde(path: string, home: string): string;
|
|
4
|
+
/**
|
|
5
|
+
* One-line summary of what selecting a host writes: repo-relative paths, then
|
|
6
|
+
* a count for anything landing outside the repo — those are the writes users
|
|
7
|
+
* can't see in `git status`, so they get named explicitly.
|
|
8
|
+
*/
|
|
9
|
+
export declare function describeWrites(writes: PlannedWrite[], repo: string, home: string, maxShown?: number): string;
|
|
10
|
+
export interface PickerRow {
|
|
11
|
+
id: string;
|
|
12
|
+
detected: boolean;
|
|
13
|
+
summary: string;
|
|
14
|
+
/** True when selecting this host writes outside the repo. */
|
|
15
|
+
hasGlobal: boolean;
|
|
16
|
+
}
|
|
17
|
+
export interface PickerState {
|
|
18
|
+
rows: PickerRow[];
|
|
19
|
+
cursor: number;
|
|
20
|
+
checked: ReadonlySet<string>;
|
|
21
|
+
done: boolean;
|
|
22
|
+
aborted: boolean;
|
|
23
|
+
}
|
|
24
|
+
/** Claude Code starts checked — it's the deep integration — everything else off. */
|
|
25
|
+
export declare function initialPickerState(plan: HostPlan[], repo: string, home: string): PickerState;
|
|
26
|
+
export type PickerKey = 'up' | 'down' | 'space' | 'all' | 'enter' | 'abort';
|
|
27
|
+
export declare const KEY_UP = "\u001B[A";
|
|
28
|
+
export declare const KEY_DOWN = "\u001B[B";
|
|
29
|
+
export declare const KEY_ESC = "\u001B";
|
|
30
|
+
export declare const KEY_CTRL_C = "\u0003";
|
|
31
|
+
/** A single keypress → the key we act on, or null to ignore. */
|
|
32
|
+
export declare function keyOf(chunk: string): PickerKey | null;
|
|
33
|
+
/**
|
|
34
|
+
* Split a raw stdin chunk into keypresses. A terminal is free to batch bytes —
|
|
35
|
+
* held keys, pasted input, or a pty replaying a script all arrive as one chunk —
|
|
36
|
+
* so a chunk is a sequence, never a single key. CSI sequences (ESC '[' final)
|
|
37
|
+
* are consumed whole so an arrow key never reads as a bare ESC (i.e. abort).
|
|
38
|
+
*/
|
|
39
|
+
export declare function keysOf(chunk: string): PickerKey[];
|
|
40
|
+
export declare function reducePicker(state: PickerState, key: PickerKey): PickerState;
|
|
41
|
+
export declare function renderPicker(state: PickerState, tty?: boolean): string;
|
|
42
|
+
/** Ids in plan order, so output ordering never depends on toggle order. */
|
|
43
|
+
export declare function pickedIds(state: PickerState): string[];
|
|
44
|
+
/**
|
|
45
|
+
* Drive the picker on a real terminal. Resolves the chosen ids, or null if the
|
|
46
|
+
* user cancelled — in which case the caller must write nothing.
|
|
47
|
+
*/
|
|
48
|
+
export declare function runPicker(plan: HostPlan[], repo: string, home: string): Promise<string[] | null>;
|
|
49
|
+
/**
|
|
50
|
+
* Shown when there's no TTY to prompt on and no flag saying what to wire.
|
|
51
|
+
* Writing nothing is deliberate: a scripted run shouldn't get files for every
|
|
52
|
+
* agent the machine happens to have installed.
|
|
53
|
+
*/
|
|
54
|
+
export declare function formatNonInteractiveHelp(detectedIds: string[]): string;
|
|
55
|
+
/**
|
|
56
|
+
* `--dry-run` output: every path init would touch, repo writes first, then a
|
|
57
|
+
* separate section for anything outside the repo.
|
|
58
|
+
*/
|
|
59
|
+
export declare function formatPlan(plan: HostPlan[], ids: string[], repo: string, home: string, tty?: boolean): string;
|
|
60
|
+
//# sourceMappingURL=cli-picker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-picker.d.ts","sourceRoot":"","sources":["../src/cli-picker.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAM9D,6DAA6D;AAC7D,wBAAgB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAExD;AAWD;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,YAAY,EAAE,EACtB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,QAAQ,SAAI,GACX,MAAM,CAiBR;AAED,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,6DAA6D;IAC7D,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,SAAS,EAAE,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC7B,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,oFAAoF;AACpF,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,WAAW,CAa5F;AAED,MAAM,MAAM,SAAS,GAAG,IAAI,GAAG,MAAM,GAAG,OAAO,GAAG,KAAK,GAAG,OAAO,GAAG,OAAO,CAAC;AAE5E,eAAO,MAAM,MAAM,aAAW,CAAC;AAC/B,eAAO,MAAM,QAAQ,aAAW,CAAC;AACjC,eAAO,MAAM,OAAO,WAAS,CAAC;AAC9B,eAAO,MAAM,UAAU,WAAS,CAAC;AAEjC,gEAAgE;AAChE,wBAAgB,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAUrD;AAED;;;;;GAKG;AACH,wBAAgB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,CAkBjD;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,WAAW,EAAE,GAAG,EAAE,SAAS,GAAG,WAAW,CAsB5E;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,WAAW,EAAE,GAAG,UAAO,GAAG,MAAM,CAqBnE;AAED,2EAA2E;AAC3E,wBAAgB,SAAS,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,EAAE,CAEtD;AAED;;;GAGG;AACH,wBAAsB,SAAS,CAC7B,IAAI,EAAE,QAAQ,EAAE,EAChB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,CAiD1B;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,MAAM,CAmBtE;AAED;;;GAGG;AACH,wBAAgB,UAAU,CACxB,IAAI,EAAE,QAAQ,EAAE,EAChB,GAAG,EAAE,MAAM,EAAE,EACb,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,GAAG,UAAgC,GAClC,MAAM,CA4BR"}
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `graft init`'s agent picker and `--dry-run` plan printer.
|
|
3
|
+
*
|
|
4
|
+
* Split three ways so the logic is testable without a TTY: `renderPicker` and
|
|
5
|
+
* `reducePicker` are pure, `runPicker` is the only part that touches stdin.
|
|
6
|
+
*/
|
|
7
|
+
import { relative, dirname, sep } from 'node:path';
|
|
8
|
+
const indigo = (s) => `\x1b[38;2;84;111;255m${s}\x1b[0m`;
|
|
9
|
+
const muted = (s) => `\x1b[38;5;244m${s}\x1b[0m`;
|
|
10
|
+
const amber = (s) => `\x1b[38;5;179m${s}\x1b[0m`;
|
|
11
|
+
/** `/Users/me/.codex/x` → `~/.codex/x`, for display only. */
|
|
12
|
+
export function tilde(path, home) {
|
|
13
|
+
return path === home || path.startsWith(home + sep) ? `~${path.slice(home.length)}` : path;
|
|
14
|
+
}
|
|
15
|
+
/** Deepest directory containing every given path. */
|
|
16
|
+
function commonDir(paths) {
|
|
17
|
+
const split = paths.map((p) => dirname(p).split(sep));
|
|
18
|
+
const first = split[0] ?? [];
|
|
19
|
+
let i = 0;
|
|
20
|
+
while (i < first.length && split.every((s) => s[i] === first[i]))
|
|
21
|
+
i++;
|
|
22
|
+
return first.slice(0, i).join(sep);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* One-line summary of what selecting a host writes: repo-relative paths, then
|
|
26
|
+
* a count for anything landing outside the repo — those are the writes users
|
|
27
|
+
* can't see in `git status`, so they get named explicitly.
|
|
28
|
+
*/
|
|
29
|
+
export function describeWrites(writes, repo, home, maxShown = 3) {
|
|
30
|
+
const repoPaths = writes.filter((w) => w.scope === 'repo').map((w) => relative(repo, w.path));
|
|
31
|
+
const globals = writes.filter((w) => w.scope === 'global');
|
|
32
|
+
const parts = [];
|
|
33
|
+
if (repoPaths.length > 0) {
|
|
34
|
+
parts.push(repoPaths.length <= maxShown
|
|
35
|
+
? repoPaths.join(', ')
|
|
36
|
+
: `${repoPaths.slice(0, maxShown).join(', ')} +${repoPaths.length - maxShown} more`);
|
|
37
|
+
}
|
|
38
|
+
if (globals.length > 0) {
|
|
39
|
+
const where = tilde(commonDir(globals.map((w) => w.path)), home);
|
|
40
|
+
parts.push(`+ ${globals.length} in ${where}/ (machine-wide)`);
|
|
41
|
+
}
|
|
42
|
+
if (!writes.some((w) => w.kind === 'mcp'))
|
|
43
|
+
parts.push('no MCP');
|
|
44
|
+
return parts.join(' · ');
|
|
45
|
+
}
|
|
46
|
+
/** Claude Code starts checked — it's the deep integration — everything else off. */
|
|
47
|
+
export function initialPickerState(plan, repo, home) {
|
|
48
|
+
return {
|
|
49
|
+
rows: plan.map((p) => ({
|
|
50
|
+
id: p.id,
|
|
51
|
+
detected: p.detected,
|
|
52
|
+
summary: describeWrites(p.writes, repo, home),
|
|
53
|
+
hasGlobal: p.writes.some((w) => w.scope === 'global'),
|
|
54
|
+
})),
|
|
55
|
+
cursor: 0,
|
|
56
|
+
checked: new Set(plan.some((p) => p.id === 'claude') ? ['claude'] : []),
|
|
57
|
+
done: false,
|
|
58
|
+
aborted: false,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
export const KEY_UP = '\x1b[A';
|
|
62
|
+
export const KEY_DOWN = '\x1b[B';
|
|
63
|
+
export const KEY_ESC = '\x1b';
|
|
64
|
+
export const KEY_CTRL_C = '\x03';
|
|
65
|
+
/** A single keypress → the key we act on, or null to ignore. */
|
|
66
|
+
export function keyOf(chunk) {
|
|
67
|
+
switch (chunk) {
|
|
68
|
+
case KEY_UP:
|
|
69
|
+
case 'k': return 'up';
|
|
70
|
+
case KEY_DOWN:
|
|
71
|
+
case 'j': return 'down';
|
|
72
|
+
case ' ': return 'space';
|
|
73
|
+
case 'a': return 'all';
|
|
74
|
+
case '\r':
|
|
75
|
+
case '\n': return 'enter';
|
|
76
|
+
case KEY_ESC:
|
|
77
|
+
case KEY_CTRL_C:
|
|
78
|
+
case 'q': return 'abort';
|
|
79
|
+
default: return null;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Split a raw stdin chunk into keypresses. A terminal is free to batch bytes —
|
|
84
|
+
* held keys, pasted input, or a pty replaying a script all arrive as one chunk —
|
|
85
|
+
* so a chunk is a sequence, never a single key. CSI sequences (ESC '[' final)
|
|
86
|
+
* are consumed whole so an arrow key never reads as a bare ESC (i.e. abort).
|
|
87
|
+
*/
|
|
88
|
+
export function keysOf(chunk) {
|
|
89
|
+
const keys = [];
|
|
90
|
+
let i = 0;
|
|
91
|
+
while (i < chunk.length) {
|
|
92
|
+
let token;
|
|
93
|
+
if (chunk[i] === KEY_ESC && chunk[i + 1] === '[') {
|
|
94
|
+
// ESC '[' then optional parameter bytes, then one final byte @-~.
|
|
95
|
+
let j = i + 2;
|
|
96
|
+
while (j < chunk.length && !/[@-~]/.test(chunk[j]))
|
|
97
|
+
j++;
|
|
98
|
+
token = chunk.slice(i, Math.min(j + 1, chunk.length));
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
token = chunk[i];
|
|
102
|
+
}
|
|
103
|
+
i += token.length;
|
|
104
|
+
const key = keyOf(token);
|
|
105
|
+
if (key !== null)
|
|
106
|
+
keys.push(key);
|
|
107
|
+
}
|
|
108
|
+
return keys;
|
|
109
|
+
}
|
|
110
|
+
export function reducePicker(state, key) {
|
|
111
|
+
const n = state.rows.length;
|
|
112
|
+
switch (key) {
|
|
113
|
+
case 'up':
|
|
114
|
+
return { ...state, cursor: (state.cursor - 1 + n) % n };
|
|
115
|
+
case 'down':
|
|
116
|
+
return { ...state, cursor: (state.cursor + 1) % n };
|
|
117
|
+
case 'space': {
|
|
118
|
+
const next = new Set(state.checked);
|
|
119
|
+
const id = state.rows[state.cursor].id;
|
|
120
|
+
if (next.has(id))
|
|
121
|
+
next.delete(id);
|
|
122
|
+
else
|
|
123
|
+
next.add(id);
|
|
124
|
+
return { ...state, checked: next };
|
|
125
|
+
}
|
|
126
|
+
case 'all': {
|
|
127
|
+
const allOn = state.rows.every((r) => state.checked.has(r.id));
|
|
128
|
+
return { ...state, checked: new Set(allOn ? [] : state.rows.map((r) => r.id)) };
|
|
129
|
+
}
|
|
130
|
+
case 'enter':
|
|
131
|
+
return { ...state, done: true };
|
|
132
|
+
case 'abort':
|
|
133
|
+
return { ...state, aborted: true };
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
export function renderPicker(state, tty = true) {
|
|
137
|
+
const dim = tty ? muted : (s) => s;
|
|
138
|
+
const hot = tty ? indigo : (s) => s;
|
|
139
|
+
const warn = tty ? amber : (s) => s;
|
|
140
|
+
// Pad on the plain label so the summary column lines up regardless of which
|
|
141
|
+
// rows carry the '(not detected)' tag or the cursor's colour codes.
|
|
142
|
+
const label = (r) => `${r.id}${r.detected ? '' : ' (not detected)'}`;
|
|
143
|
+
const width = Math.max(...state.rows.map((r) => label(r).length));
|
|
144
|
+
const lines = ['graft init — select what to wire into this repo:', ''];
|
|
145
|
+
for (const [i, row] of state.rows.entries()) {
|
|
146
|
+
const here = i === state.cursor;
|
|
147
|
+
const box = state.checked.has(row.id) ? '[x]' : '[ ]';
|
|
148
|
+
const gap = ' '.repeat(width - label(row).length);
|
|
149
|
+
const name = here ? hot(row.id) : row.id;
|
|
150
|
+
const tag = row.detected ? '' : dim(' (not detected)');
|
|
151
|
+
const summary = row.hasGlobal ? warn(row.summary) : dim(row.summary);
|
|
152
|
+
lines.push(`${here ? '›' : ' '} ${box} ${name}${tag}${gap} ${summary}`);
|
|
153
|
+
}
|
|
154
|
+
lines.push('', dim('↑↓ move · space toggle · a all · enter confirm · esc cancel'));
|
|
155
|
+
return lines.join('\n');
|
|
156
|
+
}
|
|
157
|
+
/** Ids in plan order, so output ordering never depends on toggle order. */
|
|
158
|
+
export function pickedIds(state) {
|
|
159
|
+
return state.rows.filter((r) => state.checked.has(r.id)).map((r) => r.id);
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Drive the picker on a real terminal. Resolves the chosen ids, or null if the
|
|
163
|
+
* user cancelled — in which case the caller must write nothing.
|
|
164
|
+
*/
|
|
165
|
+
export async function runPicker(plan, repo, home) {
|
|
166
|
+
let state = initialPickerState(plan, repo, home);
|
|
167
|
+
const out = process.stderr;
|
|
168
|
+
const stdin = process.stdin;
|
|
169
|
+
let lastLines = 0;
|
|
170
|
+
const draw = () => {
|
|
171
|
+
if (lastLines > 0)
|
|
172
|
+
out.write(`\x1b[${lastLines}A\x1b[0J`);
|
|
173
|
+
const text = renderPicker(state);
|
|
174
|
+
out.write(`${text}\n`);
|
|
175
|
+
lastLines = text.split('\n').length;
|
|
176
|
+
};
|
|
177
|
+
const wasRaw = Boolean(stdin.isRaw);
|
|
178
|
+
stdin.setRawMode?.(true);
|
|
179
|
+
stdin.resume();
|
|
180
|
+
draw();
|
|
181
|
+
try {
|
|
182
|
+
return await new Promise((resolve) => {
|
|
183
|
+
// Both listeners come off together: a leftover 'end' would otherwise fire
|
|
184
|
+
// after a confirmed pick and redraw the picker over init's own output.
|
|
185
|
+
const finish = (onData) => {
|
|
186
|
+
stdin.off('data', onData);
|
|
187
|
+
stdin.off('end', onEnd);
|
|
188
|
+
draw();
|
|
189
|
+
resolve(state.aborted ? null : pickedIds(state));
|
|
190
|
+
};
|
|
191
|
+
const onData = (buf) => {
|
|
192
|
+
const keys = keysOf(buf.toString('utf8'));
|
|
193
|
+
if (keys.length === 0)
|
|
194
|
+
return;
|
|
195
|
+
for (const key of keys) {
|
|
196
|
+
state = reducePicker(state, key);
|
|
197
|
+
if (state.done || state.aborted) {
|
|
198
|
+
finish(onData);
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
draw();
|
|
203
|
+
};
|
|
204
|
+
// A closed stdin (piped input that ran out) must not hang the prompt.
|
|
205
|
+
const onEnd = () => { state = { ...state, aborted: true }; finish(onData); };
|
|
206
|
+
stdin.on('data', onData);
|
|
207
|
+
stdin.on('end', onEnd);
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
finally {
|
|
211
|
+
stdin.setRawMode?.(wasRaw);
|
|
212
|
+
stdin.pause();
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Shown when there's no TTY to prompt on and no flag saying what to wire.
|
|
217
|
+
* Writing nothing is deliberate: a scripted run shouldn't get files for every
|
|
218
|
+
* agent the machine happens to have installed.
|
|
219
|
+
*/
|
|
220
|
+
export function formatNonInteractiveHelp(detectedIds) {
|
|
221
|
+
const list = detectedIds.length > 0 ? detectedIds.join(", ") : "none";
|
|
222
|
+
const examples = [
|
|
223
|
+
...(detectedIds.length > 0
|
|
224
|
+
? [
|
|
225
|
+
[`graft init --agents ${detectedIds.join(" ")}`, "wire these"],
|
|
226
|
+
["graft init --yes", "same, without spelling them out"],
|
|
227
|
+
]
|
|
228
|
+
: []),
|
|
229
|
+
["graft init --agents claude", "Claude Code only"],
|
|
230
|
+
["graft init --dry-run", "list every file first"],
|
|
231
|
+
];
|
|
232
|
+
const width = Math.max(...examples.map(([cmd]) => cmd.length));
|
|
233
|
+
return [
|
|
234
|
+
"graft init: no TTY to prompt on, and no --agents/--yes given — nothing written.",
|
|
235
|
+
`detected: ${list}`,
|
|
236
|
+
"",
|
|
237
|
+
...examples.map(([cmd, note]) => ` ${cmd.padEnd(width)} # ${note}`),
|
|
238
|
+
].join("\n");
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* `--dry-run` output: every path init would touch, repo writes first, then a
|
|
242
|
+
* separate section for anything outside the repo.
|
|
243
|
+
*/
|
|
244
|
+
export function formatPlan(plan, ids, repo, home, tty = Boolean(process.stderr.isTTY)) {
|
|
245
|
+
const dim = tty ? muted : (s) => s;
|
|
246
|
+
const warn = tty ? amber : (s) => s;
|
|
247
|
+
const writes = plan.filter((p) => ids.includes(p.id)).flatMap((p) => p.writes);
|
|
248
|
+
if (writes.length === 0)
|
|
249
|
+
return 'would write — nothing (no agents selected)';
|
|
250
|
+
const pad = (rows, f) => {
|
|
251
|
+
const w = Math.max(...rows.map((r) => f(r.path).length));
|
|
252
|
+
return rows.map((r) => ` ${f(r.path).padEnd(w)} ${dim(r.what)}`);
|
|
253
|
+
};
|
|
254
|
+
const lines = [];
|
|
255
|
+
const repoWrites = writes.filter((w) => w.scope === 'repo');
|
|
256
|
+
if (repoWrites.length > 0) {
|
|
257
|
+
lines.push('would write — this repo:', ...pad(repoWrites, (p) => relative(repo, p)));
|
|
258
|
+
}
|
|
259
|
+
const globalWrites = writes.filter((w) => w.scope === 'global');
|
|
260
|
+
if (globalWrites.length > 0) {
|
|
261
|
+
if (lines.length)
|
|
262
|
+
lines.push('');
|
|
263
|
+
lines.push(warn('would write — your machine, affects ALL repos:'), ...pad(globalWrites, (p) => tilde(p, home)), '', dim('suppress the out-of-repo writes with --no-global'));
|
|
264
|
+
}
|
|
265
|
+
lines.push('', dim('nothing was written (--dry-run)'));
|
|
266
|
+
return lines.join('\n');
|
|
267
|
+
}
|
|
268
|
+
//# sourceMappingURL=cli-picker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-picker.js","sourceRoot":"","sources":["../src/cli-picker.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.js
CHANGED
|
@@ -12,14 +12,18 @@ import { Graft } from "./engine.js";
|
|
|
12
12
|
import { resolveConfig } from "./ai/providers.js";
|
|
13
13
|
import { formatCheckReport } from "./context/check.js";
|
|
14
14
|
import { formatGraphCheckReport } from "./graph/check.js";
|
|
15
|
-
import { runInit } from "./claude/init.js";
|
|
15
|
+
import { buildGraphIfMissing, runInit } from "./claude/init.js";
|
|
16
16
|
import { runHostsInit } from "./hosts/init.js";
|
|
17
17
|
import { hostIds } from "./hosts/registry.js";
|
|
18
18
|
import { contextDirFor } from "./context/node-file.js";
|
|
19
19
|
import { loadGraphCached } from "./graph/load.js";
|
|
20
|
+
import { ensureFreshChildren, ensureFreshGraph, refreshNote } from "./graph/refresh.js";
|
|
20
21
|
import { isWorkspaceBuildRoot, readWorkspace } from "./graph/workspace.js";
|
|
21
22
|
import { runWorkspaceAsk, runWorkspaceBuild, runWorkspaceCallers, runWorkspaceCheck, runWorkspaceGrep, runWorkspaceMap, } from "./graph/workspace-cli.js";
|
|
22
23
|
import { formatInitEpilogue } from "./cli-epilogue.js";
|
|
24
|
+
import { planInit, selectedWrites } from "./hosts/plan.js";
|
|
25
|
+
import { formatNonInteractiveHelp, formatPlan, runPicker } from "./cli-picker.js";
|
|
26
|
+
import { homedir } from "node:os";
|
|
23
27
|
import { formatUpgradeReport, formatVersionReport, getNpmViewVersion, readCurrentVersion, runUpgrade } from "./cli-meta.js";
|
|
24
28
|
const program = new Command();
|
|
25
29
|
const currentVersion = readCurrentVersion(import.meta.url);
|
|
@@ -44,6 +48,27 @@ function cliConfig() {
|
|
|
44
48
|
};
|
|
45
49
|
}
|
|
46
50
|
const engineFrom = () => new Graft(cliConfig());
|
|
51
|
+
/**
|
|
52
|
+
* Bring the graph up to date with the working tree before a query answers from it
|
|
53
|
+
* — the same gate the MCP tools run (see `graph/refresh.ts`). Cheap when nothing
|
|
54
|
+
* moved; a structural, $0 rebuild when it did. The note goes to stderr so `--json`
|
|
55
|
+
* stdout stays machine-readable.
|
|
56
|
+
*/
|
|
57
|
+
async function refreshBefore(dir, opts) {
|
|
58
|
+
const globalDir = program.opts().dir;
|
|
59
|
+
const root = resolve(dir);
|
|
60
|
+
const disabled = opts.refresh === false;
|
|
61
|
+
const ws = readWorkspace(root, globalDir);
|
|
62
|
+
const r = ws
|
|
63
|
+
? await ensureFreshChildren(root, ws.children, { contextDir: globalDir, disabled })
|
|
64
|
+
: await ensureFreshGraph(root, { contextDir: globalDir, disabled });
|
|
65
|
+
const note = refreshNote(r);
|
|
66
|
+
if (note)
|
|
67
|
+
console.error(note);
|
|
68
|
+
}
|
|
69
|
+
/** Attached to every query command: `--no-refresh` answers from the graph exactly
|
|
70
|
+
* as it is on disk, no rebuild. */
|
|
71
|
+
const NO_REFRESH_FLAG = ["--no-refresh", "skip the freshness check — answer from the graph as-is"];
|
|
47
72
|
program
|
|
48
73
|
.command("version")
|
|
49
74
|
.description("Print the installed version and the latest published on npm")
|
|
@@ -68,6 +93,7 @@ program
|
|
|
68
93
|
.option("--deep", "run the LLM pass: concept nodes (graft/*.md) + per-symbol summary/crux")
|
|
69
94
|
.option("-e, --extensions <exts...>", 'code extensions to include (e.g. ".ts" ".py")')
|
|
70
95
|
.option("-j, --concurrency <n>", "files summarized in parallel during --deep (default 5)")
|
|
96
|
+
.option("--no-reuse", "re-parse every file instead of replaying unchanged ones from the extraction cache")
|
|
71
97
|
.action(async (dir, opts) => {
|
|
72
98
|
const concurrency = opts.concurrency ? Math.max(1, Number(opts.concurrency)) : undefined;
|
|
73
99
|
if (opts.concurrency && !Number.isFinite(concurrency)) {
|
|
@@ -119,10 +145,12 @@ program
|
|
|
119
145
|
const g = await engine.graph(dir, {
|
|
120
146
|
llm: deep,
|
|
121
147
|
concurrency,
|
|
148
|
+
reuse: opts.reuse,
|
|
122
149
|
onProgress: ({ phase, index, total, file }) => process.stderr.write(`\r${phase === "enrich" ? "summarizing" : "parsing"} ${index + 1}/${total}: ${file.slice(0, 50).padEnd(50)}`),
|
|
123
150
|
});
|
|
124
151
|
process.stderr.write("\n");
|
|
125
152
|
console.log(`✓ wiring: ${g.nodes} nodes (${fmt(g.byKind)}), ${g.edges} edges, ${g.cards} cards [${g.languages.join(", ")}]`);
|
|
153
|
+
console.log(` parsed: ${g.parsed} of ${g.files} files (${g.reused} replayed from cache)`);
|
|
126
154
|
if (deep) {
|
|
127
155
|
const m = g.meaning;
|
|
128
156
|
console.log(` meaning: ${m.computed} computed, ${m.cached} cached, ${m.stale} stale, ${m.pending} pending`);
|
|
@@ -143,7 +171,9 @@ program
|
|
|
143
171
|
.option("--full", "with --source: inline whole definition spans instead of the default ≤8-line crux excerpts")
|
|
144
172
|
.option("--in <path>", "narrow to nodes under this path prefix, filtered before scoring (segment-aware, like scopeOf)")
|
|
145
173
|
.option("--json", "output the result as JSON")
|
|
174
|
+
.option(...NO_REFRESH_FLAG)
|
|
146
175
|
.action(async (query, dir, opts) => {
|
|
176
|
+
await refreshBefore(dir, opts);
|
|
147
177
|
const askGlobalDir = program.opts().dir;
|
|
148
178
|
if (readWorkspace(resolve(dir), askGlobalDir)) {
|
|
149
179
|
runWorkspaceAsk(resolve(dir), askGlobalDir, query, {
|
|
@@ -175,7 +205,9 @@ program
|
|
|
175
205
|
.argument("<file>", "repo-relative path (or unique basename) of the file")
|
|
176
206
|
.argument("[dir]", "repository root", ".")
|
|
177
207
|
.option("--json", "output the result as JSON")
|
|
208
|
+
.option(...NO_REFRESH_FLAG)
|
|
178
209
|
.action(async (file, dir, opts) => {
|
|
210
|
+
await refreshBefore(dir, opts);
|
|
179
211
|
const { skeleton, formatSkeleton } = await import("./ask/ask.js");
|
|
180
212
|
const globalOpts = program.opts();
|
|
181
213
|
const r = skeleton(dir, file, { contextDir: globalOpts.dir });
|
|
@@ -275,7 +307,9 @@ program
|
|
|
275
307
|
.option("-d, --depth <n>", 'walk transitively up to N hops for blast radius, or "all" for the full connected closure (default 1)')
|
|
276
308
|
.option("--in <path>", "narrow matches to nodes whose path contains this substring")
|
|
277
309
|
.option("--json", "output as JSON")
|
|
310
|
+
.option(...NO_REFRESH_FLAG)
|
|
278
311
|
.action(async (symbol, dir, opts) => {
|
|
312
|
+
await refreshBefore(dir, opts);
|
|
279
313
|
const globalOpts = program.opts();
|
|
280
314
|
if (!opts.json && readWorkspace(resolve(dir), globalOpts.dir)) {
|
|
281
315
|
runWorkspaceCallers(resolve(dir), globalOpts.dir, symbol, {
|
|
@@ -305,7 +339,9 @@ program
|
|
|
305
339
|
.option("--fixed", "treat pattern as a literal string, not a regex")
|
|
306
340
|
.option("--in <path>", "narrow to files whose path contains this substring")
|
|
307
341
|
.option("--json", "output as JSON")
|
|
342
|
+
.option(...NO_REFRESH_FLAG)
|
|
308
343
|
.action(async (pattern, dir, opts) => {
|
|
344
|
+
await refreshBefore(dir, opts);
|
|
309
345
|
const globalOpts = program.opts();
|
|
310
346
|
if (readWorkspace(resolve(dir), globalOpts.dir)) {
|
|
311
347
|
runWorkspaceGrep(resolve(dir), globalOpts.dir, pattern, {
|
|
@@ -328,6 +364,7 @@ program
|
|
|
328
364
|
.argument("[dir]", "repository root", ".")
|
|
329
365
|
.option("--max-dirs <n>", "max directory entries shown, rest counted into dropped (default 16)")
|
|
330
366
|
.option("--json", "output as JSON")
|
|
367
|
+
.option(...NO_REFRESH_FLAG)
|
|
331
368
|
.action(async (dir, opts) => {
|
|
332
369
|
const root = resolve(dir);
|
|
333
370
|
const globalOpts = program.opts();
|
|
@@ -341,6 +378,7 @@ program
|
|
|
341
378
|
}
|
|
342
379
|
maxDirsW = n;
|
|
343
380
|
}
|
|
381
|
+
await refreshBefore(dir, opts); // after arg validation: a bad flag shouldn't cost a rebuild
|
|
344
382
|
if (!opts.json && readWorkspace(root, globalOpts.dir)) {
|
|
345
383
|
runWorkspaceMap(root, globalOpts.dir, { maxDirs: maxDirsW });
|
|
346
384
|
return;
|
|
@@ -371,7 +409,10 @@ program
|
|
|
371
409
|
.option("--list-agents", "list known agent ids and exit")
|
|
372
410
|
.option("--no-mcp", "skip MCP server registration for other agents")
|
|
373
411
|
.option("--no-hooks", "skip hook installation for other agents")
|
|
374
|
-
.
|
|
412
|
+
.option("--dry-run", "print every file init would touch, then exit without writing")
|
|
413
|
+
.option("-y, --yes", "skip the picker and wire every detected agent (the pre-0.8 default)")
|
|
414
|
+
.option("--no-global", "skip writes outside this repo (the ~/.codex/ config + hooks)")
|
|
415
|
+
.action(async (dir, opts) => {
|
|
375
416
|
if (opts.listAgents) {
|
|
376
417
|
for (const id of [...hostIds(), "claude"])
|
|
377
418
|
console.log(id);
|
|
@@ -387,9 +428,46 @@ program
|
|
|
387
428
|
process.exit(1);
|
|
388
429
|
}
|
|
389
430
|
}
|
|
390
|
-
|
|
431
|
+
// Which agents to wire, decided before anything is written. Explicit flags
|
|
432
|
+
// win; otherwise prompt on a TTY, and on a pipe write nothing rather than
|
|
433
|
+
// guessing (pre-0.8 this silently wired every agent the machine had ever
|
|
434
|
+
// installed — see --yes to get that back).
|
|
435
|
+
const home = homedir();
|
|
436
|
+
const plan = planInit(repo, { home });
|
|
437
|
+
const detectedIds = plan.filter((p) => p.detected).map((p) => p.id);
|
|
438
|
+
const noAgents = opts.agents === false;
|
|
439
|
+
let ids;
|
|
440
|
+
if (explicit)
|
|
441
|
+
ids = explicit;
|
|
442
|
+
else if (opts.allAgents)
|
|
443
|
+
ids = plan.map((p) => p.id);
|
|
444
|
+
else if (noAgents)
|
|
445
|
+
ids = ["claude"];
|
|
446
|
+
else if (opts.yes || opts.dryRun)
|
|
447
|
+
ids = detectedIds;
|
|
448
|
+
else if (process.stdin.isTTY && process.stderr.isTTY) {
|
|
449
|
+
const picked = await runPicker(plan, repo, home);
|
|
450
|
+
if (picked === null) {
|
|
451
|
+
console.error("· cancelled — nothing written");
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
454
|
+
ids = picked;
|
|
455
|
+
}
|
|
456
|
+
else {
|
|
457
|
+
console.error(formatNonInteractiveHelp(detectedIds));
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
460
|
+
if (opts.dryRun) {
|
|
461
|
+
console.error(formatPlan(plan, ids, repo, home));
|
|
462
|
+
return;
|
|
463
|
+
}
|
|
464
|
+
if (ids.length === 0) {
|
|
465
|
+
console.error("· no agents selected — nothing written");
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
const wantClaude = ids.includes("claude");
|
|
469
|
+
const cliPath = fileURLToPath(import.meta.url);
|
|
391
470
|
if (wantClaude) {
|
|
392
|
-
const cliPath = fileURLToPath(import.meta.url);
|
|
393
471
|
const res = runInit(repo, { build: opts.build, cliPath });
|
|
394
472
|
console.error(`✓ wrote ${res.settingsPath}`);
|
|
395
473
|
for (const s of res.shims)
|
|
@@ -405,22 +483,33 @@ program
|
|
|
405
483
|
for (const w of res.warnings)
|
|
406
484
|
console.error(`⚠ ${w}`);
|
|
407
485
|
}
|
|
408
|
-
|
|
409
|
-
|
|
486
|
+
// `ids` is already resolved, so hosts init is always driven by an explicit
|
|
487
|
+
// list — never by its own detection fallback.
|
|
488
|
+
const others = ids.filter((id) => id !== "claude");
|
|
489
|
+
if (others.length > 0) {
|
|
410
490
|
const r = runHostsInit(repo, {
|
|
411
|
-
agents:
|
|
412
|
-
|
|
491
|
+
agents: others,
|
|
492
|
+
home,
|
|
413
493
|
mcp: opts.mcp,
|
|
414
494
|
hooks: opts.hooks,
|
|
495
|
+
global: opts.global,
|
|
415
496
|
});
|
|
416
497
|
for (const w of r.written)
|
|
417
498
|
console.error(`✓ ${w.id}: ${w.path} (${w.action})`);
|
|
418
|
-
if (!explicit && !opts.allAgents && r.written.length === 0)
|
|
419
|
-
console.error("· no other agents detected (see --list-agents / --all-agents)");
|
|
420
499
|
for (const m of r.mcp)
|
|
421
500
|
console.error(`✓ mcp ${m.id}: ${m.path} (${m.action})`);
|
|
422
501
|
for (const h of r.hooks)
|
|
423
502
|
console.error(`✓ hook ${h.id}: ${h.path} (${h.action})`);
|
|
503
|
+
// Only worth saying when there was actually something out-of-repo to skip.
|
|
504
|
+
if (opts.global === false && selectedWrites(plan, ids).some((w) => w.scope === "global"))
|
|
505
|
+
console.error("· skipped out-of-repo writes (--no-global)");
|
|
506
|
+
}
|
|
507
|
+
// Every host's wiring points at graft/, so the graph is built whatever was
|
|
508
|
+
// selected — not only when Claude Code is in the list (runInit does its own).
|
|
509
|
+
if (!wantClaude) {
|
|
510
|
+
console.error(buildGraphIfMissing(repo, { build: opts.build, cliPath })
|
|
511
|
+
? "✓ built the graph (graft build)"
|
|
512
|
+
: "· skipped graph build");
|
|
424
513
|
}
|
|
425
514
|
const globalOpts = program.opts();
|
|
426
515
|
const outDir = contextDirFor(repo, globalOpts.dir);
|