iterate-plugin 3.12.0 → 3.14.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/README.md +8 -8
- package/README.zh-CN.md +5 -4
- package/dist/tools/config.js +109 -9
- package/dist/tools/preflight.js +45 -4
- package/dist/validation-detect.js +193 -0
- package/lib/client.js +267 -7
- package/lib/parse.js +52 -0
- package/package.json +22 -20
- package/src/client/context-menu.ts +289 -0
- package/src/client/i18n.ts +3 -0
- package/src/client/index.ts +145 -8
- package/src/tools/config.ts +113 -10
- package/src/tools/preflight.ts +52 -4
- package/src/validation-detect.ts +207 -0
package/lib/client.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* iterate-plugin client source-digest:
|
|
1
|
+
/* iterate-plugin client source-digest: 5b22267e6de6fb0564d60874b3de1211755cdeb398f6c7ffa87dfa1007e6796f */
|
|
2
2
|
window.__ModuleLoader__.load({ id: "iterate-plugin", factory: (require) => {
|
|
3
3
|
var module = { exports: {} };
|
|
4
4
|
var exports = module.exports;
|
|
@@ -1250,6 +1250,13 @@ var START_INSTRUCTIONS = {
|
|
|
1250
1250
|
full: START_INSTRUCTION_FULL,
|
|
1251
1251
|
reviewOnly: START_INSTRUCTION_REVIEW_ONLY
|
|
1252
1252
|
};
|
|
1253
|
+
function buildScopedReviewInstruction(scope) {
|
|
1254
|
+
const hasFile = scope && typeof scope.file === "string" && scope.file.length > 0;
|
|
1255
|
+
const hasDir = !hasFile && scope && typeof scope.dir === "string" && scope.dir.length > 0;
|
|
1256
|
+
if (!hasFile && !hasDir) return "";
|
|
1257
|
+
const subject = hasFile ? `\u6587\u4EF6 \`${scope.file}\`${typeof scope.line === "number" && scope.line > 0 ? `\uFF08\u7B2C ${scope.line} \u884C\uFF09` : ""}` : `\u76EE\u5F55 \`${scope.dir}\``;
|
|
1258
|
+
return `\u5F00\u59CB\u4E00\u6B21\u4EC5\u8BC4\u5BA1\uFF08dry-run\uFF0C\u4E0D\u4FEE\u6539\u4EFB\u4F55\u6587\u4EF6\uFF09\uFF0C\u5BA1\u67E5\u8303\u56F4\u9650\u5B9A\u5728${subject}\uFF1A\u8BF7\u8C03\u7528 \`workflow\` \u5DE5\u5177\u8FD0\u884C iterate \u5DE5\u4F5C\u6D41\uFF0Cmode: "dry-run"\uFF0C\u6309\u7CFB\u7EDF\u63D0\u793A\u7684 Iterate Workflow \u6267\u884C plan \u2192 \u8BC4\u5BA1 \u2192 \u5206\u8BCA \u2192 \`iterate_review aggregate\` / \`meta-review\` \u7EC8\u62A5\u5E76 \`iterate_transcript\` capture\uFF1B\u8BC4\u5BA1\u65F6\u628A\u8303\u56F4\u9650\u5B9A\u5728${subject}\uFF0C\u5176\u4F59\u6587\u4EF6\u4EC5\u4F5C\u4E0A\u4E0B\u6587\u3001\u4E0D\u5F97\u7ED9\u51FA\u4FEE\u590D\u3002\u5168\u7A0B\u4E0D\u8981\u8C03\u7528 \`iterate_fix\` / \`iterate_rollback\`\u3002`;
|
|
1259
|
+
}
|
|
1253
1260
|
function fixFindingPayload(finding) {
|
|
1254
1261
|
const f = finding && typeof finding === "object" ? finding : {};
|
|
1255
1262
|
const file = String(f.file ?? "");
|
|
@@ -1343,6 +1350,18 @@ function buildPreflightInstruction() {
|
|
|
1343
1350
|
${JSON.stringify({}, null, 2)}
|
|
1344
1351
|
\`\`\``;
|
|
1345
1352
|
}
|
|
1353
|
+
function buildValidationApplyInstruction(commands) {
|
|
1354
|
+
const list = Array.isArray(commands) ? commands.filter((c) => typeof c === "string" && c.length > 0) : [];
|
|
1355
|
+
const payload = {
|
|
1356
|
+
operation: "write",
|
|
1357
|
+
updates: { validation: { commands: { default: list } } }
|
|
1358
|
+
};
|
|
1359
|
+
return `\u8BF7\u8C03\u7528 \`iterate_config\` \u628A\u68C0\u6D4B\u5230\u7684\u9A8C\u8BC1\u547D\u4EE4\u5199\u5165 \`validation.commands.default\`\uFF08\u4F1A\u5148\u5907\u4EFD\u914D\u7F6E\uFF09\uFF1A
|
|
1360
|
+
|
|
1361
|
+
\`\`\`json
|
|
1362
|
+
${JSON.stringify(payload, null, 2)}
|
|
1363
|
+
\`\`\``;
|
|
1364
|
+
}
|
|
1346
1365
|
function buildRollbackInstruction(id) {
|
|
1347
1366
|
return `\u8BF7\u8C03\u7528 \`iterate_rollback\` \u56DE\u6EDA\u4EE5\u4E0B\u4FEE\u590D\uFF1A
|
|
1348
1367
|
|
|
@@ -2755,6 +2774,7 @@ var EN = {
|
|
|
2755
2774
|
\u590D\u5236\u9884\u68C0\u6307\u4EE4: "Copy preflight instruction",
|
|
2756
2775
|
\u9A8C\u8BC1\u547D\u4EE4: "Validation commands",
|
|
2757
2776
|
"\u5DF2\u914D\u7F6E {a0} \u6761\u9A8C\u8BC1\u547D\u4EE4": "{a0} validation command(s) configured",
|
|
2777
|
+
"\u672A\u914D\u7F6E validation.commands\uFF08\u963B\u65AD\u9879\uFF09\u2014\u2014 \u68C0\u6D4B\u5230 {a0} \u9879\u76EE\uFF0C\u5EFA\u8BAE\uFF1A{a1}": "validation.commands is not configured (blocking) \u2014 detected {a0} project; suggested: {a1}",
|
|
2758
2778
|
"\u672A\u914D\u7F6E validation.commands \u2014\u2014 \u672C\u8F6E\u65E0\u6CD5\u8BC1\u660E\u4FEE\u590D\uFF0C\u5C5E\u963B\u65AD\u9879": "validation.commands is not configured \u2014 the run cannot prove fixes (blocking)",
|
|
2759
2779
|
"Git \u4ED3\u5E93": "Git repository",
|
|
2760
2780
|
"\u5DF2\u68C0\u6D4B\u5230 Git \u4ED3\u5E93": "Git repository detected",
|
|
@@ -2771,6 +2791,7 @@ var EN = {
|
|
|
2771
2791
|
"\u5B58\u5728\u4E2D\u65AD\u65AD\u70B9\uFF08\u5DF2\u6062\u590D {a0} \u6B21\uFF09\u2014\u2014 \u6062\u590D\u6216\u6E05\u9664\u540E\u518D\u5F00\u8DD1": "An interrupted checkpoint is waiting (resumed {a0}x) \u2014 resume or clear it first",
|
|
2772
2792
|
\u65E0\u4E2D\u65AD\u65AD\u70B9: "No interrupted checkpoint",
|
|
2773
2793
|
\u914D\u7F6E\u9A8C\u8BC1\u547D\u4EE4: "Configure validation",
|
|
2794
|
+
\u5E94\u7528\u5EFA\u8BAE: "Apply suggestion",
|
|
2774
2795
|
\u6062\u590D\u65AD\u70B9: "Resume checkpoint",
|
|
2775
2796
|
"\u963B\u65AD {a0} \xB7 \u8B66\u544A {a1}": "Blocking {a0} \xB7 warnings {a1}",
|
|
2776
2797
|
"\u9884\u68C0\u5931\u8D25\uFF1A{a0}": "Preflight failed: {a0}",
|
|
@@ -2844,6 +2865,135 @@ function subscribeSession(listener) {
|
|
|
2844
2865
|
};
|
|
2845
2866
|
}
|
|
2846
2867
|
|
|
2868
|
+
// src/client/context-menu.ts
|
|
2869
|
+
var OBS_OPEN_EVENT = "iterate-plugin:open-observatory";
|
|
2870
|
+
function openObservatory(detail) {
|
|
2871
|
+
if (typeof window === "undefined" || typeof window.dispatchEvent !== "function") return false;
|
|
2872
|
+
try {
|
|
2873
|
+
window.dispatchEvent(new CustomEvent(OBS_OPEN_EVENT, { detail: detail ?? {} }));
|
|
2874
|
+
return true;
|
|
2875
|
+
} catch {
|
|
2876
|
+
return false;
|
|
2877
|
+
}
|
|
2878
|
+
}
|
|
2879
|
+
var LABELS = {
|
|
2880
|
+
"iterate.open-panel": { zh: "\u6253\u5F00 iterate \u8D28\u91CF\u6307\u6325\u4E2D\u5FC3", en: "Open iterate command center" },
|
|
2881
|
+
"iterate.preflight": { zh: "\u590D\u5236\u5F00\u8DD1\u9884\u68C0\u6307\u4EE4", en: "Copy preflight instruction" },
|
|
2882
|
+
"iterate.dry-run": { zh: "\u590D\u5236 dry-run \u5BA1\u67E5\u6307\u4EE4", en: "Copy dry-run review instruction" },
|
|
2883
|
+
"iterate.resume": { zh: "\u590D\u5236\u65AD\u70B9\u6062\u590D\u6307\u4EE4", en: "Copy checkpoint-resume instruction" },
|
|
2884
|
+
"iterate.pull": { zh: "\u590D\u5236\u62C9\u53D6\u78C1\u76D8\u5FEB\u7167\u6307\u4EE4", en: "Copy disk-snapshot pull instruction" },
|
|
2885
|
+
"iterate.review-file": { zh: "\u590D\u5236\u300C\u4EC5\u5BA1\u67E5\u6B64\u6587\u4EF6\u300D\u6307\u4EE4", en: 'Copy "review this file only" instruction' },
|
|
2886
|
+
"iterate.review-dir": { zh: "\u590D\u5236\u300C\u4EC5\u5BA1\u67E5\u6B64\u76EE\u5F55\u300D\u6307\u4EE4", en: 'Copy "review this directory only" instruction' }
|
|
2887
|
+
};
|
|
2888
|
+
function pick(id, lang) {
|
|
2889
|
+
const entry = LABELS[id];
|
|
2890
|
+
if (!entry) return id;
|
|
2891
|
+
return lang === "zh" ? entry.zh : entry.en;
|
|
2892
|
+
}
|
|
2893
|
+
var COPY_FAILURE = {
|
|
2894
|
+
zh: "\u590D\u5236\u5931\u8D25\uFF1A\u526A\u8D34\u677F\u88AB\u62D2\u7EDD\u3002\u8BF7\u6539\u4E3A\u5728\u89C2\u6D4B\u53F0\u9762\u677F\u91CC\u7528\u540C\u4E00\u6307\u4EE4\u7684\u300C\u590D\u5236\u300D\u6309\u94AE\uFF0C\u6216\u624B\u52A8\u9009\u4E2D\u6307\u4EE4\u6587\u672C\u590D\u5236\u3002",
|
|
2895
|
+
en: 'Copy failed: clipboard denied. Use the matching "Copy" button in the observatory panel, or select the instruction text manually.'
|
|
2896
|
+
};
|
|
2897
|
+
function buildSessionMenuEntries(lang, opts) {
|
|
2898
|
+
return [
|
|
2899
|
+
{ id: "iterate.open-panel", label: pick("iterate.open-panel", lang), openTab: "live" },
|
|
2900
|
+
{ id: "iterate.preflight", label: pick("iterate.preflight", lang), separatorBefore: true },
|
|
2901
|
+
{ id: "iterate.dry-run", label: pick("iterate.dry-run", lang) },
|
|
2902
|
+
{ id: "iterate.resume", label: pick("iterate.resume", lang), disabled: opts?.hasCheckpoint === false },
|
|
2903
|
+
{ id: "iterate.pull", label: pick("iterate.pull", lang), separatorBefore: true }
|
|
2904
|
+
];
|
|
2905
|
+
}
|
|
2906
|
+
function buildFileMenuEntries(lang) {
|
|
2907
|
+
return [
|
|
2908
|
+
{ id: "iterate.review-file", label: pick("iterate.review-file", lang) },
|
|
2909
|
+
{ id: "iterate.open-panel", label: pick("iterate.open-panel", lang) }
|
|
2910
|
+
];
|
|
2911
|
+
}
|
|
2912
|
+
function buildDirectoryMenuEntries(lang) {
|
|
2913
|
+
return [
|
|
2914
|
+
{ id: "iterate.review-dir", label: pick("iterate.review-dir", lang) },
|
|
2915
|
+
{ id: "iterate.preflight", label: pick("iterate.preflight", lang), separatorBefore: true },
|
|
2916
|
+
{ id: "iterate.open-panel", label: pick("iterate.open-panel", lang) }
|
|
2917
|
+
];
|
|
2918
|
+
}
|
|
2919
|
+
function toAction(entry, deps, lang) {
|
|
2920
|
+
const action = {
|
|
2921
|
+
id: entry.id,
|
|
2922
|
+
label: entry.label,
|
|
2923
|
+
danger: entry.danger,
|
|
2924
|
+
separatorBefore: entry.separatorBefore
|
|
2925
|
+
};
|
|
2926
|
+
if (entry.disabled) action.disabled = true;
|
|
2927
|
+
if (entry.openTab) {
|
|
2928
|
+
action.run = () => {
|
|
2929
|
+
deps.openPanel({ tab: entry.openTab });
|
|
2930
|
+
deps.notify(lang === "zh" ? "\u5DF2\u6253\u5F00 iterate \u89C2\u6D4B\u53F0\u3002" : "Iterate observatory opened.", true);
|
|
2931
|
+
};
|
|
2932
|
+
return action;
|
|
2933
|
+
}
|
|
2934
|
+
if (entry.instruction) {
|
|
2935
|
+
const text = entry.instruction;
|
|
2936
|
+
const failureLabel = COPY_FAILURE[lang];
|
|
2937
|
+
action.failureLabel = failureLabel;
|
|
2938
|
+
action.run = async () => {
|
|
2939
|
+
const ok = await deps.copy(text);
|
|
2940
|
+
if (!ok) throw new Error(failureLabel);
|
|
2941
|
+
deps.notify(lang === "zh" ? "\u6307\u4EE4\u5DF2\u590D\u5236\uFF0C\u7C98\u8D34\u7ED9\u6A21\u578B\u5373\u53EF\u3002" : "Instruction copied \u2014 paste it to the model.", true);
|
|
2942
|
+
};
|
|
2943
|
+
}
|
|
2944
|
+
return action;
|
|
2945
|
+
}
|
|
2946
|
+
function registerIterateContextMenus(service, deps, instructionByEntry) {
|
|
2947
|
+
const unregister = [];
|
|
2948
|
+
const register = (target, order, build) => {
|
|
2949
|
+
try {
|
|
2950
|
+
const dispose = service.register({
|
|
2951
|
+
id: `iterate-plugin.${target}`,
|
|
2952
|
+
target,
|
|
2953
|
+
order,
|
|
2954
|
+
resolve: (t2, _signal) => {
|
|
2955
|
+
const lang = getLang();
|
|
2956
|
+
return build(lang, t2).map((entry) => {
|
|
2957
|
+
const full = { ...entry, instruction: entry.instruction ?? instructionByEntry(entry.id) };
|
|
2958
|
+
return toAction(full, deps, lang);
|
|
2959
|
+
});
|
|
2960
|
+
}
|
|
2961
|
+
});
|
|
2962
|
+
unregister.push(dispose);
|
|
2963
|
+
} catch (err) {
|
|
2964
|
+
if (typeof console !== "undefined" && typeof console.error === "function") {
|
|
2965
|
+
console.error("[iterate-ui] context-menu registration failed for target", target, err);
|
|
2966
|
+
}
|
|
2967
|
+
}
|
|
2968
|
+
};
|
|
2969
|
+
register("session", 300, (_lang, t2) => {
|
|
2970
|
+
const target = t2;
|
|
2971
|
+
return buildSessionMenuEntries(getLang(), { hasCheckpoint: target?.value?.sessionId ? true : void 0 });
|
|
2972
|
+
});
|
|
2973
|
+
register("file", 300, (_lang, t2) => {
|
|
2974
|
+
const target = t2;
|
|
2975
|
+
return buildFileMenuEntries(getLang()).map((e) => ({
|
|
2976
|
+
...e,
|
|
2977
|
+
instruction: e.id === "iterate.review-file" ? instructionByEntry(`file:${target?.value?.path ?? ""}${typeof target?.value?.line === "number" ? `:${target.value.line}` : ""}`) : e.instruction
|
|
2978
|
+
}));
|
|
2979
|
+
});
|
|
2980
|
+
register("directory", 300, (_lang, t2) => {
|
|
2981
|
+
const target = t2;
|
|
2982
|
+
return buildDirectoryMenuEntries(getLang()).map((e) => ({
|
|
2983
|
+
...e,
|
|
2984
|
+
instruction: e.id === "iterate.review-dir" ? instructionByEntry(`dir:${target?.value?.path ?? ""}`) : e.instruction
|
|
2985
|
+
}));
|
|
2986
|
+
});
|
|
2987
|
+
return () => {
|
|
2988
|
+
for (const dispose of unregister.splice(0)) {
|
|
2989
|
+
try {
|
|
2990
|
+
dispose();
|
|
2991
|
+
} catch {
|
|
2992
|
+
}
|
|
2993
|
+
}
|
|
2994
|
+
};
|
|
2995
|
+
}
|
|
2996
|
+
|
|
2847
2997
|
// src/client/index.ts
|
|
2848
2998
|
var React = require("react");
|
|
2849
2999
|
var name = "iterate-plugin";
|
|
@@ -3280,12 +3430,42 @@ function readTheme(ctx) {
|
|
|
3280
3430
|
}
|
|
3281
3431
|
return void 0;
|
|
3282
3432
|
}
|
|
3433
|
+
function readContextMenus(ctx) {
|
|
3434
|
+
if (!ctx || typeof ctx.get !== "function") return void 0;
|
|
3435
|
+
const raw = ctx.get("contextMenus", false);
|
|
3436
|
+
if (!raw || typeof raw !== "object") return void 0;
|
|
3437
|
+
const svc = raw;
|
|
3438
|
+
if (typeof svc.register !== "function") return void 0;
|
|
3439
|
+
if (typeof svc.notify !== "function") return void 0;
|
|
3440
|
+
return svc;
|
|
3441
|
+
}
|
|
3442
|
+
function sessionIdOfSession(session) {
|
|
3443
|
+
if (!session || typeof session !== "object") return null;
|
|
3444
|
+
const s = session;
|
|
3445
|
+
const candidates = [
|
|
3446
|
+
s.sessionId,
|
|
3447
|
+
s.id,
|
|
3448
|
+
s.header,
|
|
3449
|
+
s.session
|
|
3450
|
+
];
|
|
3451
|
+
for (const c of candidates) {
|
|
3452
|
+
if (typeof c === "string" && c) return c;
|
|
3453
|
+
if (c && typeof c === "object") {
|
|
3454
|
+
const o = c;
|
|
3455
|
+
for (const k of ["sessionId", "id"]) {
|
|
3456
|
+
if (typeof o[k] === "string" && o[k]) return o[k];
|
|
3457
|
+
}
|
|
3458
|
+
}
|
|
3459
|
+
}
|
|
3460
|
+
return null;
|
|
3461
|
+
}
|
|
3283
3462
|
var slotsSvc = void 0;
|
|
3284
3463
|
var themeSvc = void 0;
|
|
3285
3464
|
var storage2 = null;
|
|
3286
3465
|
var themeDisposer = null;
|
|
3287
3466
|
var themeListener = null;
|
|
3288
3467
|
var themeEnabled = true;
|
|
3468
|
+
var menuDisposer = null;
|
|
3289
3469
|
var roundPulseListeners = [];
|
|
3290
3470
|
function emitRoundPulse(round, converged) {
|
|
3291
3471
|
const payload = { round, converged: converged === true };
|
|
@@ -4593,6 +4773,21 @@ function ObservatoryPanel(props) {
|
|
|
4593
4773
|
doc.addEventListener("keydown", onKeyDown);
|
|
4594
4774
|
return () => doc.removeEventListener("keydown", onKeyDown);
|
|
4595
4775
|
}, [open]);
|
|
4776
|
+
const panelSessionId = sessionIdOfSession(session);
|
|
4777
|
+
React.useEffect(() => {
|
|
4778
|
+
if (typeof window === "undefined" || typeof window.addEventListener !== "function") return;
|
|
4779
|
+
const onOpen = (ev) => {
|
|
4780
|
+
const detail = ev.detail;
|
|
4781
|
+
const detailSession = detail && typeof detail.sessionId === "string" && detail.sessionId ? detail.sessionId : null;
|
|
4782
|
+
if (detailSession && panelSessionId && detailSession !== panelSessionId) return;
|
|
4783
|
+
setOpen(true);
|
|
4784
|
+
const target = detail && typeof detail.tab === "string" ? detail.tab : "live";
|
|
4785
|
+
const valid = OBS_TABS.some((x) => x.key === target);
|
|
4786
|
+
setTab(valid ? target : "live");
|
|
4787
|
+
};
|
|
4788
|
+
window.addEventListener(OBS_OPEN_EVENT, onOpen);
|
|
4789
|
+
return () => window.removeEventListener(OBS_OPEN_EVENT, onOpen);
|
|
4790
|
+
}, [panelSessionId]);
|
|
4596
4791
|
const copyInstruction = (key, text) => {
|
|
4597
4792
|
if (!text) return;
|
|
4598
4793
|
copyText(text).then((ok) => {
|
|
@@ -5797,7 +5992,15 @@ function ObservatoryPanel(props) {
|
|
|
5797
5992
|
label: t("\u9A8C\u8BC1\u547D\u4EE4"),
|
|
5798
5993
|
detail: (d) => {
|
|
5799
5994
|
const n = Number(d.commandCount ?? 0);
|
|
5800
|
-
|
|
5995
|
+
if (n > 0) return tf("\u5DF2\u914D\u7F6E {a0} \u6761\u9A8C\u8BC1\u547D\u4EE4", { a0: n });
|
|
5996
|
+
const suggested = Array.isArray(d.suggestedCommands) ? d.suggestedCommands.map((c) => String(c)).filter((c) => c.length > 0) : [];
|
|
5997
|
+
if (suggested.length > 0) {
|
|
5998
|
+
return tf("\u672A\u914D\u7F6E validation.commands\uFF08\u963B\u65AD\u9879\uFF09\u2014\u2014 \u68C0\u6D4B\u5230 {a0} \u9879\u76EE\uFF0C\u5EFA\u8BAE\uFF1A{a1}", {
|
|
5999
|
+
a0: String(d.ecosystem || ""),
|
|
6000
|
+
a1: suggested.join(" \xB7 ")
|
|
6001
|
+
});
|
|
6002
|
+
}
|
|
6003
|
+
return t("\u672A\u914D\u7F6E validation.commands \u2014\u2014 \u672C\u8F6E\u65E0\u6CD5\u8BC1\u660E\u4FEE\u590D\uFF0C\u5C5E\u963B\u65AD\u9879");
|
|
5801
6004
|
}
|
|
5802
6005
|
},
|
|
5803
6006
|
git: {
|
|
@@ -5832,10 +6035,19 @@ function ObservatoryPanel(props) {
|
|
|
5832
6035
|
}
|
|
5833
6036
|
}
|
|
5834
6037
|
};
|
|
5835
|
-
const fixFor = (id) => {
|
|
6038
|
+
const fixFor = (id, detail) => {
|
|
5836
6039
|
switch (id) {
|
|
5837
|
-
case "validation":
|
|
6040
|
+
case "validation": {
|
|
6041
|
+
const suggested = Array.isArray(detail.suggestedCommands) ? detail.suggestedCommands.map((c) => String(c)).filter((c) => c.length > 0) : [];
|
|
6042
|
+
if (suggested.length > 0) {
|
|
6043
|
+
return {
|
|
6044
|
+
key: "preflight-fix-validation",
|
|
6045
|
+
label: t("\u5E94\u7528\u5EFA\u8BAE"),
|
|
6046
|
+
instruction: buildValidationApplyInstruction(suggested)
|
|
6047
|
+
};
|
|
6048
|
+
}
|
|
5838
6049
|
return { key: "preflight-fix-validation", label: t("\u914D\u7F6E\u9A8C\u8BC1\u547D\u4EE4"), instruction: buildConfigFieldInstruction("validation.commands") };
|
|
6050
|
+
}
|
|
5839
6051
|
case "stale-gate":
|
|
5840
6052
|
return { key: "preflight-fix-gate", label: t("\u6E05\u9664\u95E8\u7981"), instruction: buildQualityGateClearInstruction() };
|
|
5841
6053
|
case "interrupted-checkpoint":
|
|
@@ -5849,14 +6061,14 @@ function ObservatoryPanel(props) {
|
|
|
5849
6061
|
const status = String(c.status || "warn");
|
|
5850
6062
|
const meta = CHECK_META[id];
|
|
5851
6063
|
const label = meta ? meta.label : id || "?";
|
|
5852
|
-
const
|
|
5853
|
-
const fix = status !== "pass" ? fixFor(id) : null;
|
|
6064
|
+
const detailText = meta ? meta.detail(c.detail || {}) : "";
|
|
6065
|
+
const fix = status !== "pass" ? fixFor(id, c.detail || {}) : null;
|
|
5854
6066
|
return React.createElement(
|
|
5855
6067
|
"div",
|
|
5856
6068
|
{ key: `pf-${i}`, className: "iterate-obs-row" },
|
|
5857
6069
|
React.createElement("span", { className: "iterate-gate", "data-status": status }, status.toUpperCase()),
|
|
5858
6070
|
React.createElement("b", {}, label),
|
|
5859
|
-
React.createElement("span", { className: "iterate-obs-msg" },
|
|
6071
|
+
React.createElement("span", { className: "iterate-obs-msg" }, detailText),
|
|
5860
6072
|
fix ? React.createElement("button", {
|
|
5861
6073
|
className: "iterate-btn",
|
|
5862
6074
|
"data-copied": copiedKey === fix.key ? "" : void 0,
|
|
@@ -6186,6 +6398,54 @@ function apply(ctx) {
|
|
|
6186
6398
|
)
|
|
6187
6399
|
);
|
|
6188
6400
|
}
|
|
6401
|
+
{
|
|
6402
|
+
const menuSvc = readContextMenus(ctx);
|
|
6403
|
+
if (menuSvc) {
|
|
6404
|
+
const instructionByEntry = (id) => {
|
|
6405
|
+
if (id === "iterate.preflight") return buildPreflightInstruction();
|
|
6406
|
+
if (id === "iterate.dry-run") return START_INSTRUCTIONS.reviewOnly;
|
|
6407
|
+
if (id === "iterate.resume") return buildCheckpointResumeInstruction();
|
|
6408
|
+
if (id === "iterate.pull") return buildDiskSnapshotInstruction();
|
|
6409
|
+
if (id.startsWith("file:")) {
|
|
6410
|
+
const rest = id.slice("file:".length);
|
|
6411
|
+
const colon = rest.lastIndexOf(":");
|
|
6412
|
+
const path = colon > 0 ? rest.slice(0, colon) : rest;
|
|
6413
|
+
const line = colon > 0 ? Number(rest.slice(colon + 1)) : void 0;
|
|
6414
|
+
return buildScopedReviewInstruction({ file: path, ...Number.isInteger(line) && line > 0 ? { line } : {} });
|
|
6415
|
+
}
|
|
6416
|
+
if (id.startsWith("dir:")) return buildScopedReviewInstruction({ dir: id.slice("dir:".length) });
|
|
6417
|
+
return "";
|
|
6418
|
+
};
|
|
6419
|
+
if (menuDisposer) {
|
|
6420
|
+
try {
|
|
6421
|
+
menuDisposer();
|
|
6422
|
+
} catch {
|
|
6423
|
+
}
|
|
6424
|
+
menuDisposer = null;
|
|
6425
|
+
}
|
|
6426
|
+
menuDisposer = registerIterateContextMenus(
|
|
6427
|
+
menuSvc,
|
|
6428
|
+
{
|
|
6429
|
+
copy: (text) => copyText(text),
|
|
6430
|
+
openPanel: (detail) => {
|
|
6431
|
+
openObservatory(detail);
|
|
6432
|
+
},
|
|
6433
|
+
notify: (text, success, action) => {
|
|
6434
|
+
menuSvc.notify(text, success, action);
|
|
6435
|
+
}
|
|
6436
|
+
},
|
|
6437
|
+
instructionByEntry
|
|
6438
|
+
);
|
|
6439
|
+
if (typeof ctx.effect === "function") {
|
|
6440
|
+
ctx.effect(() => {
|
|
6441
|
+
if (menuDisposer) {
|
|
6442
|
+
menuDisposer();
|
|
6443
|
+
menuDisposer = null;
|
|
6444
|
+
}
|
|
6445
|
+
});
|
|
6446
|
+
}
|
|
6447
|
+
}
|
|
6448
|
+
}
|
|
6189
6449
|
registerThemeListener(ctx);
|
|
6190
6450
|
}
|
|
6191
6451
|
return module.exports; } });
|
package/lib/parse.js
CHANGED
|
@@ -1788,6 +1788,34 @@ export const START_INSTRUCTIONS = {
|
|
|
1788
1788
|
reviewOnly: START_INSTRUCTION_REVIEW_ONLY,
|
|
1789
1789
|
}
|
|
1790
1790
|
|
|
1791
|
+
/**
|
|
1792
|
+
* Scoped dry-run review instruction (right-click menu: file / directory).
|
|
1793
|
+
*
|
|
1794
|
+
* `iterate_review plan` has no per-call `scope` parameter, so a single-file or
|
|
1795
|
+
* single-directory review is expressed as a directed instruction the model
|
|
1796
|
+
* resolves through the `workflow` tool exactly like the full dry-run flow, but
|
|
1797
|
+
* with the review scope explicitly narrowed to the clicked subject. The user
|
|
1798
|
+
* never has to type the path themselves.
|
|
1799
|
+
*
|
|
1800
|
+
* @param {{ file?: string, line?: number, dir?: string }} scope
|
|
1801
|
+
* @returns {string} empty when no scope is given (defensive; never throw)
|
|
1802
|
+
*/
|
|
1803
|
+
export function buildScopedReviewInstruction(scope) {
|
|
1804
|
+
const hasFile = scope && typeof scope.file === 'string' && scope.file.length > 0
|
|
1805
|
+
const hasDir = !hasFile && scope && typeof scope.dir === 'string' && scope.dir.length > 0
|
|
1806
|
+
if (!hasFile && !hasDir) return ''
|
|
1807
|
+
const subject = hasFile
|
|
1808
|
+
? `文件 \`${scope.file}\`${typeof scope.line === 'number' && scope.line > 0 ? `(第 ${scope.line} 行)` : ''}`
|
|
1809
|
+
: `目录 \`${scope.dir}\``
|
|
1810
|
+
return (
|
|
1811
|
+
`开始一次仅评审(dry-run,不修改任何文件),审查范围限定在${subject}:` +
|
|
1812
|
+
'请调用 `workflow` 工具运行 iterate 工作流,mode: "dry-run",' +
|
|
1813
|
+
`按系统提示的 Iterate Workflow 执行 plan → 评审 → 分诊 → \`iterate_review aggregate\` / \`meta-review\` 终报并 \`iterate_transcript\` capture;` +
|
|
1814
|
+
`评审时把范围限定在${subject},其余文件仅作上下文、不得给出修复。` +
|
|
1815
|
+
'全程不要调用 `iterate_fix` / `iterate_rollback`。'
|
|
1816
|
+
)
|
|
1817
|
+
}
|
|
1818
|
+
|
|
1791
1819
|
/** Normalize an arbitrary finding-ish node into the payload field set. */
|
|
1792
1820
|
function fixFindingPayload(finding) {
|
|
1793
1821
|
const f = finding && typeof finding === 'object' ? finding : {}
|
|
@@ -1954,6 +1982,30 @@ export function buildPreflightInstruction() {
|
|
|
1954
1982
|
)
|
|
1955
1983
|
}
|
|
1956
1984
|
|
|
1985
|
+
/**
|
|
1986
|
+
* `iterate_config` write instruction that installs the validation commands the
|
|
1987
|
+
* preflight panel detected. Copies the exact command set the user saw, so the
|
|
1988
|
+
* model applies it deterministically instead of re-detecting (and drifting).
|
|
1989
|
+
*
|
|
1990
|
+
* @param {string[]} commands
|
|
1991
|
+
* @returns {string}
|
|
1992
|
+
*/
|
|
1993
|
+
export function buildValidationApplyInstruction(commands) {
|
|
1994
|
+
const list = Array.isArray(commands)
|
|
1995
|
+
? commands.filter((c) => typeof c === 'string' && c.length > 0)
|
|
1996
|
+
: []
|
|
1997
|
+
const payload = {
|
|
1998
|
+
operation: 'write',
|
|
1999
|
+
updates: { validation: { commands: { default: list } } },
|
|
2000
|
+
}
|
|
2001
|
+
return (
|
|
2002
|
+
'请调用 `iterate_config` 把检测到的验证命令写入 `validation.commands.default`(会先备份配置):\n\n' +
|
|
2003
|
+
'```json\n' +
|
|
2004
|
+
`${JSON.stringify(payload, null, 2)}\n` +
|
|
2005
|
+
'```'
|
|
2006
|
+
)
|
|
2007
|
+
}
|
|
2008
|
+
|
|
1957
2009
|
/**
|
|
1958
2010
|
* `iterate_rollback` payload for one applied fix id.
|
|
1959
2011
|
*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "iterate-plugin",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.14.0",
|
|
4
4
|
"description": "dsh plugin that turns the iterate skill into an autonomous closed-loop harness with quality command center and experience bank (v3.3). Features: plan -> parallel review xN -> atomic fixes -> validate -> loop -> auto-stop, plus dry-run pure-review mode, quality gate compute/persist, writable experience bank, defense events stream (record + bilingual labels), and native command buttons — with a live quality command center (F8/F9/F10 render real session data), §8 assign-fix instruction, and task_mode indicator wired end to end.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -54,7 +54,9 @@
|
|
|
54
54
|
"0.2.1-rc.2": "compatible",
|
|
55
55
|
"0.2.1-rc.3": "compatible",
|
|
56
56
|
"0.2.1-rc.4": "compatible",
|
|
57
|
-
"0.2.
|
|
57
|
+
"0.2.1-rc.5": "compatible",
|
|
58
|
+
"0.2.2-alpha.2": "compatible",
|
|
59
|
+
"0.2.2-alpha.3": "compatible"
|
|
58
60
|
}
|
|
59
61
|
},
|
|
60
62
|
"client": {
|
|
@@ -95,10 +97,10 @@
|
|
|
95
97
|
"js-yaml": "4.3.2"
|
|
96
98
|
},
|
|
97
99
|
"peerDependencies": {
|
|
98
|
-
"@deepseek-ai/cordis": "^4.0.5-alpha.2 || ~4.0.6-alpha.1",
|
|
99
|
-
"@deepseek-ai/dsh-session": "0.1.1-rc.1 || 0.1.2-alpha.4 || 0.1.2-alpha.5 || 0.1.2-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.6-alpha.1 || 0.1.6-alpha.2 || 0.1.7-alpha.1 || 0.1.7-alpha.2 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-alpha.1 || 0.2.1-alpha.2 || 0.2.1-alpha.3 || 0.2.1-alpha.4 || 0.2.1-alpha.5 || 0.2.1-rc.1 || 0.2.1-rc.2 || 0.2.1-rc.3 || 0.2.1-rc.4 || 0.2.2-alpha.2",
|
|
100
|
-
"@deepseek-ai/dsh-tools": "0.1.1-rc.1 || 0.1.2-alpha.4 || 0.1.2-alpha.5 || 0.1.2-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.6-alpha.1 || 0.1.6-alpha.2 || 0.1.7-alpha.1 || 0.1.7-alpha.2 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-alpha.1 || 0.2.1-alpha.2 || 0.2.1-alpha.3 || 0.2.1-alpha.4 || 0.2.1-alpha.5 || 0.2.1-rc.1 || 0.2.1-rc.2 || 0.2.1-rc.3 || 0.2.1-rc.4 || 0.2.2-alpha.2",
|
|
101
|
-
"@deepseek-ai/dsh-util-values": "0.1.2-alpha.5 || 0.1.2-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.6-alpha.1 || 0.1.6-alpha.2 || 0.1.7-alpha.1 || 0.1.7-alpha.2 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-alpha.1 || 0.2.1-alpha.2 || 0.2.1-alpha.3 || 0.2.1-alpha.4 || 0.2.1-alpha.5 || 0.2.1-rc.1 || 0.2.1-rc.2 || 0.2.1-rc.3 || 0.2.1-rc.4 || 0.2.2-alpha.2"
|
|
100
|
+
"@deepseek-ai/cordis": "^4.0.5-alpha.2 || ~4.0.6-alpha.1 || ~4.0.6-alpha.2",
|
|
101
|
+
"@deepseek-ai/dsh-session": "0.1.1-rc.1 || 0.1.2-alpha.4 || 0.1.2-alpha.5 || 0.1.2-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.6-alpha.1 || 0.1.6-alpha.2 || 0.1.7-alpha.1 || 0.1.7-alpha.2 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-alpha.1 || 0.2.1-alpha.2 || 0.2.1-alpha.3 || 0.2.1-alpha.4 || 0.2.1-alpha.5 || 0.2.1-rc.1 || 0.2.1-rc.2 || 0.2.1-rc.3 || 0.2.1-rc.4 || 0.2.1-rc.5 || 0.2.2-alpha.2 || 0.2.2-alpha.3",
|
|
102
|
+
"@deepseek-ai/dsh-tools": "0.1.1-rc.1 || 0.1.2-alpha.4 || 0.1.2-alpha.5 || 0.1.2-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.6-alpha.1 || 0.1.6-alpha.2 || 0.1.7-alpha.1 || 0.1.7-alpha.2 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-alpha.1 || 0.2.1-alpha.2 || 0.2.1-alpha.3 || 0.2.1-alpha.4 || 0.2.1-alpha.5 || 0.2.1-rc.1 || 0.2.1-rc.2 || 0.2.1-rc.3 || 0.2.1-rc.4 || 0.2.1-rc.5 || 0.2.2-alpha.2 || 0.2.2-alpha.3",
|
|
103
|
+
"@deepseek-ai/dsh-util-values": "0.1.2-alpha.5 || 0.1.2-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.6-alpha.1 || 0.1.6-alpha.2 || 0.1.7-alpha.1 || 0.1.7-alpha.2 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-alpha.1 || 0.2.1-alpha.2 || 0.2.1-alpha.3 || 0.2.1-alpha.4 || 0.2.1-alpha.5 || 0.2.1-rc.1 || 0.2.1-rc.2 || 0.2.1-rc.3 || 0.2.1-rc.4 || 0.2.1-rc.5 || 0.2.2-alpha.2 || 0.2.2-alpha.3"
|
|
102
104
|
},
|
|
103
105
|
"peerDependenciesMeta": {
|
|
104
106
|
"@deepseek-ai/cordis": {
|
|
@@ -115,20 +117,20 @@
|
|
|
115
117
|
}
|
|
116
118
|
},
|
|
117
119
|
"devDependencies": {
|
|
118
|
-
"@deepseek-ai/cordis": "4.0.6-alpha.
|
|
119
|
-
"@deepseek-ai/dsh-agent": "0.2.2-alpha.
|
|
120
|
-
"@deepseek-ai/dsh-jobs": "0.2.2-alpha.
|
|
121
|
-
"@deepseek-ai/dsh-llm": "0.2.2-alpha.
|
|
122
|
-
"@deepseek-ai/dsh-ptc-runtime": "0.2.2-alpha.
|
|
123
|
-
"@deepseek-ai/dsh-sandbox": "0.2.2-alpha.
|
|
124
|
-
"@deepseek-ai/dsh-sandbox-policy": "0.2.2-alpha.
|
|
125
|
-
"@deepseek-ai/dsh-scope": "0.2.2-alpha.
|
|
126
|
-
"@deepseek-ai/dsh-session": "0.2.2-alpha.
|
|
127
|
-
"@deepseek-ai/dsh-system-prompt": "0.2.2-alpha.
|
|
128
|
-
"@deepseek-ai/dsh-tools": "0.2.2-alpha.
|
|
129
|
-
"@deepseek-ai/dsh-user-approval": "0.2.2-alpha.
|
|
130
|
-
"@deepseek-ai/dsh-util-values": "0.2.2-alpha.
|
|
131
|
-
"@deepseek-ai/dsh-working-directory": "0.2.2-alpha.
|
|
120
|
+
"@deepseek-ai/cordis": "4.0.6-alpha.2",
|
|
121
|
+
"@deepseek-ai/dsh-agent": "0.2.2-alpha.3",
|
|
122
|
+
"@deepseek-ai/dsh-jobs": "0.2.2-alpha.3",
|
|
123
|
+
"@deepseek-ai/dsh-llm": "0.2.2-alpha.3",
|
|
124
|
+
"@deepseek-ai/dsh-ptc-runtime": "0.2.2-alpha.3",
|
|
125
|
+
"@deepseek-ai/dsh-sandbox": "0.2.2-alpha.3",
|
|
126
|
+
"@deepseek-ai/dsh-sandbox-policy": "0.2.2-alpha.3",
|
|
127
|
+
"@deepseek-ai/dsh-scope": "0.2.2-alpha.3",
|
|
128
|
+
"@deepseek-ai/dsh-session": "0.2.2-alpha.3",
|
|
129
|
+
"@deepseek-ai/dsh-system-prompt": "0.2.2-alpha.3",
|
|
130
|
+
"@deepseek-ai/dsh-tools": "0.2.2-alpha.3",
|
|
131
|
+
"@deepseek-ai/dsh-user-approval": "0.2.2-alpha.3",
|
|
132
|
+
"@deepseek-ai/dsh-util-values": "0.2.2-alpha.3",
|
|
133
|
+
"@deepseek-ai/dsh-working-directory": "0.2.2-alpha.3",
|
|
132
134
|
"@types/js-yaml": "4.0.9",
|
|
133
135
|
"@types/node": "22.15.0",
|
|
134
136
|
"@types/react": "19.2.2",
|