@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.
- package/dist/bin.mjs +207 -17
- 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
|
|
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
|
|
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 (
|
|
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(
|
|
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
|
|
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/
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
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
|
-
`${
|
|
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(`${
|
|
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(`${
|
|
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
|
-
|
|
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(
|
|
1058
|
+
console.error(chalk9.red(`\u2717 Error (${error.statusCode}): ${error.message}`));
|
|
869
1059
|
} else {
|
|
870
|
-
console.error(
|
|
1060
|
+
console.error(chalk9.red(`\u2717 Error: ${error.message}`));
|
|
871
1061
|
}
|
|
872
1062
|
} else if (error instanceof Error) {
|
|
873
|
-
console.error(
|
|
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.
|
|
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.
|
|
16
|
+
"@stndrds/schema": "1.0.0-alpha.278"
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
19
19
|
"@types/node": "^25.6.0",
|