@stndrds/cli 1.0.0-alpha.276 → 1.0.0-alpha.278

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.
Files changed (2) hide show
  1. package/dist/bin.mjs +207 -17
  2. package/package.json +2 -2
package/dist/bin.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/program.ts
4
- import chalk7 from "chalk";
4
+ import chalk9 from "chalk";
5
5
  import { Command } from "commander";
6
6
 
7
7
  // src/client.ts
@@ -250,13 +250,25 @@ function registerBundlesCommand(program) {
250
250
  }
251
251
 
252
252
  // src/commands/connectors.ts
253
+ import { ValidationError } from "@stndrds/schema";
253
254
  import chalk3 from "chalk";
254
- var PROVIDERS = ["gmail", "outlook"];
255
+ var PROVIDER_IDS = {
256
+ gmail: true,
257
+ outlook: true,
258
+ "google-calendar": true,
259
+ "outlook-calendar": true
260
+ };
261
+ var PROVIDERS = Object.keys(PROVIDER_IDS);
255
262
  function resolveScope(scope) {
256
263
  return scope === "actor" ? "actor" : "tenant";
257
264
  }
258
265
  function registerConnectorsCommand(program) {
259
- const connectors = program.command("connectors").description("Manage email connectors (Gmail / Outlook OAuth connections)");
266
+ const connectors = program.command("connectors").description("Manage email and calendar connectors (OAuth connections)");
267
+ connectors.command("providers").description("List the connector providers this deployment holds credentials for").action(async (_opts, cmd) => {
268
+ const client = getClientFromCommand(cmd);
269
+ const result = await client.get("/connectors/providers");
270
+ formatOutput(result, getFormat(cmd));
271
+ });
260
272
  connectors.command("list").description("List connector connections").option("--scope <scope>", "connection scope (tenant or actor)", "tenant").action(async (opts, cmd) => {
261
273
  const client = getClientFromCommand(cmd);
262
274
  const result = await client.get("/connectors/connections", {
@@ -264,9 +276,12 @@ function registerConnectorsCommand(program) {
264
276
  });
265
277
  formatOutput(result, getFormat(cmd));
266
278
  });
267
- connectors.command("connect").description("Start an OAuth flow and return the authorization URL to open").requiredOption("--provider <provider>", "connector provider (gmail or outlook)").option("--scope <scope>", "connection scope (tenant or actor)", "tenant").action(async (opts, cmd) => {
279
+ connectors.command("connect").description("Start an OAuth flow and return the authorization URL to open").requiredOption(
280
+ "--provider <provider>",
281
+ `connector provider (${PROVIDERS.join(", ")}); run "connectors providers" for the ones this deployment configured`
282
+ ).option("--scope <scope>", "connection scope (tenant or actor)", "tenant").action(async (opts, cmd) => {
268
283
  if (!PROVIDERS.includes(opts.provider)) {
269
- throw new Error(`--provider must be one of: ${PROVIDERS.join(", ")}`);
284
+ throw new ValidationError(`--provider must be one of: ${PROVIDERS.join(", ")}`, []);
270
285
  }
271
286
  const client = getClientFromCommand(cmd);
272
287
  const result = await client.post("/connectors/auth/start", {
@@ -429,8 +444,155 @@ function registerKeysCommand(program) {
429
444
  });
430
445
  }
431
446
 
432
- // src/commands/pull.ts
447
+ // src/commands/mcp.ts
448
+ import { RESOURCE_VISIBILITIES, ValidationError as ValidationError2 } from "@stndrds/schema";
433
449
  import chalk5 from "chalk";
450
+ var AUTH_TYPES = ["none", "header"];
451
+ function buildAuth(opts) {
452
+ const type = opts.authType ?? "none";
453
+ if (!AUTH_TYPES.includes(type)) {
454
+ throw new ValidationError2(`--auth-type must be one of: ${AUTH_TYPES.join(", ")}`, []);
455
+ }
456
+ if (type === "none") {
457
+ return { type: "none" };
458
+ }
459
+ if (!(opts.headerName && opts.secret)) {
460
+ throw new ValidationError2('--auth-type "header" requires both --header-name and --secret.', []);
461
+ }
462
+ return { type: "header", headerName: opts.headerName, secret: opts.secret };
463
+ }
464
+ function resolveVisibility(visibility) {
465
+ if (visibility === void 0) {
466
+ return "workspace";
467
+ }
468
+ if (!RESOURCE_VISIBILITIES.includes(visibility)) {
469
+ throw new ValidationError2(
470
+ `--visibility must be one of: ${RESOURCE_VISIBILITIES.join(", ")}`,
471
+ []
472
+ );
473
+ }
474
+ return visibility;
475
+ }
476
+ function registerMcpCommand(program) {
477
+ const mcp = program.command("mcp").description("Manage MCP servers mounted into this workspace's agents");
478
+ mcp.command("list").description("List connected MCP servers").action(async (_opts, cmd) => {
479
+ const client = getClientFromCommand(cmd);
480
+ const result = await client.get("/mcp-servers");
481
+ formatOutput(result, getFormat(cmd));
482
+ });
483
+ mcp.command("catalog").description("List the vendored MCP catalog entries available to connect").action(async (_opts, cmd) => {
484
+ const client = getClientFromCommand(cmd);
485
+ const result = await client.get("/mcp-servers/catalog");
486
+ formatOutput(result, getFormat(cmd));
487
+ });
488
+ mcp.command("connect").description("Connect a remote MCP server and mount its tools").requiredOption("--slug <slug>", "unique slug for the server").requiredOption("--name <name>", "display name").requiredOption("--url <url>", "remote MCP endpoint URL").option("--visibility <visibility>", "workspace or private", "workspace").option("--catalog-entry <id>", "catalog entry ID this server instantiates").option("--auth-type <type>", "none or header", "none").option("--header-name <name>", 'header name when --auth-type is "header"').option("--secret <secret>", 'header value when --auth-type is "header"').action(async (opts, cmd) => {
489
+ const auth = buildAuth(opts);
490
+ const visibility = resolveVisibility(opts.visibility);
491
+ const client = getClientFromCommand(cmd);
492
+ const result = await client.post("/mcp-servers", {
493
+ slug: opts.slug,
494
+ name: opts.name,
495
+ url: opts.url,
496
+ visibility,
497
+ catalogEntryId: opts.catalogEntry ?? null,
498
+ auth
499
+ });
500
+ formatOutput(result, getFormat(cmd));
501
+ });
502
+ mcp.command("refresh").description("Re-discover a server's tools and refresh its status").argument("<id>", "MCP server ID").action(async (id, _opts, cmd) => {
503
+ const client = getClientFromCommand(cmd);
504
+ const result = await client.post(`/mcp-servers/${id}/refresh`);
505
+ formatOutput(result, getFormat(cmd));
506
+ });
507
+ mcp.command("trust").description("Mark a server trusted so its tools run without per-call approval").argument("<id>", "MCP server ID").option("--revoke", "revoke trust instead of granting it").action(async (id, opts, cmd) => {
508
+ const trusted = !opts.revoke;
509
+ const client = getClientFromCommand(cmd);
510
+ await client.post(`/mcp-servers/${id}/trust`, { trusted });
511
+ process.stdout.write(
512
+ `${chalk5.green("\u2713")} MCP server ${id} ${trusted ? "trusted" : "untrusted"}.
513
+ `
514
+ );
515
+ });
516
+ mcp.command("disconnect").description("Disconnect (delete) an MCP server").argument("<id>", "MCP server ID").option("--yes", "disconnect without confirmation").action(async (id, opts, cmd) => {
517
+ if (!opts.yes) {
518
+ throw new ValidationError2(
519
+ 'Disconnecting an MCP server is explicit. Re-run with "--yes" to confirm.',
520
+ []
521
+ );
522
+ }
523
+ const client = getClientFromCommand(cmd);
524
+ await client.delete(`/mcp-servers/${id}`);
525
+ process.stdout.write(`${chalk5.green("\u2713")} MCP server ${id} disconnected.
526
+ `);
527
+ });
528
+ }
529
+
530
+ // src/commands/meetings.ts
531
+ import { ValidationError as ValidationError3 } from "@stndrds/schema";
532
+ var ORDERS = ["asc", "desc"];
533
+ function parseOrder(order) {
534
+ if (ORDERS.includes(order)) return order;
535
+ throw new ValidationError3(`--order must be one of: ${ORDERS.join(", ")}`, []);
536
+ }
537
+ function parseCount(flag, value) {
538
+ const parsed = Number(value);
539
+ if (!Number.isInteger(parsed) || parsed < 0) {
540
+ throw new ValidationError3(`${flag} must be a non-negative integer`, []);
541
+ }
542
+ return parsed;
543
+ }
544
+ function buildQuery(opts) {
545
+ const query = {};
546
+ if (opts.search !== void 0) query.search = opts.search;
547
+ if (opts.since !== void 0) query.since = opts.since;
548
+ if (opts.before !== void 0) query.before = opts.before;
549
+ if (opts.addresses !== void 0) query.addresses = parseCsvList(opts.addresses);
550
+ if (opts.record !== void 0) query.recordId = opts.record;
551
+ if (opts.order !== void 0) query.order = parseOrder(opts.order);
552
+ if (opts.limit !== void 0) query.limit = parseCount("--limit", opts.limit);
553
+ if (opts.offset !== void 0) query.offset = parseCount("--offset", opts.offset);
554
+ return query;
555
+ }
556
+ function withQueryOptions(command) {
557
+ return command.option("--search <text>", "match title, description and location").option("--since <iso>", "inclusive ISO lower bound on the start").option("--before <iso>", "exclusive ISO upper bound on the start").option("--addresses <emails>", "comma-separated participant addresses to restrict to").option("--record <id>", "only meetings linked to this record").option("--order <order>", "asc for what is coming next, desc to read history").option("--limit <n>", "max meetings to return").option("--offset <n>", "number of meetings to skip");
558
+ }
559
+ function registerMeetingsCommand(program) {
560
+ const meetings = program.command("meetings").description("Read calendar meetings and the records each one concerns");
561
+ withQueryOptions(
562
+ meetings.command("list").description("List meetings, newest window first by default")
563
+ ).action(async (opts, cmd) => {
564
+ const client = getClientFromCommand(cmd);
565
+ const result = await client.post("/meetings/search", buildQuery(opts));
566
+ formatOutput(result, getFormat(cmd));
567
+ });
568
+ meetings.command("get").description("Get one meeting, with its participants and linked records").argument("<id>", "meeting ID").action(async (id, _opts, cmd) => {
569
+ const client = getClientFromCommand(cmd);
570
+ const result = await client.get(`/meetings/${id}`);
571
+ formatOutput(result, getFormat(cmd));
572
+ });
573
+ withQueryOptions(
574
+ meetings.command("for-record").description("List the meetings a record's email addresses appear in").argument("<recordId>", "record ID").option(
575
+ "--email-attributes <ids>",
576
+ "comma-separated email attribute IDs to match participants on"
577
+ )
578
+ ).action(
579
+ async (recordId, opts, cmd) => {
580
+ const client = getClientFromCommand(cmd);
581
+ const result = await client.post(`/meetings/records/${recordId}`, {
582
+ // The API defaults an absent list to none, which matches nothing —
583
+ // send the key only when the caller named the attributes.
584
+ ...opts.emailAttributes !== void 0 && {
585
+ emailAttributeIds: parseCsvList(opts.emailAttributes)
586
+ },
587
+ query: buildQuery(opts)
588
+ });
589
+ formatOutput(result, getFormat(cmd));
590
+ }
591
+ );
592
+ }
593
+
594
+ // src/commands/pull.ts
595
+ import chalk6 from "chalk";
434
596
 
435
597
  // src/drift/reconciliation-prompt.ts
436
598
  var PREAMBLE = [
@@ -515,7 +677,7 @@ function registerPullCommand(program) {
515
677
  try {
516
678
  client = getClientFromCommand(cmd);
517
679
  } catch (error) {
518
- console.error(chalk5.red(`\u2717 ${messageOf(error)}`));
680
+ console.error(chalk6.red(`\u2717 ${messageOf(error)}`));
519
681
  process.exit(2);
520
682
  return;
521
683
  }
@@ -525,14 +687,14 @@ function registerPullCommand(program) {
525
687
  console.info(JSON.stringify(state, null, 2));
526
688
  process.exit(0);
527
689
  } catch (error) {
528
- console.error(chalk5.red(`\u2717 ${messageOf(error)}`));
690
+ console.error(chalk6.red(`\u2717 ${messageOf(error)}`));
529
691
  process.exit(2);
530
692
  }
531
693
  return;
532
694
  }
533
695
  const result = await runPullCommand(client);
534
696
  if (result.exitCode === 2) {
535
- console.error(chalk5.red(`\u2717 ${result.errorMessage}`));
697
+ console.error(chalk6.red(`\u2717 ${result.errorMessage}`));
536
698
  process.exit(2);
537
699
  return;
538
700
  }
@@ -628,7 +790,7 @@ function registerRecordsCommand(program) {
628
790
  // src/commands/root.ts
629
791
  import { stdin as input, stdout as output } from "process";
630
792
  import { createInterface } from "readline/promises";
631
- import chalk6 from "chalk";
793
+ import chalk7 from "chalk";
632
794
 
633
795
  // src/config.ts
634
796
  import { mkdir, readFile as readFile3, rm, writeFile } from "fs/promises";
@@ -768,7 +930,7 @@ function registerRootCommands(program) {
768
930
  await client.get("/api-keys");
769
931
  await upsertProfile({ name: opts.name, apiUrl: opts.url, apiKey });
770
932
  process.stdout.write(
771
- `${chalk6.green("\u2713")} Standards instance "${opts.name}" saved and selected.
933
+ `${chalk7.green("\u2713")} Standards instance "${opts.name}" saved and selected.
772
934
  `
773
935
  );
774
936
  process.stdout.write(` API URL: ${opts.url}
@@ -780,7 +942,7 @@ function registerRootCommands(program) {
780
942
  });
781
943
  program.command("use").description("Select the active Standards instance").argument("<name>", "instance name").action(async (name) => {
782
944
  await setCurrentProfile(name);
783
- process.stdout.write(`${chalk6.green("\u2713")} Standards instance "${name}" selected.
945
+ process.stdout.write(`${chalk7.green("\u2713")} Standards instance "${name}" selected.
784
946
  `);
785
947
  });
786
948
  program.command("instances").description("List configured Standards instances").action(async (_opts, cmd) => {
@@ -799,7 +961,7 @@ function registerRootCommands(program) {
799
961
  });
800
962
  program.command("logout").description("Remove a Standards instance from local CLI config").argument("[name]", "instance name, defaults to current").action(async (name) => {
801
963
  await removeProfile(name);
802
- process.stdout.write(`${chalk6.green("\u2713")} Standards instance removed.
964
+ process.stdout.write(`${chalk7.green("\u2713")} Standards instance removed.
803
965
  `);
804
966
  });
805
967
  }
@@ -819,6 +981,31 @@ function registerSchemaCommand(program) {
819
981
  });
820
982
  }
821
983
 
984
+ // src/commands/search.ts
985
+ import chalk8 from "chalk";
986
+ function registerSearchCommand(program) {
987
+ const search = program.command("search").description("Maintain the Standards search index");
988
+ search.command("reindex").description("Clear the tenant search index and re-inject every record").option("--yes", "reindex without confirmation").action(async (opts, cmd) => {
989
+ if (!opts.yes) {
990
+ throw new Error(
991
+ 'A full reindex clears the index before refilling it. Re-run with "--yes" to confirm.'
992
+ );
993
+ }
994
+ const { tenant } = getGlobalOptions(cmd);
995
+ if (!tenant) {
996
+ throw new Error(
997
+ 'A full reindex names its tenant explicitly. Pass "--tenant <id>" with the tenant you are authenticated in.'
998
+ );
999
+ }
1000
+ const client = getClientFromCommand(cmd);
1001
+ await client.post("/admin/search/full-reindex", { tenantId: tenant });
1002
+ process.stdout.write(
1003
+ `${chalk8.green("\u2713")} Full reindex accepted for tenant ${tenant}. It runs in the background \u2014 follow the server logs for progress.
1004
+ `
1005
+ );
1006
+ });
1007
+ }
1008
+
822
1009
  // src/program.ts
823
1010
  var PUBLIC_COMMANDS = /* @__PURE__ */ new Set(["login", "use", "instances", "current", "logout", "help"]);
824
1011
  function isPublicCommand(actionCommand) {
@@ -838,6 +1025,9 @@ function createProgram() {
838
1025
  registerAuthCommand(program);
839
1026
  registerBundlesCommand(program);
840
1027
  registerConnectorsCommand(program);
1028
+ registerMcpCommand(program);
1029
+ registerMeetingsCommand(program);
1030
+ registerSearchCommand(program);
841
1031
  program.hook("preAction", async (_thisCommand, actionCommand) => {
842
1032
  const raw = program.opts();
843
1033
  const resolved = await resolveCliConfig({
@@ -851,7 +1041,7 @@ function createProgram() {
851
1041
  program.setOptionValue("tenant", raw.tenant);
852
1042
  if (!(resolved.apiKey || isPublicCommand(actionCommand))) {
853
1043
  console.error(
854
- chalk7.red(
1044
+ chalk9.red(
855
1045
  `\u2717 Error: No Standards instance configured. Run "standards login" or pass --api-key.`
856
1046
  )
857
1047
  );
@@ -865,12 +1055,12 @@ async function runProgram(argv = process.argv) {
865
1055
  await program.parseAsync(argv).catch((error) => {
866
1056
  if (error instanceof ApiClientError) {
867
1057
  if (error.statusCode > 0) {
868
- console.error(chalk7.red(`\u2717 Error (${error.statusCode}): ${error.message}`));
1058
+ console.error(chalk9.red(`\u2717 Error (${error.statusCode}): ${error.message}`));
869
1059
  } else {
870
- console.error(chalk7.red(`\u2717 Error: ${error.message}`));
1060
+ console.error(chalk9.red(`\u2717 Error: ${error.message}`));
871
1061
  }
872
1062
  } else if (error instanceof Error) {
873
- console.error(chalk7.red(`\u2717 Error: ${error.message}`));
1063
+ console.error(chalk9.red(`\u2717 Error: ${error.message}`));
874
1064
  }
875
1065
  process.exit(1);
876
1066
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stndrds/cli",
3
- "version": "1.0.0-alpha.276",
3
+ "version": "1.0.0-alpha.278",
4
4
  "description": "CLI tool to interact with Standards API",
5
5
  "type": "module",
6
6
  "bin": {
@@ -13,7 +13,7 @@
13
13
  "chalk": "^5.4.1",
14
14
  "cli-table3": "^0.6.5",
15
15
  "commander": "^13.1.0",
16
- "@stndrds/schema": "1.0.0-alpha.276"
16
+ "@stndrds/schema": "1.0.0-alpha.278"
17
17
  },
18
18
  "devDependencies": {
19
19
  "@types/node": "^25.6.0",