@stndrds/cli 1.0.0-alpha.277 → 1.0.0-alpha.279

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 +183 -19
  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 chalk8 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
  }
@@ -820,7 +982,7 @@ function registerSchemaCommand(program) {
820
982
  }
821
983
 
822
984
  // src/commands/search.ts
823
- import chalk7 from "chalk";
985
+ import chalk8 from "chalk";
824
986
  function registerSearchCommand(program) {
825
987
  const search = program.command("search").description("Maintain the Standards search index");
826
988
  search.command("reindex").description("Clear the tenant search index and re-inject every record").option("--yes", "reindex without confirmation").action(async (opts, cmd) => {
@@ -838,7 +1000,7 @@ function registerSearchCommand(program) {
838
1000
  const client = getClientFromCommand(cmd);
839
1001
  await client.post("/admin/search/full-reindex", { tenantId: tenant });
840
1002
  process.stdout.write(
841
- `${chalk7.green("\u2713")} Full reindex accepted for tenant ${tenant}. It runs in the background \u2014 follow the server logs for progress.
1003
+ `${chalk8.green("\u2713")} Full reindex accepted for tenant ${tenant}. It runs in the background \u2014 follow the server logs for progress.
842
1004
  `
843
1005
  );
844
1006
  });
@@ -863,6 +1025,8 @@ function createProgram() {
863
1025
  registerAuthCommand(program);
864
1026
  registerBundlesCommand(program);
865
1027
  registerConnectorsCommand(program);
1028
+ registerMcpCommand(program);
1029
+ registerMeetingsCommand(program);
866
1030
  registerSearchCommand(program);
867
1031
  program.hook("preAction", async (_thisCommand, actionCommand) => {
868
1032
  const raw = program.opts();
@@ -877,7 +1041,7 @@ function createProgram() {
877
1041
  program.setOptionValue("tenant", raw.tenant);
878
1042
  if (!(resolved.apiKey || isPublicCommand(actionCommand))) {
879
1043
  console.error(
880
- chalk8.red(
1044
+ chalk9.red(
881
1045
  `\u2717 Error: No Standards instance configured. Run "standards login" or pass --api-key.`
882
1046
  )
883
1047
  );
@@ -891,12 +1055,12 @@ async function runProgram(argv = process.argv) {
891
1055
  await program.parseAsync(argv).catch((error) => {
892
1056
  if (error instanceof ApiClientError) {
893
1057
  if (error.statusCode > 0) {
894
- console.error(chalk8.red(`\u2717 Error (${error.statusCode}): ${error.message}`));
1058
+ console.error(chalk9.red(`\u2717 Error (${error.statusCode}): ${error.message}`));
895
1059
  } else {
896
- console.error(chalk8.red(`\u2717 Error: ${error.message}`));
1060
+ console.error(chalk9.red(`\u2717 Error: ${error.message}`));
897
1061
  }
898
1062
  } else if (error instanceof Error) {
899
- console.error(chalk8.red(`\u2717 Error: ${error.message}`));
1063
+ console.error(chalk9.red(`\u2717 Error: ${error.message}`));
900
1064
  }
901
1065
  process.exit(1);
902
1066
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stndrds/cli",
3
- "version": "1.0.0-alpha.277",
3
+ "version": "1.0.0-alpha.279",
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.277"
16
+ "@stndrds/schema": "1.0.0-alpha.279"
17
17
  },
18
18
  "devDependencies": {
19
19
  "@types/node": "^25.6.0",