@mnemom/mnemom 0.9.0 → 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/commands/advisories.d.ts +32 -0
- package/dist/commands/advisories.js +158 -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 +443 -15
- package/dist/lib/api.d.ts +393 -0
- package/dist/lib/api.js +676 -5
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -3,16 +3,21 @@ 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")
|
|
15
|
-
.version("0.
|
|
20
|
+
.version("0.9.1")
|
|
16
21
|
.option("--agent <name>", "Select agent by name (or set MNEMOM_AGENT)");
|
|
17
22
|
program
|
|
18
23
|
.command("status")
|
|
@@ -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 () => {
|
|
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) => {
|
|
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();
|