facult 1.0.3 → 1.2.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 +491 -15
- package/package.json +1 -1
- package/src/adapters/codex.ts +1 -0
- package/src/adapters/types.ts +1 -0
- package/src/agents.ts +205 -0
- package/src/ai-state.ts +80 -0
- package/src/ai.ts +1763 -0
- package/src/audit/update-index.ts +13 -10
- package/src/autosync.ts +1028 -0
- package/src/builtin.ts +61 -0
- package/src/cli-context.ts +198 -0
- package/src/doctor.ts +128 -0
- package/src/enable-disable.ts +13 -7
- package/src/global-docs.ts +505 -0
- package/src/graph-query.ts +175 -0
- package/src/graph.ts +119 -0
- package/src/index-builder.ts +1104 -44
- package/src/index.ts +458 -24
- package/src/manage.ts +2482 -215
- package/src/paths.ts +181 -17
- package/src/query.ts +147 -7
- package/src/remote.ts +145 -10
- package/src/snippets.ts +106 -0
- package/src/trust-list.ts +1 -0
- package/src/trust.ts +13 -11
package/src/index.ts
CHANGED
|
@@ -2,12 +2,28 @@
|
|
|
2
2
|
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { getAllAdapters } from "./adapters";
|
|
5
|
+
import { aiCommand } from "./ai";
|
|
5
6
|
import { auditCommand } from "./audit";
|
|
7
|
+
import { autosyncCommand } from "./autosync";
|
|
8
|
+
import {
|
|
9
|
+
type CapabilityScopeMode,
|
|
10
|
+
parseCliContextArgs,
|
|
11
|
+
resolveCliContextRoot,
|
|
12
|
+
} from "./cli-context";
|
|
6
13
|
import { consolidateCommand } from "./consolidate";
|
|
14
|
+
import { doctorCommand } from "./doctor";
|
|
7
15
|
import { disableCommand, enableCommand } from "./enable-disable";
|
|
16
|
+
import type { AssetScope, AssetSourceKind } from "./graph";
|
|
17
|
+
import {
|
|
18
|
+
graphDependencies,
|
|
19
|
+
graphDependents,
|
|
20
|
+
loadGraph,
|
|
21
|
+
resolveGraphNode,
|
|
22
|
+
} from "./graph-query";
|
|
8
23
|
import type {
|
|
9
24
|
AgentEntry,
|
|
10
25
|
FacultIndex,
|
|
26
|
+
InstructionEntry,
|
|
11
27
|
McpEntry,
|
|
12
28
|
SkillEntry,
|
|
13
29
|
SnippetEntry,
|
|
@@ -23,9 +39,11 @@ import { migrateCommand } from "./migrate";
|
|
|
23
39
|
import type { QueryFilters } from "./query";
|
|
24
40
|
import {
|
|
25
41
|
filterAgents,
|
|
42
|
+
filterInstructions,
|
|
26
43
|
filterMcp,
|
|
27
44
|
filterSkills,
|
|
28
45
|
filterSnippets,
|
|
46
|
+
findCapabilities,
|
|
29
47
|
loadIndex,
|
|
30
48
|
} from "./query";
|
|
31
49
|
import {
|
|
@@ -42,9 +60,15 @@ import { snippetsCommand } from "./snippets-cli";
|
|
|
42
60
|
import { trustCommand, untrustCommand } from "./trust";
|
|
43
61
|
import { parseJsonLenient } from "./util/json";
|
|
44
62
|
|
|
45
|
-
type ListKind = "skills" | "mcp" | "agents" | "snippets";
|
|
63
|
+
type ListKind = "skills" | "mcp" | "agents" | "snippets" | "instructions";
|
|
46
64
|
|
|
47
|
-
const LIST_KINDS: ListKind[] = [
|
|
65
|
+
const LIST_KINDS: ListKind[] = [
|
|
66
|
+
"skills",
|
|
67
|
+
"mcp",
|
|
68
|
+
"agents",
|
|
69
|
+
"snippets",
|
|
70
|
+
"instructions",
|
|
71
|
+
];
|
|
48
72
|
|
|
49
73
|
export interface ListCommandOptions {
|
|
50
74
|
kind: ListKind;
|
|
@@ -52,6 +76,25 @@ export interface ListCommandOptions {
|
|
|
52
76
|
json: boolean;
|
|
53
77
|
}
|
|
54
78
|
|
|
79
|
+
export interface FindCommandOptions {
|
|
80
|
+
text: string;
|
|
81
|
+
json: boolean;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
type GraphCommandKind = "show" | "deps" | "dependents";
|
|
85
|
+
|
|
86
|
+
interface ContextualCommandOptions {
|
|
87
|
+
rootArg?: string;
|
|
88
|
+
scopeMode: CapabilityScopeMode;
|
|
89
|
+
sourceKind?: AssetSourceKind;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
interface GraphCommandOptions {
|
|
93
|
+
kind: GraphCommandKind;
|
|
94
|
+
target: string;
|
|
95
|
+
json: boolean;
|
|
96
|
+
}
|
|
97
|
+
|
|
55
98
|
function printHelp() {
|
|
56
99
|
console.log(`facult — inspect local agent configs for skills + MCP servers
|
|
57
100
|
|
|
@@ -61,11 +104,16 @@ Usage:
|
|
|
61
104
|
facult audit --non-interactive [name|mcp:<name>] [--severity <level>] [--rules <path>] [--from <path>] [--json]
|
|
62
105
|
facult audit --non-interactive [name|mcp:<name>] --with <claude|codex> [--from <path>] [--max-items <n|all>] [--json]
|
|
63
106
|
facult migrate [--from <path>] [--dry-run] [--move] [--write-config]
|
|
107
|
+
facult doctor [--repair]
|
|
64
108
|
facult consolidate [--force] [--auto <mode>] [scan options]
|
|
65
109
|
facult index [--force]
|
|
66
|
-
facult list [skills|mcp|agents|snippets] [--enabled-for TOOL] [--untrusted] [--flagged] [--pending] [--json]
|
|
110
|
+
facult list [skills|mcp|agents|snippets|instructions] [--enabled-for TOOL] [--untrusted] [--flagged] [--pending] [--json]
|
|
67
111
|
facult show <name>
|
|
68
112
|
facult show mcp:<name> [--show-secrets]
|
|
113
|
+
facult show instruction:<name>
|
|
114
|
+
facult find <query> [--json]
|
|
115
|
+
facult graph <show|deps|dependents> <asset> [--json]
|
|
116
|
+
facult ai <writeback|evolve> [args...]
|
|
69
117
|
facult adapters
|
|
70
118
|
facult trust <name> [moreNames...]
|
|
71
119
|
facult untrust <name> [moreNames...]
|
|
@@ -75,6 +123,7 @@ Usage:
|
|
|
75
123
|
facult enable <name> [moreNames...] [--for <tools>]
|
|
76
124
|
facult disable <name> [moreNames...] [--for <tools>]
|
|
77
125
|
facult sync [tool] [--dry-run]
|
|
126
|
+
facult autosync <cmd> [args...]
|
|
78
127
|
facult search <query> [--index <name>] [--limit <n>]
|
|
79
128
|
facult install <index:item> [--as <name>] [--dry-run] [--force] [--strict-source-trust]
|
|
80
129
|
facult update [--apply] [--strict-source-trust]
|
|
@@ -89,11 +138,15 @@ Usage:
|
|
|
89
138
|
Commands:
|
|
90
139
|
scan Scan common config locations (Cursor, Claude, Claude Desktop, etc.)
|
|
91
140
|
audit Security audits (interactive by default; use --non-interactive for scripts)
|
|
92
|
-
migrate Copy/move a legacy canonical store to
|
|
141
|
+
migrate Copy/move a legacy canonical store to the current canonical root
|
|
142
|
+
doctor Inspect and repair local facult state
|
|
93
143
|
consolidate Deduplicate and copy skills + MCP configs (interactive or --auto)
|
|
94
144
|
index Build a queryable index from the canonical store (see FACULT_ROOT_DIR)
|
|
95
|
-
list List indexed skills, MCP servers, agents, or
|
|
145
|
+
list List indexed skills, MCP servers, agents, snippets, or instructions
|
|
96
146
|
show Show a single indexed entry, including file contents
|
|
147
|
+
find Search local indexed capabilities across asset types
|
|
148
|
+
graph Inspect explicit capability graph nodes and dependencies
|
|
149
|
+
ai Record, group, and evolve AI writeback into reviewable proposals
|
|
97
150
|
adapters List registered tool adapters
|
|
98
151
|
trust Mark a skill or MCP server as trusted (annotation only)
|
|
99
152
|
untrust Remove trusted annotation
|
|
@@ -103,6 +156,7 @@ Commands:
|
|
|
103
156
|
enable Enable skills or MCP servers for tools
|
|
104
157
|
disable Disable skills or MCP servers for tools
|
|
105
158
|
sync Sync managed tools with canonical configs
|
|
159
|
+
autosync Install/manage a background autosync service
|
|
106
160
|
search Search remote indices (builtin + provider aliases + configured)
|
|
107
161
|
install Install an item from a remote index
|
|
108
162
|
update Check/apply updates for remotely installed items
|
|
@@ -140,6 +194,11 @@ Options:
|
|
|
140
194
|
--self (update) run self-update flow instead of remote item updates
|
|
141
195
|
--strict-source-trust Enforce trust-only remote install/update actions
|
|
142
196
|
--show-secrets (show) Print raw secret values (unsafe)
|
|
197
|
+
--root Select a canonical .ai root explicitly
|
|
198
|
+
--global Force the global canonical root
|
|
199
|
+
--project Force the nearest repo-local .ai root
|
|
200
|
+
--scope Capability view scope: merged|global|project
|
|
201
|
+
--source Filter to builtin|global|project asset provenance
|
|
143
202
|
`);
|
|
144
203
|
}
|
|
145
204
|
|
|
@@ -147,13 +206,18 @@ function printListHelp() {
|
|
|
147
206
|
console.log(`facult list — list indexed entries from the canonical store
|
|
148
207
|
|
|
149
208
|
Usage:
|
|
150
|
-
facult list [skills|mcp|agents|snippets] [options]
|
|
209
|
+
facult list [skills|mcp|agents|snippets|instructions] [options]
|
|
151
210
|
|
|
152
211
|
Options:
|
|
153
212
|
--enabled-for TOOL Only include entries enabled for a tool
|
|
154
213
|
--untrusted Only include entries that are not trusted
|
|
155
214
|
--flagged Only include entries flagged by audit
|
|
156
215
|
--pending Only include entries pending audit
|
|
216
|
+
--root PATH Select a canonical .ai root explicitly
|
|
217
|
+
--global Force the global canonical root
|
|
218
|
+
--project Force the nearest repo-local .ai root
|
|
219
|
+
--scope SCOPE merged|global|project (default: merged)
|
|
220
|
+
--source KIND builtin|global|project
|
|
157
221
|
--json Print JSON array
|
|
158
222
|
`);
|
|
159
223
|
}
|
|
@@ -164,9 +228,49 @@ function printShowHelp() {
|
|
|
164
228
|
Usage:
|
|
165
229
|
facult show <name>
|
|
166
230
|
facult show mcp:<name> [--show-secrets]
|
|
231
|
+
facult show instruction:<name>
|
|
167
232
|
|
|
168
233
|
Options:
|
|
169
234
|
--show-secrets (mcp) Print raw secret values (unsafe)
|
|
235
|
+
--root PATH Select a canonical .ai root explicitly
|
|
236
|
+
--global Force the global canonical root
|
|
237
|
+
--project Force the nearest repo-local .ai root
|
|
238
|
+
--scope SCOPE merged|global|project (default: merged)
|
|
239
|
+
--source KIND builtin|global|project
|
|
240
|
+
`);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function printFindHelp() {
|
|
244
|
+
console.log(`facult find — search local indexed capabilities across asset types
|
|
245
|
+
|
|
246
|
+
Usage:
|
|
247
|
+
facult find <query> [--json]
|
|
248
|
+
|
|
249
|
+
Options:
|
|
250
|
+
--root PATH Select a canonical .ai root explicitly
|
|
251
|
+
--global Force the global canonical root
|
|
252
|
+
--project Force the nearest repo-local .ai root
|
|
253
|
+
--scope SCOPE merged|global|project (default: merged)
|
|
254
|
+
--source KIND builtin|global|project
|
|
255
|
+
--json Print JSON array
|
|
256
|
+
`);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
function printGraphHelp() {
|
|
260
|
+
console.log(`facult graph — inspect explicit capability graph nodes and relations
|
|
261
|
+
|
|
262
|
+
Usage:
|
|
263
|
+
facult graph show <asset> [--json]
|
|
264
|
+
facult graph deps <asset> [--json]
|
|
265
|
+
facult graph dependents <asset> [--json]
|
|
266
|
+
|
|
267
|
+
Options:
|
|
268
|
+
--root PATH Select a canonical .ai root explicitly
|
|
269
|
+
--global Force the global canonical root
|
|
270
|
+
--project Force the nearest repo-local .ai root
|
|
271
|
+
--scope SCOPE merged|global|project (default: merged)
|
|
272
|
+
--source KIND builtin|global|project
|
|
273
|
+
--json Print JSON
|
|
170
274
|
`);
|
|
171
275
|
}
|
|
172
276
|
|
|
@@ -241,15 +345,111 @@ export function parseListArgs(argv: string[]): ListCommandOptions {
|
|
|
241
345
|
return { kind, filters, json };
|
|
242
346
|
}
|
|
243
347
|
|
|
348
|
+
export function parseFindArgs(argv: string[]): FindCommandOptions {
|
|
349
|
+
let json = false;
|
|
350
|
+
const terms: string[] = [];
|
|
351
|
+
|
|
352
|
+
for (const arg of argv) {
|
|
353
|
+
if (!arg) {
|
|
354
|
+
continue;
|
|
355
|
+
}
|
|
356
|
+
if (arg === "--json") {
|
|
357
|
+
json = true;
|
|
358
|
+
continue;
|
|
359
|
+
}
|
|
360
|
+
if (arg.startsWith("-")) {
|
|
361
|
+
throw new Error(`Unknown option: ${arg}`);
|
|
362
|
+
}
|
|
363
|
+
terms.push(arg);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
const text = terms.join(" ").trim();
|
|
367
|
+
if (!text) {
|
|
368
|
+
throw new Error("find requires a query");
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
return { text, json };
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
function parseGraphArgs(argv: string[]): GraphCommandOptions {
|
|
375
|
+
const [kind, ...rest] = argv;
|
|
376
|
+
if (!(kind === "show" || kind === "deps" || kind === "dependents")) {
|
|
377
|
+
throw new Error(`Unknown graph command: ${kind ?? "<missing>"}`);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
let json = false;
|
|
381
|
+
let target: string | null = null;
|
|
382
|
+
for (const arg of rest) {
|
|
383
|
+
if (!arg) {
|
|
384
|
+
continue;
|
|
385
|
+
}
|
|
386
|
+
if (arg === "--json") {
|
|
387
|
+
json = true;
|
|
388
|
+
continue;
|
|
389
|
+
}
|
|
390
|
+
if (arg.startsWith("-")) {
|
|
391
|
+
throw new Error(`Unknown option: ${arg}`);
|
|
392
|
+
}
|
|
393
|
+
if (target) {
|
|
394
|
+
throw new Error(`graph ${kind} accepts a single asset selector`);
|
|
395
|
+
}
|
|
396
|
+
target = arg;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
if (!target) {
|
|
400
|
+
throw new Error(`graph ${kind} requires an asset selector`);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
return { kind, target, json };
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
function scopeFilterForMode(
|
|
407
|
+
scopeMode: CapabilityScopeMode
|
|
408
|
+
): AssetScope | undefined {
|
|
409
|
+
return scopeMode === "project" ? "project" : undefined;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
function resolveContextualOptions(
|
|
413
|
+
argv: string[],
|
|
414
|
+
opts?: { allowSource?: boolean }
|
|
415
|
+
): { argv: string[]; context: ContextualCommandOptions } {
|
|
416
|
+
const parsed = parseCliContextArgs(argv, {
|
|
417
|
+
allowSource: opts?.allowSource,
|
|
418
|
+
});
|
|
419
|
+
return {
|
|
420
|
+
argv: parsed.argv,
|
|
421
|
+
context: {
|
|
422
|
+
rootArg: parsed.rootArg,
|
|
423
|
+
scopeMode: parsed.scope,
|
|
424
|
+
sourceKind: parsed.sourceKind,
|
|
425
|
+
},
|
|
426
|
+
};
|
|
427
|
+
}
|
|
428
|
+
|
|
244
429
|
async function listCommand(argv: string[]) {
|
|
245
|
-
|
|
430
|
+
const { argv: contextualArgv, context } = resolveContextualOptions(argv, {
|
|
431
|
+
allowSource: true,
|
|
432
|
+
});
|
|
433
|
+
|
|
434
|
+
if (
|
|
435
|
+
contextualArgv.includes("--help") ||
|
|
436
|
+
contextualArgv.includes("-h") ||
|
|
437
|
+
contextualArgv[0] === "help"
|
|
438
|
+
) {
|
|
246
439
|
printListHelp();
|
|
247
440
|
return;
|
|
248
441
|
}
|
|
249
442
|
|
|
250
443
|
let opts: ListCommandOptions;
|
|
251
444
|
try {
|
|
252
|
-
opts = parseListArgs(
|
|
445
|
+
opts = parseListArgs(contextualArgv);
|
|
446
|
+
if (context.sourceKind) {
|
|
447
|
+
opts.filters.sourceKind = context.sourceKind;
|
|
448
|
+
}
|
|
449
|
+
const scopeFilter = scopeFilterForMode(context.scopeMode);
|
|
450
|
+
if (scopeFilter) {
|
|
451
|
+
opts.filters.scope = scopeFilter;
|
|
452
|
+
}
|
|
253
453
|
} catch (err) {
|
|
254
454
|
console.error(err instanceof Error ? err.message : String(err));
|
|
255
455
|
process.exitCode = 1;
|
|
@@ -258,14 +458,25 @@ async function listCommand(argv: string[]) {
|
|
|
258
458
|
|
|
259
459
|
let index: FacultIndex;
|
|
260
460
|
try {
|
|
261
|
-
index = await loadIndex(
|
|
461
|
+
index = await loadIndex({
|
|
462
|
+
rootDir: resolveCliContextRoot({
|
|
463
|
+
rootArg: context.rootArg,
|
|
464
|
+
scope: context.scopeMode,
|
|
465
|
+
cwd: process.cwd(),
|
|
466
|
+
}),
|
|
467
|
+
});
|
|
262
468
|
} catch (err) {
|
|
263
469
|
console.error(err instanceof Error ? err.message : String(err));
|
|
264
470
|
process.exitCode = 1;
|
|
265
471
|
return;
|
|
266
472
|
}
|
|
267
473
|
|
|
268
|
-
let entries:
|
|
474
|
+
let entries:
|
|
475
|
+
| SkillEntry[]
|
|
476
|
+
| McpEntry[]
|
|
477
|
+
| AgentEntry[]
|
|
478
|
+
| SnippetEntry[]
|
|
479
|
+
| InstructionEntry[] = [];
|
|
269
480
|
|
|
270
481
|
switch (opts.kind) {
|
|
271
482
|
case "skills":
|
|
@@ -280,6 +491,9 @@ async function listCommand(argv: string[]) {
|
|
|
280
491
|
case "snippets":
|
|
281
492
|
entries = filterSnippets(index.snippets ?? {}, opts.filters);
|
|
282
493
|
break;
|
|
494
|
+
case "instructions":
|
|
495
|
+
entries = filterInstructions(index.instructions ?? {}, opts.filters);
|
|
496
|
+
break;
|
|
283
497
|
default:
|
|
284
498
|
entries = [];
|
|
285
499
|
break;
|
|
@@ -301,7 +515,7 @@ async function listCommand(argv: string[]) {
|
|
|
301
515
|
const trustedLabel = meta.trusted === true ? "trusted" : "untrusted";
|
|
302
516
|
const auditLabel = (meta.auditStatus ?? "pending").trim().toLowerCase();
|
|
303
517
|
console.log(
|
|
304
|
-
`${skill.name}${desc}\t[${trustedLabel}; audit=${auditLabel}]`
|
|
518
|
+
`${skill.name}${desc}\t[${trustedLabel}; audit=${auditLabel}]${formatSourceMeta(skill)}`
|
|
305
519
|
);
|
|
306
520
|
} else if (opts.kind === "mcp") {
|
|
307
521
|
const meta = entry as McpEntry & {
|
|
@@ -310,9 +524,11 @@ async function listCommand(argv: string[]) {
|
|
|
310
524
|
};
|
|
311
525
|
const trustedLabel = meta.trusted === true ? "trusted" : "untrusted";
|
|
312
526
|
const auditLabel = (meta.auditStatus ?? "pending").trim().toLowerCase();
|
|
313
|
-
console.log(
|
|
527
|
+
console.log(
|
|
528
|
+
`${entry.name}\t[${trustedLabel}; audit=${auditLabel}]${formatSourceMeta(entry)}`
|
|
529
|
+
);
|
|
314
530
|
} else {
|
|
315
|
-
console.log(entry.name);
|
|
531
|
+
console.log(`${entry.name}${formatSourceMeta(entry)}`);
|
|
316
532
|
}
|
|
317
533
|
}
|
|
318
534
|
}
|
|
@@ -325,6 +541,60 @@ async function readEntryContents(entryPath: string): Promise<string> {
|
|
|
325
541
|
return file.text();
|
|
326
542
|
}
|
|
327
543
|
|
|
544
|
+
async function findCommand(argv: string[]) {
|
|
545
|
+
const { argv: contextualArgv, context } = resolveContextualOptions(argv, {
|
|
546
|
+
allowSource: true,
|
|
547
|
+
});
|
|
548
|
+
|
|
549
|
+
if (
|
|
550
|
+
contextualArgv.includes("--help") ||
|
|
551
|
+
contextualArgv.includes("-h") ||
|
|
552
|
+
contextualArgv[0] === "help"
|
|
553
|
+
) {
|
|
554
|
+
printFindHelp();
|
|
555
|
+
return;
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
let opts: FindCommandOptions;
|
|
559
|
+
try {
|
|
560
|
+
opts = parseFindArgs(contextualArgv);
|
|
561
|
+
} catch (err) {
|
|
562
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
563
|
+
process.exitCode = 1;
|
|
564
|
+
return;
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
let index: FacultIndex;
|
|
568
|
+
try {
|
|
569
|
+
index = await loadIndex({
|
|
570
|
+
rootDir: resolveCliContextRoot({
|
|
571
|
+
rootArg: context.rootArg,
|
|
572
|
+
scope: context.scopeMode,
|
|
573
|
+
cwd: process.cwd(),
|
|
574
|
+
}),
|
|
575
|
+
});
|
|
576
|
+
} catch (err) {
|
|
577
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
578
|
+
process.exitCode = 1;
|
|
579
|
+
return;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
const matches = findCapabilities(index, {
|
|
583
|
+
text: opts.text,
|
|
584
|
+
sourceKind: context.sourceKind,
|
|
585
|
+
scope: scopeFilterForMode(context.scopeMode),
|
|
586
|
+
});
|
|
587
|
+
if (opts.json) {
|
|
588
|
+
console.log(`${JSON.stringify(matches, null, 2)}`);
|
|
589
|
+
return;
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
for (const entry of matches) {
|
|
593
|
+
const desc = entry.description ? `\t${entry.description}` : "";
|
|
594
|
+
console.log(`${entry.kind}:${entry.name}${desc}${formatSourceMeta(entry)}`);
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
|
|
328
598
|
const SECRET_KEY_RE = /(TOKEN|KEY|SECRET|PASSWORD|PASS|BEARER)/i;
|
|
329
599
|
const SECRETY_STRING_RE =
|
|
330
600
|
/\b(sk-[A-Za-z0-9]{10,}|ghp_[A-Za-z0-9]{10,}|github_pat_[A-Za-z0-9_]{10,})\b/g;
|
|
@@ -333,6 +603,21 @@ function redactPossibleSecrets(value: string): string {
|
|
|
333
603
|
return value.replace(SECRETY_STRING_RE, "<redacted>");
|
|
334
604
|
}
|
|
335
605
|
|
|
606
|
+
function formatSourceMeta(entry: {
|
|
607
|
+
sourceKind?: string;
|
|
608
|
+
scope?: string;
|
|
609
|
+
}): string {
|
|
610
|
+
const source = entry.sourceKind?.trim();
|
|
611
|
+
const scope = entry.scope?.trim();
|
|
612
|
+
if (!(source || scope)) {
|
|
613
|
+
return "";
|
|
614
|
+
}
|
|
615
|
+
if (source && scope) {
|
|
616
|
+
return `\t[${source}/${scope}]`;
|
|
617
|
+
}
|
|
618
|
+
return `\t[${source ?? scope}]`;
|
|
619
|
+
}
|
|
620
|
+
|
|
336
621
|
function sanitizeForDisplay(value: unknown): unknown {
|
|
337
622
|
if (typeof value === "string") {
|
|
338
623
|
return redactPossibleSecrets(value);
|
|
@@ -355,14 +640,22 @@ function sanitizeForDisplay(value: unknown): unknown {
|
|
|
355
640
|
}
|
|
356
641
|
|
|
357
642
|
async function showCommand(argv: string[]) {
|
|
358
|
-
|
|
643
|
+
const { argv: contextualArgv, context } = resolveContextualOptions(argv, {
|
|
644
|
+
allowSource: true,
|
|
645
|
+
});
|
|
646
|
+
|
|
647
|
+
if (
|
|
648
|
+
contextualArgv.includes("--help") ||
|
|
649
|
+
contextualArgv.includes("-h") ||
|
|
650
|
+
contextualArgv[0] === "help"
|
|
651
|
+
) {
|
|
359
652
|
printShowHelp();
|
|
360
653
|
return;
|
|
361
654
|
}
|
|
362
655
|
|
|
363
656
|
let showSecrets = false;
|
|
364
657
|
let raw: string | null = null;
|
|
365
|
-
for (const arg of
|
|
658
|
+
for (const arg of contextualArgv) {
|
|
366
659
|
if (!arg) {
|
|
367
660
|
continue;
|
|
368
661
|
}
|
|
@@ -390,7 +683,13 @@ async function showCommand(argv: string[]) {
|
|
|
390
683
|
|
|
391
684
|
let index: FacultIndex;
|
|
392
685
|
try {
|
|
393
|
-
index = await loadIndex(
|
|
686
|
+
index = await loadIndex({
|
|
687
|
+
rootDir: resolveCliContextRoot({
|
|
688
|
+
rootArg: context.rootArg,
|
|
689
|
+
scope: context.scopeMode,
|
|
690
|
+
cwd: process.cwd(),
|
|
691
|
+
}),
|
|
692
|
+
});
|
|
394
693
|
} catch (err) {
|
|
395
694
|
console.error(err instanceof Error ? err.message : String(err));
|
|
396
695
|
process.exitCode = 1;
|
|
@@ -403,25 +702,60 @@ async function showCommand(argv: string[]) {
|
|
|
403
702
|
if (raw.startsWith("mcp:")) {
|
|
404
703
|
kind = "mcp";
|
|
405
704
|
name = raw.slice("mcp:".length);
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
|
|
705
|
+
} else if (raw.startsWith("instruction:")) {
|
|
706
|
+
kind = "instructions";
|
|
707
|
+
name = raw.slice("instruction:".length);
|
|
708
|
+
} else if (raw.startsWith("instructions:")) {
|
|
709
|
+
kind = "instructions";
|
|
710
|
+
name = raw.slice("instructions:".length);
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
let entry:
|
|
714
|
+
| SkillEntry
|
|
715
|
+
| McpEntry
|
|
716
|
+
| AgentEntry
|
|
717
|
+
| SnippetEntry
|
|
718
|
+
| InstructionEntry
|
|
719
|
+
| null = null;
|
|
409
720
|
const skill = index.skills[name];
|
|
410
721
|
const mcpServer = index.mcp?.servers?.[name];
|
|
411
722
|
const agent = index.agents?.[name];
|
|
412
723
|
const snippet = index.snippets?.[name];
|
|
724
|
+
const instruction = index.instructions?.[name];
|
|
725
|
+
const matchesContext = (candidate: {
|
|
726
|
+
sourceKind?: string;
|
|
727
|
+
scope?: string;
|
|
728
|
+
}): boolean => {
|
|
729
|
+
if (context.sourceKind && candidate.sourceKind !== context.sourceKind) {
|
|
730
|
+
return false;
|
|
731
|
+
}
|
|
732
|
+
const scopeFilter = scopeFilterForMode(context.scopeMode);
|
|
733
|
+
if (scopeFilter && candidate.scope !== scopeFilter) {
|
|
734
|
+
return false;
|
|
735
|
+
}
|
|
736
|
+
return true;
|
|
737
|
+
};
|
|
413
738
|
|
|
414
|
-
if (kind === "skills" && skill) {
|
|
739
|
+
if (kind === "skills" && skill && matchesContext(skill)) {
|
|
415
740
|
entry = skill;
|
|
416
|
-
} else if (kind === "mcp" && mcpServer) {
|
|
741
|
+
} else if (kind === "mcp" && mcpServer && matchesContext(mcpServer)) {
|
|
417
742
|
entry = mcpServer;
|
|
418
|
-
} else if (kind === "skills" && agent) {
|
|
743
|
+
} else if (kind === "skills" && agent && matchesContext(agent)) {
|
|
419
744
|
kind = "agents";
|
|
420
745
|
entry = agent;
|
|
421
|
-
} else if (kind === "skills" && snippet) {
|
|
746
|
+
} else if (kind === "skills" && snippet && matchesContext(snippet)) {
|
|
422
747
|
kind = "snippets";
|
|
423
748
|
entry = snippet;
|
|
424
|
-
} else if (
|
|
749
|
+
} else if (
|
|
750
|
+
kind === "instructions" &&
|
|
751
|
+
instruction &&
|
|
752
|
+
matchesContext(instruction)
|
|
753
|
+
) {
|
|
754
|
+
entry = instruction;
|
|
755
|
+
} else if (kind === "skills" && instruction && matchesContext(instruction)) {
|
|
756
|
+
kind = "instructions";
|
|
757
|
+
entry = instruction;
|
|
758
|
+
} else if (kind === "skills" && mcpServer && matchesContext(mcpServer)) {
|
|
425
759
|
kind = "mcp";
|
|
426
760
|
entry = mcpServer;
|
|
427
761
|
}
|
|
@@ -468,6 +802,91 @@ async function showCommand(argv: string[]) {
|
|
|
468
802
|
console.log(displayContents);
|
|
469
803
|
}
|
|
470
804
|
|
|
805
|
+
async function graphCommand(argv: string[]) {
|
|
806
|
+
const { argv: contextualArgv, context } = resolveContextualOptions(argv, {
|
|
807
|
+
allowSource: true,
|
|
808
|
+
});
|
|
809
|
+
|
|
810
|
+
if (
|
|
811
|
+
contextualArgv.includes("--help") ||
|
|
812
|
+
contextualArgv.includes("-h") ||
|
|
813
|
+
contextualArgv[0] === "help"
|
|
814
|
+
) {
|
|
815
|
+
printGraphHelp();
|
|
816
|
+
return;
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
let opts: GraphCommandOptions;
|
|
820
|
+
try {
|
|
821
|
+
opts = parseGraphArgs(contextualArgv);
|
|
822
|
+
} catch (err) {
|
|
823
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
824
|
+
process.exitCode = 1;
|
|
825
|
+
return;
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
try {
|
|
829
|
+
const graph = await loadGraph({
|
|
830
|
+
rootDir: resolveCliContextRoot({
|
|
831
|
+
rootArg: context.rootArg,
|
|
832
|
+
scope: context.scopeMode,
|
|
833
|
+
cwd: process.cwd(),
|
|
834
|
+
}),
|
|
835
|
+
});
|
|
836
|
+
const node = resolveGraphNode(graph, opts.target, {
|
|
837
|
+
sourceKind: context.sourceKind,
|
|
838
|
+
scope: scopeFilterForMode(context.scopeMode),
|
|
839
|
+
});
|
|
840
|
+
if (!node) {
|
|
841
|
+
throw new Error(`Graph node not found: ${opts.target}`);
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
const deps = graphDependencies(graph, node.id);
|
|
845
|
+
const dependents = graphDependents(graph, node.id);
|
|
846
|
+
|
|
847
|
+
if (opts.json) {
|
|
848
|
+
if (opts.kind === "show") {
|
|
849
|
+
console.log(
|
|
850
|
+
JSON.stringify({ node, dependencies: deps, dependents }, null, 2)
|
|
851
|
+
);
|
|
852
|
+
} else if (opts.kind === "deps") {
|
|
853
|
+
console.log(JSON.stringify(deps, null, 2));
|
|
854
|
+
} else {
|
|
855
|
+
console.log(JSON.stringify(dependents, null, 2));
|
|
856
|
+
}
|
|
857
|
+
return;
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
if (opts.kind === "show") {
|
|
861
|
+
console.log(node.id);
|
|
862
|
+
console.log(JSON.stringify(node, null, 2));
|
|
863
|
+
console.log("\nDependencies:");
|
|
864
|
+
for (const dep of deps) {
|
|
865
|
+
console.log(
|
|
866
|
+
`- ${dep.edge.kind}\t${dep.node.id}\t(${dep.edge.locator})`
|
|
867
|
+
);
|
|
868
|
+
}
|
|
869
|
+
console.log("\nDependents:");
|
|
870
|
+
for (const dependent of dependents) {
|
|
871
|
+
console.log(
|
|
872
|
+
`- ${dependent.edge.kind}\t${dependent.node.id}\t(${dependent.edge.locator})`
|
|
873
|
+
);
|
|
874
|
+
}
|
|
875
|
+
return;
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
const relations = opts.kind === "deps" ? deps : dependents;
|
|
879
|
+
for (const relation of relations) {
|
|
880
|
+
console.log(
|
|
881
|
+
`${relation.edge.kind}\t${relation.node.id}\t(${relation.edge.locator})`
|
|
882
|
+
);
|
|
883
|
+
}
|
|
884
|
+
} catch (err) {
|
|
885
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
886
|
+
process.exitCode = 1;
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
|
|
471
890
|
function adaptersCommand(argv: string[]) {
|
|
472
891
|
if (argv.includes("--help") || argv.includes("-h") || argv[0] === "help") {
|
|
473
892
|
console.log(
|
|
@@ -509,6 +928,9 @@ async function main(argv: string[]) {
|
|
|
509
928
|
case "migrate":
|
|
510
929
|
await migrateCommand(rest);
|
|
511
930
|
return;
|
|
931
|
+
case "doctor":
|
|
932
|
+
await doctorCommand(rest);
|
|
933
|
+
return;
|
|
512
934
|
case "consolidate":
|
|
513
935
|
await consolidateCommand(rest);
|
|
514
936
|
return;
|
|
@@ -521,6 +943,15 @@ async function main(argv: string[]) {
|
|
|
521
943
|
case "show":
|
|
522
944
|
await showCommand(rest);
|
|
523
945
|
return;
|
|
946
|
+
case "find":
|
|
947
|
+
await findCommand(rest);
|
|
948
|
+
return;
|
|
949
|
+
case "graph":
|
|
950
|
+
await graphCommand(rest);
|
|
951
|
+
return;
|
|
952
|
+
case "ai":
|
|
953
|
+
await aiCommand(rest);
|
|
954
|
+
return;
|
|
524
955
|
case "adapters":
|
|
525
956
|
await adaptersCommand(rest);
|
|
526
957
|
return;
|
|
@@ -548,6 +979,9 @@ async function main(argv: string[]) {
|
|
|
548
979
|
case "sync":
|
|
549
980
|
await syncCommand(rest);
|
|
550
981
|
return;
|
|
982
|
+
case "autosync":
|
|
983
|
+
await autosyncCommand(rest);
|
|
984
|
+
return;
|
|
551
985
|
case "search":
|
|
552
986
|
await searchCommand(rest);
|
|
553
987
|
return;
|