@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 +0 -8
- 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 -94
- 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 +21 -4
- package/dist/production-intelligence.js +360 -107
- package/dist/schemas.d.ts +20 -43
- package/dist/schemas.js +10 -26
- package/package.json +1 -1
- package/skills/moda-cli/SKILL.md +152 -56
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* moda.intelligence.v1 — the unified Moda intelligence wire format (MODA-388).
|
|
3
|
+
*
|
|
4
|
+
* ONE versioned payload that every surface projects from:
|
|
5
|
+
* - CLI `moda ask --json` / `--agent` (the agent-facing contract),
|
|
6
|
+
* - the backend `POST /api/cli/ask` response,
|
|
7
|
+
* - the (future) MCP server's `structuredContent`,
|
|
8
|
+
* - the dashboard UI.
|
|
9
|
+
*
|
|
10
|
+
* Design rules:
|
|
11
|
+
* - snake_case everywhere (no mixed casing — the prior split between the
|
|
12
|
+
* snake_case envelope and the camelCase `production_ask.v0.1` data payload
|
|
13
|
+
* was the main source of agent-integration pain).
|
|
14
|
+
* - It is a SUPERSET. Differentiation between a human reader and an agent is a
|
|
15
|
+
* RENDERING concern at the edge, not a forked schema:
|
|
16
|
+
* · human projection → narrative `answer_markdown`, `summary.confidence`
|
|
17
|
+
* as a word, raw ids/anchors hidden.
|
|
18
|
+
* · agent projection → full `evidence_refs` (with `anchor` + `grounding`),
|
|
19
|
+
* `answer_claims` (claim → evidence), structured
|
|
20
|
+
* `next_commands`.
|
|
21
|
+
* - Additive evolution only within v1; breaking changes bump the version.
|
|
22
|
+
*
|
|
23
|
+
* This module is the SINGLE SOURCE OF TRUTH for the shape. The backend mirrors
|
|
24
|
+
* these field names on the wire and the contract tests validate real CLI output
|
|
25
|
+
* against {@link MODA_INTELLIGENCE_V1_JSON_SCHEMA}.
|
|
26
|
+
*/
|
|
27
|
+
export const INTELLIGENCE_SCHEMA_VERSION = 'moda.intelligence.v1';
|
|
28
|
+
// ───────────────────────────── JSON Schema (draft-07) ─────────────────────────
|
|
29
|
+
const provenanceSchema = { type: 'string', enum: ['measured', 'inferred'] };
|
|
30
|
+
const mutabilitySchema = {
|
|
31
|
+
type: 'string',
|
|
32
|
+
enum: ['read', 'write', 'sync', 'unknown'],
|
|
33
|
+
};
|
|
34
|
+
const confidenceSchema = {
|
|
35
|
+
type: 'string',
|
|
36
|
+
enum: ['high', 'medium', 'low', 'unknown'],
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Published draft-07 JSON Schema for {@link ModaIntelligenceV1}. This is what
|
|
40
|
+
* `moda --json-schemas` emits and what the contract tests validate CLI/backend
|
|
41
|
+
* output against. Keep in lockstep with the interfaces above.
|
|
42
|
+
*/
|
|
43
|
+
export const MODA_INTELLIGENCE_V1_JSON_SCHEMA = {
|
|
44
|
+
$schema: 'http://json-schema.org/draft-07/schema#',
|
|
45
|
+
$id: 'moda.intelligence.v1',
|
|
46
|
+
title: 'Moda Intelligence v1',
|
|
47
|
+
type: 'object',
|
|
48
|
+
additionalProperties: false,
|
|
49
|
+
required: [
|
|
50
|
+
'schema_version',
|
|
51
|
+
'generated_at',
|
|
52
|
+
'command',
|
|
53
|
+
'source',
|
|
54
|
+
'degraded',
|
|
55
|
+
'question',
|
|
56
|
+
'summary',
|
|
57
|
+
'answer_markdown',
|
|
58
|
+
'answer_claims',
|
|
59
|
+
'findings',
|
|
60
|
+
'evidence_refs',
|
|
61
|
+
'next_commands',
|
|
62
|
+
'warnings',
|
|
63
|
+
],
|
|
64
|
+
properties: {
|
|
65
|
+
schema_version: { const: 'moda.intelligence.v1' },
|
|
66
|
+
generated_at: { type: 'string', format: 'date-time' },
|
|
67
|
+
command: { type: 'string' },
|
|
68
|
+
source: { type: 'string', enum: ['cloud', 'local_fallback'] },
|
|
69
|
+
degraded: { type: 'boolean' },
|
|
70
|
+
question: { type: 'string' },
|
|
71
|
+
summary: {
|
|
72
|
+
type: 'object',
|
|
73
|
+
additionalProperties: false,
|
|
74
|
+
required: ['text', 'confidence'],
|
|
75
|
+
properties: { text: { type: 'string' }, confidence: confidenceSchema },
|
|
76
|
+
},
|
|
77
|
+
answer_markdown: { type: 'string' },
|
|
78
|
+
answer_claims: {
|
|
79
|
+
type: 'array',
|
|
80
|
+
items: {
|
|
81
|
+
type: 'object',
|
|
82
|
+
additionalProperties: false,
|
|
83
|
+
required: ['text', 'kind', 'status', 'evidence_ref_ids'],
|
|
84
|
+
properties: {
|
|
85
|
+
text: { type: 'string' },
|
|
86
|
+
value: { type: 'number' },
|
|
87
|
+
kind: { type: 'string', enum: ['percentage', 'count', 'qualitative'] },
|
|
88
|
+
status: {
|
|
89
|
+
type: 'string',
|
|
90
|
+
enum: ['grounded', 'ungrounded', 'unverifiable'],
|
|
91
|
+
},
|
|
92
|
+
evidence_ref_ids: { type: 'array', items: { type: 'string' } },
|
|
93
|
+
matched_path: { type: 'string' },
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
findings: {
|
|
98
|
+
type: 'array',
|
|
99
|
+
items: {
|
|
100
|
+
type: 'object',
|
|
101
|
+
additionalProperties: false,
|
|
102
|
+
required: ['id', 'title', 'evidence_ref_ids', 'recommended_actions'],
|
|
103
|
+
properties: {
|
|
104
|
+
id: { type: 'string' },
|
|
105
|
+
title: { type: 'string' },
|
|
106
|
+
severity: {
|
|
107
|
+
type: 'string',
|
|
108
|
+
enum: ['critical', 'high', 'medium', 'low', 'info'],
|
|
109
|
+
},
|
|
110
|
+
description: { type: 'string' },
|
|
111
|
+
evidence_ref_ids: { type: 'array', items: { type: 'string' } },
|
|
112
|
+
recommended_actions: {
|
|
113
|
+
type: 'array',
|
|
114
|
+
items: {
|
|
115
|
+
type: 'object',
|
|
116
|
+
additionalProperties: false,
|
|
117
|
+
required: ['id', 'title', 'mutability', 'requires_approval'],
|
|
118
|
+
properties: {
|
|
119
|
+
id: { type: 'string' },
|
|
120
|
+
title: { type: 'string' },
|
|
121
|
+
rationale: { type: 'string' },
|
|
122
|
+
command: { type: 'string' },
|
|
123
|
+
mutability: mutabilitySchema,
|
|
124
|
+
requires_approval: { type: 'boolean' },
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
evidence_refs: {
|
|
132
|
+
type: 'array',
|
|
133
|
+
items: {
|
|
134
|
+
type: 'object',
|
|
135
|
+
additionalProperties: false,
|
|
136
|
+
required: ['id', 'kind', 'label', 'grounding'],
|
|
137
|
+
properties: {
|
|
138
|
+
id: { type: 'string' },
|
|
139
|
+
kind: { type: 'string' },
|
|
140
|
+
label: { type: 'string' },
|
|
141
|
+
anchor: {
|
|
142
|
+
type: 'object',
|
|
143
|
+
additionalProperties: false,
|
|
144
|
+
properties: {
|
|
145
|
+
conversation_id: { type: 'string' },
|
|
146
|
+
message_index: { type: 'number' },
|
|
147
|
+
run_id: { type: 'string' },
|
|
148
|
+
tool_name: { type: 'string' },
|
|
149
|
+
},
|
|
150
|
+
},
|
|
151
|
+
snippet: { type: 'string' },
|
|
152
|
+
grounding: provenanceSchema,
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
},
|
|
156
|
+
next_commands: {
|
|
157
|
+
type: 'array',
|
|
158
|
+
items: {
|
|
159
|
+
type: 'object',
|
|
160
|
+
additionalProperties: false,
|
|
161
|
+
required: ['command', 'mutability', 'requires_approval'],
|
|
162
|
+
properties: {
|
|
163
|
+
command: { type: 'string' },
|
|
164
|
+
purpose: { type: 'string' },
|
|
165
|
+
mutability: mutabilitySchema,
|
|
166
|
+
requires_approval: { type: 'boolean' },
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
warnings: { type: 'array', items: { type: 'string' } },
|
|
171
|
+
meta: { type: 'object' },
|
|
172
|
+
},
|
|
173
|
+
};
|
|
174
|
+
//# sourceMappingURL=intelligence-schema.js.map
|
package/dist/output.d.ts
CHANGED
|
@@ -1,7 +1,18 @@
|
|
|
1
1
|
export type CliOutputMode = 'human' | 'json' | 'agent' | 'agent-stream';
|
|
2
2
|
export declare const AGENT_SCHEMA_VERSION = "moda.agent.v1";
|
|
3
3
|
export declare const AGENT_EVENT_SCHEMA_VERSION = "moda.agent_event.v1";
|
|
4
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Stable process exit codes that an external agent can branch on:
|
|
6
|
+
* 0 ok — grounded answer from Moda Cloud intelligence.
|
|
7
|
+
* 3 degraded — answer produced from a local/degraded fallback (lower trust).
|
|
8
|
+
* 1 error — command/input/unexpected failure (see envelope `errors[]`).
|
|
9
|
+
* `EXIT_DEGRADED` is intentionally distinct so a caller can tell a degraded
|
|
10
|
+
* answer apart from both success and hard failure without parsing the payload.
|
|
11
|
+
*/
|
|
12
|
+
export declare const EXIT_OK = 0;
|
|
13
|
+
export declare const EXIT_ERROR = 1;
|
|
14
|
+
export declare const EXIT_DEGRADED = 3;
|
|
15
|
+
export type AgentStatus = 'ok' | 'degraded' | 'error';
|
|
5
16
|
export type AgentConfidence = 'high' | 'medium' | 'low' | 'unknown';
|
|
6
17
|
export interface AgentSummary {
|
|
7
18
|
text: string;
|
|
@@ -94,12 +105,24 @@ export interface CliOutput {
|
|
|
94
105
|
mode: CliOutputMode;
|
|
95
106
|
quiet: boolean;
|
|
96
107
|
writeData(data: unknown, options?: {
|
|
97
|
-
status?: 'success' | 'error';
|
|
108
|
+
status?: 'success' | 'degraded' | 'error';
|
|
98
109
|
meta?: Record<string, unknown>;
|
|
99
110
|
} & AgentWriteOptions): void;
|
|
100
111
|
writeEvent(event: Omit<AgentEvent, 'schema_version' | 'command' | 'generated_at'>): void;
|
|
101
112
|
}
|
|
113
|
+
/** Flag-only resolution (default human). Kept for callers that only have flags. */
|
|
102
114
|
export declare function outputModeFromFlags(flags: Record<string, string>): CliOutputMode;
|
|
115
|
+
/**
|
|
116
|
+
* Resolve the effective output mode for a real CLI invocation, in priority
|
|
117
|
+
* order: explicit flags -> `MODA_FORMAT` -> agent-environment detection ->
|
|
118
|
+
* TTY detection (piped/redirected => agent JSON) -> human prose. This is what
|
|
119
|
+
* makes the CLI agent-safe: a piped/automated caller gets structured output
|
|
120
|
+
* with zero flags, while a human at a terminal still gets prose.
|
|
121
|
+
*/
|
|
122
|
+
export declare function resolveOutputMode(flags: Record<string, string>, opts?: {
|
|
123
|
+
isTTY?: boolean;
|
|
124
|
+
env?: NodeJS.ProcessEnv;
|
|
125
|
+
}): CliOutputMode;
|
|
103
126
|
export declare function createCliOutput(options: {
|
|
104
127
|
command: string;
|
|
105
128
|
mode: CliOutputMode;
|
package/dist/output.js
CHANGED
|
@@ -1,12 +1,77 @@
|
|
|
1
1
|
export const AGENT_SCHEMA_VERSION = 'moda.agent.v1';
|
|
2
2
|
export const AGENT_EVENT_SCHEMA_VERSION = 'moda.agent_event.v1';
|
|
3
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Stable process exit codes that an external agent can branch on:
|
|
5
|
+
* 0 ok — grounded answer from Moda Cloud intelligence.
|
|
6
|
+
* 3 degraded — answer produced from a local/degraded fallback (lower trust).
|
|
7
|
+
* 1 error — command/input/unexpected failure (see envelope `errors[]`).
|
|
8
|
+
* `EXIT_DEGRADED` is intentionally distinct so a caller can tell a degraded
|
|
9
|
+
* answer apart from both success and hard failure without parsing the payload.
|
|
10
|
+
*/
|
|
11
|
+
export const EXIT_OK = 0;
|
|
12
|
+
export const EXIT_ERROR = 1;
|
|
13
|
+
export const EXIT_DEGRADED = 3;
|
|
14
|
+
/**
|
|
15
|
+
* Output mode requested by explicit flags only, or `undefined` when the caller
|
|
16
|
+
* did not pick one. Explicit flags always win over auto-detection.
|
|
17
|
+
*/
|
|
18
|
+
function explicitModeFromFlags(flags) {
|
|
4
19
|
if (flags.agent === 'true' && (flags.stream === 'true' || flags.format === 'ndjson'))
|
|
5
20
|
return 'agent-stream';
|
|
6
21
|
if (flags.agent === 'true')
|
|
7
22
|
return 'agent';
|
|
8
23
|
if (flags.json === 'true')
|
|
9
24
|
return 'json';
|
|
25
|
+
if (flags.human === 'true' || flags.prose === 'true')
|
|
26
|
+
return 'human';
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
/** Flag-only resolution (default human). Kept for callers that only have flags. */
|
|
30
|
+
export function outputModeFromFlags(flags) {
|
|
31
|
+
return explicitModeFromFlags(flags) ?? 'human';
|
|
32
|
+
}
|
|
33
|
+
function outputModeFromEnv(env) {
|
|
34
|
+
const fmt = (env.MODA_FORMAT ?? '').trim().toLowerCase();
|
|
35
|
+
if (fmt === 'human' || fmt === 'json' || fmt === 'agent')
|
|
36
|
+
return fmt;
|
|
37
|
+
if (fmt === 'agent-stream' || fmt === 'ndjson')
|
|
38
|
+
return 'agent-stream';
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
function truthyEnv(value) {
|
|
42
|
+
return value != null && value !== '' && value !== '0' && value.toLowerCase() !== 'false';
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* True when the process appears to be driven by an agent / automation rather
|
|
46
|
+
* than an interactive human (Claude Code, Cursor, generic CI, or an explicit
|
|
47
|
+
* `MODA_AGENT` opt-in). Such callers get machine-parseable output by default.
|
|
48
|
+
*/
|
|
49
|
+
function isAgentEnvironment(env) {
|
|
50
|
+
return (truthyEnv(env.CLAUDECODE) ||
|
|
51
|
+
truthyEnv(env.CURSOR) ||
|
|
52
|
+
truthyEnv(env.CI) ||
|
|
53
|
+
truthyEnv(env.MODA_AGENT));
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Resolve the effective output mode for a real CLI invocation, in priority
|
|
57
|
+
* order: explicit flags -> `MODA_FORMAT` -> agent-environment detection ->
|
|
58
|
+
* TTY detection (piped/redirected => agent JSON) -> human prose. This is what
|
|
59
|
+
* makes the CLI agent-safe: a piped/automated caller gets structured output
|
|
60
|
+
* with zero flags, while a human at a terminal still gets prose.
|
|
61
|
+
*/
|
|
62
|
+
export function resolveOutputMode(flags, opts = {}) {
|
|
63
|
+
const explicit = explicitModeFromFlags(flags);
|
|
64
|
+
if (explicit)
|
|
65
|
+
return explicit;
|
|
66
|
+
const env = opts.env ?? process.env;
|
|
67
|
+
const fromEnv = outputModeFromEnv(env);
|
|
68
|
+
if (fromEnv)
|
|
69
|
+
return fromEnv;
|
|
70
|
+
if (isAgentEnvironment(env))
|
|
71
|
+
return 'agent';
|
|
72
|
+
const isTTY = opts.isTTY ?? Boolean(process.stdout.isTTY);
|
|
73
|
+
if (!isTTY)
|
|
74
|
+
return 'agent';
|
|
10
75
|
return 'human';
|
|
11
76
|
}
|
|
12
77
|
export function createCliOutput(options) {
|
|
@@ -19,7 +84,11 @@ export function createCliOutput(options) {
|
|
|
19
84
|
if (options.mode === 'agent' || options.mode === 'agent-stream') {
|
|
20
85
|
const envelope = createAgentEnvelope({
|
|
21
86
|
command: options.command,
|
|
22
|
-
status: writeOptions.status === 'error'
|
|
87
|
+
status: writeOptions.status === 'error'
|
|
88
|
+
? 'error'
|
|
89
|
+
: writeOptions.status === 'degraded'
|
|
90
|
+
? 'degraded'
|
|
91
|
+
: 'ok',
|
|
23
92
|
data,
|
|
24
93
|
meta: writeOptions.meta,
|
|
25
94
|
summary: writeOptions.summary,
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import type { CommandContext } from './command-context.js';
|
|
2
2
|
import type { AgentConfidence } from './output.js';
|
|
3
|
+
import { type ModaIntelligenceV1 } from './intelligence-schema.js';
|
|
3
4
|
declare const INVESTIGATION_SCHEMA_VERSION = "production_investigation.v0.1";
|
|
4
5
|
declare const OVERVIEW_SCHEMA_VERSION = "production_overview.v0.1";
|
|
5
6
|
declare const ASK_SCHEMA_VERSION = "production_ask.v0.1";
|
|
6
7
|
type Severity = 'critical' | 'high' | 'medium' | 'low' | 'info';
|
|
7
|
-
type FindingKind = 'tool_failure' | 'loop' | 'frustration' | '
|
|
8
|
+
type FindingKind = 'tool_failure' | 'loop' | 'frustration' | 'prompt_regression' | 'skill_gap' | 'insufficient_data';
|
|
8
9
|
export interface ProductionEvidenceRef {
|
|
9
10
|
id: string;
|
|
10
|
-
kind: 'data_api' | 'tool_failure' | 'frustration' | 'loop' | '
|
|
11
|
+
kind: 'data_api' | 'tool_failure' | 'frustration' | 'loop' | 'harness' | 'ask';
|
|
11
12
|
label: string;
|
|
12
13
|
endpoint?: string;
|
|
13
14
|
conversationId?: string;
|
|
@@ -51,7 +52,6 @@ export interface ProductionInvestigation {
|
|
|
51
52
|
generatedAt: string;
|
|
52
53
|
daysBack: number;
|
|
53
54
|
scope: {
|
|
54
|
-
runId?: string;
|
|
55
55
|
conversationId?: string;
|
|
56
56
|
toolName?: string;
|
|
57
57
|
loopId?: string;
|
|
@@ -99,6 +99,13 @@ export interface ProductionAskResult {
|
|
|
99
99
|
schemaVersion: typeof ASK_SCHEMA_VERSION;
|
|
100
100
|
generatedAt: string;
|
|
101
101
|
source: 'cloud' | 'local_fallback';
|
|
102
|
+
/**
|
|
103
|
+
* True when the answer did NOT come from Moda Cloud intelligence and was
|
|
104
|
+
* instead synthesized locally (cloud unreachable / unavailable / empty). This
|
|
105
|
+
* is the canonical in-payload signal of a degraded answer, mirrored by exit
|
|
106
|
+
* code 3 and envelope status `degraded`. Always `false` on the cloud path.
|
|
107
|
+
*/
|
|
108
|
+
degraded: boolean;
|
|
102
109
|
question: string;
|
|
103
110
|
answer: string;
|
|
104
111
|
confidence: AgentConfidence;
|
|
@@ -106,6 +113,17 @@ export interface ProductionAskResult {
|
|
|
106
113
|
findings: ProductionFinding[];
|
|
107
114
|
nextCommands: string[];
|
|
108
115
|
warnings: string[];
|
|
116
|
+
/** Why the cloud path was not used (set only when `degraded` is true). */
|
|
117
|
+
fallbackReason?: string;
|
|
118
|
+
/**
|
|
119
|
+
* The canonical `moda.intelligence.v1` projection of this answer (MODA-388).
|
|
120
|
+
* This is what `moda ask --json`/`--agent` surface as the agent envelope's
|
|
121
|
+
* `data`, so every surface reads one versioned, snake_case payload (carrying
|
|
122
|
+
* per-evidence `grounding`/`anchor` and per-claim grounding verdicts). On the
|
|
123
|
+
* cloud path it is taken from `response.intelligence` when present, else
|
|
124
|
+
* synthesized from the legacy snake_case fields for back-compat.
|
|
125
|
+
*/
|
|
126
|
+
intelligence: ModaIntelligenceV1;
|
|
109
127
|
}
|
|
110
128
|
export declare function runProductionCommand(context: CommandContext): Promise<{
|
|
111
129
|
exitCode: number;
|
|
@@ -117,7 +135,6 @@ export declare function loadOverviewBriefing(options: {
|
|
|
117
135
|
export declare function investigateProduction(options: {
|
|
118
136
|
daysBack: number;
|
|
119
137
|
cwd: string;
|
|
120
|
-
runId?: string;
|
|
121
138
|
conversationId?: string;
|
|
122
139
|
toolName?: string;
|
|
123
140
|
loopId?: string;
|