@mnemom/mnemom 0.9.1 → 0.10.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/index.js CHANGED
@@ -3,12 +3,17 @@ 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";
12
17
  program
13
18
  .name("mnemom")
14
19
  .description("Transparent AI agent tracing")
@@ -55,9 +60,7 @@ program
55
60
  process.exit(1);
56
61
  }
57
62
  });
58
- const license = program
59
- .command("license")
60
- .description("Enterprise license management");
63
+ const license = program.command("license").description("Enterprise license management");
61
64
  license
62
65
  .command("activate <jwt>")
63
66
  .description("Activate an enterprise license")
@@ -97,9 +100,7 @@ license
97
100
  // ============================================================================
98
101
  // Card commands (alignment card)
99
102
  // ============================================================================
100
- const cardCmd = program
101
- .command("card")
102
- .description("Manage alignment card");
103
+ const cardCmd = program.command("card").description("Manage alignment card");
103
104
  cardCmd
104
105
  .command("show")
105
106
  .description("Display alignment card (YAML)")
@@ -174,9 +175,7 @@ cardCmd
174
175
  // ============================================================================
175
176
  // Protection card commands
176
177
  // ============================================================================
177
- const protectionCmd = program
178
- .command("protection")
179
- .description("Manage protection card");
178
+ const protectionCmd = program.command("protection").description("Manage protection card");
180
179
  protectionCmd
181
180
  .command("show")
182
181
  .description("Display protection card (YAML)")
@@ -241,12 +240,16 @@ const policyCmd = program
241
240
  policyCmd
242
241
  .command("init")
243
242
  .description("(removed) Use `mnemom card validate`")
244
- .action(async () => { await policyInitCommand(); });
243
+ .action(async () => {
244
+ await policyInitCommand();
245
+ });
245
246
  policyCmd
246
247
  .command("validate")
247
248
  .argument("<file>", "Path to policy file")
248
249
  .description("(removed) Use `mnemom card validate`")
249
- .action(async (file) => { await policyValidateCommand(file); });
250
+ .action(async (file) => {
251
+ await policyValidateCommand(file);
252
+ });
250
253
  policyCmd
251
254
  .command("publish")
252
255
  .argument("<file>", "Path to policy file")
@@ -297,6 +300,401 @@ program
297
300
  }
298
301
  });
299
302
  // ============================================================================
