facult 2.7.0 → 2.7.2

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.
@@ -69,6 +69,12 @@ export interface AgentEntry {
69
69
  path: string;
70
70
  description?: string;
71
71
  lastModifiedAt?: string;
72
+ enabledFor?: string[];
73
+ trusted?: boolean;
74
+ trustedAt?: string;
75
+ trustedBy?: string;
76
+ auditStatus?: "pending" | "passed" | "flagged";
77
+ lastAuditAt?: string;
72
78
  }
73
79
 
74
80
  export interface SnippetEntry {
@@ -197,6 +203,53 @@ function extractIndexMeta(entry: unknown): {
197
203
  };
198
204
  }
199
205
 
206
+ function findPreviousEntryByCanonicalRef(
207
+ previous: Record<string, unknown> | undefined,
208
+ canonicalRef: string | undefined,
209
+ fallbackName: string
210
+ ): unknown {
211
+ if (!previous) {
212
+ return undefined;
213
+ }
214
+ if (typeof canonicalRef === "string") {
215
+ for (const value of Object.values(previous)) {
216
+ if (!isPlainObject(value)) {
217
+ continue;
218
+ }
219
+ if (value.canonicalRef === canonicalRef) {
220
+ return value;
221
+ }
222
+ }
223
+ }
224
+ const legacyFallback = previous[fallbackName];
225
+ if (
226
+ isPlainObject(legacyFallback) &&
227
+ typeof legacyFallback.canonicalRef !== "string"
228
+ ) {
229
+ return legacyFallback;
230
+ }
231
+ return undefined;
232
+ }
233
+
234
+ function findPreviousMcpEntry(
235
+ previous: Record<string, unknown> | undefined,
236
+ canonicalRef: string | undefined,
237
+ name: string
238
+ ): unknown {
239
+ if (!previous) {
240
+ return undefined;
241
+ }
242
+ const candidate = previous[name];
243
+ if (!isPlainObject(candidate)) {
244
+ return undefined;
245
+ }
246
+ return typeof candidate.canonicalRef !== "string" ||
247
+ (typeof canonicalRef === "string" &&
248
+ candidate.canonicalRef === canonicalRef)
249
+ ? candidate
250
+ : undefined;
251
+ }
252
+
200
253
  function stripQuotes(s: string): string {
201
254
  const t = s.trim();
202
255
  if (
@@ -489,8 +542,12 @@ async function indexSkills(
489
542
  const md = await Bun.file(skillMd).text();
490
543
  const { description, tags } = parseSkillMarkdown(md);
491
544
  const name = basename(d);
492
-
493
- const prev = previous?.[name];
545
+ const canonicalRef = canonicalRefForPath(source, "skills", d);
546
+ const prev = findPreviousEntryByCanonicalRef(
547
+ previous,
548
+ canonicalRef,
549
+ name
550
+ );
494
551
  const meta = extractIndexMeta(prev);
495
552
 
496
553
  out[name] = {
@@ -498,7 +555,7 @@ async function indexSkills(
498
555
  path: d,
499
556
  description,
500
557
  tags,
501
- canonicalRef: canonicalRefForPath(source, "skills", d),
558
+ canonicalRef,
502
559
  lastModifiedAt: await statIsoTime(skillMd),
503
560
  enabledFor: meta.enabledFor,
504
561
  trusted: meta.trusted ?? false,
@@ -550,12 +607,13 @@ async function indexMcpServers(
550
607
 
551
608
  const lm = await statIsoTime(mcpConfigPath);
552
609
  for (const name of Object.keys(serversObj).sort()) {
553
- const prev = previous?.[name];
610
+ const canonicalRef = canonicalRefForPath(source, "mcp", mcpConfigPath);
611
+ const prev = findPreviousMcpEntry(previous, canonicalRef, name);
554
612
  const meta = extractIndexMeta(prev);
555
613
  out[name] = {
556
614
  name,
557
615
  path: mcpConfigPath,
558
- canonicalRef: canonicalRefForPath(source, "mcp", mcpConfigPath),
616
+ canonicalRef,
559
617
  lastModifiedAt: lm,
560
618
  definition: serversObj[name],
561
619
  enabledFor: meta.enabledFor,
@@ -576,7 +634,8 @@ async function indexMcpServers(
576
634
 
577
635
  async function indexAgents(
578
636
  agentsDir: string,
579
- source: IndexedSource
637
+ source: IndexedSource,
638
+ previous?: Record<string, unknown>
580
639
  ): Promise<Record<string, AgentEntry>> {
581
640
  const out: Record<string, AgentEntry> = {};
582
641
  const files: string[] = [];
@@ -596,6 +655,9 @@ async function indexAgents(
596
655
  for (const p of files) {
597
656
  const name =
598
657
  basename(p) === "agent.toml" ? basename(dirname(p)) : basename(p);
658
+ const canonicalRef = canonicalRefForPath(source, "agents", p);
659
+ const prev = findPreviousEntryByCanonicalRef(previous, canonicalRef, name);
660
+ const meta = extractIndexMeta(prev);
599
661
  let description: string | undefined;
600
662
  try {
601
663
  const raw = await Bun.file(p).text();
@@ -611,8 +673,14 @@ async function indexAgents(
611
673
  name,
612
674
  path: p,
613
675
  description,
614
- canonicalRef: canonicalRefForPath(source, "agents", p),
676
+ canonicalRef,
615
677
  lastModifiedAt: await statIsoTime(p),
678
+ enabledFor: meta.enabledFor,
679
+ trusted: meta.trusted ?? false,
680
+ trustedAt: meta.trustedAt,
681
+ trustedBy: meta.trustedBy,
682
+ auditStatus: meta.auditStatus ?? "pending",
683
+ lastAuditAt: meta.lastAuditAt,
616
684
  ...entryScopeMeta(source),
617
685
  };
618
686
  }
@@ -782,6 +850,9 @@ async function indexSourceAssets(
782
850
  const prevSkills = isPlainObject(previousIndex?.skills)
783
851
  ? (previousIndex?.skills as Record<string, unknown>)
784
852
  : undefined;
853
+ const prevAgents = isPlainObject(previousIndex?.agents)
854
+ ? (previousIndex?.agents as Record<string, unknown>)
855
+ : undefined;
785
856
  const prevMcpMap =
786
857
  isPlainObject(previousIndex?.mcp) &&
787
858
  isPlainObject((previousIndex.mcp as Record<string, unknown>).servers)
@@ -795,7 +866,7 @@ async function indexSourceAssets(
795
866
  await Promise.all([
796
867
  indexSkills(skillsDir, source, prevSkills),
797
868
  indexMcpServers(canonicalMcpPath, source, prevMcpMap),
798
- indexAgents(agentsDir, source),
869
+ indexAgents(agentsDir, source, prevAgents),
799
870
  indexSnippets(snippetsDir, source),
800
871
  indexInstructions(instructionsDir, source),
801
872
  indexToolAssets(toolsDir, source),
package/src/index.ts CHANGED
@@ -1,10 +1,6 @@
1
1
  #!/usr/bin/env bun
2
2
 
3
3
  import { join } from "node:path";
4
- import { getAllAdapters } from "./adapters";
5
- import { aiCommand } from "./ai";
6
- import { auditCommand } from "./audit";
7
- import { autosyncCommand } from "./autosync";
8
4
  import {
9
5
  type CapabilityScopeMode,
10
6
  parseCliContextArgs,
@@ -20,9 +16,6 @@ import {
20
16
  renderPage,
21
17
  renderTable,
22
18
  } from "./cli-ui";
23
- import { consolidateCommand } from "./consolidate";
24
- import { doctorCommand } from "./doctor";
25
- import { disableCommand, enableCommand } from "./enable-disable";
26
19
  import type { AssetScope, AssetSourceKind } from "./graph";
27
20
  import {
28
21
  graphDependencies,
@@ -38,14 +31,6 @@ import type {
38
31
  SkillEntry,
39
32
  SnippetEntry,
40
33
  } from "./index-builder";
41
- import { indexCommand } from "./index-builder";
42
- import {
43
- manageCommand,
44
- managedCommand,
45
- syncCommand,
46
- unmanageCommand,
47
- } from "./manage";
48
- import { migrateCommand } from "./migrate";
49
34
  import type { QueryFilters } from "./query";
50
35
  import {
51
36
  filterAgents,
@@ -56,18 +41,6 @@ import {
56
41
  findCapabilities,
57
42
  loadIndex,
58
43
  } from "./query";
59
- import {
60
- installCommand,
61
- searchCommand,
62
- sourcesCommand,
63
- templatesCommand,
64
- updateCommand,
65
- verifySourceCommand,
66
- } from "./remote";
67
- import { scanCommand } from "./scan";
68
- import { selfUpdateCommand } from "./self-update";
69
- import { snippetsCommand } from "./snippets-cli";
70
- import { trustCommand, untrustCommand } from "./trust";
71
44
  import { parseJsonLenient } from "./util/json";
72
45
 
73
46
  type ListKind = "skills" | "mcp" | "agents" | "snippets" | "instructions";
@@ -1131,7 +1104,7 @@ async function graphCommand(argv: string[]) {
1131
1104
  }
1132
1105
  }
1133
1106
 
1134
- function adaptersCommand(argv: string[]) {
1107
+ async function adaptersCommand(argv: string[]) {
1135
1108
  if (argv.includes("--help") || argv.includes("-h") || argv[0] === "help") {
1136
1109
  console.log(
1137
1110
  renderPage({
@@ -1147,6 +1120,7 @@ function adaptersCommand(argv: string[]) {
1147
1120
  );
1148
1121
  return;
1149
1122
  }
1123
+ const { getAllAdapters } = await import("./adapters");
1150
1124
  const adapters = getAllAdapters();
1151
1125
  if (!adapters.length) {
1152
1126
  console.log(
@@ -1186,28 +1160,35 @@ async function main(argv: string[]) {
1186
1160
 
1187
1161
  // Convenience: allow `fclt --show-duplicates` as shorthand for `fclt scan --show-duplicates`.
1188
1162
  if (cmd === "--show-duplicates") {
1163
+ const { scanCommand } = await import("./scan");
1189
1164
  await scanCommand([cmd, ...rest]);
1190
1165
  return;
1191
1166
  }
1192
1167
 
1193
1168
  switch (cmd) {
1194
1169
  case "scan":
1195
- await scanCommand(rest);
1170
+ await import("./scan").then(({ scanCommand }) => scanCommand(rest));
1196
1171
  return;
1197
1172
  case "audit":
1198
- await auditCommand(rest);
1173
+ await import("./audit").then(({ auditCommand }) => auditCommand(rest));
1199
1174
  return;
1200
1175
  case "migrate":
1201
- await migrateCommand(rest);
1176
+ await import("./migrate").then(({ migrateCommand }) =>
1177
+ migrateCommand(rest)
1178
+ );
1202
1179
  return;
1203
1180
  case "doctor":
1204
- await doctorCommand(rest);
1181
+ await import("./doctor").then(({ doctorCommand }) => doctorCommand(rest));
1205
1182
  return;
1206
1183
  case "consolidate":
1207
- await consolidateCommand(rest);
1184
+ await import("./consolidate").then(({ consolidateCommand }) =>
1185
+ consolidateCommand(rest)
1186
+ );
1208
1187
  return;
1209
1188
  case "index":
1210
- await indexCommand(rest);
1189
+ await import("./index-builder").then(({ indexCommand }) =>
1190
+ indexCommand(rest)
1191
+ );
1211
1192
  return;
1212
1193
  case "list":
1213
1194
  await listCommand(rest);
@@ -1222,65 +1203,91 @@ async function main(argv: string[]) {
1222
1203
  await graphCommand(rest);
1223
1204
  return;
1224
1205
  case "ai":
1225
- await aiCommand(rest);
1206
+ await import("./ai").then(({ aiCommand }) => aiCommand(rest));
1226
1207
  return;
1227
1208
  case "adapters":
1228
1209
  await adaptersCommand(rest);
1229
1210
  return;
1230
1211
  case "trust":
1231
- await trustCommand(rest);
1212
+ await import("./trust").then(({ trustCommand }) => trustCommand(rest));
1232
1213
  return;
1233
1214
  case "untrust":
1234
- await untrustCommand(rest);
1215
+ await import("./trust").then(({ untrustCommand }) =>
1216
+ untrustCommand(rest)
1217
+ );
1235
1218
  return;
1236
1219
  case "manage":
1237
- await manageCommand(rest);
1220
+ await import("./manage").then(({ manageCommand }) => manageCommand(rest));
1238
1221
  return;
1239
1222
  case "unmanage":
1240
- await unmanageCommand(rest);
1223
+ await import("./manage").then(({ unmanageCommand }) =>
1224
+ unmanageCommand(rest)
1225
+ );
1241
1226
  return;
1242
1227
  case "managed":
1243
- await managedCommand(rest);
1228
+ await import("./manage").then(({ managedCommand }) =>
1229
+ managedCommand(rest)
1230
+ );
1244
1231
  return;
1245
1232
  case "enable":
1246
- await enableCommand(rest);
1233
+ await import("./enable-disable").then(({ enableCommand }) =>
1234
+ enableCommand(rest)
1235
+ );
1247
1236
  return;
1248
1237
  case "disable":
1249
- await disableCommand(rest);
1238
+ await import("./enable-disable").then(({ disableCommand }) =>
1239
+ disableCommand(rest)
1240
+ );
1250
1241
  return;
1251
1242
  case "sync":
1252
- await syncCommand(rest);
1243
+ await import("./manage").then(({ syncCommand }) => syncCommand(rest));
1253
1244
  return;
1254
1245
  case "autosync":
1255
- await autosyncCommand(rest);
1246
+ await import("./autosync").then(({ autosyncCommand }) =>
1247
+ autosyncCommand(rest)
1248
+ );
1256
1249
  return;
1257
1250
  case "search":
1258
- await searchCommand(rest);
1251
+ await import("./remote").then(({ searchCommand }) => searchCommand(rest));
1259
1252
  return;
1260
1253
  case "install":
1261
- await installCommand(rest);
1254
+ await import("./remote").then(({ installCommand }) =>
1255
+ installCommand(rest)
1256
+ );
1262
1257
  return;
1263
1258
  case "update":
1264
1259
  if (rest.includes("--self")) {
1265
- await selfUpdateCommand(rest.filter((arg) => arg !== "--self"));
1260
+ await import("./self-update").then(({ selfUpdateCommand }) =>
1261
+ selfUpdateCommand(rest.filter((arg) => arg !== "--self"))
1262
+ );
1266
1263
  return;
1267
1264
  }
1268
- await updateCommand(rest);
1265
+ await import("./remote").then(({ updateCommand }) => updateCommand(rest));
1269
1266
  return;
1270
1267
  case "self-update":
1271
- await selfUpdateCommand(rest);
1268
+ await import("./self-update").then(({ selfUpdateCommand }) =>
1269
+ selfUpdateCommand(rest)
1270
+ );
1272
1271
  return;
1273
1272
  case "verify-source":
1274
- await verifySourceCommand(rest);
1273
+ await import("./remote").then(({ verifySourceCommand }) =>
1274
+ verifySourceCommand(rest)
1275
+ );
1275
1276
  return;
1276
1277
  case "templates":
1277
- await templatesCommand(rest);
1278
+ await import("./remote").then(({ templatesCommand }) =>
1279
+ templatesCommand(rest)
1280
+ );
1278
1281
  return;
1279
1282
  case "sources":
1280
- await sourcesCommand(rest);
1283
+ await import("./remote").then(({ sourcesCommand }) =>
1284
+ sourcesCommand(rest)
1285
+ );
1281
1286
  return;
1282
1287
  case "snippets":
1283
- await snippetsCommand(rest);
1288
+ await import("./snippets-cli").then(({ snippetsCommand }) =>
1289
+ snippetsCommand(rest)
1290
+ );
1284
1291
  return;
1285
1292
  default:
1286
1293
  console.error(`Unknown command: ${cmd}`);