@mnemom/mnemom 0.9.1 → 0.11.0
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/commands/advisories.d.ts +32 -0
- package/dist/commands/advisories.js +158 -0
- package/dist/commands/api-key.d.ts +37 -0
- package/dist/commands/api-key.js +181 -0
- package/dist/commands/governance.d.ts +85 -0
- package/dist/commands/governance.js +331 -0
- package/dist/commands/org.d.ts +23 -0
- package/dist/commands/org.js +122 -0
- package/dist/commands/posture.d.ts +71 -0
- package/dist/commands/posture.js +440 -0
- package/dist/commands/team.d.ts +56 -0
- package/dist/commands/team.js +507 -0
- package/dist/commands/validate.d.ts +23 -0
- package/dist/commands/validate.js +150 -0
- package/dist/index.js +713 -14
- package/dist/lib/api.d.ts +576 -0
- package/dist/lib/api.js +884 -5
- package/dist/lib/format.d.ts +4 -0
- package/dist/lib/format.js +6 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3,12 +3,18 @@ import { program } from "commander";
|
|
|
3
3
|
import { statusCommand } from "./commands/status.js";
|
|
4
4
|
import { integrityCommand } from "./commands/integrity.js";
|
|
5
5
|
import { logsCommand } from "./commands/logs.js";
|
|
6
|
-
import { licenseActivateCommand, licenseStatusCommand, licenseDeactivateCommand } from "./commands/license.js";
|
|
7
|
-
import { cardShowCommand, cardPublishCommand, cardValidateCommand, cardEditCommand, cardEvaluateCommand } from "./commands/card.js";
|
|
6
|
+
import { licenseActivateCommand, licenseStatusCommand, licenseDeactivateCommand, } from "./commands/license.js";
|
|
7
|
+
import { cardShowCommand, cardPublishCommand, cardValidateCommand, cardEditCommand, cardEvaluateCommand, } from "./commands/card.js";
|
|
8
8
|
import { policyInitCommand, policyValidateCommand, policyPublishCommand, policyListCommand, policyTestCommand, policyEvaluateCommand, } from "./commands/policy.js";
|
|
9
|
-
import { protectionShowCommand, protectionPublishCommand, protectionValidateCommand, protectionEditCommand } from "./commands/protection.js";
|
|
9
|
+
import { protectionShowCommand, protectionPublishCommand, protectionValidateCommand, protectionEditCommand, } from "./commands/protection.js";
|
|
10
10
|
import { agentsListCommand } from "./commands/agents.js";
|
|
11
|
+
import { orgListCommand, orgShowCommand } from "./commands/org.js";
|
|
12
|
+
import { teamListCommand, teamShowCommand, teamTemplateCommand, teamPreviewComposeCommand, teamAdminGrantCommand, teamAdminRevokeCommand, teamAdminListCommand, teamCoverageCommand, } from "./commands/team.js";
|
|
13
|
+
import { advisoriesListCommand, advisoriesShowCommand, } from "./commands/advisories.js";
|
|
14
|
+
import { postureListCommand, postureShowCommand, postureCreateCommand, postureUpdateCommand, postureCloneCommand, postureRevisionsCommand, postureDiffCommand, postureAssignCommand, postureUnassignCommand, posturePreviewComposeCommand, postureDeleteCommand, } from "./commands/posture.js";
|
|
11
15
|
import { loginCommand, logoutCommand, whoamiCommand } from "./commands/auth.js";
|
|
16
|
+
import { validateSafeHouseCommand } from "./commands/validate.js";
|
|
17
|
+
import { apiKeyListCommand, apiKeyCreateCommand, apiKeyRotateCommand, apiKeyRevokeCommand, } from "./commands/api-key.js";
|
|
12
18
|
program
|
|
13
19
|
.name("mnemom")
|
|
14
20
|
.description("Transparent AI agent tracing")
|
|
@@ -55,9 +61,7 @@ program
|
|
|
55
61
|
process.exit(1);
|
|
56
62
|
}
|
|
57
63
|
});
|
|
58
|
-
const license = program
|
|
59
|
-
.command("license")
|
|
60
|
-
.description("Enterprise license management");
|
|
64
|
+
const license = program.command("license").description("Enterprise license management");
|
|
61
65
|
license
|
|
62
66
|
.command("activate <jwt>")
|
|
63
67
|
.description("Activate an enterprise license")
|
|
@@ -97,9 +101,7 @@ license
|
|
|
97
101
|
// ============================================================================
|
|
98
102
|
// Card commands (alignment card)
|
|
99
103
|
// ============================================================================
|
|
100
|
-
const cardCmd = program
|
|
101
|
-
.command("card")
|
|
102
|
-
.description("Manage alignment card");
|
|
104
|
+
const cardCmd = program.command("card").description("Manage alignment card");
|
|
103
105
|
cardCmd
|
|
104
106
|
.command("show")
|
|
105
107
|
.description("Display alignment card (YAML)")
|
|
@@ -174,9 +176,7 @@ cardCmd
|
|
|
174
176
|
// ============================================================================
|
|
175
177
|
// Protection card commands
|
|
176
178
|
// ============================================================================
|
|
177
|
-
const protectionCmd = program
|
|
178
|
-
.command("protection")
|
|
179
|
-
.description("Manage protection card");
|
|
179
|
+
const protectionCmd = program.command("protection").description("Manage protection card");
|
|
180
180
|
protectionCmd
|
|
181
181
|
.command("show")
|
|
182
182
|
.description("Display protection card (YAML)")
|
|
@@ -241,12 +241,16 @@ const policyCmd = program
|
|
|
241
241
|
policyCmd
|
|
242
242
|
.command("init")
|
|
243
243
|
.description("(removed) Use `mnemom card validate`")
|
|
244
|
-
.action(async () => {
|
|
244
|
+
.action(async () => {
|
|
245
|
+
await policyInitCommand();
|
|
246
|
+
});
|
|
245
247
|
policyCmd
|
|
246
248
|
.command("validate")
|
|
247
249
|
.argument("<file>", "Path to policy file")
|
|
248
250
|
.description("(removed) Use `mnemom card validate`")
|
|
249
|
-
.action(async (file) => {
|
|
251
|
+
.action(async (file) => {
|
|
252
|
+
await policyValidateCommand(file);
|
|
253
|
+
});
|
|
250
254
|
policyCmd
|
|
251
255
|
.command("publish")
|
|
252
256
|
.argument("<file>", "Path to policy file")
|
|
@@ -297,6 +301,607 @@ program
|
|
|
297
301
|
}
|
|
298
302
|
});
|
|
299
303
|
// ============================================================================
|
|
304
|
+
// Organization management (ADR-044, Piece 1 of T1-3.1)
|
|
305
|
+
// ============================================================================
|
|
306
|
+
const orgCmd = program
|
|
307
|
+
.command("org")
|
|
308
|
+
.description("Manage your organizations (personal + multi-user)");
|
|
309
|
+
orgCmd
|
|
310
|
+
.command("list")
|
|
311
|
+
.description("List every org you are a member of, including your personal org")
|
|
312
|
+
.option("--json", "Output JSON instead of a human-readable table")
|
|
313
|
+
.action(async (options) => {
|
|
314
|
+
try {
|
|
315
|
+
await orgListCommand({ json: options.json });
|
|
316
|
+
}
|
|
317
|
+
catch (error) {
|
|
318
|
+
console.error("Error:", error instanceof Error ? error.message : error);
|
|
319
|
+
process.exit(1);
|
|
320
|
+
}
|
|
321
|
+
});
|
|
322
|
+
orgCmd
|
|
323
|
+
.command("show [org_id]")
|
|
324
|
+
.description("Show details of an org (default: your personal org if --personal, else single membership)")
|
|
325
|
+
.option("--personal", "Show your personal-org-of-one (per ADR-044)")
|
|
326
|
+
.option("--json", "Output JSON instead of human-readable text")
|
|
327
|
+
.action(async (orgId, options) => {
|
|
328
|
+
try {
|
|
329
|
+
await orgShowCommand(orgId, { personal: options.personal, json: options.json });
|
|
330
|
+
}
|
|
331
|
+
catch (error) {
|
|
332
|
+
console.error("Error:", error instanceof Error ? error.message : error);
|
|
333
|
+
process.exit(1);
|
|
334
|
+
}
|
|
335
|
+
});
|
|
336
|
+
// ============================================================================
|
|
337
|
+
// Team management (ADR-044 amended, Piece 2 of T1-3.1)
|
|
338
|
+
//
|
|
339
|
+
// Per ADR-044 + Charter §I11: team membership is OPTIONAL. Solo agents
|
|
340
|
+
// (zero teams) compose under Platform → Org → Agent. Backend RBAC for
|
|
341
|
+
// team-template endpoints is purely org-level (requireOrgRole on the
|
|
342
|
+
// team's parent org); Team Admin role lands in Piece 5.
|
|
343
|
+
// ============================================================================
|
|
344
|
+
const teamCmd = program
|
|
345
|
+
.command("team")
|
|
346
|
+
.description("Manage teams and their scope-cascade templates");
|
|
347
|
+
teamCmd
|
|
348
|
+
.command("list")
|
|
349
|
+
.description("List every team across all orgs you are a member of")
|
|
350
|
+
.option("--json", "Output JSON instead of a human-readable table")
|
|
351
|
+
.action(async (options) => {
|
|
352
|
+
try {
|
|
353
|
+
await teamListCommand({ json: options.json });
|
|
354
|
+
}
|
|
355
|
+
catch (error) {
|
|
356
|
+
console.error("Error:", error instanceof Error ? error.message : error);
|
|
357
|
+
process.exit(1);
|
|
358
|
+
}
|
|
359
|
+
});
|
|
360
|
+
teamCmd
|
|
361
|
+
.command("show <team_id>")
|
|
362
|
+
.description("Show details of a single team")
|
|
363
|
+
.option("--json", "Output JSON instead of human-readable text")
|
|
364
|
+
.action(async (teamId, options) => {
|
|
365
|
+
try {
|
|
366
|
+
await teamShowCommand(teamId, { json: options.json });
|
|
367
|
+
}
|
|
368
|
+
catch (error) {
|
|
369
|
+
console.error("Error:", error instanceof Error ? error.message : error);
|
|
370
|
+
process.exit(1);
|
|
371
|
+
}
|
|
372
|
+
});
|
|
373
|
+
teamCmd
|
|
374
|
+
.command("alignment-template <team_id>")
|
|
375
|
+
.description("Read or write the team's alignment template")
|
|
376
|
+
.option("--set <file>", "Write the template from a YAML or JSON file")
|
|
377
|
+
.option("--clear", "Clear the template")
|
|
378
|
+
.option("--json", "Output JSON instead of human-readable text")
|
|
379
|
+
.action(async (teamId, options) => {
|
|
380
|
+
try {
|
|
381
|
+
await teamTemplateCommand("alignment", teamId, options);
|
|
382
|
+
}
|
|
383
|
+
catch (error) {
|
|
384
|
+
console.error("Error:", error instanceof Error ? error.message : error);
|
|
385
|
+
process.exit(1);
|
|
386
|
+
}
|
|
387
|
+
});
|
|
388
|
+
teamCmd
|
|
389
|
+
.command("protection-template <team_id>")
|
|
390
|
+
.description("Read or write the team's protection template")
|
|
391
|
+
.option("--set <file>", "Write the template from a YAML or JSON file")
|
|
392
|
+
.option("--clear", "Clear the template")
|
|
393
|
+
.option("--json", "Output JSON instead of human-readable text")
|
|
394
|
+
.action(async (teamId, options) => {
|
|
395
|
+
try {
|
|
396
|
+
await teamTemplateCommand("protection", teamId, options);
|
|
397
|
+
}
|
|
398
|
+
catch (error) {
|
|
399
|
+
console.error("Error:", error instanceof Error ? error.message : error);
|
|
400
|
+
process.exit(1);
|
|
401
|
+
}
|
|
402
|
+
});
|
|
403
|
+
teamCmd
|
|
404
|
+
.command("preview-compose <team_id>")
|
|
405
|
+
.description("Dry-run the composer with a draft template (alignment by default)")
|
|
406
|
+
.option("--protection", "Preview protection template (default: alignment)")
|
|
407
|
+
.option("--from <file>", "Read draft template from a file (default: stdin)")
|
|
408
|
+
.option("--json", "Output JSON instead of human-readable text")
|
|
409
|
+
.action(async (teamId, options) => {
|
|
410
|
+
try {
|
|
411
|
+
await teamPreviewComposeCommand(teamId, options);
|
|
412
|
+
}
|
|
413
|
+
catch (error) {
|
|
414
|
+
console.error("Error:", error instanceof Error ? error.message : error);
|
|
415
|
+
process.exit(1);
|
|
416
|
+
}
|
|
417
|
+
});
|
|
418
|
+
// `mnemom team admin {grant,revoke,list}` — Piece 5 of T1-3.1 (ADR-046).
|
|
419
|
+
const teamAdminCmd = teamCmd
|
|
420
|
+
.command("admin")
|
|
421
|
+
.description("Manage team_admin grants (Piece 5 of T1-3.1, ADR-046)");
|
|
422
|
+
teamAdminCmd
|
|
423
|
+
.command("grant <team_id>")
|
|
424
|
+
.description("Grant team_admin role to a user on this team")
|
|
425
|
+
.requiredOption("--user <user_id>", "User ID to grant team_admin to")
|
|
426
|
+
.option("--json", "Output JSON instead of human-readable text")
|
|
427
|
+
.action(async (teamId, options) => {
|
|
428
|
+
try {
|
|
429
|
+
await teamAdminGrantCommand(teamId, options);
|
|
430
|
+
}
|
|
431
|
+
catch (error) {
|
|
432
|
+
console.error("Error:", error instanceof Error ? error.message : error);
|
|
433
|
+
process.exit(1);
|
|
434
|
+
}
|
|
435
|
+
});
|
|
436
|
+
teamAdminCmd
|
|
437
|
+
.command("revoke <team_id>")
|
|
438
|
+
.description("Revoke a team_admin grant (admin or self)")
|
|
439
|
+
.requiredOption("--user <user_id>", "User ID to revoke (use your own ID for self-revoke)")
|
|
440
|
+
.option("--json", "Output JSON instead of human-readable text")
|
|
441
|
+
.action(async (teamId, options) => {
|
|
442
|
+
try {
|
|
443
|
+
await teamAdminRevokeCommand(teamId, options);
|
|
444
|
+
}
|
|
445
|
+
catch (error) {
|
|
446
|
+
console.error("Error:", error instanceof Error ? error.message : error);
|
|
447
|
+
process.exit(1);
|
|
448
|
+
}
|
|
449
|
+
});
|
|
450
|
+
teamAdminCmd
|
|
451
|
+
.command("list <team_id>")
|
|
452
|
+
.description("List active team_admin grants on a team")
|
|
453
|
+
.option("--json", "Output JSON instead of human-readable text")
|
|
454
|
+
.action(async (teamId, options) => {
|
|
455
|
+
try {
|
|
456
|
+
await teamAdminListCommand(teamId, options);
|
|
457
|
+
}
|
|
458
|
+
catch (error) {
|
|
459
|
+
console.error("Error:", error instanceof Error ? error.message : error);
|
|
460
|
+
process.exit(1);
|
|
461
|
+
}
|
|
462
|
+
});
|
|
463
|
+
// `mnemom team coverage <team_id>` — Piece 6 of T1-3.1 (ADR-040 + ADR-045 +
|
|
464
|
+
// ADR-047). Compliance-grade proof-of-coverage for a team's sideband
|
|
465
|
+
// detector sweeps; per-axis 30-day summary + per-day rows.
|
|
466
|
+
teamCmd
|
|
467
|
+
.command("coverage <team_id>")
|
|
468
|
+
.description("Show last-30-day sideband sweep coverage for a team")
|
|
469
|
+
.option("--rows", "Include per-day rows in addition to per-axis summary")
|
|
470
|
+
.option("--json", "Output JSON instead of human-readable text")
|
|
471
|
+
.action(async (teamId, options) => {
|
|
472
|
+
try {
|
|
473
|
+
await teamCoverageCommand(teamId, options);
|
|
474
|
+
}
|
|
475
|
+
catch (error) {
|
|
476
|
+
console.error("Error:", error instanceof Error ? error.message : error);
|
|
477
|
+
process.exit(1);
|
|
478
|
+
}
|
|
479
|
+
});
|
|
480
|
+
// ============================================================================
|
|
481
|
+
// Sideband advisories (Piece 6 of T1-3.1, ADR-040 + ADR-045 + ADR-047)
|
|
482
|
+
//
|
|
483
|
+
// Surface the `pending_advisories` rows where source LIKE 'sideband.%' as a
|
|
484
|
+
// CLI-readable cross-turn carryover view. Detector firings (coherence,
|
|
485
|
+
// fault-line, fleet, drift) land here; the gateway injects them on the
|
|
486
|
+
// agent's next turn.
|
|
487
|
+
// ============================================================================
|
|
488
|
+
const advisoriesCmd = program
|
|
489
|
+
.command("advisories")
|
|
490
|
+
.description("List + inspect sideband advisories (pending_advisories rows)");
|
|
491
|
+
advisoriesCmd
|
|
492
|
+
.command("list")
|
|
493
|
+
.description("List recent sideband advisories scoped to one agent or one team")
|
|
494
|
+
.option("--agent <id>", "Scope to a single agent")
|
|
495
|
+
.option("--team <id>", "Scope to all agents in a team")
|
|
496
|
+
.option("--source <source>", "Filter to one source (e.g. sideband.coherence)")
|
|
497
|
+
.option("--limit <n>", "Page size (default 50 for agent, 100 for team)")
|
|
498
|
+
.option("--since <iso>", "Only advisories created at or after this ISO timestamp")
|
|
499
|
+
.option("--json", "Output JSON")
|
|
500
|
+
.action(async (options) => {
|
|
501
|
+
try {
|
|
502
|
+
await advisoriesListCommand(options);
|
|
503
|
+
}
|
|
504
|
+
catch (error) {
|
|
505
|
+
console.error("Error:", error instanceof Error ? error.message : error);
|
|
506
|
+
process.exit(1);
|
|
507
|
+
}
|
|
508
|
+
});
|
|
509
|
+
advisoriesCmd
|
|
510
|
+
.command("show <advisory_id>")
|
|
511
|
+
.description("Show one advisory's full content (nudge_content + source_ref)")
|
|
512
|
+
.option("--agent <id>", "Scope lookup to this agent")
|
|
513
|
+
.option("--team <id>", "Scope lookup to this team")
|
|
514
|
+
.option("--json", "Output JSON")
|
|
515
|
+
.action(async (advisoryId, options) => {
|
|
516
|
+
try {
|
|
517
|
+
await advisoriesShowCommand(advisoryId, options);
|
|
518
|
+
}
|
|
519
|
+
catch (error) {
|
|
520
|
+
console.error("Error:", error instanceof Error ? error.message : error);
|
|
521
|
+
process.exit(1);
|
|
522
|
+
}
|
|
523
|
+
});
|
|
524
|
+
// ============================================================================
|
|
525
|
+
// Governance signals (ADR-048) — operator-actionable observation surface
|
|
526
|
+
//
|
|
527
|
+
// Distinct from `mnemom advisories list` (which now narrows to runtime.* /
|
|
528
|
+
// manual.* per ADR-048 §1). Surfaces sideband.* + future protection.* /
|
|
529
|
+
// posture.* signals from governance_signals: ack/resolve/dismiss workflow,
|
|
530
|
+
// notification destinations (slack/email/pagerduty/webhook), escalation
|
|
531
|
+
// rules.
|
|
532
|
+
// ============================================================================
|
|
533
|
+
import { governanceSignalsListCommand, governanceSignalsShowCommand, governanceSignalsAckCommand, governanceSignalsResolveCommand, governanceSignalsDismissCommand, governanceDestinationsListCommand, governanceDestinationsAddCommand, governanceDestinationsRemoveCommand, governanceDestinationsTestCommand, governanceRulesListCommand, governanceRulesAddCommand, governanceRulesRemoveCommand, } from "./commands/governance.js";
|
|
534
|
+
const governanceCmd = program
|
|
535
|
+
.command("governance")
|
|
536
|
+
.description("Operator workflow for governance_signals (ADR-048)");
|
|
537
|
+
const govSignalsCmd = governanceCmd
|
|
538
|
+
.command("signals")
|
|
539
|
+
.description("List, inspect, and transition governance_signals");
|
|
540
|
+
govSignalsCmd
|
|
541
|
+
.command("list")
|
|
542
|
+
.description("List governance signals at platform/org/team/agent scope")
|
|
543
|
+
.option("--org <id>", "Org scope")
|
|
544
|
+
.option("--team <id>", "Team scope")
|
|
545
|
+
.option("--agent <id>", "Per-agent slice (signals affecting this agent)")
|
|
546
|
+
.option("--source <s>", "Filter by source (sideband.{drift,coherence,fault_line,fleet})")
|
|
547
|
+
.option("--severity <s>", "Filter by severity (info|warn|high|critical)")
|
|
548
|
+
.option("--status <s>", "Filter by status (open|acknowledged|resolved|dismissed|expired)")
|
|
549
|
+
.option("--scope <s>", "Filter by scope (platform|org|team|agent)")
|
|
550
|
+
.option("--pattern-type <s>", "Filter by pattern_type")
|
|
551
|
+
.option("--since <iso>", "Detected since (ISO timestamp)")
|
|
552
|
+
.option("--limit <n>", "Max rows (default 100, max 500)")
|
|
553
|
+
.option("--json", "Output JSON")
|
|
554
|
+
.action(async (options) => {
|
|
555
|
+
try {
|
|
556
|
+
await governanceSignalsListCommand(options);
|
|
557
|
+
}
|
|
558
|
+
catch (error) {
|
|
559
|
+
console.error("Error:", error instanceof Error ? error.message : error);
|
|
560
|
+
process.exit(1);
|
|
561
|
+
}
|
|
562
|
+
});
|
|
563
|
+
govSignalsCmd
|
|
564
|
+
.command("show <signal_id>")
|
|
565
|
+
.description("Show one signal in detail")
|
|
566
|
+
.option("--json", "Output JSON")
|
|
567
|
+
.action(async (signalId, options) => {
|
|
568
|
+
try {
|
|
569
|
+
await governanceSignalsShowCommand(signalId, options);
|
|
570
|
+
}
|
|
571
|
+
catch (error) {
|
|
572
|
+
console.error("Error:", error instanceof Error ? error.message : error);
|
|
573
|
+
process.exit(1);
|
|
574
|
+
}
|
|
575
|
+
});
|
|
576
|
+
govSignalsCmd
|
|
577
|
+
.command("ack <signal_id>")
|
|
578
|
+
.description("Acknowledge an open signal (org_admin / org_owner)")
|
|
579
|
+
.option("--action <text>", "Operator-authored action note")
|
|
580
|
+
.option("--json", "Output JSON")
|
|
581
|
+
.action(async (signalId, options) => {
|
|
582
|
+
try {
|
|
583
|
+
await governanceSignalsAckCommand(signalId, options);
|
|
584
|
+
}
|
|
585
|
+
catch (error) {
|
|
586
|
+
console.error("Error:", error instanceof Error ? error.message : error);
|
|
587
|
+
process.exit(1);
|
|
588
|
+
}
|
|
589
|
+
});
|
|
590
|
+
govSignalsCmd
|
|
591
|
+
.command("resolve <signal_id>")
|
|
592
|
+
.description("Resolve a signal with a resolution status")
|
|
593
|
+
.requiredOption("--status <s>", "Resolution status (action_taken|wont_fix|duplicate|false_positive|self_resolved)")
|
|
594
|
+
.option("--action <text>", "Operator-authored action note")
|
|
595
|
+
.option("--json", "Output JSON")
|
|
596
|
+
.action(async (signalId, options) => {
|
|
597
|
+
try {
|
|
598
|
+
await governanceSignalsResolveCommand(signalId, options);
|
|
599
|
+
}
|
|
600
|
+
catch (error) {
|
|
601
|
+
console.error("Error:", error instanceof Error ? error.message : error);
|
|
602
|
+
process.exit(1);
|
|
603
|
+
}
|
|
604
|
+
});
|
|
605
|
+
govSignalsCmd
|
|
606
|
+
.command("dismiss <signal_id>")
|
|
607
|
+
.description("Dismiss a signal as not actionable")
|
|
608
|
+
.option("--reason <text>", "Operator-authored dismissal reason")
|
|
609
|
+
.option("--json", "Output JSON")
|
|
610
|
+
.action(async (signalId, options) => {
|
|
611
|
+
try {
|
|
612
|
+
await governanceSignalsDismissCommand(signalId, options);
|
|
613
|
+
}
|
|
614
|
+
catch (error) {
|
|
615
|
+
console.error("Error:", error instanceof Error ? error.message : error);
|
|
616
|
+
process.exit(1);
|
|
617
|
+
}
|
|
618
|
+
});
|
|
619
|
+
const govDestCmd = governanceCmd
|
|
620
|
+
.command("destinations")
|
|
621
|
+
.description("Manage notification destinations (slack/email/pagerduty/webhook)");
|
|
622
|
+
govDestCmd
|
|
623
|
+
.command("list")
|
|
624
|
+
.description("List destinations for an org")
|
|
625
|
+
.requiredOption("--org <id>", "Org ID")
|
|
626
|
+
.option("--json", "Output JSON")
|
|
627
|
+
.action(async (options) => {
|
|
628
|
+
try {
|
|
629
|
+
await governanceDestinationsListCommand(options);
|
|
630
|
+
}
|
|
631
|
+
catch (error) {
|
|
632
|
+
console.error("Error:", error instanceof Error ? error.message : error);
|
|
633
|
+
process.exit(1);
|
|
634
|
+
}
|
|
635
|
+
});
|
|
636
|
+
govDestCmd
|
|
637
|
+
.command("add")
|
|
638
|
+
.description("Add a destination (channel + JSON config)")
|
|
639
|
+
.requiredOption("--org <id>", "Org ID")
|
|
640
|
+
.requiredOption("--channel <c>", "webhook|slack|email|pagerduty")
|
|
641
|
+
.requiredOption("--config <json>", "Channel config (e.g., '{\"url\":\"...\",\"signing_secret\":\"...\"}')")
|
|
642
|
+
.option("--name <n>", "Display name")
|
|
643
|
+
.option("--filter <json>", "Filter narrowing (sources/severities/etc)")
|
|
644
|
+
.option("--json", "Output JSON")
|
|
645
|
+
.action(async (options) => {
|
|
646
|
+
try {
|
|
647
|
+
await governanceDestinationsAddCommand(options);
|
|
648
|
+
}
|
|
649
|
+
catch (error) {
|
|
650
|
+
console.error("Error:", error instanceof Error ? error.message : error);
|
|
651
|
+
process.exit(1);
|
|
652
|
+
}
|
|
653
|
+
});
|
|
654
|
+
govDestCmd
|
|
655
|
+
.command("remove <destination_id>")
|
|
656
|
+
.description("Remove a destination")
|
|
657
|
+
.requiredOption("--org <id>", "Org ID")
|
|
658
|
+
.option("--json", "Output JSON")
|
|
659
|
+
.action(async (id, options) => {
|
|
660
|
+
try {
|
|
661
|
+
await governanceDestinationsRemoveCommand(id, options);
|
|
662
|
+
}
|
|
663
|
+
catch (error) {
|
|
664
|
+
console.error("Error:", error instanceof Error ? error.message : error);
|
|
665
|
+
process.exit(1);
|
|
666
|
+
}
|
|
667
|
+
});
|
|
668
|
+
govDestCmd
|
|
669
|
+
.command("test <destination_id>")
|
|
670
|
+
.description("Send a synthetic test signal through this destination")
|
|
671
|
+
.requiredOption("--org <id>", "Org ID")
|
|
672
|
+
.option("--json", "Output JSON")
|
|
673
|
+
.action(async (id, options) => {
|
|
674
|
+
try {
|
|
675
|
+
await governanceDestinationsTestCommand(id, options);
|
|
676
|
+
}
|
|
677
|
+
catch (error) {
|
|
678
|
+
console.error("Error:", error instanceof Error ? error.message : error);
|
|
679
|
+
process.exit(1);
|
|
680
|
+
}
|
|
681
|
+
});
|
|
682
|
+
const govRulesCmd = governanceCmd
|
|
683
|
+
.command("rules")
|
|
684
|
+
.description("Manage escalation rules (predicate → destinations)");
|
|
685
|
+
govRulesCmd
|
|
686
|
+
.command("list")
|
|
687
|
+
.description("List escalation rules for an org")
|
|
688
|
+
.requiredOption("--org <id>", "Org ID")
|
|
689
|
+
.option("--json", "Output JSON")
|
|
690
|
+
.action(async (options) => {
|
|
691
|
+
try {
|
|
692
|
+
await governanceRulesListCommand(options);
|
|
693
|
+
}
|
|
694
|
+
catch (error) {
|
|
695
|
+
console.error("Error:", error instanceof Error ? error.message : error);
|
|
696
|
+
process.exit(1);
|
|
697
|
+
}
|
|
698
|
+
});
|
|
699
|
+
govRulesCmd
|
|
700
|
+
.command("add")
|
|
701
|
+
.description("Add an escalation rule (predicate JSON + destination IDs)")
|
|
702
|
+
.requiredOption("--org <id>", "Org ID")
|
|
703
|
+
.requiredOption("--name <n>", "Rule name")
|
|
704
|
+
.requiredOption("--predicate <json>", "Predicate JSON (e.g., '{\"source\":\"sideband.fleet\",\"severity_min\":\"high\"}')")
|
|
705
|
+
.requiredOption("--destinations <ids>", "Comma-separated destination IDs")
|
|
706
|
+
.option("--json", "Output JSON")
|
|
707
|
+
.action(async (options) => {
|
|
708
|
+
try {
|
|
709
|
+
await governanceRulesAddCommand(options);
|
|
710
|
+
}
|
|
711
|
+
catch (error) {
|
|
712
|
+
console.error("Error:", error instanceof Error ? error.message : error);
|
|
713
|
+
process.exit(1);
|
|
714
|
+
}
|
|
715
|
+
});
|
|
716
|
+
govRulesCmd
|
|
717
|
+
.command("remove <rule_id>")
|
|
718
|
+
.description("Remove an escalation rule")
|
|
719
|
+
.requiredOption("--org <id>", "Org ID")
|
|
720
|
+
.option("--json", "Output JSON")
|
|
721
|
+
.action(async (id, options) => {
|
|
722
|
+
try {
|
|
723
|
+
await governanceRulesRemoveCommand(id, options);
|
|
724
|
+
}
|
|
725
|
+
catch (error) {
|
|
726
|
+
console.error("Error:", error instanceof Error ? error.message : error);
|
|
727
|
+
process.exit(1);
|
|
728
|
+
}
|
|
729
|
+
});
|
|
730
|
+
// ============================================================================
|
|
731
|
+
// Trust Posture (Piece 3 of T1-3.1, ADR-045)
|
|
732
|
+
//
|
|
733
|
+
// Postures are team-scoped policy input that drives the observer's sideband
|
|
734
|
+
// sweep. Cards remain agent-scoped runtime output; postures are a parallel
|
|
735
|
+
// artifact type. Mnemom ships three default postures (Standard / High-
|
|
736
|
+
// Compliance / Low-Latency) seeded via migration; orgs use them as-is or
|
|
737
|
+
// clone-and-customize.
|
|
738
|
+
// ============================================================================
|
|
739
|
+
const postureCmd = program
|
|
740
|
+
.command("posture")
|
|
741
|
+
.description("Manage Trust Postures (team-scoped oversight policy)");
|
|
742
|
+
postureCmd
|
|
743
|
+
.command("list")
|
|
744
|
+
.description("List visible postures (Mnemom defaults + org-owned)")
|
|
745
|
+
.option("--org <id>", "Filter to postures owned by this org")
|
|
746
|
+
.option("--no-include-platform", "Hide Mnemom-shipped platform defaults")
|
|
747
|
+
.option("--json", "Output JSON")
|
|
748
|
+
.action(async (options) => {
|
|
749
|
+
try {
|
|
750
|
+
await postureListCommand(options);
|
|
751
|
+
}
|
|
752
|
+
catch (error) {
|
|
753
|
+
console.error("Error:", error instanceof Error ? error.message : error);
|
|
754
|
+
process.exit(1);
|
|
755
|
+
}
|
|
756
|
+
});
|
|
757
|
+
postureCmd
|
|
758
|
+
.command("show <posture_id>")
|
|
759
|
+
.description("Show one posture's metadata + body summary")
|
|
760
|
+
.option("--json", "Output JSON")
|
|
761
|
+
.action(async (postureId, options) => {
|
|
762
|
+
try {
|
|
763
|
+
await postureShowCommand(postureId, options);
|
|
764
|
+
}
|
|
765
|
+
catch (error) {
|
|
766
|
+
console.error("Error:", error instanceof Error ? error.message : error);
|
|
767
|
+
process.exit(1);
|
|
768
|
+
}
|
|
769
|
+
});
|
|
770
|
+
postureCmd
|
|
771
|
+
.command("create")
|
|
772
|
+
.description("Create a new org-scope posture (body from a JSON file)")
|
|
773
|
+
.requiredOption("--org <id>", "Target org ID")
|
|
774
|
+
.requiredOption("--slug <slug>", "Kebab-case slug, unique within the org")
|
|
775
|
+
.requiredOption("--name <name>", "Display name")
|
|
776
|
+
.requiredOption("--from <file>", "Path to a JSON file with the posture body")
|
|
777
|
+
.option("--description <text>", "Optional description")
|
|
778
|
+
.option("--summary <text>", "Change summary for the initial revision")
|
|
779
|
+
.option("--json", "Output JSON")
|
|
780
|
+
.action(async (options) => {
|
|
781
|
+
try {
|
|
782
|
+
await postureCreateCommand(options);
|
|
783
|
+
}
|
|
784
|
+
catch (error) {
|
|
785
|
+
console.error("Error:", error instanceof Error ? error.message : error);
|
|
786
|
+
process.exit(1);
|
|
787
|
+
}
|
|
788
|
+
});
|
|
789
|
+
postureCmd
|
|
790
|
+
.command("update <posture_id>")
|
|
791
|
+
.description("Write a new revision (forward-only — old revisions stay queryable)")
|
|
792
|
+
.requiredOption("--from <file>", "Path to a JSON file with the new posture body")
|
|
793
|
+
.option("--summary <text>", "Change summary for this revision")
|
|
794
|
+
.option("--name <text>", "Update the posture's display name")
|
|
795
|
+
.option("--description <text>", "Update the description")
|
|
796
|
+
.option("--json", "Output JSON")
|
|
797
|
+
.action(async (postureId, options) => {
|
|
798
|
+
try {
|
|
799
|
+
await postureUpdateCommand(postureId, options);
|
|
800
|
+
}
|
|
801
|
+
catch (error) {
|
|
802
|
+
console.error("Error:", error instanceof Error ? error.message : error);
|
|
803
|
+
process.exit(1);
|
|
804
|
+
}
|
|
805
|
+
});
|
|
806
|
+
postureCmd
|
|
807
|
+
.command("clone <posture_id>")
|
|
808
|
+
.description("Clone any visible posture into an org as the customization starting point")
|
|
809
|
+
.requiredOption("--org <id>", "Target org ID")
|
|
810
|
+
.option("--slug <slug>", "Slug for the new posture (default: <source-slug>-clone)")
|
|
811
|
+
.option("--name <name>", "Display name for the new posture")
|
|
812
|
+
.option("--description <text>", "Description override")
|
|
813
|
+
.option("--json", "Output JSON")
|
|
814
|
+
.action(async (postureId, options) => {
|
|
815
|
+
try {
|
|
816
|
+
await postureCloneCommand(postureId, options);
|
|
817
|
+
}
|
|
818
|
+
catch (error) {
|
|
819
|
+
console.error("Error:", error instanceof Error ? error.message : error);
|
|
820
|
+
process.exit(1);
|
|
821
|
+
}
|
|
822
|
+
});
|
|
823
|
+
postureCmd
|
|
824
|
+
.command("revisions <posture_id>")
|
|
825
|
+
.description("List the posture's revision history (newest first)")
|
|
826
|
+
.option("--json", "Output JSON")
|
|
827
|
+
.action(async (postureId, options) => {
|
|
828
|
+
try {
|
|
829
|
+
await postureRevisionsCommand(postureId, options);
|
|
830
|
+
}
|
|
831
|
+
catch (error) {
|
|
832
|
+
console.error("Error:", error instanceof Error ? error.message : error);
|
|
833
|
+
process.exit(1);
|
|
834
|
+
}
|
|
835
|
+
});
|
|
836
|
+
postureCmd
|
|
837
|
+
.command("diff <posture_id>")
|
|
838
|
+
.description("Structural diff between two revisions of a posture")
|
|
839
|
+
.requiredOption("--from <N>", "Revision number to diff from")
|
|
840
|
+
.requiredOption("--to <M>", "Revision number to diff to")
|
|
841
|
+
.option("--json", "Output JSON")
|
|
842
|
+
.action(async (postureId, options) => {
|
|
843
|
+
try {
|
|
844
|
+
await postureDiffCommand(postureId, options);
|
|
845
|
+
}
|
|
846
|
+
catch (error) {
|
|
847
|
+
console.error("Error:", error instanceof Error ? error.message : error);
|
|
848
|
+
process.exit(1);
|
|
849
|
+
}
|
|
850
|
+
});
|
|
851
|
+
postureCmd
|
|
852
|
+
.command("assign <posture_id>")
|
|
853
|
+
.description("Assign a posture to a team (replaces any prior assignment for that team)")
|
|
854
|
+
.requiredOption("--team <team_id>", "Team UUID")
|
|
855
|
+
.option("--pin-revision <N>", "Pin to a specific revision number (default: float against current)")
|
|
856
|
+
.action(async (postureId, options) => {
|
|
857
|
+
try {
|
|
858
|
+
await postureAssignCommand(postureId, options);
|
|
859
|
+
}
|
|
860
|
+
catch (error) {
|
|
861
|
+
console.error("Error:", error instanceof Error ? error.message : error);
|
|
862
|
+
process.exit(1);
|
|
863
|
+
}
|
|
864
|
+
});
|
|
865
|
+
postureCmd
|
|
866
|
+
.command("unassign <posture_id>")
|
|
867
|
+
.description("Remove a posture's assignment from a team")
|
|
868
|
+
.requiredOption("--team <team_id>", "Team UUID")
|
|
869
|
+
.action(async (postureId, options) => {
|
|
870
|
+
try {
|
|
871
|
+
await postureUnassignCommand(postureId, options);
|
|
872
|
+
}
|
|
873
|
+
catch (error) {
|
|
874
|
+
console.error("Error:", error instanceof Error ? error.message : error);
|
|
875
|
+
process.exit(1);
|
|
876
|
+
}
|
|
877
|
+
});
|
|
878
|
+
postureCmd
|
|
879
|
+
.command("preview-compose <posture_id>")
|
|
880
|
+
.description("Preview the effective composed posture for a team if assigned")
|
|
881
|
+
.requiredOption("--team <team_id>", "Team UUID")
|
|
882
|
+
.option("--json", "Output JSON")
|
|
883
|
+
.action(async (postureId, options) => {
|
|
884
|
+
try {
|
|
885
|
+
await posturePreviewComposeCommand(postureId, options);
|
|
886
|
+
}
|
|
887
|
+
catch (error) {
|
|
888
|
+
console.error("Error:", error instanceof Error ? error.message : error);
|
|
889
|
+
process.exit(1);
|
|
890
|
+
}
|
|
891
|
+
});
|
|
892
|
+
postureCmd
|
|
893
|
+
.command("delete <posture_id>")
|
|
894
|
+
.description("Soft-delete an org-scope posture (refuses if currently assigned to any team)")
|
|
895
|
+
.action(async (postureId) => {
|
|
896
|
+
try {
|
|
897
|
+
await postureDeleteCommand(postureId);
|
|
898
|
+
}
|
|
899
|
+
catch (error) {
|
|
900
|
+
console.error("Error:", error instanceof Error ? error.message : error);
|
|
901
|
+
process.exit(1);
|
|
902
|
+
}
|
|
903
|
+
});
|
|
904
|
+
// ============================================================================
|
|
300
905
|
// Auth
|
|
301
906
|
// ============================================================================
|
|
302
907
|
program
|
|
@@ -336,4 +941,98 @@ program
|
|
|
336
941
|
process.exit(1);
|
|
337
942
|
}
|
|
338
943
|
});
|
|
944
|
+
// ── validate (Safe House Hardening T1-4) ─────────────────────────────────
|
|
945
|
+
const validateCmd = program
|
|
946
|
+
.command("validate")
|
|
947
|
+
.description("Validate platform state against quality gates");
|
|
948
|
+
validateCmd
|
|
949
|
+
.command("safe-house")
|
|
950
|
+
.description("Render Safe House harness state per lane (full/fast) — promotion-readiness signal")
|
|
951
|
+
.option("--against <env>", "Target environment ('staging' or 'production'; informational)", "staging")
|
|
952
|
+
.option("--max-age <duration>", "Reject runs older than this (e.g. 30m, 2h, 24h, 1d)", "24h")
|
|
953
|
+
.option("--lane <lane>", "Show only one lane ('full', 'fast', or 'both')", "both")
|
|
954
|
+
.option("--strict", "Exit non-zero if any selected lane is stale or red")
|
|
955
|
+
.option("--json", "Emit raw JSON state instead of rendered output")
|
|
956
|
+
.action(async (opts) => {
|
|
957
|
+
try {
|
|
958
|
+
const lane = opts.lane === "full" || opts.lane === "fast" || opts.lane === "both"
|
|
959
|
+
? opts.lane
|
|
960
|
+
: "both";
|
|
961
|
+
await validateSafeHouseCommand({
|
|
962
|
+
against: opts.against,
|
|
963
|
+
maxAge: opts.maxAge,
|
|
964
|
+
lane,
|
|
965
|
+
strict: opts.strict,
|
|
966
|
+
json: opts.json,
|
|
967
|
+
});
|
|
968
|
+
}
|
|
969
|
+
catch (error) {
|
|
970
|
+
console.error("Error:", error instanceof Error ? error.message : error);
|
|
971
|
+
process.exit(1);
|
|
972
|
+
}
|
|
973
|
+
});
|
|
974
|
+
// ── api-key (ADR-049 capability-based scopes) ────────────────────────────
|
|
975
|
+
const apiKeyCmd = program
|
|
976
|
+
.command("api-key")
|
|
977
|
+
.description("Manage personal API keys (capability-based scopes — ADR-049)");
|
|
978
|
+
apiKeyCmd
|
|
979
|
+
.command("list")
|
|
980
|
+
.description("List your active personal API keys with their scope sets")
|
|
981
|
+
.option("--json", "Emit raw JSON instead of rendered output")
|
|
982
|
+
.action(async (options) => {
|
|
983
|
+
try {
|
|
984
|
+
await apiKeyListCommand({ json: options.json });
|
|
985
|
+
}
|
|
986
|
+
catch (error) {
|
|
987
|
+
console.error("Error:", error instanceof Error ? error.message : error);
|
|
988
|
+
process.exit(1);
|
|
989
|
+
}
|
|
990
|
+
});
|
|
991
|
+
apiKeyCmd
|
|
992
|
+
.command("create")
|
|
993
|
+
.description("Mint a new personal API key. Default scopes: gateway, api:read, api:write. " +
|
|
994
|
+
"Admin scopes (admin:org, admin:platform) are role-gated at mint time.")
|
|
995
|
+
.requiredOption("--name <name>", "Friendly name for the key (e.g. 'ci-prod')")
|
|
996
|
+
.option("--scopes <list>", "Comma-separated capability scopes. Valid: " +
|
|
997
|
+
"gateway, api:read, api:write, admin:org, admin:platform. " +
|
|
998
|
+
"Default: gateway,api:read,api:write")
|
|
999
|
+
.option("--json", "Emit raw JSON instead of rendered output")
|
|
1000
|
+
.action(async (options) => {
|
|
1001
|
+
try {
|
|
1002
|
+
await apiKeyCreateCommand({
|
|
1003
|
+
name: options.name,
|
|
1004
|
+
scopes: options.scopes,
|
|
1005
|
+
json: options.json,
|
|
1006
|
+
});
|
|
1007
|
+
}
|
|
1008
|
+
catch (error) {
|
|
1009
|
+
console.error("Error:", error instanceof Error ? error.message : error);
|
|
1010
|
+
process.exit(1);
|
|
1011
|
+
}
|
|
1012
|
+
});
|
|
1013
|
+
apiKeyCmd
|
|
1014
|
+
.command("rotate <key_id>")
|
|
1015
|
+
.description("Atomic mint-new + revoke-old. Returns the new cleartext once.")
|
|
1016
|
+
.option("--json", "Emit raw JSON instead of rendered output")
|
|
1017
|
+
.action(async (keyId, options) => {
|
|
1018
|
+
try {
|
|
1019
|
+
await apiKeyRotateCommand(keyId, { json: options.json });
|
|
1020
|
+
}
|
|
1021
|
+
catch (error) {
|
|
1022
|
+
console.error("Error:", error instanceof Error ? error.message : error);
|
|
1023
|
+
process.exit(1);
|
|
1024
|
+
}
|
|
1025
|
+
});
|
|
1026
|
+
apiKeyCmd
|
|
1027
|
+
.command("revoke <key_id>")
|
|
1028
|
+
.description("Soft-revoke an active key. Action is immediate and irreversible.")
|
|
1029
|
+
.action(async (keyId) => {
|
|
1030
|
+
try {
|
|
1031
|
+
await apiKeyRevokeCommand(keyId);
|
|
1032
|
+
}
|
|
1033
|
+
catch (error) {
|
|
1034
|
+
console.error("Error:", error instanceof Error ? error.message : error);
|
|
1035
|
+
process.exit(1);
|
|
1036
|
+
}
|
|
1037
|
+
});
|
|
339
1038
|
program.parse();
|