migraguard 0.9.0 → 0.9.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/cli-contract.yaml +100 -10
- package/dist/cli.js +101 -29
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/cli-contract.yaml
CHANGED
|
@@ -900,12 +900,23 @@ commandSets:
|
|
|
900
900
|
enum: [warning, error, critical]
|
|
901
901
|
default: error
|
|
902
902
|
|
|
903
|
+
- name: output
|
|
904
|
+
aliases: [o]
|
|
905
|
+
description: Write result to a file instead of stdout.
|
|
906
|
+
valueName: file
|
|
907
|
+
schema:
|
|
908
|
+
type: string
|
|
909
|
+
file:
|
|
910
|
+
mode: write
|
|
911
|
+
mediaType: application/json
|
|
912
|
+
encoding: utf-8
|
|
913
|
+
|
|
903
914
|
- name: report-format
|
|
904
915
|
description: Output format for the audit report.
|
|
905
916
|
valueName: fmt
|
|
906
917
|
schema:
|
|
907
918
|
type: string
|
|
908
|
-
enum: [text,
|
|
919
|
+
enum: [json, text, yaml]
|
|
909
920
|
default: text
|
|
910
921
|
|
|
911
922
|
exits:
|
|
@@ -947,9 +958,13 @@ commandSets:
|
|
|
947
958
|
riskLevel: low
|
|
948
959
|
requiresConfirmation: false
|
|
949
960
|
idempotent: true
|
|
950
|
-
sideEffects:
|
|
951
|
-
|
|
961
|
+
sideEffects: [network]
|
|
962
|
+
sideEffectNote: >-
|
|
963
|
+
Network calls to LLM provider when adapter is not mock.
|
|
964
|
+
Filesystem write only when --output is specified.
|
|
952
965
|
safeDryRunOption: dry-run
|
|
966
|
+
expectedDurationMs: 120000
|
|
967
|
+
retryableExitCodes: [1, 12]
|
|
953
968
|
|
|
954
969
|
# ── propose-expand-contract ───────────────────────
|
|
955
970
|
propose-expand-contract:
|
|
@@ -1005,11 +1020,38 @@ commandSets:
|
|
|
1005
1020
|
type: boolean
|
|
1006
1021
|
default: false
|
|
1007
1022
|
|
|
1023
|
+
- name: fail-on
|
|
1024
|
+
description: Minimum severity that causes a non-zero exit.
|
|
1025
|
+
valueName: level
|
|
1026
|
+
schema:
|
|
1027
|
+
type: string
|
|
1028
|
+
enum: [warning, error, critical]
|
|
1029
|
+
default: error
|
|
1030
|
+
|
|
1031
|
+
- name: output
|
|
1032
|
+
aliases: [o]
|
|
1033
|
+
description: Write result to a file instead of stdout.
|
|
1034
|
+
valueName: file
|
|
1035
|
+
schema:
|
|
1036
|
+
type: string
|
|
1037
|
+
file:
|
|
1038
|
+
mode: write
|
|
1039
|
+
mediaType: application/json
|
|
1040
|
+
encoding: utf-8
|
|
1041
|
+
|
|
1042
|
+
- name: report-format
|
|
1043
|
+
description: Output format for the proposal report.
|
|
1044
|
+
valueName: fmt
|
|
1045
|
+
schema:
|
|
1046
|
+
type: string
|
|
1047
|
+
enum: [json, text, yaml]
|
|
1048
|
+
default: json
|
|
1049
|
+
|
|
1008
1050
|
exits:
|
|
1009
1051
|
'0':
|
|
1010
1052
|
description: Proposal generated successfully.
|
|
1011
1053
|
stdout:
|
|
1012
|
-
format:
|
|
1054
|
+
format: '{options.report-format}'
|
|
1013
1055
|
schema:
|
|
1014
1056
|
$ref: '#/components/schemas/ExpandContractProposal'
|
|
1015
1057
|
|
|
@@ -1023,6 +1065,13 @@ commandSets:
|
|
|
1023
1065
|
stderr:
|
|
1024
1066
|
format: text
|
|
1025
1067
|
|
|
1068
|
+
'10':
|
|
1069
|
+
description: Completed with blocking findings.
|
|
1070
|
+
stdout:
|
|
1071
|
+
format: '{options.report-format}'
|
|
1072
|
+
schema:
|
|
1073
|
+
$ref: '#/components/schemas/ExpandContractProposal'
|
|
1074
|
+
|
|
1026
1075
|
'11':
|
|
1027
1076
|
description: Runtime dependency missing (agent-contracts-runtime).
|
|
1028
1077
|
stderr:
|
|
@@ -1037,10 +1086,13 @@ commandSets:
|
|
|
1037
1086
|
riskLevel: low
|
|
1038
1087
|
requiresConfirmation: false
|
|
1039
1088
|
idempotent: true
|
|
1040
|
-
sideEffects:
|
|
1041
|
-
|
|
1042
|
-
|
|
1089
|
+
sideEffects: [network, file_write]
|
|
1090
|
+
sideEffectNote: >-
|
|
1091
|
+
Network calls to LLM provider when adapter is not mock.
|
|
1092
|
+
Filesystem write when --output or --output-dir is specified.
|
|
1043
1093
|
safeDryRunOption: dry-run
|
|
1094
|
+
expectedDurationMs: 120000
|
|
1095
|
+
retryableExitCodes: [1, 12]
|
|
1044
1096
|
|
|
1045
1097
|
# ── explain ───────────────────────────────────────
|
|
1046
1098
|
explain:
|
|
@@ -1084,11 +1136,38 @@ commandSets:
|
|
|
1084
1136
|
type: boolean
|
|
1085
1137
|
default: false
|
|
1086
1138
|
|
|
1139
|
+
- name: fail-on
|
|
1140
|
+
description: Minimum severity that causes a non-zero exit.
|
|
1141
|
+
valueName: level
|
|
1142
|
+
schema:
|
|
1143
|
+
type: string
|
|
1144
|
+
enum: [warning, error, critical]
|
|
1145
|
+
default: error
|
|
1146
|
+
|
|
1147
|
+
- name: output
|
|
1148
|
+
aliases: [o]
|
|
1149
|
+
description: Write result to a file instead of stdout.
|
|
1150
|
+
valueName: file
|
|
1151
|
+
schema:
|
|
1152
|
+
type: string
|
|
1153
|
+
file:
|
|
1154
|
+
mode: write
|
|
1155
|
+
mediaType: application/json
|
|
1156
|
+
encoding: utf-8
|
|
1157
|
+
|
|
1158
|
+
- name: report-format
|
|
1159
|
+
description: Output format for the explanation report.
|
|
1160
|
+
valueName: fmt
|
|
1161
|
+
schema:
|
|
1162
|
+
type: string
|
|
1163
|
+
enum: [json, text, yaml]
|
|
1164
|
+
default: json
|
|
1165
|
+
|
|
1087
1166
|
exits:
|
|
1088
1167
|
'0':
|
|
1089
1168
|
description: Explanation generated.
|
|
1090
1169
|
stdout:
|
|
1091
|
-
format:
|
|
1170
|
+
format: '{options.report-format}'
|
|
1092
1171
|
schema:
|
|
1093
1172
|
$ref: '#/components/schemas/ExplainResult'
|
|
1094
1173
|
|
|
@@ -1102,6 +1181,13 @@ commandSets:
|
|
|
1102
1181
|
stderr:
|
|
1103
1182
|
format: text
|
|
1104
1183
|
|
|
1184
|
+
'10':
|
|
1185
|
+
description: Completed with blocking findings.
|
|
1186
|
+
stdout:
|
|
1187
|
+
format: '{options.report-format}'
|
|
1188
|
+
schema:
|
|
1189
|
+
$ref: '#/components/schemas/ExplainResult'
|
|
1190
|
+
|
|
1105
1191
|
'11':
|
|
1106
1192
|
description: Runtime dependency missing (agent-contracts-runtime).
|
|
1107
1193
|
stderr:
|
|
@@ -1116,9 +1202,13 @@ commandSets:
|
|
|
1116
1202
|
riskLevel: low
|
|
1117
1203
|
requiresConfirmation: false
|
|
1118
1204
|
idempotent: true
|
|
1119
|
-
sideEffects:
|
|
1120
|
-
|
|
1205
|
+
sideEffects: [network]
|
|
1206
|
+
sideEffectNote: >-
|
|
1207
|
+
Network calls to LLM provider when adapter is not mock.
|
|
1208
|
+
Filesystem write only when --output is specified.
|
|
1121
1209
|
safeDryRunOption: dry-run
|
|
1210
|
+
expectedDurationMs: 120000
|
|
1211
|
+
retryableExitCodes: [1, 12]
|
|
1122
1212
|
|
|
1123
1213
|
components:
|
|
1124
1214
|
schemas:
|
package/dist/cli.js
CHANGED
|
@@ -314,10 +314,11 @@ var init_handoffs = __esm({
|
|
|
314
314
|
recommendation: z.string().optional(),
|
|
315
315
|
confidence: z.number().optional(),
|
|
316
316
|
evidence: z.array(z.object({
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
317
|
+
type: z.string().optional(),
|
|
318
|
+
content: z.string().optional(),
|
|
319
|
+
source: z.string().optional(),
|
|
320
|
+
kind: z.enum(["file", "command", "schema", "diff", "stdout", "stderr", "text"]).optional(),
|
|
321
|
+
location: z.string().optional()
|
|
321
322
|
})).optional(),
|
|
322
323
|
details: z.record(z.string(), z.unknown()).optional()
|
|
323
324
|
})),
|
|
@@ -6089,8 +6090,6 @@ async function runAgentTask(userRequest, taskId, auditConfig, options) {
|
|
|
6089
6090
|
retriesUsed: result.retries_used
|
|
6090
6091
|
};
|
|
6091
6092
|
}
|
|
6092
|
-
|
|
6093
|
-
// src/agents/formatter.ts
|
|
6094
6093
|
function computeExitCode(result, options) {
|
|
6095
6094
|
if (result.dryRun) return 0;
|
|
6096
6095
|
if (result.status !== "success" || !result.data) return 1;
|
|
@@ -6149,6 +6148,35 @@ function formatResultJson(result) {
|
|
|
6149
6148
|
}
|
|
6150
6149
|
return JSON.stringify(result.data, null, 2);
|
|
6151
6150
|
}
|
|
6151
|
+
function formatResultYaml(result) {
|
|
6152
|
+
if (result.dryRun) {
|
|
6153
|
+
return `dryRun: true
|
|
6154
|
+
prompt: |
|
|
6155
|
+
${indent(result.prompt)}`;
|
|
6156
|
+
}
|
|
6157
|
+
if (!result.data) {
|
|
6158
|
+
return `error: ${JSON.stringify(result.errorMessage)}
|
|
6159
|
+
status: ${result.status}`;
|
|
6160
|
+
}
|
|
6161
|
+
return toSimpleYaml(result.data);
|
|
6162
|
+
}
|
|
6163
|
+
function formatResult(result, format) {
|
|
6164
|
+
switch (format) {
|
|
6165
|
+
case "json":
|
|
6166
|
+
return formatResultJson(result);
|
|
6167
|
+
case "yaml":
|
|
6168
|
+
return formatResultYaml(result);
|
|
6169
|
+
case "text":
|
|
6170
|
+
return formatResultText(result);
|
|
6171
|
+
}
|
|
6172
|
+
}
|
|
6173
|
+
async function writeOutput(content, outputPath) {
|
|
6174
|
+
if (outputPath) {
|
|
6175
|
+
await writeFile(outputPath, content + "\n", "utf-8");
|
|
6176
|
+
} else {
|
|
6177
|
+
process.stdout.write(content + "\n");
|
|
6178
|
+
}
|
|
6179
|
+
}
|
|
6152
6180
|
function severityIcon(severity) {
|
|
6153
6181
|
switch (severity) {
|
|
6154
6182
|
case "critical":
|
|
@@ -6161,6 +6189,47 @@ function severityIcon(severity) {
|
|
|
6161
6189
|
return "\u2139";
|
|
6162
6190
|
}
|
|
6163
6191
|
}
|
|
6192
|
+
function indent(text, spaces = 2) {
|
|
6193
|
+
const pad = " ".repeat(spaces);
|
|
6194
|
+
return text.split("\n").map((l) => pad + l).join("\n");
|
|
6195
|
+
}
|
|
6196
|
+
function toSimpleYaml(obj, depth = 0) {
|
|
6197
|
+
const pad = " ".repeat(depth);
|
|
6198
|
+
if (obj === null || obj === void 0) return `${pad}null`;
|
|
6199
|
+
if (typeof obj === "string") {
|
|
6200
|
+
if (obj.includes("\n")) return `|
|
|
6201
|
+
${indent(obj, (depth + 1) * 2)}`;
|
|
6202
|
+
return JSON.stringify(obj);
|
|
6203
|
+
}
|
|
6204
|
+
if (typeof obj === "number" || typeof obj === "boolean") return String(obj);
|
|
6205
|
+
if (Array.isArray(obj)) {
|
|
6206
|
+
if (obj.length === 0) return "[]";
|
|
6207
|
+
return obj.map((item) => {
|
|
6208
|
+
const val = toSimpleYaml(item, depth + 1);
|
|
6209
|
+
if (typeof item === "object" && item !== null) {
|
|
6210
|
+
return `${pad}- ${val.trimStart()}`;
|
|
6211
|
+
}
|
|
6212
|
+
return `${pad}- ${val}`;
|
|
6213
|
+
}).join("\n");
|
|
6214
|
+
}
|
|
6215
|
+
if (typeof obj === "object") {
|
|
6216
|
+
const entries = Object.entries(obj);
|
|
6217
|
+
if (entries.length === 0) return "{}";
|
|
6218
|
+
return entries.map(([k, v]) => {
|
|
6219
|
+
const val = toSimpleYaml(v, depth + 1);
|
|
6220
|
+
if (typeof v === "object" && v !== null && !Array.isArray(v)) {
|
|
6221
|
+
return `${pad}${k}:
|
|
6222
|
+
${val}`;
|
|
6223
|
+
}
|
|
6224
|
+
if (Array.isArray(v) && v.length > 0) {
|
|
6225
|
+
return `${pad}${k}:
|
|
6226
|
+
${val}`;
|
|
6227
|
+
}
|
|
6228
|
+
return `${pad}${k}: ${val}`;
|
|
6229
|
+
}).join("\n");
|
|
6230
|
+
}
|
|
6231
|
+
return String(obj);
|
|
6232
|
+
}
|
|
6164
6233
|
|
|
6165
6234
|
// src/commands/audit.ts
|
|
6166
6235
|
async function commandAudit(config, target, opts) {
|
|
@@ -6180,12 +6249,8 @@ async function commandAudit(config, target, opts) {
|
|
|
6180
6249
|
auditConfig,
|
|
6181
6250
|
auditOpts
|
|
6182
6251
|
);
|
|
6183
|
-
const
|
|
6184
|
-
|
|
6185
|
-
process.stdout.write(formatResultJson(result) + "\n");
|
|
6186
|
-
} else {
|
|
6187
|
-
process.stdout.write(formatResultText(result) + "\n");
|
|
6188
|
-
}
|
|
6252
|
+
const content = formatResult(result, opts.reportFormat ?? "text");
|
|
6253
|
+
await writeOutput(content, opts.output);
|
|
6189
6254
|
const exitCode = computeExitCode(result, auditOpts);
|
|
6190
6255
|
if (exitCode !== 0) process.exit(exitCode);
|
|
6191
6256
|
} catch (err) {
|
|
@@ -6208,7 +6273,8 @@ async function commandProposeExpandContract(config, file, opts) {
|
|
|
6208
6273
|
model: opts.model
|
|
6209
6274
|
};
|
|
6210
6275
|
const auditOpts = {
|
|
6211
|
-
dryRun: opts.dryRun
|
|
6276
|
+
dryRun: opts.dryRun,
|
|
6277
|
+
failOn: opts.failOn
|
|
6212
6278
|
};
|
|
6213
6279
|
try {
|
|
6214
6280
|
const result = await runAgentTask(
|
|
@@ -6217,10 +6283,6 @@ async function commandProposeExpandContract(config, file, opts) {
|
|
|
6217
6283
|
auditConfig,
|
|
6218
6284
|
auditOpts
|
|
6219
6285
|
);
|
|
6220
|
-
if (result.dryRun) {
|
|
6221
|
-
process.stdout.write(formatResultText(result) + "\n");
|
|
6222
|
-
return;
|
|
6223
|
-
}
|
|
6224
6286
|
if (result.data && opts.outputDir && result.data.recommendedActions) {
|
|
6225
6287
|
const outDir = resolve(opts.outputDir);
|
|
6226
6288
|
await mkdir(outDir, { recursive: true });
|
|
@@ -6232,7 +6294,8 @@ async function commandProposeExpandContract(config, file, opts) {
|
|
|
6232
6294
|
}
|
|
6233
6295
|
}
|
|
6234
6296
|
}
|
|
6235
|
-
|
|
6297
|
+
const content = formatResult(result, opts.reportFormat ?? "json");
|
|
6298
|
+
await writeOutput(content, opts.output);
|
|
6236
6299
|
const exitCode = computeExitCode(result, auditOpts);
|
|
6237
6300
|
if (exitCode !== 0) process.exit(exitCode);
|
|
6238
6301
|
} catch (err) {
|
|
@@ -6261,7 +6324,8 @@ async function commandExplain(_config, opts) {
|
|
|
6261
6324
|
model: opts.model
|
|
6262
6325
|
};
|
|
6263
6326
|
const auditOpts = {
|
|
6264
|
-
dryRun: opts.dryRun
|
|
6327
|
+
dryRun: opts.dryRun,
|
|
6328
|
+
failOn: opts.failOn
|
|
6265
6329
|
};
|
|
6266
6330
|
try {
|
|
6267
6331
|
const result = await runAgentTask(
|
|
@@ -6270,11 +6334,10 @@ async function commandExplain(_config, opts) {
|
|
|
6270
6334
|
auditConfig,
|
|
6271
6335
|
auditOpts
|
|
6272
6336
|
);
|
|
6273
|
-
|
|
6274
|
-
|
|
6275
|
-
|
|
6276
|
-
|
|
6277
|
-
}
|
|
6337
|
+
const content = formatResult(result, opts.reportFormat ?? "json");
|
|
6338
|
+
await writeOutput(content, opts.output);
|
|
6339
|
+
const exitCode = computeExitCode(result, auditOpts);
|
|
6340
|
+
if (exitCode !== 0) process.exit(exitCode);
|
|
6278
6341
|
} catch (err) {
|
|
6279
6342
|
const exitCode = err.exitCode;
|
|
6280
6343
|
if (exitCode === EXIT_RUNTIME_MISSING) {
|
|
@@ -6413,23 +6476,32 @@ program.command("deps").description("Analyze and display migration dependency gr
|
|
|
6413
6476
|
const result = await commandDeps(config, { html: opts.html });
|
|
6414
6477
|
if (!result.ok) process.exit(1);
|
|
6415
6478
|
}));
|
|
6416
|
-
program.command("audit [target]").description("Run LLM-based migration safety audit").option("-a, --adapter <name>", "SDK adapter (cursor, claude, openai, gemini, mock)").option("--model <name>", "LLM model override").option("-n, --dry-run", "Output prompt without calling LLM").option("--fail-on <level>", "Minimum severity for non-zero exit (warning, error, critical)", "error").option("--report-format <fmt>", "Output format (text,
|
|
6479
|
+
program.command("audit [target]").description("Run LLM-based migration safety audit").option("-a, --adapter <name>", "SDK adapter (cursor, claude, openai, gemini, mock)").option("--model <name>", "LLM model override").option("-n, --dry-run", "Output prompt without calling LLM").option("--fail-on <level>", "Minimum severity for non-zero exit (warning, error, critical)", "error").option("-o, --output <file>", "Write result to a file instead of stdout").option("--report-format <fmt>", "Output format (json, text, yaml)", "text").action((target, opts) => run(async () => {
|
|
6417
6480
|
const config = await loadConfig();
|
|
6418
6481
|
await commandAudit(config, target, {
|
|
6419
6482
|
adapter: opts.adapter,
|
|
6420
6483
|
model: opts.model,
|
|
6421
6484
|
dryRun: opts.dryRun,
|
|
6422
6485
|
failOn: opts.failOn,
|
|
6486
|
+
output: opts.output,
|
|
6423
6487
|
reportFormat: opts.reportFormat
|
|
6424
6488
|
});
|
|
6425
6489
|
}));
|
|
6426
|
-
program.command("propose-expand-contract <file>").description("Propose expand/contract migration group from unsafe DDL").option("-a, --adapter <name>", "SDK adapter (cursor, claude, openai, gemini, mock)").option("--model <name>", "LLM model override").option("-n, --dry-run", "Output prompt without calling LLM").option("--output-dir <dir>", "Directory to write proposed phase files").action((file, opts) => run(async () => {
|
|
6490
|
+
program.command("propose-expand-contract <file>").description("Propose expand/contract migration group from unsafe DDL").option("-a, --adapter <name>", "SDK adapter (cursor, claude, openai, gemini, mock)").option("--model <name>", "LLM model override").option("-n, --dry-run", "Output prompt without calling LLM").option("--fail-on <level>", "Minimum severity for non-zero exit (warning, error, critical)", "error").option("-o, --output <file>", "Write result to a file instead of stdout").option("--report-format <fmt>", "Output format (json, text, yaml)", "json").option("--output-dir <dir>", "Directory to write proposed phase files").action((file, opts) => run(async () => {
|
|
6427
6491
|
const config = await loadConfig();
|
|
6428
|
-
await commandProposeExpandContract(config, file,
|
|
6492
|
+
await commandProposeExpandContract(config, file, {
|
|
6493
|
+
...opts,
|
|
6494
|
+
failOn: opts.failOn,
|
|
6495
|
+
reportFormat: opts.reportFormat
|
|
6496
|
+
});
|
|
6429
6497
|
}));
|
|
6430
|
-
program.command("explain").description("Explain command output in human-readable form using LLM").option("-a, --adapter <name>", "SDK adapter (cursor, claude, openai, gemini, mock)").option("--model <name>", "LLM model override").option("-n, --dry-run", "Output prompt without calling LLM").action((opts) => run(async () => {
|
|
6498
|
+
program.command("explain").description("Explain command output in human-readable form using LLM").option("-a, --adapter <name>", "SDK adapter (cursor, claude, openai, gemini, mock)").option("--model <name>", "LLM model override").option("-n, --dry-run", "Output prompt without calling LLM").option("--fail-on <level>", "Minimum severity for non-zero exit (warning, error, critical)", "error").option("-o, --output <file>", "Write result to a file instead of stdout").option("--report-format <fmt>", "Output format (json, text, yaml)", "json").action((opts) => run(async () => {
|
|
6431
6499
|
const config = await loadConfig();
|
|
6432
|
-
await commandExplain(config,
|
|
6500
|
+
await commandExplain(config, {
|
|
6501
|
+
...opts,
|
|
6502
|
+
failOn: opts.failOn,
|
|
6503
|
+
reportFormat: opts.reportFormat
|
|
6504
|
+
});
|
|
6433
6505
|
}));
|
|
6434
6506
|
program.parse();
|
|
6435
6507
|
//# sourceMappingURL=cli.js.map
|