303
+ // Organization management (ADR-044, Piece 1 of T1-3.1)
304
+ // ============================================================================
305
+ const orgCmd = program
306
+ .command("org")
307
+ .description("Manage your organizations (personal + multi-user)");
308
+ orgCmd
309
+ .command("list")
310
+ .description("List every org you are a member of, including your personal org")
311
+ .option("--json", "Output JSON instead of a human-readable table")
312
+ .action(async (options) => {
313
+ try {
314
+ await orgListCommand({ json: options.json });
315
+ }
316
+ catch (error) {
317
+ console.error("Error:", error instanceof Error ? error.message : error);
318
+ process.exit(1);
319
+ }
320
+ });
321
+ orgCmd
322
+ .command("show [org_id]")
323
+ .description("Show details of an org (default: your personal org if --personal, else single membership)")
324
+ .option("--personal", "Show your personal-org-of-one (per ADR-044)")
325
+ .option("--json", "Output JSON instead of human-readable text")
326
+ .action(async (orgId, options) => {
327
+ try {
328
+ await orgShowCommand(orgId, { personal: options.personal, json: options.json });
329
+ }
330
+ catch (error) {
331
+ console.error("Error:", error instanceof Error ? error.message : error);
332
+ process.exit(1);
333
+ }
334
+ });
335
+ // ============================================================================
336
+ // Team management (ADR-044 amended, Piece 2 of T1-3.1)
337
+ //
338
+ // Per ADR-044 + Charter §I11: team membership is OPTIONAL. Solo agents
339
+ // (zero teams) compose under Platform → Org → Agent. Backend RBAC for
340
+ // team-template endpoints is purely org-level (requireOrgRole on the
341
+ // team's parent org); Team Admin role lands in Piece 5.
342
+ // ============================================================================
343
+ const teamCmd = program
344
+ .command("team")
345
+ .description("Manage teams and their scope-cascade templates");
346
+ teamCmd
347
+ .command("list")
348
+ .description("List every team across all orgs you are a member of")
349
+ .option("--json", "Output JSON instead of a human-readable table")
350
+ .action(async (options) => {
351
+ try {
352
+ await teamListCommand({ json: options.json });
353
+ }
354
+ catch (error) {
355
+ console.error("Error:", error instanceof Error ? error.message : error);
356
+ process.exit(1);
357
+ }
358
+ });
359
+ teamCmd
360
+ .command("show <team_id>")
361
+ .description("Show details of a single team")
362
+ .option("--json", "Output JSON instead of human-readable text")
363
+ .action(async (teamId, options) => {
364
+ try {
365
+ await teamShowCommand(teamId, { json: options.json });
366
+ }
367
+ catch (error) {
368
+ console.error("Error:", error instanceof Error ? error.message : error);
369
+ process.exit(1);
370
+ }
371
+ });
372
+ teamCmd
373
+ .command("alignment-template <team_id>")
374
+ .description("Read or write the team's alignment template")
375
+ .option("--set <file>", "Write the template from a YAML or JSON file")
376
+ .option("--clear", "Clear the template")
377
+ .option("--json", "Output JSON instead of human-readable text")
378
+ .action(async (teamId, options) => {
379
+ try {
380
+ await teamTemplateCommand("alignment", teamId, options);
381
+ }
382
+ catch (error) {
383
+ console.error("Error:", error instanceof Error ? error.message : error);
384
+ process.exit(1);
385
+ }
386
+ });
387
+ teamCmd
388
+ .command("protection-template <team_id>")
389
+ .description("Read or write the team's protection template")
390
+ .option("--set <file>", "Write the template from a YAML or JSON file")
391
+ .option("--clear", "Clear the template")
392
+ .option("--json", "Output JSON instead of human-readable text")
393
+ .action(async (teamId, options) => {
394
+ try {
395
+ await teamTemplateCommand("protection", teamId, options);
396
+ }
397
+ catch (error) {
398
+ console.error("Error:", error instanceof Error ? error.message : error);
399
+ process.exit(1);
400
+ }
401
+ });
402
+ teamCmd
403
+ .command("preview-compose <team_id>")
404
+ .description("Dry-run the composer with a draft template (alignment by default)")
405
+ .option("--protection", "Preview protection template (default: alignment)")
406
+ .option("--from <file>", "Read draft template from a file (default: stdin)")
407
+ .option("--json", "Output JSON instead of human-readable text")
408
+ .action(async (teamId, options) => {
409
+ try {
410
+ await teamPreviewComposeCommand(teamId, options);
411
+ }
412
+ catch (error) {
413
+ console.error("Error:", error instanceof Error ? error.message : error);
414
+ process.exit(1);
415
+ }
416
+ });
417
+ // `mnemom team admin {grant,revoke,list}` — Piece 5 of T1-3.1 (ADR-046).
418
+ const teamAdminCmd = teamCmd
419
+ .command("admin")
420
+ .description("Manage team_admin grants (Piece 5 of T1-3.1, ADR-046)");
421
+ teamAdminCmd
422
+ .command("grant <team_id>")
423
+ .description("Grant team_admin role to a user on this team")
424
+ .requiredOption("--user <user_id>", "User ID to grant team_admin to")
425
+ .option("--json", "Output JSON instead of human-readable text")
426
+ .action(async (teamId, options) => {
427
+ try {
428
+ await teamAdminGrantCommand(teamId, options);
429
+ }
430
+ catch (error) {
431
+ console.error("Error:", error instanceof Error ? error.message : error);
432
+ process.exit(1);
433
+ }
434
+ });
435
+ teamAdminCmd
436
+ .command("revoke <team_id>")
437
+ .description("Revoke a team_admin grant (admin or self)")
438
+ .requiredOption("--user <user_id>", "User ID to revoke (use your own ID for self-revoke)")
439
+ .option("--json", "Output JSON instead of human-readable text")
440
+ .action(async (teamId, options) => {
441
+ try {
442
+ await teamAdminRevokeCommand(teamId, options);
443
+ }
444
+ catch (error) {
445
+ console.error("Error:", error instanceof Error ? error.message : error);
446
+ process.exit(1);
447
+ }
448
+ });
449
+ teamAdminCmd
450
+ .command("list <team_id>")
451
+ .description("List active team_admin grants on a team")
452
+ .option("--json", "Output JSON instead of human-readable text")
453
+ .action(async (teamId, options) => {
454
+ try {
455
+ await teamAdminListCommand(teamId, options);
456
+ }
457
+ catch (error) {
458
+ console.error("Error:", error instanceof Error ? error.message : error);
459
+ process.exit(1);
460
+ }
461
+ });
462
+ // `mnemom team coverage <team_id>` — Piece 6 of T1-3.1 (ADR-040 + ADR-045 +
463
+ // ADR-047). Compliance-grade proof-of-coverage for a team's sideband
464
+ // detector sweeps; per-axis 30-day summary + per-day rows.
465
+ teamCmd
466
+ .command("coverage <team_id>")
467
+ .description("Show last-30-day sideband sweep coverage for a team")
468
+ .option("--rows", "Include per-day rows in addition to per-axis summary")
469
+ .option("--json", "Output JSON instead of human-readable text")
470
+ .action(async (teamId, options) => {
471
+ try {
472
+ await teamCoverageCommand(teamId, options);
473
+ }
474
+ catch (error) {
475
+ console.error("Error:", error instanceof Error ? error.message : error);
476
+ process.exit(1);
477
+ }
478
+ });
479
+ // ============================================================================
480
+ // Sideband advisories (Piece 6 of T1-3.1, ADR-040 + ADR-045 + ADR-047)
481
+ //
482
+ // Surface the `pending_advisories` rows where source LIKE 'sideband.%' as a
483
+ // CLI-readable cross-turn carryover view. Detector firings (coherence,
484
+ // fault-line, fleet, drift) land here; the gateway injects them on the
485
+ // agent's next turn.
486
+ // ============================================================================
487
+ const advisoriesCmd = program
488
+ .command("advisories")
489
+ .description("List + inspect sideband advisories (pending_advisories rows)");
490
+ advisoriesCmd
491
+ .command("list")
492
+ .description("List recent sideband advisories scoped to one agent or one team")
493
+ .option("--agent <id>", "Scope to a single agent")
494
+ .option("--team <id>", "Scope to all agents in a team")
495
+ .option("--source <source>", "Filter to one source (e.g. sideband.coherence)")
496
+ .option("--limit <n>", "Page size (default 50 for agent, 100 for team)")
497
+ .option("--since <iso>", "Only advisories created at or after this ISO timestamp")
498
+ .option("--json", "Output JSON")
499
+ .action(async (options) => {
500
+ try {
501
+ await advisoriesListCommand(options);
502
+ }
503
+ catch (error) {
504
+ console.error("Error:", error instanceof Error ? error.message : error);
505
+ process.exit(1);
506
+ }
507
+ });
508
+ advisoriesCmd
509
+ .command("show <advisory_id>")
510
+ .description("Show one advisory's full content (nudge_content + source_ref)")
511
+ .option("--agent <id>", "Scope lookup to this agent")
512
+ .option("--team <id>", "Scope lookup to this team")
513
+ .option("--json", "Output JSON")
514
+ .action(async (advisoryId, options) => {
515
+ try {
516
+ await advisoriesShowCommand(advisoryId, options);
517
+ }
518
+ catch (error) {
519
+ console.error("Error:", error instanceof Error ? error.message : error);
520
+ process.exit(1);
521
+ }
522
+ });
523
+ // ============================================================================
524
+ // Trust Posture (Piece 3 of T1-3.1, ADR-045)
525
+ //
526
+ // Postures are team-scoped policy input that drives the observer's sideband
527
+ // sweep. Cards remain agent-scoped runtime output; postures are a parallel
528
+ // artifact type. Mnemom ships three default postures (Standard / High-
529
+ // Compliance / Low-Latency) seeded via migration; orgs use them as-is or
530
+ // clone-and-customize.
531
+ // ============================================================================
532
+ const postureCmd = program
533
+ .command("posture")
534
+ .description("Manage Trust Postures (team-scoped oversight policy)");
535
+ postureCmd
536
+ .command("list")
537
+ .description("List visible postures (Mnemom defaults + org-owned)")
538
+ .option("--org <id>", "Filter to postures owned by this org")
539
+ .option("--no-include-platform", "Hide Mnemom-shipped platform defaults")
540
+ .option("--json", "Output JSON")
541
+ .action(async (options) => {
542
+ try {
543
+ await postureListCommand(options);
544
+ }
545
+ catch (error) {
546
+ console.error("Error:", error instanceof Error ? error.message : error);
547
+ process.exit(1);
548
+ }
549
+ });
550
+ postureCmd
551
+ .command("show <posture_id>")
552
+ .description("Show one posture's metadata + body summary")
553
+ .option("--json", "Output JSON")
554
+ .action(async (postureId, options) => {
555
+ try {
556
+ await postureShowCommand(postureId, options);
557
+ }
558
+ catch (error) {
559
+ console.error("Error:", error instanceof Error ? error.message : error);
560
+ process.exit(1);
561
+ }
562
+ });
563
+ postureCmd
564
+ .command("create")
565
+ .description("Create a new org-scope posture (body from a JSON file)")
566
+ .requiredOption("--org <id>", "Target org ID")
567
+ .requiredOption("--slug <slug>", "Kebab-case slug, unique within the org")
568
+ .requiredOption("--name <name>", "Display name")
569
+ .requiredOption("--from <file>", "Path to a JSON file with the posture body")
570
+ .option("--description <text>", "Optional description")
571
+ .option("--summary <text>", "Change summary for the initial revision")
572
+ .option("--json", "Output JSON")
573
+ .action(async (options) => {
574
+ try {
575
+ await postureCreateCommand(options);
576
+ }
577
+ catch (error) {
578
+ console.error("Error:", error instanceof Error ? error.message : error);
579
+ process.exit(1);
580
+ }
581
+ });
582
+ postureCmd
583
+ .command("update <posture_id>")
584
+ .description("Write a new revision (forward-only — old revisions stay queryable)")
585
+ .requiredOption("--from <file>", "Path to a JSON file with the new posture body")
586
+ .option("--summary <text>", "Change summary for this revision")
587
+ .option("--name <text>", "Update the posture's display name")
588
+ .option("--description <text>", "Update the description")
589
+ .option("--json", "Output JSON")
590
+ .action(async (postureId, options) => {
591
+ try {
592
+ await postureUpdateCommand(postureId, options);
593
+ }
594
+ catch (error) {
595
+ console.error("Error:", error instanceof Error ? error.message : error);
596
+ process.exit(1);
597
+ }
598
+ });
599
+ postureCmd
600
+ .command("clone <posture_id>")
601
+ .description("Clone any visible posture into an org as the customization starting point")
602
+ .requiredOption("--org <id>", "Target org ID")
603
+ .option("--slug <slug>", "Slug for the new posture (default: <source-slug>-clone)")
604
+ .option("--name <name>", "Display name for the new posture")
605
+ .option("--description <text>", "Description override")
606
+ .option("--json", "Output JSON")
607
+ .action(async (postureId, options) => {
608
+ try {
609
+ await postureCloneCommand(postureId, options);
610
+ }
611
+ catch (error) {
612
+ console.error("Error:", error instanceof Error ? error.message : error);
613
+ process.exit(1);
614
+ }
615
+ });
616
+ postureCmd
617
+ .command("revisions <posture_id>")
618
+ .description("List the posture's revision history (newest first)")
619
+ .option("--json", "Output JSON")
620
+ .action(async (postureId, options) => {
621
+ try {
622
+ await postureRevisionsCommand(postureId, options);
623
+ }
624
+ catch (error) {
625
+ console.error("Error:", error instanceof Error ? error.message : error);
626
+ process.exit(1);
627
+ }
628
+ });
629
+ postureCmd
630
+ .command("diff <posture_id>")
631
+ .description("Structural diff between two revisions of a posture")
632
+ .requiredOption("--from <N>", "Revision number to diff from")
633
+ .requiredOption("--to <M>", "Revision number to diff to")
634
+ .option("--json", "Output JSON")
635
+ .action(async (postureId, options) => {
636
+ try {
637
+ await postureDiffCommand(postureId, options);
638
+ }
639
+ catch (error) {
640
+ console.error("Error:", error instanceof Error ? error.message : error);
641
+ process.exit(1);
642
+ }
643
+ });
644
+ postureCmd
645
+ .command("assign <posture_id>")
646
+ .description("Assign a posture to a team (replaces any prior assignment for that team)")
647
+ .requiredOption("--team <team_id>", "Team UUID")
648
+ .option("--pin-revision <N>", "Pin to a specific revision number (default: float against current)")
649
+ .action(async (postureId, options) => {
650
+ try {
651
+ await postureAssignCommand(postureId, options);
652
+ }
653
+ catch (error) {
654
+ console.error("Error:", error instanceof Error ? error.message : error);
655
+ process.exit(1);
656
+ }
657
+ });
658
+ postureCmd
659
+ .command("unassign <posture_id>")
660
+ .description("Remove a posture's assignment from a team")
661
+ .requiredOption("--team <team_id>", "Team UUID")
662
+ .action(async (postureId, options) => {
663
+ try {
664
+ await postureUnassignCommand(postureId, options);
665
+ }
666
+ catch (error) {
667
+ console.error("Error:", error instanceof Error ? error.message : error);
668
+ process.exit(1);
669
+ }
670
+ });
671
+ postureCmd
672
+ .command("preview-compose <posture_id>")
673
+ .description("Preview the effective composed posture for a team if assigned")
674
+ .requiredOption("--team <team_id>", "Team UUID")
675
+ .option("--json", "Output JSON")
676
+ .action(async (postureId, options) => {
677
+ try {
678
+ await posturePreviewComposeCommand(postureId, options);
679
+ }
680
+ catch (error) {
681
+ console.error("Error:", error instanceof Error ? error.message : error);
682
+ process.exit(1);
683
+ }
684
+ });
685
+ postureCmd
686
+ .command("delete <posture_id>")
687
+ .description("Soft-delete an org-scope posture (refuses if currently assigned to any team)")
688
+ .action(async (postureId) => {
689
+ try {
690
+ await postureDeleteCommand(postureId);
691
+ }
692
+ catch (error) {
693
+ console.error("Error:", error instanceof Error ? error.message : error);
694
+ process.exit(1);
695
+ }
696
+ });
697
+ // ============================================================================
300
698
  // Auth
