@standards/cli 1.0.0-alpha.416 → 1.0.0-alpha.419

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/dist/bin.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  /*! © 2025-2026 AND YOU CREATE SAS (RCS Paris 940 190 614). Proprietary — see LICENSE (Standards SDK License 1.0). */
3
- import { t as discoverBundles } from "./discover-bundles-D5RNCkan.mjs";
3
+ import { t as discoverBundles } from "./discover-bundles-DPpEZVv0.mjs";
4
4
  import { createRequire } from "node:module";
5
5
  import { styleText } from "node:util";
6
6
  import { BundleConflictError, StandardsRequestError, createTransport, syncBundle } from "@standards/client";
@@ -19,7 +19,7 @@ import { stdin, stdout } from "node:process";
19
19
  import { createInterface } from "node:readline/promises";
20
20
  import { homedir } from "node:os";
21
21
  import { isSafeSkillFilePath, skillFileText } from "@standards/constants";
22
- //#region src/output.ts
22
+ // src/output.ts
23
23
  const MAX_CELL_WIDTH = 50;
24
24
  function truncate(value, maxLength) {
25
25
  if (value.length <= maxLength) return value;
@@ -71,8 +71,7 @@ function formatOutput(data, format) {
71
71
  }
72
72
  process.stdout.write(`${formatTable(items)}\n`);
73
73
  }
74
- //#endregion
75
- //#region src/client.ts
74
+ // src/client.ts
76
75
  /** The CLI's transport: the profile's bearer key and tenant header over the shared HTTP transport. */
77
76
  function createClient(config) {
78
77
  return createTransport({
@@ -81,8 +80,7 @@ function createClient(config) {
81
80
  tenantId: config.tenantId
82
81
  });
83
82
  }
84
- //#endregion
85
- //#region src/commands/common.ts
83
+ // src/commands/common.ts
86
84
  function getGlobalOptions(cmd) {
87
85
  return cmd.optsWithGlobals();
88
86
  }
@@ -154,8 +152,7 @@ function requireConfirmation(yes, message) {
154
152
  function messageOf(error) {
155
153
  return error instanceof Error ? error.message : String(error);
156
154
  }
157
- //#endregion
158
- //#region src/commands/ai.ts
155
+ // src/commands/ai.ts
159
156
  const SCOPES = ["me", "workspace"];
160
157
  /** `GET /ai/usage` reads inclusive UTC days; anything else reaches the API as a 400. */
161
158
  const ISO_DAY = /^\d{4}-\d{2}-\d{2}$/u;
@@ -185,8 +182,7 @@ function registerAiCommand(program) {
185
182
  formatOutput(await getAppClientFromCommand(cmd).ai.wallet({}), getFormat(cmd));
186
183
  });
187
184
  }
188
- //#endregion
189
- //#region src/commands/auth.ts
185
+ // src/commands/auth.ts
190
186
  function registerAuthCommand(program) {
191
187
  program.command("auth").description("Inspect CLI authentication").command("whoami").description("Show current configuration and validate API key").action(async (_opts, cmd) => {
192
188
  const root = getGlobalOptions(cmd);
@@ -201,8 +197,7 @@ function registerAuthCommand(program) {
201
197
  if (Array.isArray(keys) && keys.length > 0) write(` Active keys: ${keys.filter((key) => !key.revokedAt).length}`);
202
198
  });
203
199
  }
204
- //#endregion
205
- //#region src/discovery/order-bundles.ts
200
+ // src/discovery/order-bundles.ts
206
201
  /**
207
202
  * Orders discovered bundles so each comes after the bundles it `uses`.
208
203
  * Bundles a `uses` names that were not discovered are already the host's concern.
@@ -223,8 +218,7 @@ async function orderByUses(discovered) {
223
218
  for (const entry of discovered) await visit(entry);
224
219
  return ordered;
225
220
  }
226
- //#endregion
227
- //#region src/commands/bundles.ts
221
+ // src/commands/bundles.ts
228
222
  const HASH_PREFIX_LENGTH = 7;
229
223
  function shortHash(hash) {
230
224
  return hash?.slice(0, HASH_PREFIX_LENGTH) ?? "";
@@ -272,6 +266,10 @@ function collectDecision(value, decisions) {
272
266
  };
273
267
  throw new ValidationError(`--decision must read <pieceId>=bind, <pieceId>=skip or <pieceId>=rename:<name> (received: ${value})`, []);
274
268
  }
269
+ /** A repeatable option's values, in the order given. */
270
+ function collectPieceId(value, pieceIds) {
271
+ return [...pieceIds, value];
272
+ }
275
273
  /** The input `preview` and `add` share: whole bundles, in one locale. */
276
274
  function addInput(names, opts) {
277
275
  return {
@@ -286,8 +284,9 @@ function withAddOptions(command) {
286
284
  }
287
285
  /**
288
286
  * The workspace's bundles: sync the ones the project declares, list what is
289
- * installed, remove one, and add a bundle the workspace may add as a copy it
290
- * owns (`preview`, then `add` with the preview's fingerprint).
287
+ * installed and where each stands, remove one, add a bundle the workspace may
288
+ * add as a copy it owns (`preview`, then `add` with the preview's fingerprint)
289
+ * and update such a copy (`update-preview`, then `update` with its fingerprint).
291
290
  */
292
291
  function registerBundlesCommand(program) {
293
292
  const bundles = program.command("bundles").description("Sync and manage the workspace's bundles");
@@ -302,6 +301,9 @@ function registerBundlesCommand(program) {
302
301
  installedAt: row.installedAt
303
302
  })), getFormat(cmd));
304
303
  }));
