@moda-ai/cli 1.9.6 → 1.10.1

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/README.md CHANGED
@@ -58,12 +58,6 @@ moda tool-failures # Tool failure overview
58
58
  moda tool-failure-detail <tool_name> # Per-tool failure detail
59
59
  moda tool-failure-detail <tool_name> --include-window --window=1
60
60
 
61
- # Agent runs runtime (workflows = recurring class, run = one execution)
62
- moda workflows --time-range=7d # Recurring workflow catalog with health
63
- moda runs # Last 7d of workflow executions
64
- moda runs --time-range=24h --outcome=partial # Last 24h, partial completions only
65
- moda runs --class-id=cron:helpscout-triage-hourly # Scoped to one workflow class
66
- moda run <run_id> # One execution + its side-effect receipts
67
61
  moda loops # Currently-active loop detections
68
62
  moda loop <detection_id> # One loop detail (signature + blast radius)
69
63
 
@@ -81,9 +75,7 @@ All commands output JSON. Pipe to `jq` for filtering:
81
75
  ```bash
82
76
  moda overview | jq '.frustrations'
83
77
  moda frustrations | jq '.frustrations[].primary_cause'
84
- moda runs --outcome=partial | jq '.runs[] | {job_id, intent_summary, outcome_reason}'
85
78
  moda loops | jq '.loops | sort_by(-.cycle_visits) | .[0:5] | .[].loop_signature_human'
86
- moda workflows | jq '.workflows | sort_by(.health) | .[] | select(.health < 0.8)'
87
79
  ```
88
80
 
89
81
  ## Prompt Management
@@ -0,0 +1,3 @@
1
+ export declare const AGENT_JSON_SCHEMAS: Record<string, unknown>;
2
+ export declare function renderJsonSchemas(): string;
3
+ //# sourceMappingURL=agent-schemas.d.ts.map
@@ -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
@@ -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
- export declare function callControlAPI(endpoint: string, options?: RequestInit, profileOptions?: ProfileIOOptions): Promise<unknown>;
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
@@ -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 <= MAX_RETRIES; 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(), REQUEST_TIMEOUT_MS);
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 < MAX_RETRIES) {
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 ${REQUEST_TIMEOUT_MS}ms: ${url}`
66
+ ? `Request timed out after ${timeoutMs}ms: ${url}`
65
67
  : `Network error: ${error instanceof Error ? error.message : String(error)}`);
66
- if (attempt < MAX_RETRIES) {
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<void>;
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;