@stndrds/cli 1.0.0-alpha.277 → 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 +183 -19
- 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
|
}
|
|
@@ -820,7 +982,7 @@ function registerSchemaCommand(program) {
|
|
|
820
982
|
}
|
|
821
983
|
|
|
822
984
|
// src/commands/search.ts
|
|
823
|
-
import
|
|
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
|
-
`${
|
|
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
|
-
|
|
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(
|
|
1058
|
+
console.error(chalk9.red(`\u2717 Error (${error.statusCode}): ${error.message}`));
|
|
895
1059
|
} else {
|
|
896
|
-
console.error(
|
|
1060
|
+
console.error(chalk9.red(`\u2717 Error: ${error.message}`));
|
|
897
1061
|
}
|
|
898
1062
|
} else if (error instanceof Error) {
|
|
899
|
-
console.error(
|
|
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.
|
|
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",
|