304
+ bundles.command("status").description("Show where each installed bundle stands and the bundles that depend on it").action((_opts, cmd) => run(async () => {
305
+ formatOutput(await getAppClientFromCommand(cmd).bundles.status({}), getFormat(cmd));
306
+ }));
305
307
  bundles.command("available").description("List the bundles the workspace may add, and whether each is installed").option("--locale <locale>", `language of the labels (${BUNDLE_LOCALES.join(", ")})`, "en").action((opts, cmd) => run(async () => {
306
308
  const { available } = await getAppClientFromCommand(cmd).bundles.list({ locale: parseLocale(opts.locale) });
307
309
  formatOutput(available, getFormat(cmd));
@@ -316,14 +318,26 @@ function registerBundlesCommand(program) {
316
318
  fingerprint: opts.fingerprint
317
319
  }), getFormat(cmd));
318
320
  }));
319
- bundles.command("remove").description("Remove a synced bundle; its pieces are demoted, never deleted").argument("<name>", "bundle name").option("--yes", "remove without confirmation").action((name, opts, cmd) => run(async () => {
321
+ bundles.command("update-preview").description("Plan an added bundle's update, piece by piece, and the plan's fingerprint").argument("<name>", "bundle name").action((name, _opts, cmd) => run(async () => {
322
+ formatOutput(await getAppClientFromCommand(cmd).bundles.updatePreview({ name }), getFormat(cmd));
323
+ }));
324
+ bundles.command("update").description("Update an added bundle as its preview showed; nothing is removed").argument("<name>", "bundle name").requiredOption("--fingerprint <fingerprint>", "the fingerprint `bundles update-preview` returned").option("--take <pieceId>", "take the new version of a piece you changed (repeatable)", collectPieceId, []).option("--skip-missing <pieceId>", "do not reinstall a missing piece (repeatable)", collectPieceId, []).option("--decision <pieceId=choice>", "how to settle a collision: bind, skip or rename:<name> (repeatable)", collectDecision, {}).action((name, opts, cmd) => run(async () => {
325
+ const { applied } = await getAppClientFromCommand(cmd).bundles.update({
326
+ name,
327
+ fingerprint: opts.fingerprint,
328
+ take: opts.take,
329
+ skipMissing: opts.skipMissing,
330
+ decisions: opts.decision
331
+ });
332
+ console.info(`${name} updated, ${applied} applied`);
333
+ }));
334
+ bundles.command("remove").description("Remove a synced bundle; its pieces are demoted, never deleted. An added bundle is refused: uninstall it from the Bundles window").argument("<name>", "bundle name").option("--yes", "remove without confirmation").action((name, opts, cmd) => run(async () => {
320
335
  requireConfirmation(opts.yes, `Removing bundle "${name}" demotes its objects to workspace-owned. Re-run with "--yes" to confirm.`);
321
336
  await getAppClientFromCommand(cmd).bundles.remove({ name });
322
337
  console.info(`${name} removed`);
323
338
  }));
324
339
  }
325
- //#endregion
326
- //#region src/commands/connectors.ts
340
+ // src/commands/connectors.ts
327
341
  const PROVIDERS = Object.keys({
328
342
  github: true,
329
343
  slack: true,
@@ -356,7 +370,7 @@ function connectDisclosure(provider, capabilities = []) {
356
370
  if (modify) lines.push("- create, change and delete your events");
357
371
  lines.push("It shows them in the workspace, links them to records and makes them searchable.", "The default assistant can read this calendar, and AI providers process your events whenever an agent works on them.");
358
372
  } else return null;
359
- lines.push("Your data is not sold and not used for ads.", "Disconnect at any time in Settings > Integrations.", "Details: https://docs.standards.new/docs/integrations/connected-accounts");
373
+ lines.push("Your data is not sold and not used for ads.", "Disconnect at any time on the Connectors page.", "Details: https://docs.standards.new/docs/integrations/connected-accounts");
360
374
  return lines.join("\n");
361
375
  }
362
376
  /** Parse a comma-separated `--capabilities` flag; unknown tiers are refused before the request. */
@@ -378,16 +392,12 @@ function registerConnectorsCommand(program) {
378
392
  connectors.command("list").description("List connector connections").option("--scope <scope>", "connection scope (tenant or actor)", "tenant").action(async (opts, cmd) => {
379
393
  formatOutput(await getAppClientFromCommand(cmd).connectors.list({ scope: resolveScope(opts.scope) }), getFormat(cmd));
380
394
  });
381
- connectors.command("connect").description("Start an OAuth flow and return the authorization URL to open").requiredOption("--provider <provider>", `connector provider (${PROVIDERS.join(", ")}); run "connectors providers" for the ones this deployment configured`).option("--scope <scope>", "connection scope (tenant or actor)", "tenant").option("--capabilities <list>", `comma-separated capability tiers beyond read (${CAPABILITIES.join(", ")})`).option("--yes", "confirm the access a mailbox or calendar connection gives Standards").action(async (opts, cmd) => {
395
+ connectors.command("connect").description("Check a provider and capabilities; the account itself is connected from the app").requiredOption("--provider <provider>", `connector provider (${PROVIDERS.join(", ")}); run "connectors providers" for the ones this deployment configured`).option("--scope <scope>", "connection scope (tenant or actor)", "tenant").option("--capabilities <list>", `comma-separated capability tiers beyond read (${CAPABILITIES.join(", ")})`).option("--yes", "confirm the access a mailbox or calendar connection gives Standards").action((opts) => {
382
396
  if (!PROVIDERS.includes(opts.provider)) throw new ValidationError(`--provider must be one of: ${PROVIDERS.join(", ")}`, []);
383
397
  const capabilities = parseCapabilities(opts.capabilities);
384
398
  const disclosure = connectDisclosure(opts.provider, capabilities);
385
399
  if (disclosure && !opts.yes) throw new Error(`${disclosure}\n\nRe-run with "--yes" to continue.`);
386
- formatOutput(await getAppClientFromCommand(cmd).connectors.startAuth({
387
- provider: opts.provider,
388
- scope: resolveScope(opts.scope),
389
- ...capabilities ? { capabilities } : {}
390
- }), getFormat(cmd));
400
+ process.stdout.write(`${opts.provider} is connected from the Standards app: open Connectors in the sidebar and connect it there.\n`);
391
401
  });
392
402
  connectors.command("disconnect").description("Disconnect (delete) a connector connection").argument("<id>", "connection ID").option("--yes", "disconnect without confirmation").option("--remove-imported", "also remove what a mail or calendar connection imported (kept by default)").action(async (id, opts, cmd) => {
393
403
  if (!opts.yes) throw new Error("Disconnecting a connector is explicit. Re-run with \"--yes\" to confirm.");
@@ -398,8 +408,7 @@ function registerConnectorsCommand(program) {
398
408
  process.stdout.write(`${styleText("green", "✓")} Connector connection ${id} disconnected.\n`);
399
409
  });
400
410
  }
401
- //#endregion
402
- //#region src/drift/shared-state.ts
411
+ // src/drift/shared-state.ts
403
412
  async function readSchemaState(client) {
404
413
  const state = parseSchemaState(await client.schemaState.get({}));
405
414
  if (createHash("sha256").update(canonicalStringify(schemaStateSourcePayload(state.entries))).digest("hex") !== state.sourceFingerprint) throw new ValidationError("Invalid schema state: sourceFingerprint does not match deployed source", []);
@@ -408,8 +417,7 @@ async function readSchemaState(client) {
408
417
  function prettyCanonical(value) {
409
418
  return JSON.stringify(JSON.parse(canonicalStringify(value)), null, 2);
410
419
  }
411
- //#endregion
412
- //#region src/commands/diff.ts
420
+ // src/commands/diff.ts
413
421
  async function runDiffCommand(client) {
414
422
  try {
415
423
  const diff = diffSchemaState(await readSchemaState(client));
@@ -443,8 +451,7 @@ function registerDiffCommand(program) {
443
451
  process.exit(result.exitCode);
444
452
  });
445
453
  }
446
- //#endregion
447
- //#region src/commands/documents.ts
454
+ // src/commands/documents.ts
448
455
  /**
449
456
  * Human-readable table row for a pack file. `id` is kept (unlike other
450
457
  * dropped fields) because `remove-file <documentId> <fileId>` requires it —
@@ -517,8 +524,7 @@ function registerDocumentsCommand(program) {
517
524
  process.stdout.write(text.endsWith("\n") ? text : `${text}\n`);
518
525
  });
519
526
  }
520
- //#endregion
521
- //#region src/commands/embeddings.ts
527
+ // src/commands/embeddings.ts
522
528
  function registerEmbeddingsCommand(program) {
523
529
  program.command("embeddings").description("Maintain record and email embeddings").command("drain").description("Embed every pending record and email of the tenant").action(async (_opts, cmd) => {
524
530
  const tenant = requireTenant(cmd, "An embedding drain names its tenant explicitly. Pass \"--tenant <id>\".");
@@ -526,8 +532,7 @@ function registerEmbeddingsCommand(program) {
526
532
  process.stdout.write(`${styleText("green", "✓")} Embedding drain accepted for tenant ${tenant}.\n`);
527
533
  });
528
534
  }
529
- //#endregion
530
- //#region src/commands/folders.ts
535
+ // src/commands/folders.ts
531
536
  function registerFoldersCommand(program) {
532
537
  program.command("folders").description("Manage record drive folders").command("reconcile-paths").description("Create a folder tree on a record drive from paths").argument("<object>", "object name (e.g. contacts)").argument("<recordId>", "record ID owning the drive").option("--path <path>", "folder path to create (repeatable)", (val, acc) => {
533
538
  acc.push(val);
@@ -547,8 +552,7 @@ function registerFoldersCommand(program) {
547
552
  }), getFormat(cmd));
548
553
  });
549
554
  }
550
- //#endregion
551
- //#region src/commands/invitations.ts
555
+ // src/commands/invitations.ts
552
556
  /** Invitation ids are `randomUUID` server-side, so anything else is a caller mistake. */
553
557
  const INVITATION_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
554
558
  /**
@@ -586,8 +590,7 @@ function registerInvitationsCommand(program) {
586
590
  formatOutput(await getAppClientFromCommand(cmd).tenantInvitations.revoke({ id: invitationId }), getFormat(cmd));
587
591
  });
588
592
  }
589
- //#endregion
590
- //#region src/commands/keys.ts
593
+ // src/commands/keys.ts
591
594
  async function resolveRoleId(client, name) {
592
595
  const match = (await client.permissions.listRoles({})).find((role) => role.name === name);
593
596
  if (!match) throw new Error(`Unknown role "${name}". Roles are listed in the app's People settings.`);
@@ -617,8 +620,7 @@ function registerKeysCommand(program) {
617
620
  process.stdout.write(`${styleText("green", "✓")} API key ${id} revoked.\n`);
618
621
  });
619
622
  }
620
- //#endregion
621
- //#region src/commands/mcp.ts
623
+ // src/commands/mcp.ts
622
624
  /** The auth types `POST /mcp-servers` accepts today — `oauth` is rejected by the API. */
623
625
  const AUTH_TYPES = ["none", "header"];
624
626
  /** Build the `auth` block the API expects, failing before the request when a header auth is incomplete. */
@@ -682,8 +684,7 @@ function registerMcpCommand(program) {
682
684
  process.stdout.write(`${styleText("green", "✓")} MCP server ${id} disconnected.\n`);
683
685
  });
684
686
  }
685
- //#endregion
686
- //#region src/commands/meetings.ts
687
+ // src/commands/meetings.ts
687
688
  const ORDERS = ["asc", "desc"];
688
689
  /** Reject a typo instead of letting it fall back to the API default silently. */
689
690
  function parseOrder(order) {
@@ -760,8 +761,7 @@ function registerMeetingsCommand(program) {
760
761
  process.stdout.write(`${styleText("green", "✓")} Meeting grants recompute accepted for tenant ${tenant}.\n`);
761
762
  });
762
763
  }
763
- //#endregion
764
- //#region src/commands/memory.ts
764
+ // src/commands/memory.ts
765
765
  function registerMemoryCommand(program) {
766
766
  program.command("memory").description("Maintain agent memory").command("backfill").description("Rebuild agent memory from the tenant's last 30 days of sessions and meetings").option("--yes", "backfill without confirmation").action(async (opts, cmd) => {
767
767
  if (!opts.yes) throw new ValidationError("A memory backfill spends model calls on the last 30 days of evidence. Re-run with \"--yes\" to confirm.", []);
@@ -770,8 +770,7 @@ function registerMemoryCommand(program) {
770
770
  process.stdout.write(`${styleText("green", "✓")} Memory backfill queued for tenant ${tenant}. It runs in the background — follow the server logs for progress.\n`);
771
771
  });
772
772
  }
773
- //#endregion
774
- //#region src/drift/reconciliation-prompt.ts
773
+ // src/drift/reconciliation-prompt.ts
775
774
  function renderReconciliationPrompt(state) {
776
775
  const lines = [
777
776
  "# Standards schema reconciliation",
@@ -786,8 +785,7 @@ function renderReconciliationPrompt(state) {
786
785
  for (const entry of changes) lines.push(`## ${entry.change} ${JSON.stringify(entry.address)}`, `Status: ${entry.status}${entry.status === "copy" ? " (retained)" : ""}`, "```json", prettyCanonical(entry.effective ?? entry.source), "```", "");
787
786
  return `${lines.join("\n").trimEnd()}\n`;
788
787
  }
789
- //#endregion
790
- //#region src/commands/pull.ts
788
+ // src/commands/pull.ts
791
789
  function registerPullCommand(program) {
792
790
  program.command("pull").description("Read deployed source vs shared runtime; excludes unbuilt local TypeScript").option("--json", "Emit canonical shared state JSON instead of guidance").action(async (opts, cmd) => {
793
791
  let code = 0;
@@ -801,15 +799,13 @@ function registerPullCommand(program) {
801
799
  process.exit(code);
802
800
  });
803
801
  }
804
- //#endregion
805
- //#region src/commands/quotas.ts
802
+ // src/commands/quotas.ts
806
803
  function registerQuotasCommand(program) {
807
804
  program.command("quotas").description("Inspect the tenant's remaining capacity").command("list").description("List one state per quota key (limit is null when nothing is enforced)").action(async (_opts, cmd) => {
808
805
  formatOutput(await getAppClientFromCommand(cmd).quotas.list({}), getFormat(cmd));
809
806
  });
810
807
  }
811
- //#endregion
812
- //#region src/commands/records.ts
808
+ // src/commands/records.ts
813
809
  function parseSortFlag(sort) {
814
810
  const [attribute, direction = "asc"] = sort.split(":");
815
811
  return [{
@@ -820,8 +816,8 @@ function parseSortFlag(sort) {
820
816
  /** Build the shared list/search request body from common query flags. */
821
817
  function buildQueryBody(opts) {
822
818
  const body = {};
823
- if (opts.limit) body.limit = Number(opts.limit);
824
- if (opts.offset) body.offset = Number(opts.offset);
819
+ if (opts.limit !== void 0) body.limit = parseCount("--limit", opts.limit);
820
+ if (opts.offset !== void 0) body.offset = parseCount("--offset", opts.offset);
825
821
  if (opts.sort) body.sorts = parseSortFlag(opts.sort);
826
822
  if (opts.filter) body.filters = JSON.parse(opts.filter);
827
823
  if (opts.fields !== void 0) body.fields = parseCsvList(opts.fields);
@@ -974,8 +970,7 @@ function registerRecordsCommand(program) {
974
970
  }), getFormat(cmd));
975
971
  });
976
972
  }
977
- //#endregion
978
- //#region src/config.ts
973
+ // src/config.ts
979
974
  const DEFAULT_API_URL = "http://localhost:4100/v1";
980
975
  const ENV_PROFILE_NAME = "sandbox";
981
976
  function getDefaultApiUrl() {
@@ -1092,8 +1087,7 @@ async function resolveCliConfig(options) {
1092
1087
  apiKey: process.env.STANDARDS_API_KEY
1093
1088
  };
1094
1089
  }
1095
- //#endregion
1096
- //#region src/commands/root.ts
1090
+ // src/commands/root.ts
1097
1091
  async function promptForMissingValue(label) {
1098
1092
  const rl = createInterface({
1099
1093
  input: stdin,
@@ -1143,8 +1137,7 @@ function registerRootCommands(program) {
1143
1137
  process.stdout.write(`${styleText("green", "✓")} Standards instance removed.\n`);
1144
1138
  });
1145
1139
  }
1146
- //#endregion
1147
- //#region src/commands/schema.ts
1140
+ // src/commands/schema.ts
1148
1141
  function registerSchemaCommand(program) {
1149
1142
  const schema = program.command("schema").description("Inspect schema objects and attributes");
1150
1143
  schema.command("list").description("List all schema objects").action(async (_opts, cmd) => {
@@ -1157,8 +1150,7 @@ function registerSchemaCommand(program) {
1157
1150
  formatOutput(await getAppClientFromCommand(cmd).schemaGroups.list({}), getFormat(cmd));
1158
1151
  });
1159
1152
  }
1160
- //#endregion
1161
- //#region src/commands/search.ts
1153
+ // src/commands/search.ts
1162
1154
  function registerSearchCommand(program) {
1163
1155
  program.command("search").description("Maintain the Standards search index").command("reindex").description("Rebuild the tenant search index beside the live one, then switch").option("--yes", "reindex without confirmation").option("--emails", "hand the tenant's stored emails back to the email indexer instead (nothing is cleared)").option("--after-id <emailId>", "with --emails, resume after the last email id a failed run reported").option("--rebuild", "with --emails and --yes, rebuild the mail search index from the stored mail instead (lifts a quarantine)").action(async (opts, cmd) => {
1164
1156
  if (opts.afterId !== void 0 && !opts.emails) throw new ValidationError("\"--after-id\" resumes an email reindex. Pass it with \"--emails\".", []);
@@ -1181,8 +1173,7 @@ function registerSearchCommand(program) {
1181
1173
  process.stdout.write(`${styleText("green", "✓")} Index rebuild accepted for tenant ${tenant}. Search keeps answering from the current index until the rebuilt one replaces it — follow the server logs for progress.\n`);
1182
1174
  });
1183
1175
  }
1184
- //#endregion
1185
- //#region src/commands/skills.ts
1176
+ // src/commands/skills.ts
1186
1177
  const SKILL_FILE = "SKILL.md";
1187
1178
  const DEFAULT_SEARCH_LIMIT = 20;
1188
1179
  /** A folder name: one path segment under the rule (`isSafeSkillFilePath`). */
@@ -1304,23 +1295,38 @@ async function runSkillsPull(client, dir, names) {
1304
1295
  }
1305
1296
  return written;
1306
1297
  }
1307
- /**
1308
- * `standards skills search`: our index, or skills.sh with `community`. Every
1309
- * row carries the same keys, because a table takes its columns from the first.
1310
- */
1311
- async function runSkillsSearch(client, query, options = {}) {
1312
- const limit = options.limit === void 0 ? DEFAULT_SEARCH_LIMIT : parseCount("--limit", options.limit);
1313
- return (await client.skillCatalog.search({
1314
- query,
1315
- scope: options.community === true ? "community" : "official",
1316
- limit
1317
- })).map(({ source, name, state, reason, description, installs }) => ({
1298
+ function searchLimit(limit) {
1299
+ return limit === void 0 ? DEFAULT_SEARCH_LIMIT : parseCount("--limit", limit);
1300
+ }
1301
+ /** Every row carries the same keys, because a table takes its columns from the first. */
1302
+ function catalogRow(result) {
1303
+ const { source, name, state, reason, description, installs } = result;
1304
+ return {
1318
1305
  source,
1319
1306
  name,
1320
1307
  state,
1321
1308
  reason,
1322
1309
  description,
1323
1310
  installs
1311
+ };
1312
+ }
1313
+ /** `standards skills search`: our index, or skills.sh with `community`. */
1314
+ async function runSkillsSearch(client, query, options = {}) {
1315
+ return (await client.skillCatalog.search({
1316
+ query,
1317
+ scope: options.community === true ? "community" : "official",
1318
+ limit: searchLimit(options.limit)
1319
+ })).map(catalogRow);
1320
+ }
1321
+ /** `standards skills top`: skills.sh's all-time leaderboard, or the last 24 hours with `trending`. */
1322
+ async function runSkillsTop(client, options = {}) {
1323
+ return (await client.skillCatalog.search({
1324
+ query: "",
1325
+ scope: options.trending === true ? "trending" : "top",
1326
+ limit: searchLimit(options.limit)
1327
+ })).map((result) => ({
1328
+ ...catalogRow(result),
1329
+ weeklyInstalls: result.weeklyInstalls
1324
1330
  }));
1325
1331
  }
1326
1332
  /** `standards skills preview`: what a source would install, the source checked here first. */
@@ -1402,6 +1408,9 @@ function registerSkillsCommand(program) {
1402
1408
  skills.command("search").description("Find skills to add: the official catalogue, or skills.sh with --community").argument("<query>", "what the skill should do").option("--community", "search skills.sh instead of the official catalogue").option("--limit <n>", "max results to return (up to 50)").action(async (query, opts, cmd) => {
1403
1409
  await printAnswer(cmd, () => runSkillsSearch(getAppClientFromCommand(cmd), query, opts));
1404
1410
  });
1411
+ skills.command("top").description("List skills.sh's most installed skills, or the last 24 hours with --trending").option("--trending", "rank by the last 24 hours instead of all time").option("--limit <n>", "max results to return (up to 50)").action(async (opts, cmd) => {
1412
+ await printAnswer(cmd, () => runSkillsTop(getAppClientFromCommand(cmd), opts));
1413
+ });
1405
1414
  skills.command("preview").description("Show what a source would install, without installing it").argument("<source>", "owner/repo@skill or owner/repo@skill#ref").action(async (source, _opts, cmd) => {
1406
1415
  await printAnswer(cmd, () => runSkillsPreview(getAppClientFromCommand(cmd), source));
1407
1416
  });
@@ -1415,8 +1424,7 @@ function registerSkillsCommand(program) {
1415
1424
  await printAnswer(cmd, () => runSkillsRefresh(getAppClientFromCommand(cmd)));
1416
1425
  });
1417
1426
  }
1418
- //#endregion
1419
- //#region src/version.ts
1427
+ // src/version.ts
1420
1428
  /**
1421
1429
  * The installed package's version, read from its own manifest: `src/` and the
1422
1430
  * built `dist/` both sit one level under it, and npm always ships
@@ -1431,8 +1439,7 @@ function cliVersion() {
1431
1439
  const manifest = createRequire(import.meta.url)("../package.json");
1432
1440
  return typeof manifest === "object" && manifest !== null && "version" in manifest && typeof manifest.version === "string" ? manifest.version : "unknown";
1433
1441
  }
1434
- //#endregion
1435
- //#region src/program.ts
1442
+ // src/program.ts
1436
1443
  const PUBLIC_COMMANDS = /* @__PURE__ */ new Set([
1437
1444
  "login",
1438
1445
  "use",
@@ -1495,8 +1502,6 @@ async function runProgram(argv = process.argv) {
1495
1502
  process.exit(1);
1496
1503
  });
1497
1504
  }
1498
- //#endregion
1499
- //#region src/bin.ts
1505
+ // src/bin.ts
1500
1506
  await runProgram();
1501
- //#endregion
1502
1507
  export {};
@@ -5,7 +5,7 @@ import { existsSync } from "node:fs";
5
5
  import { glob } from "node:fs/promises";
6
6
  import { join, relative, resolve } from "node:path";
7
7
  import { createJiti } from "jiti";
8
- //#region src/discovery/discover-bundles.ts
8
+ // src/discovery/discover-bundles.ts
9
9
  const DEFAULT_PATTERNS = ["standards/bundles/*.ts"];
10
10
  const CONFIG_FILE = "standards.config.ts";
11
11
  function messageOf(error) {
@@ -64,5 +64,4 @@ async function discoverBundles(options = {}) {
64
64
  if (files.length > 0 && found.size === 0) throw new ValidationError(`No bundle found in ${files.length} file(s) matching ${patterns.join(", ")}`, []);
65
65
  return [...found.values()].sort((a, b) => a.bundle.name.localeCompare(b.bundle.name));
66
66
  }
67
- //#endregion
68
67
  export { discoverBundles as t };
package/dist/index.d.mts CHANGED
@@ -1,6 +1,5 @@
1
1
 
2
2
  import { BundleBuilder, ObjectBuilderLike } from "@standards/schema";
3
- //#region src/discovery/define-config.d.ts
4
3
  /** What `standards.config.ts` declares. Every key is optional: the conventions apply without a file. */
5
4
  interface StandardsCliConfig {
6
5
  /** Glob pattern(s), relative to the project root, that locate the bundle files. */
@@ -8,8 +7,6 @@ interface StandardsCliConfig {
8
7
  }
9
8
  /** Types a `standards.config.ts` default export. */
10
9
  export declare function defineConfig(config: StandardsCliConfig): StandardsCliConfig;
11
- //#endregion
12
- //#region src/discovery/discover-bundles.d.ts
13
10
  type AnyBundle = BundleBuilder<string, readonly ObjectBuilderLike[]>;
14
11
  interface DiscoveredBundle {
15
12
  bundle: AnyBundle;
@@ -28,5 +25,4 @@ interface DiscoverBundlesOptions {
28
25
  * patterns match, that is a `BundleBuilder`. Files may hold anything else.
29
26
  */
30
27
  export declare function discoverBundles(options?: DiscoverBundlesOptions): Promise<DiscoveredBundle[]>;
31
- //#endregion
32
28
  export type { DiscoverBundlesOptions, DiscoveredBundle, StandardsCliConfig };
package/dist/index.mjs CHANGED
@@ -1,10 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  /*! © 2025-2026 AND YOU CREATE SAS (RCS Paris 940 190 614). Proprietary — see LICENSE (Standards SDK License 1.0). */
3
- import { t as discoverBundles } from "./discover-bundles-D5RNCkan.mjs";
4
- //#region src/discovery/define-config.ts
3
+ import { t as discoverBundles } from "./discover-bundles-DPpEZVv0.mjs";
4
+ // src/discovery/define-config.ts
5
5
  /** Types a `standards.config.ts` default export. */
6
6
  function defineConfig(config) {
7
7
  return config;
8
8
  }
9
- //#endregion
10
9
  export { defineConfig, discoverBundles };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@standards/cli",
3
- "version": "1.0.0-alpha.416",
3
+ "version": "1.0.0-alpha.419",
4
4
  "description": "CLI tool to interact with Standards API",
5
5
  "type": "module",
6
6
  "bin": {
@@ -23,20 +23,20 @@
23
23
  "node": ">=22"
24
24
  },
25
25
  "dependencies": {
26
+ "@standards/client": "1.0.0-alpha.419",
27
+ "@standards/constants": "1.0.0-alpha.419",
28
+ "@standards/schema": "1.0.0-alpha.419",
26
29
  "cli-table3": "^0.6.5",
27
30
  "commander": "^13.1.0",
28
- "jiti": "2.7.0",
29
- "@standards/client": "1.0.0-alpha.416",
30
- "@standards/constants": "1.0.0-alpha.416",
31
- "@standards/schema": "1.0.0-alpha.416"
31
+ "jiti": "2.7.0"
32
32
  },
33
33
  "devDependencies": {
34
34
  "@types/node": "^25.6.0",
35
35
  "jsdom": "^25.0.1",
36
- "tsdown": "^0.23.0",
36
+ "tsdown": "^0.23.7",
37
37
  "typescript": "^5.6.3",
38
- "typescript7": "npm:typescript@^7.0.2",
39
- "vitest": "^5.0.5"
38
+ "typescript7": "npm:typescript@7.1.0-beta",
39
+ "vitest": "^5.1.0"
40
40
  },
41
41
  "publishConfig": {
42
42
  "access": "public",