301
699
  // ============================================================================
302
700
  program
@@ -336,4 +734,34 @@ program
336
734
  process.exit(1);
337
735
  }
338
736
  });
737
+ // ── validate (Safe House Hardening T1-4) ─────────────────────────────────
738
+ const validateCmd = program
739
+ .command("validate")
740
+ .description("Validate platform state against quality gates");
741
+ validateCmd
742
+ .command("safe-house")
743
+ .description("Render Safe House harness state per lane (full/fast) — promotion-readiness signal")
744
+ .option("--against <env>", "Target environment ('staging' or 'production'; informational)", "staging")
745
+ .option("--max-age <duration>", "Reject runs older than this (e.g. 30m, 2h, 24h, 1d)", "24h")
746
+ .option("--lane <lane>", "Show only one lane ('full', 'fast', or 'both')", "both")
747
+ .option("--strict", "Exit non-zero if any selected lane is stale or red")
748
+ .option("--json", "Emit raw JSON state instead of rendered output")
749
+ .action(async (opts) => {
750
+ try {
751
+ const lane = opts.lane === "full" || opts.lane === "fast" || opts.lane === "both"
752
+ ? opts.lane
753
+ : "both";
754
+ await validateSafeHouseCommand({
755
+ against: opts.against,
756
+ maxAge: opts.maxAge,
757
+ lane,
758
+ strict: opts.strict,
759
+ json: opts.json,
760
+ });
761
+ }
762
+ catch (error) {
763
+ console.error("Error:", error instanceof Error ? error.message : error);
764
+ process.exit(1);
765
+ }
766
+ });
339
767
  program.parse();