@moda-ai/cli 1.9.6 → 1.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/agent-schemas.d.ts +3 -0
- package/dist/agent-schemas.js +298 -0
- package/dist/api-client.d.ts +12 -1
- package/dist/api-client.js +10 -8
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +68 -9
- package/dist/command-context.d.ts +6 -0
- package/dist/command-context.js +1 -1
- package/dist/intelligence-schema.d.ts +349 -0
- package/dist/intelligence-schema.js +174 -0
- package/dist/output.d.ts +25 -2
- package/dist/output.js +71 -2
- package/dist/production-intelligence.d.ts +19 -0
- package/dist/production-intelligence.js +358 -17
- package/dist/schemas.d.ts +22 -2
- package/dist/schemas.js +10 -0
- package/package.json +1 -1
- package/skills/moda-cli/SKILL.md +148 -0
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
// agent-schemas.ts
|
|
2
|
+
//
|
|
3
|
+
// Machine-readable JSON Schemas (JSON Schema draft-07) for the moda CLI's
|
|
4
|
+
// agent output contract. It is consumed by `moda --json-schemas`, which prints
|
|
5
|
+
// the document produced by `renderJsonSchemas()` so an external coding agent can
|
|
6
|
+
// introspect the exact shape of moda's agent-mode output.
|
|
7
|
+
//
|
|
8
|
+
// The canonical `moda.intelligence.v1` schema is imported from its
|
|
9
|
+
// single-source-of-truth module rather than re-declared here, so the published
|
|
10
|
+
// contract can never drift from the runtime payload.
|
|
11
|
+
//
|
|
12
|
+
// Keep these schemas in sync with:
|
|
13
|
+
// - AgentEnvelope / AgentEvent in ./output.ts (moda.agent.v1 / moda.agent_event.v1)
|
|
14
|
+
// - ProductionAskResult in ./production-intelligence.ts (production_ask.v0.1)
|
|
15
|
+
// - ModaIntelligenceV1 in ./intelligence-schema.ts (moda.intelligence.v1)
|
|
16
|
+
import { MODA_INTELLIGENCE_V1_JSON_SCHEMA } from './intelligence-schema.js';
|
|
17
|
+
const agentSummarySchema = {
|
|
18
|
+
type: 'object',
|
|
19
|
+
additionalProperties: false,
|
|
20
|
+
required: ['text', 'confidence'],
|
|
21
|
+
properties: {
|
|
22
|
+
text: { type: 'string' },
|
|
23
|
+
confidence: { type: 'string', enum: ['high', 'medium', 'low', 'unknown'] },
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
const agentFindingSchema = {
|
|
27
|
+
type: 'object',
|
|
28
|
+
additionalProperties: false,
|
|
29
|
+
required: ['id', 'title'],
|
|
30
|
+
properties: {
|
|
31
|
+
id: { type: 'string' },
|
|
32
|
+
title: { type: 'string' },
|
|
33
|
+
status: { type: 'string' },
|
|
34
|
+
severity: { type: 'string' },
|
|
35
|
+
description: { type: 'string' },
|
|
36
|
+
evidence_ref_ids: { type: 'array', items: { type: 'string' } },
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
const agentEvidenceRefSchema = {
|
|
40
|
+
type: 'object',
|
|
41
|
+
additionalProperties: false,
|
|
42
|
+
required: ['id', 'kind', 'label'],
|
|
43
|
+
properties: {
|
|
44
|
+
id: { type: 'string' },
|
|
45
|
+
kind: { type: 'string' },
|
|
46
|
+
label: { type: 'string' },
|
|
47
|
+
path: { type: 'string' },
|
|
48
|
+
line: { type: 'number' },
|
|
49
|
+
status: { type: 'string' },
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
const agentRecommendedActionSchema = {
|
|
53
|
+
type: 'object',
|
|
54
|
+
additionalProperties: false,
|
|
55
|
+
required: ['id', 'title', 'mutability', 'requires_approval'],
|
|
56
|
+
properties: {
|
|
57
|
+
id: { type: 'string' },
|
|
58
|
+
title: { type: 'string' },
|
|
59
|
+
rationale: { type: 'string' },
|
|
60
|
+
command: { type: 'string' },
|
|
61
|
+
mutability: { type: 'string', enum: ['read', 'write', 'sync', 'unknown'] },
|
|
62
|
+
requires_approval: { type: 'boolean' },
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
const agentNextCommandSchema = {
|
|
66
|
+
type: 'object',
|
|
67
|
+
additionalProperties: false,
|
|
68
|
+
required: ['command', 'purpose', 'mutability', 'requires_approval'],
|
|
69
|
+
properties: {
|
|
70
|
+
command: { type: 'string' },
|
|
71
|
+
purpose: { type: 'string' },
|
|
72
|
+
mutability: { type: 'string', enum: ['read', 'write', 'sync', 'unknown'] },
|
|
73
|
+
requires_approval: { type: 'boolean' },
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
const agentArtifactSchema = {
|
|
77
|
+
type: 'object',
|
|
78
|
+
additionalProperties: false,
|
|
79
|
+
required: ['kind', 'path'],
|
|
80
|
+
properties: {
|
|
81
|
+
kind: { type: 'string' },
|
|
82
|
+
path: { type: 'string' },
|
|
83
|
+
description: { type: 'string' },
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
const agentErrorSchema = {
|
|
87
|
+
type: 'object',
|
|
88
|
+
additionalProperties: false,
|
|
89
|
+
required: ['code', 'message', 'blocking'],
|
|
90
|
+
properties: {
|
|
91
|
+
code: { type: 'string' },
|
|
92
|
+
message: { type: 'string' },
|
|
93
|
+
cause: { type: 'string' },
|
|
94
|
+
suggested_commands: { type: 'array', items: { type: 'string' } },
|
|
95
|
+
blocking: { type: 'boolean' },
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
const agentEnvelopeSchema = {
|
|
99
|
+
$id: 'moda.agent.v1',
|
|
100
|
+
title: 'AgentEnvelope',
|
|
101
|
+
description: 'Top-level agent-mode output envelope emitted by the moda CLI.',
|
|
102
|
+
type: 'object',
|
|
103
|
+
additionalProperties: false,
|
|
104
|
+
required: [
|
|
105
|
+
'schema_version',
|
|
106
|
+
'command',
|
|
107
|
+
'status',
|
|
108
|
+
'generated_at',
|
|
109
|
+
'summary',
|
|
110
|
+
'findings',
|
|
111
|
+
'evidence_refs',
|
|
112
|
+
'recommended_actions',
|
|
113
|
+
'next_commands',
|
|
114
|
+
'artifacts',
|
|
115
|
+
'warnings',
|
|
116
|
+
'errors',
|
|
117
|
+
'data',
|
|
118
|
+
],
|
|
119
|
+
properties: {
|
|
120
|
+
schema_version: { type: 'string', const: 'moda.agent.v1' },
|
|
121
|
+
command: { type: 'string' },
|
|
122
|
+
status: { type: 'string', enum: ['ok', 'degraded', 'error'] },
|
|
123
|
+
generated_at: { type: 'string', format: 'date-time' },
|
|
124
|
+
profile: { type: 'string' },
|
|
125
|
+
summary: agentSummarySchema,
|
|
126
|
+
findings: { type: 'array', items: agentFindingSchema },
|
|
127
|
+
evidence_refs: { type: 'array', items: agentEvidenceRefSchema },
|
|
128
|
+
recommended_actions: { type: 'array', items: agentRecommendedActionSchema },
|
|
129
|
+
next_commands: { type: 'array', items: agentNextCommandSchema },
|
|
130
|
+
artifacts: { type: 'array', items: agentArtifactSchema },
|
|
131
|
+
warnings: { type: 'array', items: { type: 'string' } },
|
|
132
|
+
errors: { type: 'array', items: agentErrorSchema },
|
|
133
|
+
data: { description: 'Command-specific payload. Shape varies by command.', additionalProperties: true },
|
|
134
|
+
meta: { type: 'object', additionalProperties: true },
|
|
135
|
+
truncation: { type: 'object', additionalProperties: true },
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
const agentEventSchema = {
|
|
139
|
+
$id: 'moda.agent_event.v1',
|
|
140
|
+
title: 'AgentEvent',
|
|
141
|
+
description: 'Streaming NDJSON event emitted in agent-stream mode by the moda CLI.',
|
|
142
|
+
type: 'object',
|
|
143
|
+
additionalProperties: false,
|
|
144
|
+
required: ['schema_version', 'event', 'command', 'generated_at'],
|
|
145
|
+
properties: {
|
|
146
|
+
schema_version: { type: 'string', const: 'moda.agent_event.v1' },
|
|
147
|
+
event: {
|
|
148
|
+
type: 'string',
|
|
149
|
+
enum: ['started', 'progress', 'artifact', 'approval_required', 'completed', 'error'],
|
|
150
|
+
},
|
|
151
|
+
command: { type: 'string' },
|
|
152
|
+
generated_at: { type: 'string', format: 'date-time' },
|
|
153
|
+
status: { type: 'string', enum: ['ok', 'degraded', 'error'] },
|
|
154
|
+
phase: { type: 'string' },
|
|
155
|
+
message: { type: 'string' },
|
|
156
|
+
elapsed_ms: { type: 'number' },
|
|
157
|
+
artifact: agentArtifactSchema,
|
|
158
|
+
result: agentEnvelopeSchema,
|
|
159
|
+
error: agentErrorSchema,
|
|
160
|
+
},
|
|
161
|
+
};
|
|
162
|
+
const productionEvidenceRefSchema = {
|
|
163
|
+
type: 'object',
|
|
164
|
+
additionalProperties: false,
|
|
165
|
+
required: ['id', 'kind', 'label'],
|
|
166
|
+
properties: {
|
|
167
|
+
id: { type: 'string' },
|
|
168
|
+
kind: {
|
|
169
|
+
type: 'string',
|
|
170
|
+
enum: ['data_api', 'tool_failure', 'frustration', 'loop', 'run', 'harness', 'ask'],
|
|
171
|
+
},
|
|
172
|
+
label: { type: 'string' },
|
|
173
|
+
endpoint: { type: 'string' },
|
|
174
|
+
conversationId: { type: 'string' },
|
|
175
|
+
runId: { type: 'string' },
|
|
176
|
+
detectionId: { type: 'string' },
|
|
177
|
+
toolName: { type: 'string' },
|
|
178
|
+
path: { type: 'string' },
|
|
179
|
+
line: { type: 'number' },
|
|
180
|
+
value: { description: 'Arbitrary evidence payload.', additionalProperties: true },
|
|
181
|
+
},
|
|
182
|
+
};
|
|
183
|
+
const likelyLocationSchema = {
|
|
184
|
+
type: 'object',
|
|
185
|
+
additionalProperties: false,
|
|
186
|
+
required: ['kind', 'label', 'confidence', 'reason'],
|
|
187
|
+
properties: {
|
|
188
|
+
kind: { type: 'string', enum: ['tool', 'prompt', 'skill', 'entrypoint', 'harness', 'unknown'] },
|
|
189
|
+
path: { type: 'string' },
|
|
190
|
+
label: { type: 'string' },
|
|
191
|
+
confidence: { type: 'string', enum: ['high', 'medium', 'low', 'unknown'] },
|
|
192
|
+
reason: { type: 'string' },
|
|
193
|
+
},
|
|
194
|
+
};
|
|
195
|
+
const productionActionSchema = {
|
|
196
|
+
type: 'object',
|
|
197
|
+
additionalProperties: false,
|
|
198
|
+
required: ['id', 'title', 'rationale', 'command', 'mutability', 'requiresApproval'],
|
|
199
|
+
properties: {
|
|
200
|
+
id: { type: 'string' },
|
|
201
|
+
title: { type: 'string' },
|
|
202
|
+
rationale: { type: 'string' },
|
|
203
|
+
command: { type: 'string' },
|
|
204
|
+
mutability: { type: 'string', enum: ['read', 'write', 'sync', 'unknown'] },
|
|
205
|
+
requiresApproval: { type: 'boolean' },
|
|
206
|
+
},
|
|
207
|
+
};
|
|
208
|
+
const productionFindingSchema = {
|
|
209
|
+
type: 'object',
|
|
210
|
+
additionalProperties: false,
|
|
211
|
+
required: [
|
|
212
|
+
'id',
|
|
213
|
+
'kind',
|
|
214
|
+
'title',
|
|
215
|
+
'severity',
|
|
216
|
+
'confidence',
|
|
217
|
+
'impactScore',
|
|
218
|
+
'rankReason',
|
|
219
|
+
'summary',
|
|
220
|
+
'evidenceRefIds',
|
|
221
|
+
'likelyLocations',
|
|
222
|
+
'recommendedActions',
|
|
223
|
+
],
|
|
224
|
+
properties: {
|
|
225
|
+
id: { type: 'string' },
|
|
226
|
+
kind: {
|
|
227
|
+
type: 'string',
|
|
228
|
+
enum: [
|
|
229
|
+
'tool_failure',
|
|
230
|
+
'loop',
|
|
231
|
+
'frustration',
|
|
232
|
+
'partial_run',
|
|
233
|
+
'prompt_regression',
|
|
234
|
+
'skill_gap',
|
|
235
|
+
'insufficient_data',
|
|
236
|
+
],
|
|
237
|
+
},
|
|
238
|
+
title: { type: 'string' },
|
|
239
|
+
severity: { type: 'string', enum: ['critical', 'high', 'medium', 'low', 'info'] },
|
|
240
|
+
confidence: { type: 'string', enum: ['high', 'medium', 'low', 'unknown'] },
|
|
241
|
+
impactScore: { type: 'number' },
|
|
242
|
+
rankReason: { type: 'string' },
|
|
243
|
+
summary: { type: 'string' },
|
|
244
|
+
evidenceRefIds: { type: 'array', items: { type: 'string' } },
|
|
245
|
+
likelyLocations: { type: 'array', items: likelyLocationSchema },
|
|
246
|
+
recommendedActions: { type: 'array', items: productionActionSchema },
|
|
247
|
+
},
|
|
248
|
+
};
|
|
249
|
+
const productionAskResultSchema = {
|
|
250
|
+
$id: 'production_ask.v0.1',
|
|
251
|
+
title: 'ProductionAskResult',
|
|
252
|
+
description: 'Result payload for `moda ask`, sourced from cloud intelligence or local fallback.',
|
|
253
|
+
type: 'object',
|
|
254
|
+
additionalProperties: false,
|
|
255
|
+
required: [
|
|
256
|
+
'schemaVersion',
|
|
257
|
+
'generatedAt',
|
|
258
|
+
'source',
|
|
259
|
+
'question',
|
|
260
|
+
'answer',
|
|
261
|
+
'confidence',
|
|
262
|
+
'evidenceRefs',
|
|
263
|
+
'findings',
|
|
264
|
+
'nextCommands',
|
|
265
|
+
'warnings',
|
|
266
|
+
'degraded',
|
|
267
|
+
],
|
|
268
|
+
properties: {
|
|
269
|
+
schemaVersion: { type: 'string', const: 'production_ask.v0.1' },
|
|
270
|
+
generatedAt: { type: 'string', format: 'date-time' },
|
|
271
|
+
source: { type: 'string', enum: ['cloud', 'local_fallback'] },
|
|
272
|
+
question: { type: 'string' },
|
|
273
|
+
answer: { type: 'string' },
|
|
274
|
+
confidence: { type: 'string', enum: ['high', 'medium', 'low', 'unknown'] },
|
|
275
|
+
evidenceRefs: { type: 'array', items: productionEvidenceRefSchema },
|
|
276
|
+
findings: { type: 'array', items: productionFindingSchema },
|
|
277
|
+
nextCommands: { type: 'array', items: { type: 'string' } },
|
|
278
|
+
warnings: { type: 'array', items: { type: 'string' } },
|
|
279
|
+
degraded: { type: 'boolean' },
|
|
280
|
+
},
|
|
281
|
+
};
|
|
282
|
+
export const AGENT_JSON_SCHEMAS = {
|
|
283
|
+
'moda.agent.v1': agentEnvelopeSchema,
|
|
284
|
+
'moda.agent_event.v1': agentEventSchema,
|
|
285
|
+
// Canonical unified payload (MODA-388). Now the shape of the ask command's
|
|
286
|
+
// agent `data`. The legacy `production_ask.v0.1` schema is kept for
|
|
287
|
+
// back-compat with older agent integrations.
|
|
288
|
+
'moda.intelligence.v1': MODA_INTELLIGENCE_V1_JSON_SCHEMA,
|
|
289
|
+
'production_ask.v0.1': productionAskResultSchema,
|
|
290
|
+
};
|
|
291
|
+
export function renderJsonSchemas() {
|
|
292
|
+
return JSON.stringify({
|
|
293
|
+
$schema: 'http://json-schema.org/draft-07/schema#',
|
|
294
|
+
generated_by: 'moda-cli',
|
|
295
|
+
schemas: AGENT_JSON_SCHEMAS,
|
|
296
|
+
}, null, 2);
|
|
297
|
+
}
|
|
298
|
+
//# sourceMappingURL=agent-schemas.js.map
|
package/dist/api-client.d.ts
CHANGED
|
@@ -5,7 +5,18 @@ export declare class ApiError extends Error {
|
|
|
5
5
|
constructor(message: string, statusCode: number, responseBody: string);
|
|
6
6
|
}
|
|
7
7
|
export declare function callDataAPI(endpoint: string): Promise<unknown>;
|
|
8
|
-
|
|
8
|
+
/**
|
|
9
|
+
* Per-call transport overrides. Used by expensive, long-running, non-idempotent
|
|
10
|
+
* endpoints (e.g. the agent `ask` POST) that need a longer timeout than the
|
|
11
|
+
* default and must NOT be retried on timeout.
|
|
12
|
+
*/
|
|
13
|
+
export interface ModaRequestOptions {
|
|
14
|
+
/** Abort timeout in ms for each attempt (default REQUEST_TIMEOUT_MS). */
|
|
15
|
+
timeoutMs?: number;
|
|
16
|
+
/** Max retries (default MAX_RETRIES). Set 0 to disable retries entirely. */
|
|
17
|
+
retries?: number;
|
|
18
|
+
}
|
|
19
|
+
export declare function callControlAPI(endpoint: string, options?: RequestInit, profileOptions?: ProfileIOOptions, requestOptions?: ModaRequestOptions): Promise<unknown>;
|
|
9
20
|
export declare function getApiRequestCount(): number;
|
|
10
21
|
export declare function resetApiRequestCount(): void;
|
|
11
22
|
//# sourceMappingURL=api-client.d.ts.map
|
package/dist/api-client.js
CHANGED
|
@@ -22,19 +22,21 @@ export async function callDataAPI(endpoint) {
|
|
|
22
22
|
const url = `${resolveModaBaseUrl()}/api/v1/data${endpoint}`;
|
|
23
23
|
return callModaAPI(url, { method: 'GET' });
|
|
24
24
|
}
|
|
25
|
-
export async function callControlAPI(endpoint, options = {}, profileOptions = {}) {
|
|
25
|
+
export async function callControlAPI(endpoint, options = {}, profileOptions = {}, requestOptions = {}) {
|
|
26
26
|
const url = `${resolveModaBaseUrl(profileOptions)}/api${endpoint}`;
|
|
27
|
-
return callModaAPI(url, options, profileOptions);
|
|
27
|
+
return callModaAPI(url, options, profileOptions, requestOptions);
|
|
28
28
|
}
|
|
29
|
-
async function callModaAPI(url, options, profileOptions = {}) {
|
|
29
|
+
async function callModaAPI(url, options, profileOptions = {}, requestOptions = {}) {
|
|
30
|
+
const timeoutMs = requestOptions.timeoutMs ?? REQUEST_TIMEOUT_MS;
|
|
31
|
+
const maxRetries = requestOptions.retries ?? MAX_RETRIES;
|
|
30
32
|
let lastError;
|
|
31
|
-
for (let attempt = 0; attempt <=
|
|
33
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
32
34
|
if (attempt > 0) {
|
|
33
35
|
const backoff = INITIAL_BACKOFF_MS * Math.pow(2, attempt - 1);
|
|
34
36
|
await new Promise((resolve) => setTimeout(resolve, backoff));
|
|
35
37
|
}
|
|
36
38
|
const controller = new AbortController();
|
|
37
|
-
const timeout = setTimeout(() => controller.abort(),
|
|
39
|
+
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
38
40
|
try {
|
|
39
41
|
const response = await fetch(url, {
|
|
40
42
|
...options,
|
|
@@ -48,7 +50,7 @@ async function callModaAPI(url, options, profileOptions = {}) {
|
|
|
48
50
|
if (!response.ok) {
|
|
49
51
|
const errorText = await response.text();
|
|
50
52
|
const error = new ApiError(`API error (${response.status}): ${errorText}`, response.status, errorText);
|
|
51
|
-
if (isRetryable(response.status) && attempt <
|
|
53
|
+
if (isRetryable(response.status) && attempt < maxRetries) {
|
|
52
54
|
lastError = error;
|
|
53
55
|
continue;
|
|
54
56
|
}
|
|
@@ -61,9 +63,9 @@ async function callModaAPI(url, options, profileOptions = {}) {
|
|
|
61
63
|
throw error;
|
|
62
64
|
const isAbort = error instanceof DOMException && error.name === 'AbortError';
|
|
63
65
|
const wrapped = new Error(isAbort
|
|
64
|
-
? `Request timed out after ${
|
|
66
|
+
? `Request timed out after ${timeoutMs}ms: ${url}`
|
|
65
67
|
: `Network error: ${error instanceof Error ? error.message : String(error)}`);
|
|
66
|
-
if (attempt <
|
|
68
|
+
if (attempt < maxRetries) {
|
|
67
69
|
lastError = wrapped;
|
|
68
70
|
continue;
|
|
69
71
|
}
|
package/dist/cli.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ export interface ParsedArgs {
|
|
|
11
11
|
}
|
|
12
12
|
export declare function parseArgs(argv: string[]): ParsedArgs;
|
|
13
13
|
export declare function flagsToArgs(flags: Record<string, string>, positionalKey?: string, positionalValue?: string): Record<string, unknown>;
|
|
14
|
-
export declare function runCommand(command: string, positional: string | undefined, flags: Record<string, string>, positionals?: string[], context?: CommandContext): Promise<
|
|
14
|
+
export declare function runCommand(command: string, positional: string | undefined, flags: Record<string, string>, positionals?: string[], context?: CommandContext): Promise<number>;
|
|
15
15
|
interface CommandDispatchResult {
|
|
16
16
|
exitCode: number;
|
|
17
17
|
apiKey?: string;
|
package/dist/cli.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import { validateConfig, VERSION, resolveApiKey } from './config.js';
|
|
4
4
|
import { callDataAPI, ApiError, getApiRequestCount, resetApiRequestCount, } from './api-client.js';
|
|
5
|
-
import { OverviewSchema, ClustersSchema, ClusterConversationsSchema, ConversationsSchema, SearchSchema, WorldStateSchema, ContextSchema, FrustrationsSchema, ToolFailuresSchema, ToolFailureDetailSchema, WorkflowsSchema, RunsSchema, RunDetailSchema, LoopsSchema, LoopDetailSchema, } from './schemas.js';
|
|
5
|
+
import { OverviewSchema, ClustersSchema, ClusterConversationsSchema, ConversationsSchema, SearchSchema, WorldStateSchema, ContextSchema, AuditSchema, FrustrationsSchema, ToolFailuresSchema, ToolFailureDetailSchema, WorkflowsSchema, RunsSchema, RunDetailSchema, LoopsSchema, LoopDetailSchema, } from './schemas.js';
|
|
6
6
|
import { withFrustrationAnchors, withToolFailureAnchors, embeddedWindowSize, asRecord, asString, asNumber } from './transforms.js';
|
|
7
7
|
import { runPromptsCommand } from './prompts.js';
|
|
8
8
|
// Coding-agent capture (shadow workspace / Shadow Spark / trace hooks) is temporarily
|
|
@@ -17,7 +17,8 @@ import { buildSearchAdoptionTelemetry, isTelemetryDisabled, SEARCH_MODES, sendCl
|
|
|
17
17
|
import { isUpdateCheckDisabled, printUpdateNotice, startUpdateCheck, stripUpdateCheckFlag, } from './update-check.js';
|
|
18
18
|
import { createCommandContext } from './command-context.js';
|
|
19
19
|
import { createCommandRegistry } from './command-registry.js';
|
|
20
|
-
import { createAgentErrorEnvelope, errorToAgentError,
|
|
20
|
+
import { createAgentErrorEnvelope, errorToAgentError, resolveOutputMode, } from './output.js';
|
|
21
|
+
import { renderJsonSchemas } from './agent-schemas.js';
|
|
21
22
|
import { runAuthCommand, runConfigCommand, runKeysCommand, runProfilesCommand } from './profile-commands.js';
|
|
22
23
|
import { runAgentCommand } from './agent.js';
|
|
23
24
|
import { runProductionCommand } from './production-intelligence.js';
|
|
@@ -51,6 +52,9 @@ export function parseArgs(argv) {
|
|
|
51
52
|
const GLOBAL_BOOLEAN_FLAGS = new Set([
|
|
52
53
|
'agent',
|
|
53
54
|
'json',
|
|
55
|
+
'human',
|
|
56
|
+
'prose',
|
|
57
|
+
'json-schemas',
|
|
54
58
|
'help',
|
|
55
59
|
'version',
|
|
56
60
|
'quiet',
|
|
@@ -140,6 +144,7 @@ Commands:
|
|
|
140
144
|
search "<query>" Search conversation messages (keyword/semantic/hybrid)
|
|
141
145
|
world-state <conversation_id> Get a conversation's world state (slots/threads/events)
|
|
142
146
|
context <conversation_id> Get windowed conversation context
|
|
147
|
+
audit <conversation_id|trace_id> Raw span/trace audit (spans, hierarchy, orphans, duplicates)
|
|
143
148
|
frustrations Get user frustration detections
|
|
144
149
|
tool-failures Get tool failure overview
|
|
145
150
|
tool-failure-detail <tool_name> Get per-tool failure detail
|
|
@@ -169,6 +174,7 @@ Commands:
|
|
|
169
174
|
Options:
|
|
170
175
|
--help Show this help message
|
|
171
176
|
--version Show version number
|
|
177
|
+
--json-schemas Print JSON Schemas for the agent output contract
|
|
172
178
|
|
|
173
179
|
Common flags:
|
|
174
180
|
--days-back=N Number of days to look back (1-90)
|
|
@@ -179,6 +185,13 @@ Common flags:
|
|
|
179
185
|
--json Emit machine-readable JSON
|
|
180
186
|
--agent Emit schema-versioned agent JSON
|
|
181
187
|
--stream With --agent, emit NDJSON agent events
|
|
188
|
+
--human Force human prose (overrides auto-detection)
|
|
189
|
+
|
|
190
|
+
Output auto-detection (no flags needed):
|
|
191
|
+
Piped/redirected stdout, CI, or an agent env (CLAUDECODE/CURSOR/MODA_AGENT)
|
|
192
|
+
=> schema-versioned agent JSON. An interactive terminal => human prose.
|
|
193
|
+
Override with the flags above or MODA_FORMAT=human|json|agent|agent-stream.
|
|
194
|
+
Exit codes: 0 ok, 3 degraded (local fallback), 1 error.
|
|
182
195
|
--dry-run Show the planned mutation when supported
|
|
183
196
|
--yes Accept explicit automation defaults
|
|
184
197
|
--tui Force the human analyst dashboard when supported
|
|
@@ -261,6 +274,8 @@ Examples:
|
|
|
261
274
|
moda world-state <conversation_id> --summary-only
|
|
262
275
|
moda frustrations --days-back=14 --limit=20
|
|
263
276
|
moda context <conversation_id> --window=3
|
|
277
|
+
moda audit <conversation_id|trace_id>
|
|
278
|
+
moda audit <trace_id> --kind=trace --json
|
|
264
279
|
moda workflows --time-range=7d
|
|
265
280
|
moda runs --time-range=24h --outcome=partial
|
|
266
281
|
moda runs --class-id=cron:helpscout-triage-hourly --limit=20
|
|
@@ -386,15 +401,13 @@ export async function runCommand(command, positional, flags, positionals = posit
|
|
|
386
401
|
case 'overview': {
|
|
387
402
|
const args = flagsToArgs(flags);
|
|
388
403
|
OverviewSchema.parse(args);
|
|
389
|
-
await runProductionCommand(context);
|
|
390
|
-
break;
|
|
404
|
+
return (await runProductionCommand(context)).exitCode;
|
|
391
405
|
}
|
|
392
406
|
case 'investigate':
|
|
393
407
|
case 'failures':
|
|
394
408
|
case 'why-failed':
|
|
395
409
|
case 'ask': {
|
|
396
|
-
await runProductionCommand(context);
|
|
397
|
-
break;
|
|
410
|
+
return (await runProductionCommand(context)).exitCode;
|
|
398
411
|
}
|
|
399
412
|
case 'clusters': {
|
|
400
413
|
const args = flagsToArgs(flags);
|
|
@@ -519,6 +532,25 @@ export async function runCommand(command, positional, flags, positionals = posit
|
|
|
519
532
|
context.output.writeData(data);
|
|
520
533
|
break;
|
|
521
534
|
}
|
|
535
|
+
case 'audit':
|
|
536
|
+
case 'trace': {
|
|
537
|
+
if (!positional) {
|
|
538
|
+
throw new CliInputError('<conversation_id|trace_id> is required', 'Usage: moda audit <conversation_id|trace_id> [--kind=auto|trace|conversation] [--include-raw] [--limit=N]');
|
|
539
|
+
}
|
|
540
|
+
const args = flagsToArgs(flags, 'id', positional);
|
|
541
|
+
const params = AuditSchema.parse(args);
|
|
542
|
+
const query = new URLSearchParams();
|
|
543
|
+
if (params.kind && params.kind !== 'auto')
|
|
544
|
+
query.set('kind', params.kind);
|
|
545
|
+
if (params.include_raw === true)
|
|
546
|
+
query.set('include_raw', '1');
|
|
547
|
+
if (params.limit)
|
|
548
|
+
query.set('limit', params.limit.toString());
|
|
549
|
+
const queryString = query.toString() ? `?${query.toString()}` : '';
|
|
550
|
+
const data = await callDataAPI(`/audit/${encodeURIComponent(params.id)}${queryString}`);
|
|
551
|
+
context.output.writeData(data);
|
|
552
|
+
break;
|
|
553
|
+
}
|
|
522
554
|
case 'frustrations': {
|
|
523
555
|
const args = flagsToArgs(flags);
|
|
524
556
|
const params = FrustrationsSchema.parse(args);
|
|
@@ -631,13 +663,14 @@ export async function runCommand(command, positional, flags, positionals = posit
|
|
|
631
663
|
default:
|
|
632
664
|
throw new CliInputError(`Unknown command '${command}'`, 'Run "moda --help" for usage information.');
|
|
633
665
|
}
|
|
666
|
+
return 0;
|
|
634
667
|
}
|
|
635
668
|
function legacyCommand(metadata) {
|
|
636
669
|
return {
|
|
637
670
|
...metadata,
|
|
638
671
|
handler: async (context) => {
|
|
639
|
-
await runCommand(context.command, context.positional, context.flags, context.positionals, context);
|
|
640
|
-
return { exitCode
|
|
672
|
+
const exitCode = await runCommand(context.command, context.positional, context.flags, context.positionals, context);
|
|
673
|
+
return { exitCode };
|
|
641
674
|
},
|
|
642
675
|
};
|
|
643
676
|
}
|
|
@@ -952,6 +985,17 @@ export const commandRegistry = createCommandRegistry([
|
|
|
952
985
|
examples: ['moda context <conversation_id> --window=3'],
|
|
953
986
|
...dataApiDefaults,
|
|
954
987
|
}),
|
|
988
|
+
legacyCommand({
|
|
989
|
+
name: 'audit',
|
|
990
|
+
aliases: ['trace'],
|
|
991
|
+
description: 'Raw non-deduped span/trace audit (hierarchy, tool spans, orphans, duplicates)',
|
|
992
|
+
examples: [
|
|
993
|
+
'moda audit <conversation_id|trace_id>',
|
|
994
|
+
'moda audit <trace_id> --kind=trace --json',
|
|
995
|
+
'moda audit <conversation_id> --include-raw',
|
|
996
|
+
],
|
|
997
|
+
...dataApiDefaults,
|
|
998
|
+
}),
|
|
955
999
|
legacyCommand({
|
|
956
1000
|
name: 'frustrations',
|
|
957
1001
|
description: 'Get user frustration detections',
|
|
@@ -1139,6 +1183,10 @@ export async function dispatchParsedCommand(parsed, startedAt = Date.now()) {
|
|
|
1139
1183
|
printHelp();
|
|
1140
1184
|
return 0;
|
|
1141
1185
|
}
|
|
1186
|
+
if (command === '--json-schemas' || flags['json-schemas'] === 'true') {
|
|
1187
|
+
console.log(renderJsonSchemas());
|
|
1188
|
+
return 0;
|
|
1189
|
+
}
|
|
1142
1190
|
if (!command) {
|
|
1143
1191
|
printHelp();
|
|
1144
1192
|
return 1;
|
|
@@ -1146,7 +1194,11 @@ export async function dispatchParsedCommand(parsed, startedAt = Date.now()) {
|
|
|
1146
1194
|
const definition = commandRegistry.find(command);
|
|
1147
1195
|
if (!definition) {
|
|
1148
1196
|
const error = new CliInputError(`Unknown command '${command}'`, 'Run "moda --help" for usage information.');
|
|
1149
|
-
|
|
1197
|
+
const mode = resolveOutputMode(commandFlags, {
|
|
1198
|
+
isTTY: process.stdout.isTTY,
|
|
1199
|
+
env: process.env,
|
|
1200
|
+
});
|
|
1201
|
+
if (mode === 'agent' || mode === 'agent-stream') {
|
|
1150
1202
|
printAgentCliError(command, error);
|
|
1151
1203
|
}
|
|
1152
1204
|
else {
|
|
@@ -1173,6 +1225,13 @@ export async function dispatchParsedCommand(parsed, startedAt = Date.now()) {
|
|
|
1173
1225
|
commandFlags,
|
|
1174
1226
|
rawFlags: flags,
|
|
1175
1227
|
startedAt,
|
|
1228
|
+
// Agent-safe output auto-selection happens here (not in createCommandContext)
|
|
1229
|
+
// so direct callers/tests keep flag-only behavior. We resolve from the real
|
|
1230
|
+
// stdout TTY + environment, leaving `commandFlags` (and telemetry) untouched.
|
|
1231
|
+
outputMode: resolveOutputMode(commandFlags, {
|
|
1232
|
+
isTTY: process.stdout.isTTY,
|
|
1233
|
+
env: process.env,
|
|
1234
|
+
}),
|
|
1176
1235
|
});
|
|
1177
1236
|
try {
|
|
1178
1237
|
const result = await definition.handler(context);
|
|
@@ -45,5 +45,11 @@ export declare function createCommandContext(input: CommandContextInput, options
|
|
|
45
45
|
startedAt?: number;
|
|
46
46
|
cwd?: string;
|
|
47
47
|
env?: NodeJS.ProcessEnv;
|
|
48
|
+
/**
|
|
49
|
+
* Pre-resolved output mode from the dispatcher (TTY/env auto-detection).
|
|
50
|
+
* When omitted we fall back to flag-only resolution so direct callers
|
|
51
|
+
* (tests, internal helpers) keep their explicit behavior.
|
|
52
|
+
*/
|
|
53
|
+
outputMode?: CliOutputMode;
|
|
48
54
|
}): CommandContext;
|
|
49
55
|
//# sourceMappingURL=command-context.d.ts.map
|
package/dist/command-context.js
CHANGED
|
@@ -5,7 +5,7 @@ function flagEnabled(flags, key) {
|
|
|
5
5
|
export function createCommandContext(input, options = {}) {
|
|
6
6
|
const flags = options.commandFlags ?? input.flags;
|
|
7
7
|
const rawFlags = options.rawFlags ?? input.flags;
|
|
8
|
-
const outputMode = outputModeFromFlags(flags);
|
|
8
|
+
const outputMode = options.outputMode ?? outputModeFromFlags(flags);
|
|
9
9
|
const quiet = flagEnabled(flags, 'quiet');
|
|
10
10
|
const interactive = outputMode === 'human' &&
|
|
11
11
|
!quiet &&
|