@refrainai/cli 0.4.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/dist/ai-model-FM6GWCID.js +37 -0
- package/dist/ai-model-FM6GWCID.js.map +1 -0
- package/dist/chunk-2BVDAJZT.js +236 -0
- package/dist/chunk-2BVDAJZT.js.map +1 -0
- package/dist/chunk-2H7UOFLK.js +11 -0
- package/dist/chunk-2H7UOFLK.js.map +1 -0
- package/dist/chunk-7UCVPKD4.js +902 -0
- package/dist/chunk-7UCVPKD4.js.map +1 -0
- package/dist/chunk-AG3CFMYU.js +36 -0
- package/dist/chunk-AG3CFMYU.js.map +1 -0
- package/dist/chunk-CLYJHKPY.js +1131 -0
- package/dist/chunk-CLYJHKPY.js.map +1 -0
- package/dist/chunk-D5SI2PHK.js +74 -0
- package/dist/chunk-D5SI2PHK.js.map +1 -0
- package/dist/chunk-DJVUITRB.js +9084 -0
- package/dist/chunk-DJVUITRB.js.map +1 -0
- package/dist/chunk-H47NWH7N.js +4427 -0
- package/dist/chunk-H47NWH7N.js.map +1 -0
- package/dist/chunk-HQDXLWAY.js +109 -0
- package/dist/chunk-HQDXLWAY.js.map +1 -0
- package/dist/chunk-IGFCYKHC.js +1974 -0
- package/dist/chunk-IGFCYKHC.js.map +1 -0
- package/dist/chunk-RT664YIO.js +245 -0
- package/dist/chunk-RT664YIO.js.map +1 -0
- package/dist/chunk-RYIJPYM3.js +164 -0
- package/dist/chunk-RYIJPYM3.js.map +1 -0
- package/dist/chunk-TDSM3UXI.js +40 -0
- package/dist/chunk-TDSM3UXI.js.map +1 -0
- package/dist/chunk-UGPXCQY3.js +778 -0
- package/dist/chunk-UGPXCQY3.js.map +1 -0
- package/dist/chunk-VPK2MQAZ.js +589 -0
- package/dist/chunk-VPK2MQAZ.js.map +1 -0
- package/dist/chunk-WEYR56ZN.js +953 -0
- package/dist/chunk-WEYR56ZN.js.map +1 -0
- package/dist/chunk-XMFCXPYU.js +275 -0
- package/dist/chunk-XMFCXPYU.js.map +1 -0
- package/dist/chunk-Z33FCOTZ.js +251 -0
- package/dist/chunk-Z33FCOTZ.js.map +1 -0
- package/dist/cli.js +59 -0
- package/dist/cli.js.map +1 -0
- package/dist/compose-MTSIJY5D.js +547 -0
- package/dist/compose-MTSIJY5D.js.map +1 -0
- package/dist/config-ZSUNCFXR.js +9 -0
- package/dist/config-ZSUNCFXR.js.map +1 -0
- package/dist/fix-runbook-ZSBOTLC2.js +294 -0
- package/dist/fix-runbook-ZSBOTLC2.js.map +1 -0
- package/dist/google-sheets-DRWIVEVC.js +482 -0
- package/dist/google-sheets-DRWIVEVC.js.map +1 -0
- package/dist/registry-LZLYTNDJ.js +17 -0
- package/dist/registry-LZLYTNDJ.js.map +1 -0
- package/dist/runbook-data-helpers-KRR2SH76.js +16 -0
- package/dist/runbook-data-helpers-KRR2SH76.js.map +1 -0
- package/dist/runbook-executor-K7T6RJWJ.js +1480 -0
- package/dist/runbook-executor-K7T6RJWJ.js.map +1 -0
- package/dist/runbook-generator-MPXJBQ5N.js +800 -0
- package/dist/runbook-generator-MPXJBQ5N.js.map +1 -0
- package/dist/runbook-schema-3T6TP3JJ.js +35 -0
- package/dist/runbook-schema-3T6TP3JJ.js.map +1 -0
- package/dist/runbook-store-G5GUOWRR.js +11 -0
- package/dist/runbook-store-G5GUOWRR.js.map +1 -0
- package/dist/schema-5G6UQSPT.js +91 -0
- package/dist/schema-5G6UQSPT.js.map +1 -0
- package/dist/server-AG3LXQBI.js +8778 -0
- package/dist/server-AG3LXQBI.js.map +1 -0
- package/dist/tenant-ai-config-QPFEJUVJ.js +14 -0
- package/dist/tenant-ai-config-QPFEJUVJ.js.map +1 -0
- package/dist/yaml-patcher-VGUS2JGH.js +15 -0
- package/dist/yaml-patcher-VGUS2JGH.js.map +1 -0
- package/package.json +37 -0
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
checkHelpFlag,
|
|
4
|
+
parseModelConfig
|
|
5
|
+
} from "./chunk-2BVDAJZT.js";
|
|
6
|
+
import {
|
|
7
|
+
generatePatch
|
|
8
|
+
} from "./chunk-RYIJPYM3.js";
|
|
9
|
+
import "./chunk-D5SI2PHK.js";
|
|
10
|
+
import {
|
|
11
|
+
cancel,
|
|
12
|
+
initLocale,
|
|
13
|
+
intro,
|
|
14
|
+
log,
|
|
15
|
+
outro,
|
|
16
|
+
promptConfirm,
|
|
17
|
+
promptSelect,
|
|
18
|
+
t,
|
|
19
|
+
tf
|
|
20
|
+
} from "./chunk-7UCVPKD4.js";
|
|
21
|
+
import {
|
|
22
|
+
initModel
|
|
23
|
+
} from "./chunk-UGPXCQY3.js";
|
|
24
|
+
import "./chunk-RT664YIO.js";
|
|
25
|
+
import "./chunk-2H7UOFLK.js";
|
|
26
|
+
|
|
27
|
+
// src/fix-runbook/index.ts
|
|
28
|
+
import { readFile, writeFile } from "fs/promises";
|
|
29
|
+
|
|
30
|
+
// src/fix-runbook/config.ts
|
|
31
|
+
import { parseArgs as nodeParseArgs } from "util";
|
|
32
|
+
import { existsSync } from "fs";
|
|
33
|
+
async function parseArgs() {
|
|
34
|
+
checkHelpFlag("fix-runbook");
|
|
35
|
+
const { values } = nodeParseArgs({
|
|
36
|
+
options: {
|
|
37
|
+
runbook: { type: "string" },
|
|
38
|
+
report: { type: "string" },
|
|
39
|
+
model: { type: "string" },
|
|
40
|
+
"model-provider": { type: "string" },
|
|
41
|
+
"model-base-url": { type: "string" },
|
|
42
|
+
"model-review": { type: "string" },
|
|
43
|
+
locale: { type: "string" }
|
|
44
|
+
},
|
|
45
|
+
strict: true
|
|
46
|
+
});
|
|
47
|
+
initLocale(values.locale);
|
|
48
|
+
if (!values.runbook) {
|
|
49
|
+
throw new Error(t("cli.runbookRequired"));
|
|
50
|
+
}
|
|
51
|
+
if (!values.report) {
|
|
52
|
+
throw new Error(t("cli.reportRequired"));
|
|
53
|
+
}
|
|
54
|
+
if (!existsSync(values.runbook)) {
|
|
55
|
+
throw new Error(`Runbook file not found: ${values.runbook}`);
|
|
56
|
+
}
|
|
57
|
+
if (!existsSync(values.report)) {
|
|
58
|
+
throw new Error(`Report file not found: ${values.report}`);
|
|
59
|
+
}
|
|
60
|
+
const aiModelConfig = parseModelConfig(values);
|
|
61
|
+
return {
|
|
62
|
+
runbookPath: values.runbook,
|
|
63
|
+
reportPath: values.report,
|
|
64
|
+
aiModelConfig
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// src/fix-runbook/report-parser.ts
|
|
69
|
+
function extractSuggestions(reportContent) {
|
|
70
|
+
const suggestions = extractFromAiAgentSummary(reportContent);
|
|
71
|
+
if (suggestions.length > 0) return suggestions;
|
|
72
|
+
return extractFromDiagnostics(reportContent);
|
|
73
|
+
}
|
|
74
|
+
function extractFromAiAgentSummary(content) {
|
|
75
|
+
const summaryStart = content.indexOf("## AI Agent Summary");
|
|
76
|
+
if (summaryStart === -1) return [];
|
|
77
|
+
const afterSummary = content.slice(summaryStart + "## AI Agent Summary".length);
|
|
78
|
+
const nextSection = afterSummary.search(/\n## [^#]/);
|
|
79
|
+
const summaryContent = nextSection === -1 ? afterSummary : afterSummary.slice(0, nextSection);
|
|
80
|
+
const suggestions = [];
|
|
81
|
+
const stepPattern = /#### Step #(\d+): (.+)/g;
|
|
82
|
+
let match;
|
|
83
|
+
const stepPositions = [];
|
|
84
|
+
while ((match = stepPattern.exec(summaryContent)) !== null) {
|
|
85
|
+
stepPositions.push({
|
|
86
|
+
ordinal: parseInt(match[1], 10),
|
|
87
|
+
description: match[2].trim(),
|
|
88
|
+
start: match.index + match[0].length
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
for (let i = 0; i < stepPositions.length; i++) {
|
|
92
|
+
const pos = stepPositions[i];
|
|
93
|
+
const end = i + 1 < stepPositions.length ? stepPositions[i + 1].start : summaryContent.length;
|
|
94
|
+
const stepContent = summaryContent.slice(pos.start, end);
|
|
95
|
+
const suggestion = {
|
|
96
|
+
stepOrdinal: pos.ordinal,
|
|
97
|
+
description: pos.description,
|
|
98
|
+
error: extractField(stepContent, "\u30A8\u30E9\u30FC") ?? "Unknown",
|
|
99
|
+
category: extractField(stepContent, "\u5206\u985E")?.replace(/`/g, ""),
|
|
100
|
+
recoveryHint: extractField(stepContent, "\u63A8\u5968\u5BFE\u5FDC"),
|
|
101
|
+
yamlFix: extractField(stepContent, "YAML \u4FEE\u6B63\u63D0\u6848"),
|
|
102
|
+
contextFix: extractField(stepContent, "Context \u4FEE\u6B63\u63D0\u6848"),
|
|
103
|
+
suggestedStrategy: extractField(stepContent, "\u63A8\u5968\u6226\u7565"),
|
|
104
|
+
currentSelector: extractCodeBlock(stepContent, "\u73FE\u5728\u306E\u30BB\u30EC\u30AF\u30BF"),
|
|
105
|
+
lastSnapshotPreview: extractCodeBlock(stepContent, "\u6700\u7D42\u30B9\u30CA\u30C3\u30D7\u30B7\u30E7\u30C3\u30C8")
|
|
106
|
+
};
|
|
107
|
+
suggestions.push(suggestion);
|
|
108
|
+
}
|
|
109
|
+
return suggestions;
|
|
110
|
+
}
|
|
111
|
+
function extractFromDiagnostics(content) {
|
|
112
|
+
const diagStart = content.indexOf("## Failed Step Diagnostics");
|
|
113
|
+
if (diagStart === -1) return [];
|
|
114
|
+
const afterDiag = content.slice(diagStart);
|
|
115
|
+
const nextSection = afterDiag.search(/\n## [^#]/);
|
|
116
|
+
const diagContent = nextSection === -1 ? afterDiag : afterDiag.slice(0, nextSection);
|
|
117
|
+
const stepPattern = /### Step #(\d+) — (?:Diagnostics|Error Info|Retry Details)/g;
|
|
118
|
+
let match;
|
|
119
|
+
const ordinalContents = /* @__PURE__ */ new Map();
|
|
120
|
+
while ((match = stepPattern.exec(diagContent)) !== null) {
|
|
121
|
+
const ordinal = parseInt(match[1], 10);
|
|
122
|
+
const sectionStart = match.index + match[0].length;
|
|
123
|
+
const rest = diagContent.slice(sectionStart);
|
|
124
|
+
const nextStep = rest.search(/\n### Step #/);
|
|
125
|
+
const sectionContent = nextStep === -1 ? rest : rest.slice(0, nextStep);
|
|
126
|
+
const existing = ordinalContents.get(ordinal) ?? "";
|
|
127
|
+
ordinalContents.set(ordinal, existing + "\n" + sectionContent);
|
|
128
|
+
}
|
|
129
|
+
const suggestions = [];
|
|
130
|
+
for (const [ordinal, stepContent] of ordinalContents) {
|
|
131
|
+
const recoveryHint = extractField(stepContent, "Recovery Hint");
|
|
132
|
+
const error = extractField(stepContent, "Error") ?? "Unknown";
|
|
133
|
+
const stepResultPattern = new RegExp(`${ordinal}\\. \\[FAILED\\] (.+?) \\(`);
|
|
134
|
+
const descMatch = content.match(stepResultPattern);
|
|
135
|
+
suggestions.push({
|
|
136
|
+
stepOrdinal: ordinal,
|
|
137
|
+
description: descMatch?.[1] ?? `Step #${ordinal}`,
|
|
138
|
+
error,
|
|
139
|
+
recoveryHint,
|
|
140
|
+
currentSelector: extractCodeBlock(stepContent, "Step Action")
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
return suggestions;
|
|
144
|
+
}
|
|
145
|
+
function extractField(content, label) {
|
|
146
|
+
const listPattern = new RegExp(`- \\*\\*${escapeRegex(label)}\\*\\*: (.+?)(?:
|
|
147
|
+
|$)`);
|
|
148
|
+
const listMatch = content.match(listPattern);
|
|
149
|
+
if (listMatch) return listMatch[1].trim();
|
|
150
|
+
const boldPattern = new RegExp(`\\*\\*${escapeRegex(label)}\\*\\*: (.+?)(?:
|
|
151
|
+
|$)`);
|
|
152
|
+
const boldMatch = content.match(boldPattern);
|
|
153
|
+
return boldMatch?.[1]?.trim();
|
|
154
|
+
}
|
|
155
|
+
function extractCodeBlock(content, label) {
|
|
156
|
+
const labelIdx = content.indexOf(`**${label}**`);
|
|
157
|
+
if (labelIdx === -1) return void 0;
|
|
158
|
+
const afterLabel = content.slice(labelIdx);
|
|
159
|
+
const codeStart = afterLabel.indexOf("```");
|
|
160
|
+
if (codeStart === -1) return void 0;
|
|
161
|
+
const codeContentStart = afterLabel.indexOf("\n", codeStart) + 1;
|
|
162
|
+
const codeEnd = afterLabel.indexOf("```", codeContentStart);
|
|
163
|
+
if (codeEnd === -1) return void 0;
|
|
164
|
+
return afterLabel.slice(codeContentStart, codeEnd).trim();
|
|
165
|
+
}
|
|
166
|
+
function escapeRegex(str) {
|
|
167
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// src/fix-runbook/index.ts
|
|
171
|
+
async function main() {
|
|
172
|
+
const config = await parseArgs();
|
|
173
|
+
await initModel(config.aiModelConfig);
|
|
174
|
+
intro("fix-runbook");
|
|
175
|
+
log.info(`Runbook: ${config.runbookPath}`);
|
|
176
|
+
log.info(`Report: ${config.reportPath}`);
|
|
177
|
+
const reportContent = await readFile(config.reportPath, "utf-8");
|
|
178
|
+
const suggestions = extractSuggestions(reportContent);
|
|
179
|
+
if (suggestions.length === 0) {
|
|
180
|
+
log.warn(t("fix.noSuggestions"));
|
|
181
|
+
log.info(t("fix.noSuggestionsHint"));
|
|
182
|
+
outro(t("fix.complete"));
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
log.info(tf("fix.suggestionCount", { count: suggestions.length }));
|
|
186
|
+
const originalYaml = await readFile(config.runbookPath, "utf-8");
|
|
187
|
+
const appliedSuggestions = [];
|
|
188
|
+
let currentYaml = originalYaml;
|
|
189
|
+
for (const suggestion of suggestions) {
|
|
190
|
+
log.step(`Step #${suggestion.stepOrdinal}: ${suggestion.description}`);
|
|
191
|
+
log.info(tf("fix.errorLabel", { error: suggestion.error }));
|
|
192
|
+
if (suggestion.category) {
|
|
193
|
+
log.info(tf("fix.categoryLabel", { category: suggestion.category }));
|
|
194
|
+
}
|
|
195
|
+
if (suggestion.yamlFix) {
|
|
196
|
+
log.info(tf("fix.yamlFixLabel", { fix: suggestion.yamlFix }));
|
|
197
|
+
}
|
|
198
|
+
if (suggestion.contextFix) {
|
|
199
|
+
log.info(tf("fix.contextFixLabel", { fix: suggestion.contextFix }));
|
|
200
|
+
}
|
|
201
|
+
if (suggestion.recoveryHint) {
|
|
202
|
+
log.info(tf("fix.recoveryHintLabel", { hint: suggestion.recoveryHint }));
|
|
203
|
+
}
|
|
204
|
+
if (!suggestion.yamlFix) {
|
|
205
|
+
log.warn(t("fix.noYamlFix"));
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
const action = await promptSelect(t("fix.applyPrompt"), [
|
|
209
|
+
{ value: "apply", label: t("fix.applyLabel"), hint: t("fix.applyHint") },
|
|
210
|
+
{ value: "skip", label: t("fix.skipLabel"), hint: t("fix.skipHint") },
|
|
211
|
+
{ value: "abort", label: t("fix.abortLabel"), hint: t("fix.abortHint") }
|
|
212
|
+
]);
|
|
213
|
+
if (action === "abort") {
|
|
214
|
+
break;
|
|
215
|
+
}
|
|
216
|
+
if (action === "apply") {
|
|
217
|
+
const patchResult = await generatePatch(currentYaml, suggestion);
|
|
218
|
+
if (patchResult.success) {
|
|
219
|
+
log.success(t("fix.patchGenerated"));
|
|
220
|
+
showDiff(currentYaml, patchResult.patchedYaml);
|
|
221
|
+
const confirmed = await promptConfirm(t("fix.confirmApply"));
|
|
222
|
+
if (confirmed) {
|
|
223
|
+
currentYaml = patchResult.patchedYaml;
|
|
224
|
+
appliedSuggestions.push(suggestion);
|
|
225
|
+
log.success(tf("fix.applied", { ordinal: suggestion.stepOrdinal }));
|
|
226
|
+
} else {
|
|
227
|
+
log.info(t("fix.skippedMsg"));
|
|
228
|
+
}
|
|
229
|
+
} else {
|
|
230
|
+
log.error(tf("fix.patchFailed", { error: patchResult.error ?? "unknown" }));
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
if (appliedSuggestions.length > 0) {
|
|
235
|
+
const shouldWrite = await promptConfirm(
|
|
236
|
+
tf("fix.writePrompt", { count: appliedSuggestions.length, path: config.runbookPath })
|
|
237
|
+
);
|
|
238
|
+
if (shouldWrite) {
|
|
239
|
+
await writeFile(config.runbookPath, currentYaml, "utf-8");
|
|
240
|
+
log.success(tf("fix.writeSuccess", { path: config.runbookPath }));
|
|
241
|
+
log.info(`
|
|
242
|
+
${t("fix.verifyCommand")}`);
|
|
243
|
+
log.info(` pnpm execute -- --runbook ${config.runbookPath} --self-heal`);
|
|
244
|
+
} else {
|
|
245
|
+
log.info(t("fix.writeCancelled"));
|
|
246
|
+
}
|
|
247
|
+
} else {
|
|
248
|
+
log.info(t("fix.noChanges"));
|
|
249
|
+
}
|
|
250
|
+
outro(t("fix.complete"));
|
|
251
|
+
}
|
|
252
|
+
function showDiff(original, patched) {
|
|
253
|
+
const origLines = original.split("\n");
|
|
254
|
+
const patchLines = patched.split("\n");
|
|
255
|
+
const maxLines = Math.max(origLines.length, patchLines.length);
|
|
256
|
+
const diffLines = [];
|
|
257
|
+
let contextBefore = 0;
|
|
258
|
+
for (let i = 0; i < maxLines; i++) {
|
|
259
|
+
const orig = origLines[i];
|
|
260
|
+
const patch = patchLines[i];
|
|
261
|
+
if (orig !== patch) {
|
|
262
|
+
if (contextBefore === 0) {
|
|
263
|
+
for (let j = Math.max(0, i - 2); j < i; j++) {
|
|
264
|
+
if (origLines[j] !== void 0) {
|
|
265
|
+
diffLines.push(` ${origLines[j]}`);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
if (orig !== void 0) {
|
|
270
|
+
diffLines.push(`- ${orig}`);
|
|
271
|
+
}
|
|
272
|
+
if (patch !== void 0) {
|
|
273
|
+
diffLines.push(`+ ${patch}`);
|
|
274
|
+
}
|
|
275
|
+
contextBefore = 3;
|
|
276
|
+
} else if (contextBefore > 0) {
|
|
277
|
+
diffLines.push(` ${orig}`);
|
|
278
|
+
contextBefore--;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
if (diffLines.length > 0) {
|
|
282
|
+
log.info(diffLines.join("\n"));
|
|
283
|
+
} else {
|
|
284
|
+
log.info(t("fix.noDiff"));
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
main().catch((error) => {
|
|
288
|
+
cancel(`Fatal error: ${error instanceof Error ? error.message : String(error)}`);
|
|
289
|
+
if (error instanceof Error && error.stack) {
|
|
290
|
+
console.error(error.stack);
|
|
291
|
+
}
|
|
292
|
+
process.exit(1);
|
|
293
|
+
});
|
|
294
|
+
//# sourceMappingURL=fix-runbook-ZSBOTLC2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/fix-runbook/index.ts","../../../src/fix-runbook/config.ts","../../../src/fix-runbook/report-parser.ts"],"sourcesContent":["/**\n * fix-runbook CLI — レポートから修正提案を抽出し、runbook YAML に適用する\n *\n * Usage:\n * pnpm fix-runbook -- \\\n * --runbook ./runbooks/login-flow.yaml \\\n * --report ./runbooks/login-flow-report.md\n */\n\nimport { readFile, writeFile } from \"node:fs/promises\";\nimport { parseArgs } from \"./config\";\nimport { initModel } from \"../harness/ai-model\";\nimport { extractSuggestions, type ExtractedSuggestion } from \"./report-parser\";\nimport { generatePatch } from \"./yaml-patcher\";\nimport { intro, outro, log, cancel, promptSelect, promptConfirm } from \"../cli/prompts\";\nimport { t, tf } from \"../i18n\";\n\nasync function main() {\n const config = await parseArgs();\n await initModel(config.aiModelConfig);\n\n intro(\"fix-runbook\");\n log.info(`Runbook: ${config.runbookPath}`);\n log.info(`Report: ${config.reportPath}`);\n\n // レポートからAI Agent Summaryを読み取り、修正提案を抽出\n const reportContent = await readFile(config.reportPath, \"utf-8\");\n const suggestions = extractSuggestions(reportContent);\n\n if (suggestions.length === 0) {\n log.warn(t(\"fix.noSuggestions\"));\n log.info(t(\"fix.noSuggestionsHint\"));\n outro(t(\"fix.complete\"));\n return;\n }\n\n log.info(tf(\"fix.suggestionCount\", { count: suggestions.length }));\n\n // runbook YAML を読み込み\n const originalYaml = await readFile(config.runbookPath, \"utf-8\");\n\n // 各提案を対話的に処理\n const appliedSuggestions: ExtractedSuggestion[] = [];\n let currentYaml = originalYaml;\n\n for (const suggestion of suggestions) {\n log.step(`Step #${suggestion.stepOrdinal}: ${suggestion.description}`);\n log.info(tf(\"fix.errorLabel\", { error: suggestion.error }));\n if (suggestion.category) {\n log.info(tf(\"fix.categoryLabel\", { category: suggestion.category }));\n }\n if (suggestion.yamlFix) {\n log.info(tf(\"fix.yamlFixLabel\", { fix: suggestion.yamlFix }));\n }\n if (suggestion.contextFix) {\n log.info(tf(\"fix.contextFixLabel\", { fix: suggestion.contextFix }));\n }\n if (suggestion.recoveryHint) {\n log.info(tf(\"fix.recoveryHintLabel\", { hint: suggestion.recoveryHint }));\n }\n\n if (!suggestion.yamlFix) {\n log.warn(t(\"fix.noYamlFix\"));\n continue;\n }\n\n const action = await promptSelect(t(\"fix.applyPrompt\"), [\n { value: \"apply\", label: t(\"fix.applyLabel\"), hint: t(\"fix.applyHint\") },\n { value: \"skip\", label: t(\"fix.skipLabel\"), hint: t(\"fix.skipHint\") },\n { value: \"abort\", label: t(\"fix.abortLabel\"), hint: t(\"fix.abortHint\") },\n ]);\n\n if (action === \"abort\") {\n break;\n }\n\n if (action === \"apply\") {\n const patchResult = await generatePatch(currentYaml, suggestion);\n if (patchResult.success) {\n log.success(t(\"fix.patchGenerated\"));\n showDiff(currentYaml, patchResult.patchedYaml);\n\n const confirmed = await promptConfirm(t(\"fix.confirmApply\"));\n if (confirmed) {\n currentYaml = patchResult.patchedYaml;\n appliedSuggestions.push(suggestion);\n log.success(tf(\"fix.applied\", { ordinal: suggestion.stepOrdinal }));\n } else {\n log.info(t(\"fix.skippedMsg\"));\n }\n } else {\n log.error(tf(\"fix.patchFailed\", { error: patchResult.error ?? \"unknown\" }));\n }\n }\n }\n\n // 変更があればファイルに書き込み\n if (appliedSuggestions.length > 0) {\n const shouldWrite = await promptConfirm(\n tf(\"fix.writePrompt\", { count: appliedSuggestions.length, path: config.runbookPath }),\n );\n\n if (shouldWrite) {\n await writeFile(config.runbookPath, currentYaml, \"utf-8\");\n log.success(tf(\"fix.writeSuccess\", { path: config.runbookPath }));\n\n log.info(`\\n${t(\"fix.verifyCommand\")}`);\n log.info(` pnpm execute -- --runbook ${config.runbookPath} --self-heal`);\n } else {\n log.info(t(\"fix.writeCancelled\"));\n }\n } else {\n log.info(t(\"fix.noChanges\"));\n }\n\n outro(t(\"fix.complete\"));\n}\n\nfunction showDiff(original: string, patched: string): void {\n const origLines = original.split(\"\\n\");\n const patchLines = patched.split(\"\\n\");\n\n // 簡易差分表示: 変更のあった行を +- で表示\n const maxLines = Math.max(origLines.length, patchLines.length);\n const diffLines: string[] = [];\n let contextBefore = 0;\n\n for (let i = 0; i < maxLines; i++) {\n const orig = origLines[i];\n const patch = patchLines[i];\n\n if (orig !== patch) {\n // 変更前のコンテキスト行(最大2行)\n if (contextBefore === 0) {\n for (let j = Math.max(0, i - 2); j < i; j++) {\n if (origLines[j] !== undefined) {\n diffLines.push(` ${origLines[j]}`);\n }\n }\n }\n if (orig !== undefined) {\n diffLines.push(`- ${orig}`);\n }\n if (patch !== undefined) {\n diffLines.push(`+ ${patch}`);\n }\n contextBefore = 3;\n } else if (contextBefore > 0) {\n diffLines.push(` ${orig}`);\n contextBefore--;\n }\n }\n\n if (diffLines.length > 0) {\n log.info(diffLines.join(\"\\n\"));\n } else {\n log.info(t(\"fix.noDiff\"));\n }\n}\n\nmain().catch((error) => {\n cancel(`Fatal error: ${error instanceof Error ? error.message : String(error)}`);\n if (error instanceof Error && error.stack) {\n console.error(error.stack);\n }\n process.exit(1);\n});\n","/**\n * apply-fix CLI 引数パース\n */\n\nimport { parseArgs as nodeParseArgs } from \"node:util\";\nimport { existsSync } from \"node:fs\";\nimport { t, initLocale } from \"../i18n\";\nimport type { AIModelConfig } from \"../harness/ai-model\";\nimport { parseModelConfig } from \"../cli/config-helpers\";\nimport { checkHelpFlag } from \"../cli/help\";\n\nexport interface ApplyFixConfig {\n runbookPath: string;\n reportPath: string;\n /** AIモデル設定 */\n aiModelConfig: AIModelConfig;\n}\n\nexport async function parseArgs(): Promise<ApplyFixConfig> {\n checkHelpFlag(\"fix-runbook\");\n const { values } = nodeParseArgs({\n options: {\n runbook: { type: \"string\" },\n report: { type: \"string\" },\n model: { type: \"string\" },\n \"model-provider\": { type: \"string\" },\n \"model-base-url\": { type: \"string\" },\n \"model-review\": { type: \"string\" },\n locale: { type: \"string\" },\n },\n strict: true,\n });\n\n initLocale(values.locale);\n\n if (!values.runbook) {\n throw new Error(t(\"cli.runbookRequired\"));\n }\n if (!values.report) {\n throw new Error(t(\"cli.reportRequired\"));\n }\n\n if (!existsSync(values.runbook)) {\n throw new Error(`Runbook file not found: ${values.runbook}`);\n }\n if (!existsSync(values.report)) {\n throw new Error(`Report file not found: ${values.report}`);\n }\n\n const aiModelConfig = parseModelConfig(values);\n\n return {\n runbookPath: values.runbook,\n reportPath: values.report,\n aiModelConfig,\n };\n}\n","/**\n * report-parser — レポート Markdown から修正提案を抽出する\n *\n * AI Agent Summary セクションをパースし、各失敗ステップの修正情報を抽出。\n * フォールバックとして Failed Step Diagnostics セクションからも情報を取得。\n */\n\nexport interface ExtractedSuggestion {\n stepOrdinal: number;\n description: string;\n error: string;\n category?: string;\n recoveryHint?: string;\n currentSelector?: string;\n yamlFix?: string;\n contextFix?: string;\n suggestedStrategy?: string;\n lastSnapshotPreview?: string;\n}\n\n/**\n * レポート Markdown から修正提案を抽出する。\n * AI Agent Summary セクションを優先的にパースし、存在しない場合は\n * Failed Step Diagnostics から情報を抽出する。\n */\nexport function extractSuggestions(reportContent: string): ExtractedSuggestion[] {\n const suggestions = extractFromAiAgentSummary(reportContent);\n if (suggestions.length > 0) return suggestions;\n\n // フォールバック: Failed Step Diagnostics から抽出\n return extractFromDiagnostics(reportContent);\n}\n\n/**\n * AI Agent Summary セクションから修正提案を抽出する。\n */\nfunction extractFromAiAgentSummary(content: string): ExtractedSuggestion[] {\n const summaryStart = content.indexOf(\"## AI Agent Summary\");\n if (summaryStart === -1) return [];\n\n // セクション終端を探す(次の ## まで)\n const afterSummary = content.slice(summaryStart + \"## AI Agent Summary\".length);\n const nextSection = afterSummary.search(/\\n## [^#]/);\n const summaryContent = nextSection === -1 ? afterSummary : afterSummary.slice(0, nextSection);\n\n const suggestions: ExtractedSuggestion[] = [];\n\n // #### Step #N: description パターンで各ステップを分割\n const stepPattern = /#### Step #(\\d+): (.+)/g;\n let match: RegExpExecArray | null;\n const stepPositions: { ordinal: number; description: string; start: number }[] = [];\n\n while ((match = stepPattern.exec(summaryContent)) !== null) {\n stepPositions.push({\n ordinal: parseInt(match[1], 10),\n description: match[2].trim(),\n start: match.index + match[0].length,\n });\n }\n\n for (let i = 0; i < stepPositions.length; i++) {\n const pos = stepPositions[i];\n const end = i + 1 < stepPositions.length ? stepPositions[i + 1].start : summaryContent.length;\n const stepContent = summaryContent.slice(pos.start, end);\n\n const suggestion: ExtractedSuggestion = {\n stepOrdinal: pos.ordinal,\n description: pos.description,\n error: extractField(stepContent, \"エラー\") ?? \"Unknown\",\n category: extractField(stepContent, \"分類\")?.replace(/`/g, \"\"),\n recoveryHint: extractField(stepContent, \"推奨対応\"),\n yamlFix: extractField(stepContent, \"YAML 修正提案\"),\n contextFix: extractField(stepContent, \"Context 修正提案\"),\n suggestedStrategy: extractField(stepContent, \"推奨戦略\"),\n currentSelector: extractCodeBlock(stepContent, \"現在のセレクタ\"),\n lastSnapshotPreview: extractCodeBlock(stepContent, \"最終スナップショット\"),\n };\n\n suggestions.push(suggestion);\n }\n\n return suggestions;\n}\n\n/**\n * Failed Step Diagnostics セクションから基本情報を抽出する(フォールバック)。\n */\nfunction extractFromDiagnostics(content: string): ExtractedSuggestion[] {\n const diagStart = content.indexOf(\"## Failed Step Diagnostics\");\n if (diagStart === -1) return [];\n\n const afterDiag = content.slice(diagStart);\n const nextSection = afterDiag.search(/\\n## [^#]/);\n const diagContent = nextSection === -1 ? afterDiag : afterDiag.slice(0, nextSection);\n\n // 同一 ordinal の複数セクション(Retry Details + Diagnostics + Error Info)を統合\n const stepPattern = /### Step #(\\d+) — (?:Diagnostics|Error Info|Retry Details)/g;\n let match: RegExpExecArray | null;\n const ordinalContents = new Map<number, string>();\n\n while ((match = stepPattern.exec(diagContent)) !== null) {\n const ordinal = parseInt(match[1], 10);\n const sectionStart = match.index + match[0].length;\n const rest = diagContent.slice(sectionStart);\n const nextStep = rest.search(/\\n### Step #/);\n const sectionContent = nextStep === -1 ? rest : rest.slice(0, nextStep);\n\n const existing = ordinalContents.get(ordinal) ?? \"\";\n ordinalContents.set(ordinal, existing + \"\\n\" + sectionContent);\n }\n\n const suggestions: ExtractedSuggestion[] = [];\n\n for (const [ordinal, stepContent] of ordinalContents) {\n const recoveryHint = extractField(stepContent, \"Recovery Hint\");\n const error = extractField(stepContent, \"Error\") ?? \"Unknown\";\n\n // Step Results セクションから description を取得\n const stepResultPattern = new RegExp(`${ordinal}\\\\. \\\\[FAILED\\\\] (.+?) \\\\(`);\n const descMatch = content.match(stepResultPattern);\n\n suggestions.push({\n stepOrdinal: ordinal,\n description: descMatch?.[1] ?? `Step #${ordinal}`,\n error,\n recoveryHint,\n currentSelector: extractCodeBlock(stepContent, \"Step Action\"),\n });\n }\n\n return suggestions;\n}\n\n/**\n * `- **label**: value` または `**label**: value` パターンからフィールド値を抽出する。\n */\nfunction extractField(content: string, label: string): string | undefined {\n // `- **label**: value` パターン(AI Agent Summary 形式)\n const listPattern = new RegExp(`- \\\\*\\\\*${escapeRegex(label)}\\\\*\\\\*: (.+?)(?:\\n|$)`);\n const listMatch = content.match(listPattern);\n if (listMatch) return listMatch[1].trim();\n\n // `**label**: value` パターン(Diagnostics 形式)\n const boldPattern = new RegExp(`\\\\*\\\\*${escapeRegex(label)}\\\\*\\\\*: (.+?)(?:\\n|$)`);\n const boldMatch = content.match(boldPattern);\n return boldMatch?.[1]?.trim();\n}\n\n/**\n * ラベルの後に続くコードブロック(```...```)を抽出する。\n */\nfunction extractCodeBlock(content: string, label: string): string | undefined {\n const labelIdx = content.indexOf(`**${label}**`);\n if (labelIdx === -1) return undefined;\n\n const afterLabel = content.slice(labelIdx);\n const codeStart = afterLabel.indexOf(\"```\");\n if (codeStart === -1) return undefined;\n\n const codeContentStart = afterLabel.indexOf(\"\\n\", codeStart) + 1;\n const codeEnd = afterLabel.indexOf(\"```\", codeContentStart);\n if (codeEnd === -1) return undefined;\n\n return afterLabel.slice(codeContentStart, codeEnd).trim();\n}\n\nfunction escapeRegex(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n"],"mappings":"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","names":[]}
|