@graphit/cli 0.2.270 → 0.2.306
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/.claude-plugin/marketplace.json +3 -3
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/bin/graphit +1 -1
- package/bin/graphit.ps1 +1 -1
- package/dist/commands/connector.js +4 -2
- package/dist/commands/connector.js.map +1 -1
- package/dist/commands/dashboard.js +24 -11
- package/dist/commands/dashboard.js.map +1 -1
- package/dist/commands/ds/refresh-history.js +2 -1
- package/dist/commands/ds/refresh-history.js.map +1 -1
- package/dist/commands/ds/ui-only.js +10 -4
- package/dist/commands/ds/ui-only.js.map +1 -1
- package/dist/commands/ds.js +8 -4
- package/dist/commands/ds.js.map +1 -1
- package/dist/commands/governance.js +2 -2
- package/dist/commands/governance.js.map +1 -1
- package/dist/commands/kb-create.js +8 -8
- package/dist/commands/kb-create.js.map +1 -1
- package/dist/commands/kb-delete.js +4 -1
- package/dist/commands/kb-delete.js.map +1 -1
- package/dist/commands/kb-read.js +22 -10
- package/dist/commands/kb-read.js.map +1 -1
- package/dist/commands/kb-shared.d.ts +3 -0
- package/dist/commands/kb-shared.js +12 -0
- package/dist/commands/kb-shared.js.map +1 -1
- package/dist/commands/kb-update.js +19 -10
- package/dist/commands/kb-update.js.map +1 -1
- package/dist/commands/query.js +2 -1
- package/dist/commands/query.js.map +1 -1
- package/package.json +4 -4
- package/scripts/commander-walk.mjs +154 -0
- package/scripts/generate-commands-doc.mjs +26 -95
- package/scripts/generate-tool-manifest.mjs +613 -0
- package/scripts/verb-policy-source.json +555 -0
- package/skills/graphit/SKILL.md +2 -2
- package/skills/graphit/VERSION.json +1 -1
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
// The one Commander walk. Both generators consume it - the SKILL.md command
|
|
2
|
+
// table (generate-commands-doc.mjs) and the platform-agent tool manifest
|
|
3
|
+
// (generate-tool-manifest.mjs) - so a command, flag or description can never
|
|
4
|
+
// mean two different things on the two surfaces.
|
|
5
|
+
//
|
|
6
|
+
// Project #275: the in-app agent's tool vocabulary IS the CLI vocabulary. A
|
|
7
|
+
// second walk would be a second source of truth, which is the drift this
|
|
8
|
+
// project exists to remove.
|
|
9
|
+
//
|
|
10
|
+
// Everything below `collectVerbs` operates on the walk's own plain records, not
|
|
11
|
+
// on Commander objects. A field this file does not capture is a field neither
|
|
12
|
+
// generator can see - `mandatory` was dropped once and published 36 required
|
|
13
|
+
// flags as optional, so add to the record rather than reaching past it.
|
|
14
|
+
|
|
15
|
+
import { existsSync, readdirSync } from "node:fs";
|
|
16
|
+
import { join } from "node:path";
|
|
17
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
18
|
+
import { Command } from "commander";
|
|
19
|
+
|
|
20
|
+
export const cliRoot =
|
|
21
|
+
process.env.GRAPHIT_CLI_ROOT ??
|
|
22
|
+
join(fileURLToPath(new URL(".", import.meta.url)), "..");
|
|
23
|
+
|
|
24
|
+
// Mirrors index.ts registration order; groups not listed are appended alphabetically.
|
|
25
|
+
export const GROUP_ORDER = [
|
|
26
|
+
"auth", "status", "kb", "query", "metadata", "ds", "dashboard",
|
|
27
|
+
"connector", "governance", "team", "plugin", "setup",
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Assemble a throwaway program by importing only the dist/ registrars.
|
|
32
|
+
*
|
|
33
|
+
* NEVER import dist/index.js - module load fires the update banner,
|
|
34
|
+
* program.parse(), and a network update check.
|
|
35
|
+
*/
|
|
36
|
+
export async function buildProgram() {
|
|
37
|
+
const distCommandsDir = join(cliRoot, "dist", "commands");
|
|
38
|
+
if (!existsSync(distCommandsDir)) {
|
|
39
|
+
throw new Error(
|
|
40
|
+
`dist/commands not found at ${distCommandsDir} - run "npm run build" first`,
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
const program = new Command();
|
|
44
|
+
program.name("graphit");
|
|
45
|
+
const files = readdirSync(distCommandsDir)
|
|
46
|
+
.filter((f) => f.endsWith(".js"))
|
|
47
|
+
.sort(); // deterministic import order
|
|
48
|
+
for (const file of files) {
|
|
49
|
+
const mod = await import(pathToFileURL(join(distCommandsDir, file)).href);
|
|
50
|
+
for (const [name, value] of Object.entries(mod)) {
|
|
51
|
+
if (typeof value === "function" && /^register/.test(name)) {
|
|
52
|
+
value(program);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return program;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** `<id> [ids...]` from the walk's structured arguments. */
|
|
60
|
+
export function formatArgs(args) {
|
|
61
|
+
return args
|
|
62
|
+
.map((arg) => {
|
|
63
|
+
const name = arg.name + (arg.variadic ? "..." : "");
|
|
64
|
+
return arg.required ? `<${name}>` : `[${name}]`;
|
|
65
|
+
})
|
|
66
|
+
.join(" ");
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** `--limit --verified` from the walk's structured options. */
|
|
70
|
+
export function formatFlags(options) {
|
|
71
|
+
return options.map((opt) => opt.long || opt.flags).filter(Boolean).join(" ");
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function orderGroups(names) {
|
|
75
|
+
return [...names].sort((a, b) => {
|
|
76
|
+
const ia = GROUP_ORDER.indexOf(a);
|
|
77
|
+
const ib = GROUP_ORDER.indexOf(b);
|
|
78
|
+
if (ia === -1 && ib === -1) return a.localeCompare(b);
|
|
79
|
+
if (ia === -1) return 1;
|
|
80
|
+
if (ib === -1) return -1;
|
|
81
|
+
return ia - ib;
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Hidden options (hideHelp) are unpublished by definition - deprecated or
|
|
86
|
+
// internal flags must not be taught to agents on either surface.
|
|
87
|
+
const visibleOptions = (cmd) => (cmd.options ?? []).filter((opt) => !opt.hidden);
|
|
88
|
+
|
|
89
|
+
// A command earns its own row if it is a leaf OR it has its own args/options
|
|
90
|
+
// (e.g. `query <sql>` both takes an arg and has the `metadata` sibling group).
|
|
91
|
+
const hasOwnInvocation = (cmd) =>
|
|
92
|
+
(cmd.registeredArguments ?? []).length > 0 || (cmd.options ?? []).length > 0;
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Every invocable command in the tree, in group order then registration order.
|
|
96
|
+
*
|
|
97
|
+
* `action` is the path below the group ("create metric", "update-html", "" for
|
|
98
|
+
* a group that is itself invocable such as `query` or `status`).
|
|
99
|
+
*/
|
|
100
|
+
export function collectVerbs(program) {
|
|
101
|
+
const verbs = [];
|
|
102
|
+
|
|
103
|
+
const visit = (cmd, group, path) => {
|
|
104
|
+
const subs = cmd.commands ?? [];
|
|
105
|
+
if (subs.length === 0 || hasOwnInvocation(cmd)) {
|
|
106
|
+
verbs.push({
|
|
107
|
+
group,
|
|
108
|
+
action: path.slice(group.length).trim(),
|
|
109
|
+
command: path,
|
|
110
|
+
description: cmd.description() ?? "",
|
|
111
|
+
args: (cmd.registeredArguments ?? []).map((arg) => ({
|
|
112
|
+
name: arg.name(),
|
|
113
|
+
description: arg.description ?? "",
|
|
114
|
+
required: Boolean(arg.required),
|
|
115
|
+
variadic: Boolean(arg.variadic),
|
|
116
|
+
})),
|
|
117
|
+
options: visibleOptions(cmd).map((opt) => ({
|
|
118
|
+
flags: opt.flags,
|
|
119
|
+
long: opt.long ?? "",
|
|
120
|
+
short: opt.short ?? "",
|
|
121
|
+
description: opt.description ?? "",
|
|
122
|
+
// A value-taking option renders as `--limit <n>`; a boolean switch has
|
|
123
|
+
// no placeholder. Commander exposes both as `required`/`optional` on
|
|
124
|
+
// the option's ARGUMENT, never on the option itself - `mandatory` is
|
|
125
|
+
// the separate flag meaning ".requiredOption(), the CLI rejects the
|
|
126
|
+
// command without it".
|
|
127
|
+
takesValue: Boolean(opt.required || opt.optional),
|
|
128
|
+
valueOptional: Boolean(opt.optional),
|
|
129
|
+
mandatory: Boolean(opt.mandatory),
|
|
130
|
+
negated: Boolean(opt.negate),
|
|
131
|
+
variadic: Boolean(opt.variadic),
|
|
132
|
+
defaultValue: opt.defaultValue,
|
|
133
|
+
choices: opt.argChoices ?? null,
|
|
134
|
+
})),
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
for (const sub of subs) {
|
|
138
|
+
visit(sub, group, `${path} ${sub.name()}`.trim());
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
for (const name of orderGroups(program.commands.map((c) => c.name()))) {
|
|
143
|
+
const top = program.commands.find((c) => c.name() === name);
|
|
144
|
+
visit(top, name, name);
|
|
145
|
+
}
|
|
146
|
+
return verbs;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/** Group name -> its top-level `.description()`. */
|
|
150
|
+
export function collectGroupDescriptions(program) {
|
|
151
|
+
const out = new Map();
|
|
152
|
+
for (const top of program.commands) out.set(top.name(), top.description() ?? "");
|
|
153
|
+
return out;
|
|
154
|
+
}
|
|
@@ -9,123 +9,54 @@
|
|
|
9
9
|
//
|
|
10
10
|
// Requires a prior `npm run build` (it imports the compiled registrars from dist/).
|
|
11
11
|
|
|
12
|
-
import { existsSync, readFileSync,
|
|
12
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
13
13
|
import { join } from "node:path";
|
|
14
|
-
import {
|
|
15
|
-
|
|
14
|
+
import {
|
|
15
|
+
buildProgram,
|
|
16
|
+
cliRoot,
|
|
17
|
+
collectGroupDescriptions,
|
|
18
|
+
collectVerbs,
|
|
19
|
+
formatArgs,
|
|
20
|
+
formatFlags,
|
|
21
|
+
} from "./commander-walk.mjs";
|
|
16
22
|
|
|
17
23
|
const checkOnly = process.argv.includes("--check");
|
|
18
24
|
const toStdout = process.argv.includes("--stdout");
|
|
19
25
|
|
|
20
|
-
const cliRoot =
|
|
21
|
-
process.env.GRAPHIT_CLI_ROOT ??
|
|
22
|
-
join(fileURLToPath(new URL(".", import.meta.url)), "..");
|
|
23
|
-
const distCommandsDir = join(cliRoot, "dist", "commands");
|
|
24
26
|
const skillPath = join(cliRoot, "skills", "graphit", "SKILL.md");
|
|
25
27
|
|
|
26
28
|
const START = "<!-- COMMANDS:START -->";
|
|
27
29
|
const END = "<!-- COMMANDS:END -->";
|
|
28
30
|
|
|
29
|
-
// Mirrors index.ts registration order; groups not listed are appended alphabetically.
|
|
30
|
-
const GROUP_ORDER = [
|
|
31
|
-
"auth", "status", "kb", "query", "metadata", "ds", "dashboard",
|
|
32
|
-
"connector", "governance", "team", "plugin", "setup",
|
|
33
|
-
];
|
|
34
|
-
|
|
35
|
-
// Assemble a throwaway program by importing only the dist/ registrars (never
|
|
36
|
-
// dist/index.js - that fires the update banner + program.parse() at load).
|
|
37
|
-
async function buildProgram() {
|
|
38
|
-
if (!existsSync(distCommandsDir)) {
|
|
39
|
-
throw new Error(
|
|
40
|
-
`dist/commands not found at ${distCommandsDir} - run "npm run build" first`,
|
|
41
|
-
);
|
|
42
|
-
}
|
|
43
|
-
const program = new Command();
|
|
44
|
-
program.name("graphit");
|
|
45
|
-
const files = readdirSync(distCommandsDir)
|
|
46
|
-
.filter((f) => f.endsWith(".js"))
|
|
47
|
-
.sort(); // deterministic import order
|
|
48
|
-
for (const file of files) {
|
|
49
|
-
const mod = await import(pathToFileURL(join(distCommandsDir, file)).href);
|
|
50
|
-
for (const [name, value] of Object.entries(mod)) {
|
|
51
|
-
if (typeof value === "function" && /^register/.test(name)) {
|
|
52
|
-
value(program);
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
return program;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
31
|
function esc(text) {
|
|
60
32
|
return String(text ?? "").replace(/\r?\n/g, " ").replace(/\|/g, "\\|").trim();
|
|
61
33
|
}
|
|
62
34
|
|
|
63
|
-
function formatArgs(cmd) {
|
|
64
|
-
return (cmd.registeredArguments ?? [])
|
|
65
|
-
.map((arg) => {
|
|
66
|
-
const name = arg.name() + (arg.variadic ? "..." : "");
|
|
67
|
-
return arg.required ? `<${name}>` : `[${name}]`;
|
|
68
|
-
})
|
|
69
|
-
.join(" ");
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
function formatFlags(cmd) {
|
|
73
|
-
return (cmd.options ?? [])
|
|
74
|
-
// Hidden options (hideHelp) are unpublished by definition - deprecated or
|
|
75
|
-
// internal flags must not be taught to agents via the command table.
|
|
76
|
-
.filter((opt) => !opt.hidden)
|
|
77
|
-
.map((opt) => opt.long ?? opt.flags)
|
|
78
|
-
.filter(Boolean)
|
|
79
|
-
.join(" ");
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// A command earns its own row if it is a leaf OR it has its own args/options
|
|
83
|
-
// (e.g. `query <sql>` both takes an arg and has the `metadata` sibling group).
|
|
84
|
-
function hasOwnInvocation(cmd) {
|
|
85
|
-
return (
|
|
86
|
-
(cmd.registeredArguments ?? []).length > 0 ||
|
|
87
|
-
(cmd.options ?? []).length > 0
|
|
88
|
-
);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
function collectRows(cmd, path, rows) {
|
|
92
|
-
const subs = cmd.commands ?? [];
|
|
93
|
-
if (subs.length === 0 || hasOwnInvocation(cmd)) {
|
|
94
|
-
rows.push({
|
|
95
|
-
command: `${path}${formatArgs(cmd) ? ` ${formatArgs(cmd)}` : ""}`,
|
|
96
|
-
description: cmd.description(),
|
|
97
|
-
flags: formatFlags(cmd),
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
|
-
for (const sub of subs) {
|
|
101
|
-
collectRows(sub, `${path} ${sub.name()}`.trim(), rows);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
function orderGroups(names) {
|
|
106
|
-
return [...names].sort((a, b) => {
|
|
107
|
-
const ia = GROUP_ORDER.indexOf(a);
|
|
108
|
-
const ib = GROUP_ORDER.indexOf(b);
|
|
109
|
-
if (ia === -1 && ib === -1) return a.localeCompare(b);
|
|
110
|
-
if (ia === -1) return 1;
|
|
111
|
-
if (ib === -1) return -1;
|
|
112
|
-
return ia - ib;
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
|
|
116
35
|
function renderBlock(program) {
|
|
36
|
+
const groupDescriptions = collectGroupDescriptions(program);
|
|
117
37
|
const groups = new Map();
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
groups.
|
|
38
|
+
// collectVerbs already returns groups in GROUP_ORDER, so insertion order here
|
|
39
|
+
// is the render order - no second sort.
|
|
40
|
+
for (const verb of collectVerbs(program)) {
|
|
41
|
+
if (!groups.has(verb.group)) {
|
|
42
|
+
groups.set(verb.group, {
|
|
43
|
+
description: groupDescriptions.get(verb.group),
|
|
44
|
+
rows: [],
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
const args = formatArgs(verb.args);
|
|
48
|
+
groups.get(verb.group).rows.push({
|
|
49
|
+
command: `${verb.command}${args ? ` ${args}` : ""}`,
|
|
50
|
+
description: verb.description,
|
|
51
|
+
flags: formatFlags(verb.options),
|
|
52
|
+
});
|
|
122
53
|
}
|
|
123
54
|
const lines = [
|
|
124
55
|
"",
|
|
125
56
|
"_Generated from the CLI by `npm run gen:commands` - do not hand-edit between the markers. Run `graphit <cmd> --help` for exact flag values and descriptions._",
|
|
126
57
|
"",
|
|
127
58
|
];
|
|
128
|
-
for (const name of
|
|
59
|
+
for (const name of groups.keys()) {
|
|
129
60
|
const { description, rows } = groups.get(name);
|
|
130
61
|
lines.push(`**${name}**${description ? ` - ${esc(description)}` : ""}`);
|
|
131
62
|
for (const row of rows) {
|