@moda-ai/cli 1.19.1 → 1.20.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/cli.js +7 -2
- package/dist/harness.js +69 -1
- package/dist/schemas.d.ts +9 -6
- package/dist/schemas.js +1 -0
- package/package.json +1 -1
- package/skills/integration/index.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -143,6 +143,7 @@ Commands:
|
|
|
143
143
|
harness scan Discover local runtime agents and write .moda/harness.json
|
|
144
144
|
harness candidates Static (no-LLM) harness candidate pre-pass with file:line citations
|
|
145
145
|
harness sync Sync the local harness graph to Moda Cloud
|
|
146
|
+
harness delete <id-or-key> Permanently delete a synced harness from Moda Cloud
|
|
146
147
|
harness agents List detected runtime agents and families
|
|
147
148
|
harness explain Explain the discovered harness graph
|
|
148
149
|
agent context Emit local Moda context for coding agents
|
|
@@ -284,6 +285,7 @@ Examples:
|
|
|
284
285
|
moda harness validate-report
|
|
285
286
|
moda harness approve --yes
|
|
286
287
|
moda harness sync --from-report .moda/harness-report.json
|
|
288
|
+
moda harness delete my-harness-key --yes
|
|
287
289
|
moda --agent doctor
|
|
288
290
|
moda agent context
|
|
289
291
|
moda agent next-action
|
|
@@ -507,7 +509,7 @@ export async function runCommand(command, positional, flags, positionals = posit
|
|
|
507
509
|
// reject an empty/whitespace query with the shared CLI input error before
|
|
508
510
|
// it reaches the schema (which also guards via q.min(1)).
|
|
509
511
|
if (!positional || positional.trim() === '') {
|
|
510
|
-
throw new CliInputError('<query> is required', 'Usage: moda search "<query>" [--mode=keyword|semantic|hybrid] [--user-id=ID] [--time-range=RANGE] [--limit=N]');
|
|
512
|
+
throw new CliInputError('<query> is required', 'Usage: moda search "<query>" [--mode=keyword|semantic|hybrid] [--user-id=ID] [--time-range=RANGE] [--include-tool-io] [--limit=N]');
|
|
511
513
|
}
|
|
512
514
|
const args = flagsToArgs(flags, 'q', positional);
|
|
513
515
|
const params = SearchSchema.parse(args);
|
|
@@ -521,6 +523,8 @@ export async function runCommand(command, positional, flags, positionals = posit
|
|
|
521
523
|
query.set('time_range', params.time_range);
|
|
522
524
|
if (params.limit)
|
|
523
525
|
query.set('limit', params.limit.toString());
|
|
526
|
+
if (params.include_tool_io)
|
|
527
|
+
query.set('include_tool_io', 'true');
|
|
524
528
|
const data = await callDataAPI(`/search?${query.toString()}`);
|
|
525
529
|
recordSearchTelemetry(context, data);
|
|
526
530
|
context.output.writeData(data);
|
|
@@ -878,13 +882,14 @@ export const commandRegistry = createCommandRegistry([
|
|
|
878
882
|
},
|
|
879
883
|
{
|
|
880
884
|
name: 'harness',
|
|
881
|
-
description: 'Analyze, validate, approve, sync, and explain the local multi-agent harness graph',
|
|
885
|
+
description: 'Analyze, validate, approve, sync, delete, and explain the local multi-agent harness graph',
|
|
882
886
|
examples: [
|
|
883
887
|
'moda harness analyze --summary',
|
|
884
888
|
'moda harness analyze --remote',
|
|
885
889
|
'moda harness pull --sync',
|
|
886
890
|
'moda harness approve --yes',
|
|
887
891
|
'moda harness sync --from-report .moda/harness-report.json',
|
|
892
|
+
'moda harness delete my-harness-key --yes',
|
|
888
893
|
'moda harness explain --agent=agent_support',
|
|
889
894
|
],
|
|
890
895
|
auth: 'none',
|
package/dist/harness.js
CHANGED
|
@@ -259,6 +259,47 @@ export async function runHarnessCommand(context) {
|
|
|
259
259
|
});
|
|
260
260
|
return { exitCode: 0 };
|
|
261
261
|
}
|
|
262
|
+
case 'delete': {
|
|
263
|
+
const idOrKey = context.positionals[1]
|
|
264
|
+
?? (context.flags.harness && context.flags.harness !== 'true' ? context.flags.harness : undefined);
|
|
265
|
+
if (!idOrKey) {
|
|
266
|
+
throw new CliInputError('Missing harness id or key to delete.', 'Usage: moda harness delete <harness-id-or-key> [--yes]');
|
|
267
|
+
}
|
|
268
|
+
const profileOptions = { profile: context.profile, env: context.env };
|
|
269
|
+
if (!resolveApiKey(profileOptions) && !context.dryRun) {
|
|
270
|
+
throw new CliInputError('No Moda API key found for harness delete.', 'Run `moda init` first, set MODA_API_KEY, or select a profile with an API key.');
|
|
271
|
+
}
|
|
272
|
+
// Identity banner (same pattern as sync): deletion is destructive and
|
|
273
|
+
// tenant-scoped, so the resolved credential and destination tenant must
|
|
274
|
+
// be visible BEFORE the user confirms — a shadowed or stale key would
|
|
275
|
+
// otherwise delete from the wrong tenant silently.
|
|
276
|
+
const identity = describeSyncIdentity(profileOptions);
|
|
277
|
+
if (identity) {
|
|
278
|
+
const label = identity.tenantSource === 'api-key'
|
|
279
|
+
? describeSyncTenantLabel(identity)
|
|
280
|
+
: describeSyncTenantLabel({
|
|
281
|
+
tenantId: tenant?.tenantId ?? identity.tenantId,
|
|
282
|
+
tenantSource: 'config',
|
|
283
|
+
});
|
|
284
|
+
writeHumanProgress(context, `Deleting as ${identity.credential} → tenant ${label}`);
|
|
285
|
+
}
|
|
286
|
+
if (context.dryRun) {
|
|
287
|
+
context.output.writeData({
|
|
288
|
+
endpoint: `/api/harnesses/${idOrKey}`,
|
|
289
|
+
harnessKey: idOrKey,
|
|
290
|
+
deleted: false,
|
|
291
|
+
dryRun: true,
|
|
292
|
+
});
|
|
293
|
+
return { exitCode: 0 };
|
|
294
|
+
}
|
|
295
|
+
await confirmHarnessDelete(context, idOrKey);
|
|
296
|
+
const response = await callControlAPI(`/harnesses/${encodeURIComponent(idOrKey)}`, { method: 'DELETE' }, profileOptions);
|
|
297
|
+
writeHumanProgress(context, `Deleted harness ${response.harnessKey ?? idOrKey} from tenant ${response.tenantId ?? 'unknown'} ` +
|
|
298
|
+
`(${response.deleted?.versions ?? 0} versions, ${response.deleted?.agents ?? 0} agents, ` +
|
|
299
|
+
`${response.deleted?.artifacts ?? 0} artifacts, ${response.deleted?.relationships ?? 0} relationships).`);
|
|
300
|
+
context.output.writeData({ ...response, dryRun: false });
|
|
301
|
+
return { exitCode: 0 };
|
|
302
|
+
}
|
|
262
303
|
case 'analyze': {
|
|
263
304
|
await approveScanIfNeeded(scanPlan, {
|
|
264
305
|
context,
|
|
@@ -494,7 +535,7 @@ export async function runHarnessCommand(context) {
|
|
|
494
535
|
return { exitCode: 0 };
|
|
495
536
|
}
|
|
496
537
|
default:
|
|
497
|
-
throw new CliInputError(`Unknown harness command '${subcommand}'.`, 'Usage: moda harness analyze|pull|validate-report|approve|scan|candidates|sync|agents|graph|explain|write-summary|status');
|
|
538
|
+
throw new CliInputError(`Unknown harness command '${subcommand}'.`, 'Usage: moda harness analyze|pull|validate-report|approve|scan|candidates|sync|delete|agents|graph|explain|write-summary|status');
|
|
498
539
|
}
|
|
499
540
|
}
|
|
500
541
|
export function writeHarnessAnalyzeResult(context, payload) {
|
|
@@ -1916,6 +1957,33 @@ async function approveScanIfNeeded(scanPlan, options = {}) {
|
|
|
1916
1957
|
throw new CliInputError(options.declinedMessage ?? 'Harness scan was not approved.', options.declinedHint ?? 'Run `moda harness scan --path=<dir>` for a narrower scan, or rerun with `--yes` after reviewing the read plan.');
|
|
1917
1958
|
}
|
|
1918
1959
|
}
|
|
1960
|
+
/**
|
|
1961
|
+
* Interactive confirmation gate for `harness delete`. `--yes` skips it; in
|
|
1962
|
+
* machine-readable modes or without a TTY the command refuses with a
|
|
1963
|
+
* resumable input-required error instead of prompting (same posture as the
|
|
1964
|
+
* broad-scan approval above) so agents/CI never hang on stdin.
|
|
1965
|
+
*/
|
|
1966
|
+
async function confirmHarnessDelete(context, idOrKey) {
|
|
1967
|
+
if (context.yes)
|
|
1968
|
+
return;
|
|
1969
|
+
const message = `Permanently delete harness '${idOrKey}' and all of its synced versions from Moda Cloud?`;
|
|
1970
|
+
if (context.outputMode !== 'human' || process.stdin.isTTY !== true) {
|
|
1971
|
+
throw new CliInputRequiredError(message, {
|
|
1972
|
+
id: 'harness_delete_approval',
|
|
1973
|
+
question: message,
|
|
1974
|
+
kind: 'confirm',
|
|
1975
|
+
choices: [
|
|
1976
|
+
{ value: 'yes', label: 'Delete harness', resume_flags: ['--yes'] },
|
|
1977
|
+
{ value: 'no', label: 'Keep harness', resume_flags: [] },
|
|
1978
|
+
],
|
|
1979
|
+
resume_command: ['moda', 'harness', 'delete', idOrKey, '--yes'],
|
|
1980
|
+
}, 'Re-run with `--yes` to confirm the deletion.');
|
|
1981
|
+
}
|
|
1982
|
+
const approved = await confirm({ message, default: false });
|
|
1983
|
+
if (!approved) {
|
|
1984
|
+
throw new CliInputError('Harness delete was not approved.', 'Re-run with `--yes` to skip the prompt, or leave the harness in place.');
|
|
1985
|
+
}
|
|
1986
|
+
}
|
|
1919
1987
|
export function writeHumanProgress(context, message) {
|
|
1920
1988
|
if (context.outputMode !== 'human')
|
|
1921
1989
|
return;
|
package/dist/schemas.d.ts
CHANGED
|
@@ -83,12 +83,12 @@ export declare const ContextSchema: z.ZodObject<{
|
|
|
83
83
|
window: z.ZodOptional<z.ZodDefault<z.ZodNumber>>;
|
|
84
84
|
}, "strip", z.ZodTypeAny, {
|
|
85
85
|
conversation_id: string;
|
|
86
|
-
msg_index?: number | undefined;
|
|
87
86
|
window?: number | undefined;
|
|
87
|
+
msg_index?: number | undefined;
|
|
88
88
|
}, {
|
|
89
89
|
conversation_id: string;
|
|
90
|
-
msg_index?: number | undefined;
|
|
91
90
|
window?: number | undefined;
|
|
91
|
+
msg_index?: number | undefined;
|
|
92
92
|
}>;
|
|
93
93
|
export declare const FrustrationsSchema: z.ZodObject<{
|
|
94
94
|
days_back: z.ZodOptional<z.ZodDefault<z.ZodNumber>>;
|
|
@@ -97,16 +97,16 @@ export declare const FrustrationsSchema: z.ZodObject<{
|
|
|
97
97
|
include_window: z.ZodOptional<z.ZodEffects<z.ZodBoolean, boolean, unknown>>;
|
|
98
98
|
window: z.ZodOptional<z.ZodDefault<z.ZodNumber>>;
|
|
99
99
|
}, "strip", z.ZodTypeAny, {
|
|
100
|
+
window?: number | undefined;
|
|
100
101
|
days_back?: number | undefined;
|
|
101
102
|
limit?: number | undefined;
|
|
102
103
|
offset?: number | undefined;
|
|
103
|
-
window?: number | undefined;
|
|
104
104
|
include_window?: boolean | undefined;
|
|
105
105
|
}, {
|
|
106
|
+
window?: number | undefined;
|
|
106
107
|
days_back?: number | undefined;
|
|
107
108
|
limit?: number | undefined;
|
|
108
109
|
offset?: number | undefined;
|
|
109
|
-
window?: number | undefined;
|
|
110
110
|
include_window?: unknown;
|
|
111
111
|
}>;
|
|
112
112
|
export declare const ToolFailuresSchema: z.ZodObject<{
|
|
@@ -126,19 +126,19 @@ export declare const ToolFailureDetailSchema: z.ZodObject<{
|
|
|
126
126
|
window: z.ZodOptional<z.ZodDefault<z.ZodNumber>>;
|
|
127
127
|
}, "strip", z.ZodTypeAny, {
|
|
128
128
|
tool_name: string;
|
|
129
|
+
window?: number | undefined;
|
|
129
130
|
subtype?: string | undefined;
|
|
130
131
|
days_back?: number | undefined;
|
|
131
132
|
limit?: number | undefined;
|
|
132
133
|
offset?: number | undefined;
|
|
133
|
-
window?: number | undefined;
|
|
134
134
|
include_window?: boolean | undefined;
|
|
135
135
|
}, {
|
|
136
136
|
tool_name: string;
|
|
137
|
+
window?: number | undefined;
|
|
137
138
|
subtype?: string | undefined;
|
|
138
139
|
days_back?: number | undefined;
|
|
139
140
|
limit?: number | undefined;
|
|
140
141
|
offset?: number | undefined;
|
|
141
|
-
window?: number | undefined;
|
|
142
142
|
include_window?: unknown;
|
|
143
143
|
}>;
|
|
144
144
|
/**
|
|
@@ -172,17 +172,20 @@ export declare const SearchSchema: z.ZodObject<{
|
|
|
172
172
|
user_id: z.ZodOptional<z.ZodString>;
|
|
173
173
|
time_range: z.ZodOptional<z.ZodDefault<z.ZodEnum<["all", "1h", "3d", "7d", "24h", "30d", "90d"]>>>;
|
|
174
174
|
limit: z.ZodOptional<z.ZodDefault<z.ZodNumber>>;
|
|
175
|
+
include_tool_io: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>;
|
|
175
176
|
}, "strip", z.ZodTypeAny, {
|
|
176
177
|
q: string;
|
|
177
178
|
mode?: "keyword" | "semantic" | "hybrid" | undefined;
|
|
178
179
|
time_range?: "all" | "1h" | "3d" | "7d" | "24h" | "30d" | "90d" | undefined;
|
|
179
180
|
limit?: number | undefined;
|
|
180
181
|
user_id?: string | undefined;
|
|
182
|
+
include_tool_io?: boolean | undefined;
|
|
181
183
|
}, {
|
|
182
184
|
q: string;
|
|
183
185
|
mode?: "keyword" | "semantic" | "hybrid" | undefined;
|
|
184
186
|
time_range?: "all" | "1h" | "3d" | "7d" | "24h" | "30d" | "90d" | undefined;
|
|
185
187
|
limit?: number | undefined;
|
|
186
188
|
user_id?: string | undefined;
|
|
189
|
+
include_tool_io?: boolean | undefined;
|
|
187
190
|
}>;
|
|
188
191
|
//# sourceMappingURL=schemas.d.ts.map
|
package/dist/schemas.js
CHANGED
|
@@ -91,5 +91,6 @@ export const SearchSchema = z.object({
|
|
|
91
91
|
user_id: z.string().optional(),
|
|
92
92
|
time_range: z.enum(TIME_RANGES).default('all').optional(),
|
|
93
93
|
limit: z.number().min(1).max(100).default(20).optional(),
|
|
94
|
+
include_tool_io: z.boolean().default(false).optional(),
|
|
94
95
|
});
|
|
95
96
|
//# sourceMappingURL=schemas.js.map
|
package/package.json
CHANGED