facult 1.1.0 → 1.2.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 +312 -26
- package/package.json +1 -1
- package/src/agents.ts +26 -1
- package/src/ai-state.ts +27 -2
- package/src/ai.ts +1763 -0
- package/src/audit/update-index.ts +1 -0
- package/src/autosync.ts +96 -27
- package/src/builtin.ts +61 -0
- package/src/cli-context.ts +198 -0
- package/src/enable-disable.ts +1 -0
- package/src/global-docs.ts +50 -6
- package/src/graph-query.ts +175 -0
- package/src/graph.ts +119 -0
- package/src/index-builder.ts +1099 -41
- package/src/index.ts +445 -23
- package/src/manage.ts +1904 -187
- package/src/paths.ts +137 -5
- package/src/query.ts +135 -4
- package/src/remote.ts +140 -9
- package/src/trust-list.ts +1 -0
- package/src/trust.ts +1 -0
package/src/index.ts
CHANGED
|
@@ -2,14 +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";
|
|
6
7
|
import { autosyncCommand } from "./autosync";
|
|
8
|
+
import {
|
|
9
|
+
type CapabilityScopeMode,
|
|
10
|
+
parseCliContextArgs,
|
|
11
|
+
resolveCliContextRoot,
|
|
12
|
+
} from "./cli-context";
|
|
7
13
|
import { consolidateCommand } from "./consolidate";
|
|
8
14
|
import { doctorCommand } from "./doctor";
|
|
9
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";
|
|
10
23
|
import type {
|
|
11
24
|
AgentEntry,
|
|
12
25
|
FacultIndex,
|
|
26
|
+
InstructionEntry,
|
|
13
27
|
McpEntry,
|
|
14
28
|
SkillEntry,
|
|
15
29
|
SnippetEntry,
|
|
@@ -25,9 +39,11 @@ import { migrateCommand } from "./migrate";
|
|
|
25
39
|
import type { QueryFilters } from "./query";
|
|
26
40
|
import {
|
|
27
41
|
filterAgents,
|
|
42
|
+
filterInstructions,
|
|
28
43
|
filterMcp,
|
|
29
44
|
filterSkills,
|
|
30
45
|
filterSnippets,
|
|
46
|
+
findCapabilities,
|
|
31
47
|
loadIndex,
|
|
32
48
|
} from "./query";
|
|
33
49
|
import {
|
|
@@ -44,9 +60,15 @@ import { snippetsCommand } from "./snippets-cli";
|
|
|
44
60
|
import { trustCommand, untrustCommand } from "./trust";
|
|
45
61
|
import { parseJsonLenient } from "./util/json";
|
|
46
62
|
|
|
47
|
-
type ListKind = "skills" | "mcp" | "agents" | "snippets";
|
|
63
|
+
type ListKind = "skills" | "mcp" | "agents" | "snippets" | "instructions";
|
|
48
64
|
|
|
49
|
-
const LIST_KINDS: ListKind[] = [
|
|
65
|
+
const LIST_KINDS: ListKind[] = [
|
|
66
|
+
"skills",
|
|
67
|
+
"mcp",
|
|
68
|
+
"agents",
|
|
69
|
+
"snippets",
|
|
70
|
+
"instructions",
|
|
71
|
+
];
|
|
50
72
|
|
|
51
73
|
export interface ListCommandOptions {
|
|
52
74
|
kind: ListKind;
|
|
@@ -54,6 +76,25 @@ export interface ListCommandOptions {
|
|
|
54
76
|
json: boolean;
|
|
55
77
|
}
|
|
56
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
|
+
|
|
57
98
|
function printHelp() {
|
|
58
99
|
console.log(`facult — inspect local agent configs for skills + MCP servers
|
|
59
100
|
|
|
@@ -66,9 +107,13 @@ Usage:
|
|
|
66
107
|
facult doctor [--repair]
|
|
67
108
|
facult consolidate [--force] [--auto <mode>] [scan options]
|
|
68
109
|
facult index [--force]
|
|
69
|
-
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]
|
|
70
111
|
facult show <name>
|
|
71
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...]
|
|
72
117
|
facult adapters
|
|
73
118
|
facult trust <name> [moreNames...]
|
|
74
119
|
facult untrust <name> [moreNames...]
|
|
@@ -97,8 +142,11 @@ Commands:
|
|
|
97
142
|
doctor Inspect and repair local facult state
|
|
98
143
|
consolidate Deduplicate and copy skills + MCP configs (interactive or --auto)
|
|
99
144
|
index Build a queryable index from the canonical store (see FACULT_ROOT_DIR)
|
|
100
|
-
list List indexed skills, MCP servers, agents, or
|
|
145
|
+
list List indexed skills, MCP servers, agents, snippets, or instructions
|
|
101
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
|
|
102
150
|
adapters List registered tool adapters
|
|
103
151
|
trust Mark a skill or MCP server as trusted (annotation only)
|
|
104
152
|
untrust Remove trusted annotation
|
|
@@ -146,6 +194,11 @@ Options:
|
|
|
146
194
|
--self (update) run self-update flow instead of remote item updates
|
|
147
195
|
--strict-source-trust Enforce trust-only remote install/update actions
|
|
148
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
|
|
149
202
|
`);
|
|
150
203
|
}
|
|
151
204
|
|
|
@@ -153,13 +206,18 @@ function printListHelp() {
|
|
|
153
206
|
console.log(`facult list — list indexed entries from the canonical store
|
|
154
207
|
|
|
155
208
|
Usage:
|
|
156
|
-
facult list [skills|mcp|agents|snippets] [options]
|
|
209
|
+
facult list [skills|mcp|agents|snippets|instructions] [options]
|
|
157
210
|
|
|
158
211
|
Options:
|
|
159
212
|
--enabled-for TOOL Only include entries enabled for a tool
|
|
160
213
|
--untrusted Only include entries that are not trusted
|
|
161
214
|
--flagged Only include entries flagged by audit
|
|
162
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
|
|
163
221
|
--json Print JSON array
|
|
164
222
|
`);
|
|
165
223
|
}
|
|
@@ -170,9 +228,49 @@ function printShowHelp() {
|
|
|
170
228
|
Usage:
|
|
171
229
|
facult show <name>
|
|
172
230
|
facult show mcp:<name> [--show-secrets]
|
|
231
|
+
facult show instruction:<name>
|
|
173
232
|
|
|
174
233
|
Options:
|
|
175
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
|
|
176
274
|
`);
|
|
177
275
|
}
|
|
178
276
|
|
|
@@ -247,15 +345,111 @@ export function parseListArgs(argv: string[]): ListCommandOptions {
|
|
|
247
345
|
return { kind, filters, json };
|
|
248
346
|
}
|
|
249
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
|
+
|
|
250
429
|
async function listCommand(argv: string[]) {
|
|
251
|
-
|
|
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
|
+
) {
|
|
252
439
|
printListHelp();
|
|
253
440
|
return;
|
|
254
441
|
}
|
|
255
442
|
|
|
256
443
|
let opts: ListCommandOptions;
|
|
257
444
|
try {
|
|
258
|
-
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
|
+
}
|
|
259
453
|
} catch (err) {
|
|
260
454
|
console.error(err instanceof Error ? err.message : String(err));
|
|
261
455
|
process.exitCode = 1;
|
|
@@ -264,14 +458,25 @@ async function listCommand(argv: string[]) {
|
|
|
264
458
|
|
|
265
459
|
let index: FacultIndex;
|
|
266
460
|
try {
|
|
267
|
-
index = await loadIndex(
|
|
461
|
+
index = await loadIndex({
|
|
462
|
+
rootDir: resolveCliContextRoot({
|
|
463
|
+
rootArg: context.rootArg,
|
|
464
|
+
scope: context.scopeMode,
|
|
465
|
+
cwd: process.cwd(),
|
|
466
|
+
}),
|
|
467
|
+
});
|
|
268
468
|
} catch (err) {
|
|
269
469
|
console.error(err instanceof Error ? err.message : String(err));
|
|
270
470
|
process.exitCode = 1;
|
|
271
471
|
return;
|
|
272
472
|
}
|
|
273
473
|
|
|
274
|
-
let entries:
|
|
474
|
+
let entries:
|
|
475
|
+
| SkillEntry[]
|
|
476
|
+
| McpEntry[]
|
|
477
|
+
| AgentEntry[]
|
|
478
|
+
| SnippetEntry[]
|
|
479
|
+
| InstructionEntry[] = [];
|
|
275
480
|
|
|
276
481
|
switch (opts.kind) {
|
|
277
482
|
case "skills":
|
|
@@ -286,6 +491,9 @@ async function listCommand(argv: string[]) {
|
|
|
286
491
|
case "snippets":
|
|
287
492
|
entries = filterSnippets(index.snippets ?? {}, opts.filters);
|
|
288
493
|
break;
|
|
494
|
+
case "instructions":
|
|
495
|
+
entries = filterInstructions(index.instructions ?? {}, opts.filters);
|
|
496
|
+
break;
|
|
289
497
|
default:
|
|
290
498
|
entries = [];
|
|
291
499
|
break;
|
|
@@ -307,7 +515,7 @@ async function listCommand(argv: string[]) {
|
|
|
307
515
|
const trustedLabel = meta.trusted === true ? "trusted" : "untrusted";
|
|
308
516
|
const auditLabel = (meta.auditStatus ?? "pending").trim().toLowerCase();
|
|
309
517
|
console.log(
|
|
310
|
-
`${skill.name}${desc}\t[${trustedLabel}; audit=${auditLabel}]`
|
|
518
|
+
`${skill.name}${desc}\t[${trustedLabel}; audit=${auditLabel}]${formatSourceMeta(skill)}`
|
|
311
519
|
);
|
|
312
520
|
} else if (opts.kind === "mcp") {
|
|
313
521
|
const meta = entry as McpEntry & {
|
|
@@ -316,9 +524,11 @@ async function listCommand(argv: string[]) {
|
|
|
316
524
|
};
|
|
317
525
|
const trustedLabel = meta.trusted === true ? "trusted" : "untrusted";
|
|
318
526
|
const auditLabel = (meta.auditStatus ?? "pending").trim().toLowerCase();
|
|
319
|
-
console.log(
|
|
527
|
+
console.log(
|
|
528
|
+
`${entry.name}\t[${trustedLabel}; audit=${auditLabel}]${formatSourceMeta(entry)}`
|
|
529
|
+
);
|
|
320
530
|
} else {
|
|
321
|
-
console.log(entry.name);
|
|
531
|
+
console.log(`${entry.name}${formatSourceMeta(entry)}`);
|
|
322
532
|
}
|
|
323
533
|
}
|
|
324
534
|
}
|
|
@@ -331,6 +541,60 @@ async function readEntryContents(entryPath: string): Promise<string> {
|
|
|
331
541
|
return file.text();
|
|
332
542
|
}
|
|
333
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
|
+
|
|
334
598
|
const SECRET_KEY_RE = /(TOKEN|KEY|SECRET|PASSWORD|PASS|BEARER)/i;
|
|
335
599
|
const SECRETY_STRING_RE =
|
|
336
600
|
/\b(sk-[A-Za-z0-9]{10,}|ghp_[A-Za-z0-9]{10,}|github_pat_[A-Za-z0-9_]{10,})\b/g;
|
|
@@ -339,6 +603,21 @@ function redactPossibleSecrets(value: string): string {
|
|
|
339
603
|
return value.replace(SECRETY_STRING_RE, "<redacted>");
|
|
340
604
|
}
|
|
341
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
|
+
|
|
342
621
|
function sanitizeForDisplay(value: unknown): unknown {
|
|
343
622
|
if (typeof value === "string") {
|
|
344
623
|
return redactPossibleSecrets(value);
|
|
@@ -361,14 +640,22 @@ function sanitizeForDisplay(value: unknown): unknown {
|
|
|
361
640
|
}
|
|
362
641
|
|
|
363
642
|
async function showCommand(argv: string[]) {
|
|
364
|
-
|
|
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
|
+
) {
|
|
365
652
|
printShowHelp();
|
|
366
653
|
return;
|
|
367
654
|
}
|
|
368
655
|
|
|
369
656
|
let showSecrets = false;
|
|
370
657
|
let raw: string | null = null;
|
|
371
|
-
for (const arg of
|
|
658
|
+
for (const arg of contextualArgv) {
|
|
372
659
|
if (!arg) {
|
|
373
660
|
continue;
|
|
374
661
|
}
|
|
@@ -396,7 +683,13 @@ async function showCommand(argv: string[]) {
|
|
|
396
683
|
|
|
397
684
|
let index: FacultIndex;
|
|
398
685
|
try {
|
|
399
|
-
index = await loadIndex(
|
|
686
|
+
index = await loadIndex({
|
|
687
|
+
rootDir: resolveCliContextRoot({
|
|
688
|
+
rootArg: context.rootArg,
|
|
689
|
+
scope: context.scopeMode,
|
|
690
|
+
cwd: process.cwd(),
|
|
691
|
+
}),
|
|
692
|
+
});
|
|
400
693
|
} catch (err) {
|
|
401
694
|
console.error(err instanceof Error ? err.message : String(err));
|
|
402
695
|
process.exitCode = 1;
|
|
@@ -409,25 +702,60 @@ async function showCommand(argv: string[]) {
|
|
|
409
702
|
if (raw.startsWith("mcp:")) {
|
|
410
703
|
kind = "mcp";
|
|
411
704
|
name = raw.slice("mcp:".length);
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
|
|
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;
|
|
415
720
|
const skill = index.skills[name];
|
|
416
721
|
const mcpServer = index.mcp?.servers?.[name];
|
|
417
722
|
const agent = index.agents?.[name];
|
|
418
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
|
+
};
|
|
419
738
|
|
|
420
|
-
if (kind === "skills" && skill) {
|
|
739
|
+
if (kind === "skills" && skill && matchesContext(skill)) {
|
|
421
740
|
entry = skill;
|
|
422
|
-
} else if (kind === "mcp" && mcpServer) {
|
|
741
|
+
} else if (kind === "mcp" && mcpServer && matchesContext(mcpServer)) {
|
|
423
742
|
entry = mcpServer;
|
|
424
|
-
} else if (kind === "skills" && agent) {
|
|
743
|
+
} else if (kind === "skills" && agent && matchesContext(agent)) {
|
|
425
744
|
kind = "agents";
|
|
426
745
|
entry = agent;
|
|
427
|
-
} else if (kind === "skills" && snippet) {
|
|
746
|
+
} else if (kind === "skills" && snippet && matchesContext(snippet)) {
|
|
428
747
|
kind = "snippets";
|
|
429
748
|
entry = snippet;
|
|
430
|
-
} 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)) {
|
|
431
759
|
kind = "mcp";
|
|
432
760
|
entry = mcpServer;
|
|
433
761
|
}
|
|
@@ -474,6 +802,91 @@ async function showCommand(argv: string[]) {
|
|
|
474
802
|
console.log(displayContents);
|
|
475
803
|
}
|
|
476
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
|
+
|
|
477
890
|
function adaptersCommand(argv: string[]) {
|
|
478
891
|
if (argv.includes("--help") || argv.includes("-h") || argv[0] === "help") {
|
|
479
892
|
console.log(
|
|
@@ -530,6 +943,15 @@ async function main(argv: string[]) {
|
|
|
530
943
|
case "show":
|
|
531
944
|
await showCommand(rest);
|
|
532
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;
|
|
533
955
|
case "adapters":
|
|
534
956
|
await adaptersCommand(rest);
|
|
535
957
|
return;
|