@mnemom/mnemom 0.14.1 → 0.14.3
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/agents.js +14 -6
- package/dist/commands/integrity.js +3 -3
- package/dist/commands/logs.js +31 -4
- package/dist/commands/status.js +2 -3
- package/dist/index.js +27 -4
- package/dist/lib/api.d.ts +18 -6
- package/dist/lib/api.js +5 -5
- package/package.json +1 -1
package/dist/commands/agents.js
CHANGED
|
@@ -1,14 +1,24 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
-
import { listOrgAgents, listMyOrgs, getAgentByName, claimAgent, MnemomApiError, } from "../lib/api.js";
|
|
2
|
+
import { listAgents, listOrgAgents, listMyOrgs, getAgentByName, claimAgent, MnemomApiError, } from "../lib/api.js";
|
|
3
3
|
import { requireAuth } from "../lib/auth.js";
|
|
4
4
|
import { fmt } from "../lib/format.js";
|
|
5
5
|
export async function agentsListCommand(options = {}) {
|
|
6
|
-
await requireAuth();
|
|
6
|
+
const cred = await requireAuth();
|
|
7
7
|
console.log(fmt.header("Agents"));
|
|
8
8
|
console.log();
|
|
9
|
+
// API keys are agent-scoped, not user/org-scoped. --org requires a session to
|
|
10
|
+
// resolve org membership; route the key to the compatible endpoint instead so
|
|
11
|
+
// a valid key is never reported as unauthenticated.
|
|
12
|
+
if (cred.type === "api-key" && options.org) {
|
|
13
|
+
console.log(fmt.warn("API keys can't filter by org — org membership is a session concept.") + "\n");
|
|
14
|
+
console.log(fmt.dim(" To list org-scoped agents, log in with a session: mnemom login") + "\n");
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
// Show the Org column only when a JWT session aggregates across all orgs.
|
|
18
|
+
const showOrg = cred.type === "jwt" && !options.org;
|
|
9
19
|
let agents;
|
|
10
20
|
try {
|
|
11
|
-
agents = await listOrgAgents(options.org);
|
|
21
|
+
agents = cred.type === "api-key" ? await listAgents() : await listOrgAgents(options.org);
|
|
12
22
|
}
|
|
13
23
|
catch (err) {
|
|
14
24
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -19,10 +29,8 @@ export async function agentsListCommand(options = {}) {
|
|
|
19
29
|
console.log(options.org ? ` No agents found in org '${options.org}'.\n` : " No agents found.\n");
|
|
20
30
|
return;
|
|
21
31
|
}
|
|
22
|
-
// Show the Org column only when aggregating across orgs; with --org it's redundant.
|
|
23
|
-
const showOrg = !options.org;
|
|
24
32
|
const nameW = 24;
|
|
25
|
-
const idW =
|
|
33
|
+
const idW = Math.max("ID".length, ...agents.map((a) => a.id.length)) + 2;
|
|
26
34
|
const seenW = 14;
|
|
27
35
|
const statusW = 14;
|
|
28
36
|
const orgW = 22;
|
|
@@ -2,14 +2,14 @@ import { resolveAgentId, getIntegrity, MnemomApiError } from "../lib/api.js";
|
|
|
2
2
|
import { fmt } from "../lib/format.js";
|
|
3
3
|
export async function integrityCommand(agentName) {
|
|
4
4
|
const agentId = await resolveAgentId(agentName);
|
|
5
|
-
console.log("\nFetching
|
|
5
|
+
console.log("\nFetching agent activity...\n");
|
|
6
6
|
try {
|
|
7
7
|
const integrity = await getIntegrity(agentId);
|
|
8
8
|
// Field names match the docs.mnemom.ai canonical IntegrityScore schema:
|
|
9
9
|
// integrity_score (in [0,1]), total_traces, verified_traces, violation_count.
|
|
10
10
|
const scorePercent = (integrity.integrity_score * 100).toFixed(1);
|
|
11
11
|
const scoreBar = generateScoreBar(integrity.integrity_score);
|
|
12
|
-
console.log(fmt.header("
|
|
12
|
+
console.log(fmt.header("Agent Activity (AAP)"));
|
|
13
13
|
console.log(` ${fmt.label("Score: ", `${scorePercent}% ${scoreBar}`)}`);
|
|
14
14
|
console.log(` ${fmt.label("Total: ", `${integrity.total_traces} traces`)}`);
|
|
15
15
|
console.log(` ${fmt.label("Verified: ", `${integrity.verified_traces}`)}`);
|
|
@@ -30,7 +30,7 @@ export async function integrityCommand(agentName) {
|
|
|
30
30
|
// undocumented 404 to a synthetic 500 carrying spec_deviation.original_status,
|
|
31
31
|
// and effectiveStatus surfaces the true status (=== status when documented).
|
|
32
32
|
if (error instanceof MnemomApiError && error.effectiveStatus === 404) {
|
|
33
|
-
console.log(fmt.header("
|
|
33
|
+
console.log(fmt.header("Agent Activity (AAP)"));
|
|
34
34
|
console.log(` ${fmt.label("Score: ", "N/A")}`);
|
|
35
35
|
console.log(` ${fmt.label("Total: ", "0 traces")}`);
|
|
36
36
|
console.log(` ${fmt.label("Verified: ", "0")}`);
|
package/dist/commands/logs.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { resolveAgentId, getTraces, MnemomApiError } from "../lib/api.js";
|
|
2
|
-
import { getGatewayUrl } from "../lib/config.js";
|
|
1
|
+
import { resolveAgentId, getTraces, MnemomApiError, } from "../lib/api.js";
|
|
2
|
+
import { getGatewayUrl, getWebsiteUrl } from "../lib/config.js";
|
|
3
3
|
import { fmt } from "../lib/format.js";
|
|
4
4
|
export async function logsCommand(options = {}) {
|
|
5
5
|
const agentId = await resolveAgentId(options.agentName);
|
|
@@ -20,7 +20,7 @@ export async function logsCommand(options = {}) {
|
|
|
20
20
|
displayTrace(trace);
|
|
21
21
|
}
|
|
22
22
|
console.log(`\nView more: mnemom logs --limit ${limit + 10}`);
|
|
23
|
-
console.log(`Dashboard:
|
|
23
|
+
console.log(`Dashboard: ${getWebsiteUrl()}/agents/${agentId}\n`);
|
|
24
24
|
}
|
|
25
25
|
catch (error) {
|
|
26
26
|
// A 404 means the agent isn't registered yet — treat as the empty state.
|
|
@@ -60,9 +60,36 @@ function displayTrace(trace) {
|
|
|
60
60
|
console.log(` ${fmt.label("Reason:", ` ${preview}`)}`);
|
|
61
61
|
}
|
|
62
62
|
if (trace.verification && trace.verification.violations.length > 0) {
|
|
63
|
-
|
|
63
|
+
const issues = trace.verification.violations.map(formatViolation).join("; ");
|
|
64
|
+
console.log(` ${fmt.label("Issues:", ` ${issues}`)}`);
|
|
64
65
|
}
|
|
65
66
|
}
|
|
67
|
+
/**
|
|
68
|
+
* Render a single policy violation as a readable one-line string.
|
|
69
|
+
*
|
|
70
|
+
* The wire shape is an object ({type,tool,severity,reason} — canonical
|
|
71
|
+
* `PolicyViolation`); a naive `.join(", ")` string-coerces each to
|
|
72
|
+
* "[object Object]". We compose only the fields that are present, e.g.
|
|
73
|
+
* "[high] forbidden — write_file: tool not in capability set", and tolerate a
|
|
74
|
+
* bare-string element (legacy/forward compatibility) by returning it verbatim.
|
|
75
|
+
*/
|
|
76
|
+
function formatViolation(v) {
|
|
77
|
+
if (typeof v === "string")
|
|
78
|
+
return v;
|
|
79
|
+
let line = "";
|
|
80
|
+
if (v.severity)
|
|
81
|
+
line += `[${v.severity}] `;
|
|
82
|
+
if (v.type)
|
|
83
|
+
line += v.type;
|
|
84
|
+
if (v.tool)
|
|
85
|
+
line += `${v.type ? " — " : ""}${v.tool}`;
|
|
86
|
+
if (v.reason)
|
|
87
|
+
line += `${v.type || v.tool ? ": " : ""}${v.reason}`;
|
|
88
|
+
const out = line.trim();
|
|
89
|
+
// Fall back to a structured dump only if no known field was present, so we
|
|
90
|
+
// never silently emit an empty Issues entry or "[object Object]".
|
|
91
|
+
return out || JSON.stringify(v);
|
|
92
|
+
}
|
|
66
93
|
function formatTimestamp(iso) {
|
|
67
94
|
try {
|
|
68
95
|
const date = new Date(iso);
|
package/dist/commands/status.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { getGatewayUrl } from "../lib/config.js";
|
|
1
|
+
import { getGatewayUrl, getWebsiteUrl } from "../lib/config.js";
|
|
2
2
|
import { resolveAgentId, getAgent, getIntegrity, getTraces, MnemomApiError } from "../lib/api.js";
|
|
3
3
|
import { isLoggedIn, getAuthInfo } from "../lib/auth.js";
|
|
4
4
|
import { fmt } from "../lib/format.js";
|
|
5
|
-
const DASHBOARD_URL = "https://mnemom.ai";
|
|
6
5
|
export async function statusCommand(agentName) {
|
|
7
6
|
console.log(fmt.header("mnemom status"));
|
|
8
7
|
console.log();
|
|
@@ -31,7 +30,7 @@ export async function statusCommand(agentName) {
|
|
|
31
30
|
console.log();
|
|
32
31
|
console.log(fmt.label("Agent ID: ", agentId));
|
|
33
32
|
console.log(fmt.label("Gateway: ", gatewayUrl));
|
|
34
|
-
console.log(fmt.label("Dashboard:", ` ${
|
|
33
|
+
console.log(fmt.label("Dashboard:", ` ${getWebsiteUrl()}/agents/${agentId}`));
|
|
35
34
|
// Trace summary if API connectivity is healthy
|
|
36
35
|
if (apiCheck.status === "ok") {
|
|
37
36
|
await showTraceSummary(agentId);
|
package/dist/index.js
CHANGED
|
@@ -109,10 +109,11 @@ const cardCmd = program.command("card").description("Manage alignment card");
|
|
|
109
109
|
cardCmd
|
|
110
110
|
.command("show")
|
|
111
111
|
.description("Display alignment card (YAML)")
|
|
112
|
-
.
|
|
112
|
+
.option("--agent <name>", "Agent name or ID (or set MNEMOM_AGENT)")
|
|
113
|
+
.action(async (subOpts) => {
|
|
113
114
|
try {
|
|
114
115
|
const opts = program.opts();
|
|
115
|
-
await cardShowCommand(opts.agent);
|
|
116
|
+
await cardShowCommand(subOpts.agent ?? opts.agent);
|
|
116
117
|
}
|
|
117
118
|
catch (error) {
|
|
118
119
|
console.error("Error:", error instanceof Error ? error.message : error);
|
|
@@ -122,11 +123,14 @@ cardCmd
|
|
|
122
123
|
cardCmd
|
|
123
124
|
.command("edit")
|
|
124
125
|
.description("Edit alignment card in $EDITOR")
|
|
126
|
+
.option("--agent <name>", "Agent name or ID (or set MNEMOM_AGENT)")
|
|
125
127
|
.option("--idempotency-key <uuid>", "Reuse a specific Idempotency-Key (for retries; default: auto)")
|
|
126
128
|
.action(async (subOpts) => {
|
|
127
129
|
try {
|
|
128
130
|
const opts = program.opts();
|
|
129
|
-
await cardEditCommand(opts.agent, {
|
|
131
|
+
await cardEditCommand(subOpts.agent ?? opts.agent, {
|
|
132
|
+
idempotencyKey: subOpts.idempotencyKey,
|
|
133
|
+
});
|
|
130
134
|
}
|
|
131
135
|
catch (error) {
|
|
132
136
|
console.error("Error:", error instanceof Error ? error.message : error);
|
|
@@ -137,11 +141,14 @@ cardCmd
|
|
|
137
141
|
.command("publish")
|
|
138
142
|
.argument("<file>", "Path to alignment card file (YAML or JSON)")
|
|
139
143
|
.description("Publish alignment card")
|
|
144
|
+
.option("--agent <name>", "Agent name or ID (or set MNEMOM_AGENT)")
|
|
140
145
|
.option("--idempotency-key <uuid>", "Reuse a specific Idempotency-Key (for retries; default: auto)")
|
|
141
146
|
.action(async (file, subOpts) => {
|
|
142
147
|
try {
|
|
143
148
|
const opts = program.opts();
|
|
144
|
-
await cardPublishCommand(file, opts.agent, {
|
|
149
|
+
await cardPublishCommand(file, subOpts.agent ?? opts.agent, {
|
|
150
|
+
idempotencyKey: subOpts.idempotencyKey,
|
|
151
|
+
});
|
|
145
152
|
}
|
|
146
153
|
catch (error) {
|
|
147
154
|
console.error("Error:", error instanceof Error ? error.message : error);
|
|
@@ -531,6 +538,17 @@ advisoriesCmd
|
|
|
531
538
|
.option("--json", "Output JSON")
|
|
532
539
|
.action(async (options) => {
|
|
533
540
|
try {
|
|
541
|
+
// The program-level `--agent` shadows this subcommand's own `--agent`
|
|
542
|
+
// (Commander binds the shared long flag to the parent program, not the
|
|
543
|
+
// subcommand — verified against commander@12), so resolve the agent
|
|
544
|
+
// scope here from the explicit sources: the subcommand flag and the
|
|
545
|
+
// global `--agent`. Fall back to MNEMOM_AGENT only when `--team` is NOT
|
|
546
|
+
// set — a stray env var alongside an explicit `--team` must not inject
|
|
547
|
+
// an agent and spuriously trip the handler's mutual-exclusion guard,
|
|
548
|
+
// whereas an explicit `--agent` alongside `--team` should still trip
|
|
549
|
+
// it. (MNE-238)
|
|
550
|
+
const explicitAgent = options.agent ?? program.opts().agent;
|
|
551
|
+
options.agent = options.team ? explicitAgent : (explicitAgent ?? process.env.MNEMOM_AGENT);
|
|
534
552
|
await advisoriesListCommand(options);
|
|
535
553
|
}
|
|
536
554
|
catch (error) {
|
|
@@ -546,6 +564,11 @@ advisoriesCmd
|
|
|
546
564
|
.option("--json", "Output JSON")
|
|
547
565
|
.action(async (advisoryId, options) => {
|
|
548
566
|
try {
|
|
567
|
+
// Same global `--agent` shadow fix as `advisories list` (MNE-238):
|
|
568
|
+
// resolve the explicit agent (local ?? global), and fall back to
|
|
569
|
+
// MNEMOM_AGENT only when `--team` is not set.
|
|
570
|
+
const explicitAgent = options.agent ?? program.opts().agent;
|
|
571
|
+
options.agent = options.team ? explicitAgent : (explicitAgent ?? process.env.MNEMOM_AGENT);
|
|
549
572
|
await advisoriesShowCommand(advisoryId, options);
|
|
550
573
|
}
|
|
551
574
|
catch (error) {
|
package/dist/lib/api.d.ts
CHANGED
|
@@ -72,7 +72,19 @@ export interface IntegrityScore {
|
|
|
72
72
|
* reasoning, tool_name } — none of which the wire emits. `mnemom logs` rendered
|
|
73
73
|
* every action as "[object Object]" and flagged EVERY trace as [VIOLATION]
|
|
74
74
|
* (undefined `verified` is falsy). Field names + nesting now match the wire.
|
|
75
|
+
*
|
|
76
|
+
* `verification.violations` elements are OBJECTS ({type,tool,severity,reason}),
|
|
77
|
+
* not strings — produced by the observer/gateway mappers (canonical
|
|
78
|
+
* `PolicyViolation` in shared/policy-engine). A prior pass corrected `action`'s
|
|
79
|
+
* nesting but left `violations` mistyped, which re-introduced "[object Object]"
|
|
80
|
+
* on the Issues line. All fields are optional here for forward/backward tolerance.
|
|
75
81
|
*/
|
|
82
|
+
export interface TraceViolation {
|
|
83
|
+
type?: string;
|
|
84
|
+
tool?: string;
|
|
85
|
+
severity?: string;
|
|
86
|
+
reason?: string;
|
|
87
|
+
}
|
|
76
88
|
export interface Trace {
|
|
77
89
|
trace_id: string;
|
|
78
90
|
agent_id: string;
|
|
@@ -90,7 +102,7 @@ export interface Trace {
|
|
|
90
102
|
};
|
|
91
103
|
verification: {
|
|
92
104
|
verified: boolean;
|
|
93
|
-
violations:
|
|
105
|
+
violations: TraceViolation[];
|
|
94
106
|
} | null;
|
|
95
107
|
created_at?: string;
|
|
96
108
|
}
|
|
@@ -208,11 +220,11 @@ export interface AgentListItem {
|
|
|
208
220
|
key_prefix?: string | null;
|
|
209
221
|
}
|
|
210
222
|
/**
|
|
211
|
-
*
|
|
212
|
-
*
|
|
213
|
-
*
|
|
214
|
-
*
|
|
215
|
-
*
|
|
223
|
+
* Key-compatible agent listing — `GET /v1/agents` is scoped by the caller's
|
|
224
|
+
* `claimed_by` rows (the pre-ADR-062 boundary). JWT callers should prefer
|
|
225
|
+
* {@link listOrgAgents} (org-scoped, the ADR-062 canonical boundary).
|
|
226
|
+
* API-key callers use this path because the org-scoped route rejects API keys;
|
|
227
|
+
* routing here avoids the false "Not authenticated" error (MNE-194 F10).
|
|
216
228
|
*/
|
|
217
229
|
export declare function listAgents(): Promise<AgentListItem[]>;
|
|
218
230
|
export interface OrgListItem {
|
package/dist/lib/api.js
CHANGED
|
@@ -206,11 +206,11 @@ export async function getAgent(id) {
|
|
|
206
206
|
return fetchApi(`/v1/agents/${id}`);
|
|
207
207
|
}
|
|
208
208
|
/**
|
|
209
|
-
*
|
|
210
|
-
*
|
|
211
|
-
*
|
|
212
|
-
*
|
|
213
|
-
*
|
|
209
|
+
* Key-compatible agent listing — `GET /v1/agents` is scoped by the caller's
|
|
210
|
+
* `claimed_by` rows (the pre-ADR-062 boundary). JWT callers should prefer
|
|
211
|
+
* {@link listOrgAgents} (org-scoped, the ADR-062 canonical boundary).
|
|
212
|
+
* API-key callers use this path because the org-scoped route rejects API keys;
|
|
213
|
+
* routing here avoids the false "Not authenticated" error (MNE-194 F10).
|
|
214
214
|
*/
|
|
215
215
|
export async function listAgents() {
|
|
216
216
|
const url = validateUrl(`${API_BASE}/v1/agents?limit=100`);
|