facult 1.3.0 → 2.1.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/src/scan.ts CHANGED
@@ -512,7 +512,7 @@ function defaultSourceSpecs(
512
512
  const specs: SourceSpec[] = [
513
513
  {
514
514
  id: "facult",
515
- name: "facult (canonical)",
515
+ name: "fclt (canonical)",
516
516
  candidates: [canonicalRoot],
517
517
  skillDirs: [join(canonicalRoot, "skills")],
518
518
  configFiles: [
@@ -1677,7 +1677,7 @@ function printSourceAssets(assets: SourceResult["assets"]) {
1677
1677
  }
1678
1678
 
1679
1679
  function printHuman(res: ScanResult) {
1680
- console.log(`facult scan — ${res.scannedAt}`);
1680
+ console.log(`fclt scan — ${res.scannedAt}`);
1681
1681
  console.log("");
1682
1682
 
1683
1683
  const foundSources = res.sources.filter((s) => s.found);
@@ -1976,7 +1976,7 @@ async function computeAssetContentDuplicates(
1976
1976
  function _printSkillsTable(res: ScanResult) {
1977
1977
  const all = computeSkillOccurrences(res);
1978
1978
 
1979
- console.log(`facult scan — ${res.scannedAt}`);
1979
+ console.log(`fclt scan — ${res.scannedAt}`);
1980
1980
  console.log("Skills (deduplicated by SKILL.md parent directory name):");
1981
1981
 
1982
1982
  if (all.length === 0) {
@@ -2009,7 +2009,7 @@ function _printSkillsTable(res: ScanResult) {
2009
2009
  function printSkillDuplicatesTable(res: ScanResult) {
2010
2010
  const all = computeSkillOccurrences(res).filter((d) => d.count > 1);
2011
2011
 
2012
- console.log(`facult scan — ${res.scannedAt}`);
2012
+ console.log(`fclt scan — ${res.scannedAt}`);
2013
2013
  console.log("Duplicate skills (same skill name appears in multiple places):");
2014
2014
 
2015
2015
  if (all.length === 0) {
@@ -2232,14 +2232,14 @@ export async function writeState(res: ScanResult) {
2232
2232
  }
2233
2233
 
2234
2234
  function printScanHelp() {
2235
- console.log(`facult scan — inventory local agent configs across tools
2235
+ console.log(`fclt scan — inventory local agent configs across tools
2236
2236
 
2237
2237
  Usage:
2238
- facult scan [--json] [--show-duplicates] [--tui]
2239
- facult scan --from <path> [--from <path> ...]
2238
+ fclt scan [--json] [--show-duplicates] [--tui]
2239
+ fclt scan --from <path> [--from <path> ...]
2240
2240
 
2241
2241
  Notes:
2242
- - If no --from roots are provided and no scanFrom is configured, facult defaults to scanning ~.
2242
+ - If no --from roots are provided and no scanFrom is configured, fclt defaults to scanning ~.
2243
2243
 
2244
2244
  Options:
2245
2245
  --json Print full JSON (ScanResult)
package/src/schema.ts CHANGED
@@ -3,7 +3,7 @@ export interface Provenance {
3
3
  sourceId: string;
4
4
  /** Path to the config file this item came from (if applicable). */
5
5
  sourcePath: string;
6
- /** ISO timestamp when facult imported/consolidated this item. */
6
+ /** ISO timestamp when fclt imported/consolidated this item. */
7
7
  importedAt: string;
8
8
  /** Optional source file mtime at import time (ISO). */
9
9
  sourceModifiedAt?: string;
@@ -8,8 +8,10 @@ import {
8
8
 
9
9
  const REPO_OWNER = "hack-dance";
10
10
  const REPO_NAME = "facult";
11
+ const PACKAGE_NAME = "facult";
11
12
  const DOWNLOAD_RETRIES = 12;
12
13
  const DOWNLOAD_RETRY_DELAY_MS = 5000;
14
+ const CLI_BASENAME_PATTERN = /^(fclt|facult)(\.exe)?$/;
13
15
 
14
16
  type InstallMethod =
15
17
  | "script-dev"
@@ -40,11 +42,11 @@ interface DetectInstallMethodContext {
40
42
  }
41
43
 
42
44
  function printHelp() {
43
- console.log(`facult self-update — update facult itself based on install method
45
+ console.log(`fclt self-update — update fclt itself based on install method
44
46
 
45
47
  Usage:
46
- facult self-update [--version <x.y.z|latest>] [--dry-run]
47
- facult update --self [--version <x.y.z|latest>] [--dry-run]
48
+ fclt self-update [--version <x.y.z|latest>] [--dry-run]
49
+ fclt update --self [--version <x.y.z|latest>] [--dry-run]
48
50
 
49
51
  Options:
50
52
  --version Target version (defaults to latest)
@@ -131,7 +133,8 @@ export function detectInstallMethod(
131
133
  if (
132
134
  facultBins.some(
133
135
  (facultBin) =>
134
- exec.startsWith(facultBin + sep) && basename(exec).startsWith("facult")
136
+ exec.startsWith(facultBin + sep) &&
137
+ CLI_BASENAME_PATTERN.test(basename(exec))
135
138
  )
136
139
  ) {
137
140
  return "release-script";
@@ -173,7 +176,7 @@ async function resolveLatestTag(): Promise<string> {
173
176
  const url = `https://api.github.com/repos/${REPO_OWNER}/${REPO_NAME}/releases/latest`;
174
177
  const res = await fetch(url, {
175
178
  headers: {
176
- "user-agent": "facult-self-update",
179
+ "user-agent": "fclt-self-update",
177
180
  accept: "application/vnd.github+json",
178
181
  },
179
182
  });
@@ -232,11 +235,16 @@ async function selfUpdateBinary(args: {
232
235
  const explicitTag = normalizeVersionTag(args.requestedVersion);
233
236
  const tag = explicitTag ?? (await resolveLatestTag());
234
237
  const version = stripTagPrefix(tag);
235
- const assetName = `facult-${version}-${target.platform}-${target.arch}${target.ext}`;
236
- const url = `https://github.com/${REPO_OWNER}/${REPO_NAME}/releases/download/${tag}/${assetName}`;
238
+ const assetNames = [
239
+ `${PACKAGE_NAME}-${version}-${target.platform}-${target.arch}${target.ext}`,
240
+ `facult-${version}-${target.platform}-${target.arch}${target.ext}`,
241
+ ];
242
+ const urls = assetNames.map(
243
+ (assetName) =>
244
+ `https://github.com/${REPO_OWNER}/${REPO_NAME}/releases/download/${tag}/${assetName}`
245
+ );
237
246
 
238
- const defaultBinaryName =
239
- target.platform === "windows" ? "facult.exe" : "facult";
247
+ const defaultBinaryName = target.platform === "windows" ? "fclt.exe" : "fclt";
240
248
  const fallbackPath = join(
241
249
  preferredGlobalFacultStateDir(args.home),
242
250
  "bin",
@@ -245,17 +253,19 @@ async function selfUpdateBinary(args: {
245
253
  const currentExec = process.execPath;
246
254
  const preferredPath =
247
255
  args.state?.binaryPath ||
248
- (basename(currentExec).startsWith("facult") ? currentExec : fallbackPath);
256
+ (CLI_BASENAME_PATTERN.test(basename(currentExec))
257
+ ? currentExec
258
+ : fallbackPath);
249
259
  const binaryPath = resolve(preferredPath);
250
260
 
251
261
  if (args.dryRun) {
252
- console.log(`[dry-run] Would download ${url}`);
262
+ console.log(`[dry-run] Would download ${urls[0]}`);
253
263
  console.log(`[dry-run] Would replace ${binaryPath}`);
254
264
  return;
255
265
  }
256
266
 
257
267
  await mkdir(dirname(binaryPath), { recursive: true });
258
- const bytes = await fetchReleaseBinaryWithRetry(url);
268
+ const bytes = await fetchFirstReleaseBinaryWithRetry(urls);
259
269
  const tmpPath = `${binaryPath}.tmp-${Date.now()}`;
260
270
  await Bun.write(tmpPath, Buffer.from(bytes));
261
271
  if (target.platform !== "windows") {
@@ -268,7 +278,7 @@ async function selfUpdateBinary(args: {
268
278
  packageVersion: version,
269
279
  binaryPath,
270
280
  });
271
- console.log(`Updated facult binary to ${version}`);
281
+ console.log(`Updated fclt binary to ${version}`);
272
282
  console.log(`Path: ${binaryPath}`);
273
283
  }
274
284
 
@@ -307,7 +317,7 @@ async function selfUpdateViaPackageManager(args: {
307
317
  ? stripTagPrefix(args.requestedVersion)
308
318
  : "latest";
309
319
 
310
- const installSpec = `facult@${targetVersion}`;
320
+ const installSpec = `${PACKAGE_NAME}@${targetVersion}`;
311
321
  const cmd =
312
322
  pm === "npm"
313
323
  ? ["npm", "install", "-g", installSpec]
@@ -329,7 +339,7 @@ async function selfUpdateViaPackageManager(args: {
329
339
  if (code !== 0) {
330
340
  throw new Error(`Self-update failed via ${pm} (exit ${code}).`);
331
341
  }
332
- console.log(`Updated facult via ${pm}: ${installSpec}`);
342
+ console.log(`Updated fclt via ${pm}: ${installSpec}`);
333
343
  }
334
344
 
335
345
  async function fetchReleaseBinaryWithRetry(url: string): Promise<ArrayBuffer> {
@@ -340,7 +350,7 @@ async function fetchReleaseBinaryWithRetry(url: string): Promise<ArrayBuffer> {
340
350
  try {
341
351
  const response = await fetch(url, {
342
352
  headers: {
343
- "user-agent": "facult-self-update",
353
+ "user-agent": "fclt-self-update",
344
354
  accept: "application/octet-stream",
345
355
  },
346
356
  });
@@ -375,6 +385,20 @@ async function fetchReleaseBinaryWithRetry(url: string): Promise<ArrayBuffer> {
375
385
  throw new Error(`Failed to download ${url}.${statusDetail}`);
376
386
  }
377
387
 
388
+ async function fetchFirstReleaseBinaryWithRetry(
389
+ urls: string[]
390
+ ): Promise<ArrayBuffer> {
391
+ let lastError: unknown;
392
+ for (const url of urls) {
393
+ try {
394
+ return await fetchReleaseBinaryWithRetry(url);
395
+ } catch (error) {
396
+ lastError = error;
397
+ }
398
+ }
399
+ throw lastError instanceof Error ? lastError : new Error("Download failed.");
400
+ }
401
+
378
402
  function sleep(ms: number): Promise<void> {
379
403
  return new Promise((resolve) => {
380
404
  setTimeout(resolve, ms);
@@ -10,14 +10,14 @@ import {
10
10
  const EDITOR_SPLIT_RE = /\s+/;
11
11
 
12
12
  function printSnippetsHelp() {
13
- console.log(`facult snippets — sync reusable blocks across config files
13
+ console.log(`fclt snippets — sync reusable blocks across config files
14
14
 
15
15
  Usage:
16
- facult snippets list [--json]
17
- facult snippets show <name> [--json]
18
- facult snippets create <name>
19
- facult snippets edit <name>
20
- facult snippets sync [--dry-run] [file...]
16
+ fclt snippets list [--json]
17
+ fclt snippets show <name> [--json]
18
+ fclt snippets create <name>
19
+ fclt snippets edit <name>
20
+ fclt snippets sync [--dry-run] [file...]
21
21
 
22
22
  Notes:
23
23
  - <name> is the snippet marker name (e.g. codingstyle, global/codingstyle, myproject/context)
package/src/trust.ts CHANGED
@@ -36,7 +36,7 @@ async function loadIndex(homeDir: string): Promise<FacultIndex> {
36
36
  });
37
37
  const file = Bun.file(indexPath);
38
38
  if (!(await file.exists())) {
39
- throw new Error(`Index not found at ${indexPath}. Run "facult index".`);
39
+ throw new Error(`Index not found at ${indexPath}. Run "fclt index".`);
40
40
  }
41
41
  const raw = await file.text();
42
42
  return JSON.parse(raw) as FacultIndex;
@@ -130,11 +130,11 @@ function parseNamesFromArgv(argv: string[]): string[] {
130
130
 
131
131
  export async function trustCommand(argv: string[]) {
132
132
  if (argv.includes("--help") || argv.includes("-h") || argv[0] === "help") {
133
- console.log(`facult trust — mark skills or MCP servers as trusted (annotation only)
133
+ console.log(`fclt trust — mark skills or MCP servers as trusted (annotation only)
134
134
 
135
135
  Usage:
136
- facult trust <name> [moreNames...]
137
- facult trust mcp:<name> [moreNames...]
136
+ fclt trust <name> [moreNames...]
137
+ fclt trust mcp:<name> [moreNames...]
138
138
  `);
139
139
  return;
140
140
  }
@@ -143,7 +143,7 @@ Usage:
143
143
  await applyTrust({ names, mode: "trust" });
144
144
  console.log(`Marked as trusted: ${names.join(", ")}`);
145
145
  console.log(
146
- 'Note: Trust is an annotation. Run "facult audit" for security review.'
146
+ 'Note: Trust is an annotation. Run "fclt audit" for security review.'
147
147
  );
148
148
  } catch (err) {
149
149
  console.error(err instanceof Error ? err.message : String(err));
@@ -153,11 +153,11 @@ Usage:
153
153
 
154
154
  export async function untrustCommand(argv: string[]) {
155
155
  if (argv.includes("--help") || argv.includes("-h") || argv[0] === "help") {
156
- console.log(`facult untrust — remove trusted annotation
156
+ console.log(`fclt untrust — remove trusted annotation
157
157
 
158
158
  Usage:
159
- facult untrust <name> [moreNames...]
160
- facult untrust mcp:<name> [moreNames...]
159
+ fclt untrust <name> [moreNames...]
160
+ fclt untrust mcp:<name> [moreNames...]
161
161
  `);
162
162
  return;
163
163
  }
package/src/tui.ts CHANGED
@@ -29,7 +29,7 @@ export async function runSkillsTui(res: ScanResult): Promise<void> {
29
29
  height,
30
30
  borderStyle: "double",
31
31
  borderColor: "#4CC9F0",
32
- title: "facult scan — skills",
32
+ title: "fclt scan — skills",
33
33
  titleAlignment: "center",
34
34
  backgroundColor: "#001122",
35
35
  });