@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
|
@@ -0,0 +1,440 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `mnemom posture ...` commands — Piece 3 of T1-3.1 (ADR-045).
|
|
3
|
+
*
|
|
4
|
+
* mnemom posture list [--org <id>] [--include-platform=false] [--json]
|
|
5
|
+
* mnemom posture show <posture_id> [--json]
|
|
6
|
+
* mnemom posture create --org <id> --slug <slug> --name <name>
|
|
7
|
+
* --from <file> [--description <text>]
|
|
8
|
+
* mnemom posture update <posture_id> --from <file> [--summary <text>]
|
|
9
|
+
* mnemom posture clone <posture_id> --org <id> [--slug <slug>] [--name <name>]
|
|
10
|
+
* mnemom posture revisions <posture_id> [--json]
|
|
11
|
+
* mnemom posture diff <posture_id> --from <N> --to <M> [--json]
|
|
12
|
+
* mnemom posture assign <posture_id> --team <team_id> [--pin-revision <N>]
|
|
13
|
+
* mnemom posture unassign <posture_id> --team <team_id>
|
|
14
|
+
* mnemom posture preview-compose <posture_id> --team <team_id> [--json]
|
|
15
|
+
* mnemom posture delete <posture_id>
|
|
16
|
+
*
|
|
17
|
+
* Per ADR-045: postures are team-scoped policy input; cards remain
|
|
18
|
+
* agent-scoped runtime output. The CLI authenticates the user the same
|
|
19
|
+
* way `mnemom team` and `mnemom org` do — login token or MNEMOM_API_KEY.
|
|
20
|
+
*/
|
|
21
|
+
import { readFileSync } from "node:fs";
|
|
22
|
+
import { listPostures, getPosture, listPostureRevisions, diffPostureRevisions, createPosture, updatePosture, clonePosture, deletePosture, assignPosture, unassignPosture, previewComposePosture, } from "../lib/api.js";
|
|
23
|
+
import { requireAuth } from "../lib/auth.js";
|
|
24
|
+
import { fmt } from "../lib/format.js";
|
|
25
|
+
// ─── Helpers ─────────────────────────────────────────────────────────────
|
|
26
|
+
function readBodyFile(path) {
|
|
27
|
+
let raw;
|
|
28
|
+
try {
|
|
29
|
+
raw = readFileSync(path, "utf8");
|
|
30
|
+
}
|
|
31
|
+
catch (err) {
|
|
32
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
33
|
+
console.error(fmt.error(`Failed to read '${path}': ${msg}`) + "\n");
|
|
34
|
+
process.exit(1);
|
|
35
|
+
// process.exit is `never` in prod; tests mock it to undefined. Rethrow
|
|
36
|
+
// so this function still satisfies its return type and the test is
|
|
37
|
+
// decisive (caller should not get back a sentinel "undefined as PostureBody").
|
|
38
|
+
throw err;
|
|
39
|
+
}
|
|
40
|
+
let parsed;
|
|
41
|
+
try {
|
|
42
|
+
parsed = JSON.parse(raw);
|
|
43
|
+
}
|
|
44
|
+
catch (err) {
|
|
45
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
46
|
+
console.error(fmt.error(`Invalid JSON in '${path}': ${msg}`) + "\n");
|
|
47
|
+
process.exit(1);
|
|
48
|
+
throw err;
|
|
49
|
+
}
|
|
50
|
+
// Server validates strictly; CLI just forwards.
|
|
51
|
+
return parsed;
|
|
52
|
+
}
|
|
53
|
+
function severityBadge(s) {
|
|
54
|
+
return s.toUpperCase();
|
|
55
|
+
}
|
|
56
|
+
// ─── mnemom posture list ─────────────────────────────────────────────────
|
|
57
|
+
export async function postureListCommand(opts) {
|
|
58
|
+
await requireAuth();
|
|
59
|
+
let postures;
|
|
60
|
+
try {
|
|
61
|
+
postures = await listPostures({
|
|
62
|
+
orgId: opts.org,
|
|
63
|
+
includePlatform: opts.includePlatform,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
catch (err) {
|
|
67
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
68
|
+
console.error(fmt.error(`Failed to list postures: ${msg}`) + "\n");
|
|
69
|
+
process.exit(1);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
if (opts.json) {
|
|
73
|
+
console.log(JSON.stringify(postures, null, 2));
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
console.log(fmt.header("Trust Postures"));
|
|
77
|
+
console.log();
|
|
78
|
+
if (postures.length === 0) {
|
|
79
|
+
console.log(" No postures found.\n");
|
|
80
|
+
if (!opts.org) {
|
|
81
|
+
console.log(" Tip: specify --org <id> to see your org-owned postures.\n");
|
|
82
|
+
}
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
const slugW = 22;
|
|
86
|
+
const nameW = 24;
|
|
87
|
+
const idW = 16;
|
|
88
|
+
const scopeW = 10;
|
|
89
|
+
const revW = 6;
|
|
90
|
+
const header = "Slug".padEnd(slugW) +
|
|
91
|
+
"Name".padEnd(nameW) +
|
|
92
|
+
"Posture ID".padEnd(idW) +
|
|
93
|
+
"Scope".padEnd(scopeW) +
|
|
94
|
+
"Rev".padEnd(revW);
|
|
95
|
+
console.log(` ${header}`);
|
|
96
|
+
console.log(` ${"─".repeat(slugW + nameW + idW + scopeW + revW)}`);
|
|
97
|
+
for (const p of postures) {
|
|
98
|
+
const slug = p.slug.slice(0, slugW - 2).padEnd(slugW);
|
|
99
|
+
const name = p.name.slice(0, nameW - 2).padEnd(nameW);
|
|
100
|
+
const id = p.posture_id.slice(0, idW - 2).padEnd(idW);
|
|
101
|
+
const scope = (p.is_default ? "platform*" : p.scope).padEnd(scopeW);
|
|
102
|
+
const revNo = p.body
|
|
103
|
+
? // current_revision body has an N-counter implied by revision history
|
|
104
|
+
// — but we don't refetch; use posture summary's signal.
|
|
105
|
+
"current"
|
|
106
|
+
: "—";
|
|
107
|
+
const rev = revNo.padEnd(revW);
|
|
108
|
+
console.log(` ${slug}${name}${id}${scope}${rev}`);
|
|
109
|
+
}
|
|
110
|
+
console.log(`\n Total: ${postures.length} posture(s)`);
|
|
111
|
+
console.log(` (* = Mnemom-shipped default; immutable)\n`);
|
|
112
|
+
}
|
|
113
|
+
// ─── mnemom posture show ─────────────────────────────────────────────────
|
|
114
|
+
export async function postureShowCommand(postureId, opts) {
|
|
115
|
+
await requireAuth();
|
|
116
|
+
if (!postureId) {
|
|
117
|
+
console.error(fmt.error("Usage: mnemom posture show <posture_id> [--json]") + "\n");
|
|
118
|
+
process.exit(1);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
let p;
|
|
122
|
+
try {
|
|
123
|
+
p = await getPosture(postureId);
|
|
124
|
+
}
|
|
125
|
+
catch (err) {
|
|
126
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
127
|
+
console.error(fmt.error(`Failed to fetch posture: ${msg}`) + "\n");
|
|
128
|
+
process.exit(1);
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
if (opts.json) {
|
|
132
|
+
console.log(JSON.stringify(p, null, 2));
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
console.log(fmt.header(p.name + (p.is_default ? " (Mnemom-shipped default)" : "")));
|
|
136
|
+
console.log();
|
|
137
|
+
console.log(` Posture ID: ${p.posture_id}`);
|
|
138
|
+
console.log(` Slug: ${p.slug}`);
|
|
139
|
+
console.log(` Scope: ${p.scope}${p.org_id ? ` (org: ${p.org_id})` : ""}`);
|
|
140
|
+
if (p.description)
|
|
141
|
+
console.log(` Description: ${p.description}`);
|
|
142
|
+
console.log(` Revision: ${p.current_revision_id ?? "—"}`);
|
|
143
|
+
console.log(` Created: ${new Date(p.created_at).toLocaleDateString()}`);
|
|
144
|
+
if (p.deleted_at)
|
|
145
|
+
console.log(` ${fmt.warn("Deleted:")} ${p.deleted_at}`);
|
|
146
|
+
console.log();
|
|
147
|
+
if (p.body) {
|
|
148
|
+
console.log(` Body summary:`);
|
|
149
|
+
console.log(` coherence: enabled=${p.body.sideband.coherence.enabled} ` +
|
|
150
|
+
`cadence=${p.body.sideband.coherence.cadence_seconds}s ` +
|
|
151
|
+
`severity=${severityBadge(p.body.sideband.coherence.severity_on_fire)}`);
|
|
152
|
+
console.log(` fault_line: enabled=${p.body.sideband.fault_line.enabled} ` +
|
|
153
|
+
`floor=${severityBadge(p.body.sideband.fault_line.severity_floor)} ` +
|
|
154
|
+
`severity=${severityBadge(p.body.sideband.fault_line.severity_on_fire)}`);
|
|
155
|
+
console.log(` fleet: enabled=${p.body.sideband.fleet.enabled} ` +
|
|
156
|
+
`cadence=${p.body.sideband.fleet.cadence_seconds}s ` +
|
|
157
|
+
`severity=${severityBadge(p.body.sideband.fleet.severity_on_fire)}`);
|
|
158
|
+
console.log(`\n Use --json to see the full body.`);
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
console.log(` No body (no current revision).`);
|
|
162
|
+
}
|
|
163
|
+
console.log();
|
|
164
|
+
}
|
|
165
|
+
// ─── mnemom posture create ───────────────────────────────────────────────
|
|
166
|
+
export async function postureCreateCommand(opts) {
|
|
167
|
+
await requireAuth();
|
|
168
|
+
if (!opts.org || !opts.slug || !opts.name || !opts.from) {
|
|
169
|
+
console.error(fmt.error("Usage: mnemom posture create --org <id> --slug <slug> --name <name> --from <file> [--description <text>]") + "\n");
|
|
170
|
+
process.exit(1);
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
const body = readBodyFile(opts.from);
|
|
174
|
+
let result;
|
|
175
|
+
try {
|
|
176
|
+
result = await createPosture({
|
|
177
|
+
scope: "org",
|
|
178
|
+
org_id: opts.org,
|
|
179
|
+
slug: opts.slug,
|
|
180
|
+
name: opts.name,
|
|
181
|
+
description: opts.description ?? null,
|
|
182
|
+
body,
|
|
183
|
+
change_summary: opts.summary ?? "Initial revision.",
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
catch (err) {
|
|
187
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
188
|
+
console.error(fmt.error(`Failed to create posture: ${msg}`) + "\n");
|
|
189
|
+
process.exit(1);
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
if (opts.json) {
|
|
193
|
+
console.log(JSON.stringify(result, null, 2));
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
console.log(fmt.success(`Created posture ${result.posture_id} (slug: ${result.slug})`));
|
|
197
|
+
console.log(` Org: ${result.org_id}`);
|
|
198
|
+
console.log(` Revision: ${result.current_revision_id} (revision_no=1)\n`);
|
|
199
|
+
}
|
|
200
|
+
// ─── mnemom posture update ───────────────────────────────────────────────
|
|
201
|
+
export async function postureUpdateCommand(postureId, opts) {
|
|
202
|
+
await requireAuth();
|
|
203
|
+
if (!postureId || !opts.from) {
|
|
204
|
+
console.error(fmt.error("Usage: mnemom posture update <posture_id> --from <file> [--summary <text>] [--name <text>] [--description <text>]") + "\n");
|
|
205
|
+
process.exit(1);
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
const body = readBodyFile(opts.from);
|
|
209
|
+
let result;
|
|
210
|
+
try {
|
|
211
|
+
result = await updatePosture(postureId, {
|
|
212
|
+
body,
|
|
213
|
+
change_summary: opts.summary ?? null,
|
|
214
|
+
name: opts.name,
|
|
215
|
+
description: opts.description,
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
catch (err) {
|
|
219
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
220
|
+
console.error(fmt.error(`Failed to update posture: ${msg}`) + "\n");
|
|
221
|
+
process.exit(1);
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
if (opts.json) {
|
|
225
|
+
console.log(JSON.stringify(result, null, 2));
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
console.log(fmt.success(`New revision written for ${result.posture_id}`));
|
|
229
|
+
console.log(` Current revision: ${result.current_revision_id}`);
|
|
230
|
+
console.log(` (Old revisions remain queryable; this is forward-only.)\n`);
|
|
231
|
+
}
|
|
232
|
+
// ─── mnemom posture clone ────────────────────────────────────────────────
|
|
233
|
+
export async function postureCloneCommand(postureId, opts) {
|
|
234
|
+
await requireAuth();
|
|
235
|
+
if (!postureId || !opts.org) {
|
|
236
|
+
console.error(fmt.error("Usage: mnemom posture clone <posture_id> --org <id> [--slug <slug>] [--name <name>]") + "\n");
|
|
237
|
+
process.exit(1);
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
let result;
|
|
241
|
+
try {
|
|
242
|
+
result = await clonePosture(postureId, {
|
|
243
|
+
org_id: opts.org,
|
|
244
|
+
slug: opts.slug,
|
|
245
|
+
name: opts.name,
|
|
246
|
+
description: opts.description,
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
catch (err) {
|
|
250
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
251
|
+
console.error(fmt.error(`Failed to clone posture: ${msg}`) + "\n");
|
|
252
|
+
process.exit(1);
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
if (opts.json) {
|
|
256
|
+
console.log(JSON.stringify(result, null, 2));
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
console.log(fmt.success(`Cloned ${postureId} → ${result.posture_id}`));
|
|
260
|
+
console.log(` Slug: ${result.slug}`);
|
|
261
|
+
console.log(` Org: ${result.org_id}`);
|
|
262
|
+
console.log(` Revision: ${result.current_revision_id} (revision_no=1)\n`);
|
|
263
|
+
}
|
|
264
|
+
// ─── mnemom posture revisions ────────────────────────────────────────────
|
|
265
|
+
export async function postureRevisionsCommand(postureId, opts) {
|
|
266
|
+
await requireAuth();
|
|
267
|
+
if (!postureId) {
|
|
268
|
+
console.error(fmt.error("Usage: mnemom posture revisions <posture_id> [--json]") + "\n");
|
|
269
|
+
process.exit(1);
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
const revisions = await listPostureRevisions(postureId).catch((err) => {
|
|
273
|
+
console.error(fmt.error(`Failed to list revisions: ${err instanceof Error ? err.message : err}`) + "\n");
|
|
274
|
+
process.exit(1);
|
|
275
|
+
throw err;
|
|
276
|
+
});
|
|
277
|
+
if (opts.json) {
|
|
278
|
+
console.log(JSON.stringify(revisions, null, 2));
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
console.log(fmt.header(`Revisions of ${postureId}`));
|
|
282
|
+
console.log();
|
|
283
|
+
if (revisions.length === 0) {
|
|
284
|
+
console.log(" No revisions found.\n");
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
for (const rev of revisions) {
|
|
288
|
+
const date = new Date(rev.authored_at).toLocaleString();
|
|
289
|
+
console.log(` v${rev.revision_no.toString().padStart(3, "0")} ${date}`);
|
|
290
|
+
console.log(` ${rev.revision_id}`);
|
|
291
|
+
if (rev.change_summary)
|
|
292
|
+
console.log(` ${rev.change_summary}`);
|
|
293
|
+
console.log();
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
// ─── mnemom posture diff ─────────────────────────────────────────────────
|
|
297
|
+
export async function postureDiffCommand(postureId, opts) {
|
|
298
|
+
await requireAuth();
|
|
299
|
+
if (!postureId || !opts.from || !opts.to) {
|
|
300
|
+
console.error(fmt.error("Usage: mnemom posture diff <posture_id> --from <N> --to <M> [--json]") + "\n");
|
|
301
|
+
process.exit(1);
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
const fromNo = parseInt(opts.from, 10);
|
|
305
|
+
const toNo = parseInt(opts.to, 10);
|
|
306
|
+
if (Number.isNaN(fromNo) || Number.isNaN(toNo)) {
|
|
307
|
+
console.error(fmt.error("--from and --to must be integers (revision numbers).") + "\n");
|
|
308
|
+
process.exit(1);
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
const result = await diffPostureRevisions(postureId, fromNo, toNo).catch((err) => {
|
|
312
|
+
console.error(fmt.error(`Diff failed: ${err instanceof Error ? err.message : err}`) + "\n");
|
|
313
|
+
process.exit(1);
|
|
314
|
+
throw err;
|
|
315
|
+
});
|
|
316
|
+
if (opts.json) {
|
|
317
|
+
console.log(JSON.stringify(result, null, 2));
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
console.log(fmt.header(`Diff: ${postureId} v${fromNo} → v${toNo}`));
|
|
321
|
+
console.log();
|
|
322
|
+
if (result.changes.length === 0) {
|
|
323
|
+
console.log(" No structural differences.\n");
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
for (const c of result.changes) {
|
|
327
|
+
const op = c.op === "added"
|
|
328
|
+
? fmt.success(" + added ")
|
|
329
|
+
: c.op === "removed"
|
|
330
|
+
? fmt.error(" - removed")
|
|
331
|
+
: fmt.warn(" ~ changed");
|
|
332
|
+
console.log(`${op} ${c.path}`);
|
|
333
|
+
if (c.op === "changed") {
|
|
334
|
+
console.log(` before: ${JSON.stringify(c.before)}`);
|
|
335
|
+
console.log(` after: ${JSON.stringify(c.after)}`);
|
|
336
|
+
}
|
|
337
|
+
else if (c.op === "added") {
|
|
338
|
+
console.log(` value: ${JSON.stringify(c.after)}`);
|
|
339
|
+
}
|
|
340
|
+
else {
|
|
341
|
+
console.log(` value: ${JSON.stringify(c.before)}`);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
console.log();
|
|
345
|
+
}
|
|
346
|
+
// ─── mnemom posture assign / unassign ────────────────────────────────────
|
|
347
|
+
export async function postureAssignCommand(postureId, opts) {
|
|
348
|
+
await requireAuth();
|
|
349
|
+
if (!postureId || !opts.team) {
|
|
350
|
+
console.error(fmt.error("Usage: mnemom posture assign <posture_id> --team <team_id> [--pin-revision <N>]") +
|
|
351
|
+
"\n");
|
|
352
|
+
process.exit(1);
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
const pin = opts.pinRevision ? parseInt(opts.pinRevision, 10) : null;
|
|
356
|
+
if (opts.pinRevision && Number.isNaN(pin)) {
|
|
357
|
+
console.error(fmt.error("--pin-revision must be an integer.") + "\n");
|
|
358
|
+
process.exit(1);
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
const result = await assignPosture(postureId, opts.team, pin).catch((err) => {
|
|
362
|
+
console.error(fmt.error(`Assign failed: ${err instanceof Error ? err.message : err}`) + "\n");
|
|
363
|
+
process.exit(1);
|
|
364
|
+
throw err;
|
|
365
|
+
});
|
|
366
|
+
console.log(fmt.success(`Assigned ${postureId} → team ${opts.team}`));
|
|
367
|
+
if (result.replaced_prior) {
|
|
368
|
+
console.log(` (Replaced a prior assignment — one active posture per team.)`);
|
|
369
|
+
}
|
|
370
|
+
if (pin !== null)
|
|
371
|
+
console.log(` Pinned to revision_no=${pin}.`);
|
|
372
|
+
console.log();
|
|
373
|
+
}
|
|
374
|
+
export async function postureUnassignCommand(postureId, opts) {
|
|
375
|
+
await requireAuth();
|
|
376
|
+
if (!postureId || !opts.team) {
|
|
377
|
+
console.error(fmt.error("Usage: mnemom posture unassign <posture_id> --team <team_id>") + "\n");
|
|
378
|
+
process.exit(1);
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
await unassignPosture(postureId, opts.team).catch((err) => {
|
|
382
|
+
console.error(fmt.error(`Unassign failed: ${err instanceof Error ? err.message : err}`) + "\n");
|
|
383
|
+
process.exit(1);
|
|
384
|
+
throw err;
|
|
385
|
+
});
|
|
386
|
+
console.log(fmt.success(`Unassigned ${postureId} from team ${opts.team}\n`));
|
|
387
|
+
}
|
|
388
|
+
// ─── mnemom posture preview-compose ──────────────────────────────────────
|
|
389
|
+
export async function posturePreviewComposeCommand(postureId, opts) {
|
|
390
|
+
await requireAuth();
|
|
391
|
+
if (!postureId || !opts.team) {
|
|
392
|
+
console.error(fmt.error("Usage: mnemom posture preview-compose <posture_id> --team <team_id> [--json]") +
|
|
393
|
+
"\n");
|
|
394
|
+
process.exit(1);
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
const result = await previewComposePosture(postureId, opts.team).catch((err) => {
|
|
398
|
+
console.error(fmt.error(`Preview-compose failed: ${err instanceof Error ? err.message : err}`) + "\n");
|
|
399
|
+
process.exit(1);
|
|
400
|
+
throw err;
|
|
401
|
+
});
|
|
402
|
+
if (opts.json) {
|
|
403
|
+
console.log(JSON.stringify(result, null, 2));
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
console.log(fmt.header(`Preview-compose: ${postureId} → team ${opts.team}`));
|
|
407
|
+
console.log();
|
|
408
|
+
console.log(` Cascade applied:`);
|
|
409
|
+
for (const s of result.composed.scopes_applied) {
|
|
410
|
+
console.log(` ${s.scope.padEnd(8)} ${s.posture_id} (rev ${s.revision_no})`);
|
|
411
|
+
}
|
|
412
|
+
console.log();
|
|
413
|
+
const body = result.composed.body;
|
|
414
|
+
console.log(` Effective:`);
|
|
415
|
+
console.log(` coherence: enabled=${body.sideband.coherence.enabled} ` +
|
|
416
|
+
`cadence=${body.sideband.coherence.cadence_seconds}s ` +
|
|
417
|
+
`severity=${severityBadge(body.sideband.coherence.severity_on_fire)}`);
|
|
418
|
+
console.log(` fault_line: enabled=${body.sideband.fault_line.enabled} ` +
|
|
419
|
+
`floor=${severityBadge(body.sideband.fault_line.severity_floor)} ` +
|
|
420
|
+
`severity=${severityBadge(body.sideband.fault_line.severity_on_fire)}`);
|
|
421
|
+
console.log(` fleet: enabled=${body.sideband.fleet.enabled} ` +
|
|
422
|
+
`cadence=${body.sideband.fleet.cadence_seconds}s ` +
|
|
423
|
+
`severity=${severityBadge(body.sideband.fleet.severity_on_fire)}`);
|
|
424
|
+
console.log(`\n Use --json to see the full body.\n`);
|
|
425
|
+
}
|
|
426
|
+
// ─── mnemom posture delete ───────────────────────────────────────────────
|
|
427
|
+
export async function postureDeleteCommand(postureId) {
|
|
428
|
+
await requireAuth();
|
|
429
|
+
if (!postureId) {
|
|
430
|
+
console.error(fmt.error("Usage: mnemom posture delete <posture_id>") + "\n");
|
|
431
|
+
process.exit(1);
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
434
|
+
await deletePosture(postureId).catch((err) => {
|
|
435
|
+
console.error(fmt.error(`Delete failed: ${err instanceof Error ? err.message : err}`) + "\n");
|
|
436
|
+
process.exit(1);
|
|
437
|
+
throw err;
|
|
438
|
+
});
|
|
439
|
+
console.log(fmt.success(`Soft-deleted posture ${postureId}\n`));
|
|
440
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `mnemom team ...` commands — Piece 2 of T1-3.1 (ADR-044 amended);
|
|
3
|
+
* extended in Piece 5 (ADR-046) with `team admin {grant,revoke,list}`.
|
|
4
|
+
*
|
|
5
|
+
* mnemom team list — list all teams across orgs
|
|
6
|
+
* mnemom team show <team_id> [--json] — show one team's detail
|
|
7
|
+
* mnemom team alignment-template <team_id> — read alignment template
|
|
8
|
+
* mnemom team alignment-template <team_id> --set <f> — write from YAML/JSON file
|
|
9
|
+
* mnemom team alignment-template <team_id> --clear — clear template
|
|
10
|
+
* mnemom team protection-template <team_id> [...] — same shape (protection)
|
|
11
|
+
* mnemom team preview-compose <team_id> [--protection] — dry-run from stdin/file
|
|
12
|
+
* mnemom team admin grant <team_id> --user <user_id> — grant team_admin
|
|
13
|
+
* mnemom team admin revoke <team_id> --user <user_id> — revoke team_admin
|
|
14
|
+
* mnemom team admin list <team_id> [--json] — list active grants
|
|
15
|
+
*
|
|
16
|
+
* Per ADR-044 amended + Charter §I11: team membership is OPTIONAL. Teams
|
|
17
|
+
* are an agent grouping primitive within an org; users have no team
|
|
18
|
+
* concept. Backend RBAC for the template endpoints is purely org-level
|
|
19
|
+
* (requireOrgRole on team.org_id). The Team Admin role added in Piece 5
|
|
20
|
+
* (ADR-046) is the FIRST user-team association — a per-(org, team, user)
|
|
21
|
+
* grant managed via `mnemom team admin`.
|
|
22
|
+
*/
|
|
23
|
+
import { type TeamTemplateKind } from "../lib/api.js";
|
|
24
|
+
export declare function teamListCommand(opts: {
|
|
25
|
+
json?: boolean;
|
|
26
|
+
}): Promise<void>;
|
|
27
|
+
export declare function teamShowCommand(teamId: string | undefined, opts: {
|
|
28
|
+
json?: boolean;
|
|
29
|
+
}): Promise<void>;
|
|
30
|
+
interface TemplateOpts {
|
|
31
|
+
set?: string;
|
|
32
|
+
clear?: boolean;
|
|
33
|
+
json?: boolean;
|
|
34
|
+
}
|
|
35
|
+
export declare function teamTemplateCommand(kind: TeamTemplateKind, teamId: string | undefined, opts: TemplateOpts): Promise<void>;
|
|
36
|
+
export declare function teamPreviewComposeCommand(teamId: string | undefined, opts: {
|
|
37
|
+
protection?: boolean;
|
|
38
|
+
from?: string;
|
|
39
|
+
json?: boolean;
|
|
40
|
+
}): Promise<void>;
|
|
41
|
+
export declare function teamAdminGrantCommand(teamId: string | undefined, opts: {
|
|
42
|
+
user?: string;
|
|
43
|
+
json?: boolean;
|
|
44
|
+
}): Promise<void>;
|
|
45
|
+
export declare function teamAdminRevokeCommand(teamId: string | undefined, opts: {
|
|
46
|
+
user?: string;
|
|
47
|
+
json?: boolean;
|
|
48
|
+
}): Promise<void>;
|
|
49
|
+
export declare function teamAdminListCommand(teamId: string | undefined, opts: {
|
|
50
|
+
json?: boolean;
|
|
51
|
+
}): Promise<void>;
|
|
52
|
+
export declare function teamCoverageCommand(teamId: string, opts?: {
|
|
53
|
+
json?: boolean;
|
|
54
|
+
rows?: boolean;
|
|
55
|
+
}): Promise<void>;
|
|
56
|
+
export {};
|