iterate-plugin 3.6.0 → 3.7.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 +37 -6
- package/README.zh-CN.md +29 -5
- package/dist/config-loader.js +7 -1
- package/dist/file-lock.js +40 -12
- package/dist/index.js +7 -0
- package/dist/live.js +2 -1
- package/dist/session-hooks.js +6 -1
- package/dist/tools/decision-log.js +4 -10
- package/dist/working-directory.js +114 -0
- package/lib/client.js +1097 -461
- package/lib/parse.js +253 -58
- package/package.json +16 -11
- package/src/client/i18n.ts +517 -0
- package/src/client/index.ts +531 -340
- package/src/client/session-cache.ts +54 -0
- package/src/config-loader.ts +7 -1
- package/src/file-lock.ts +36 -9
- package/src/index.ts +7 -0
- package/src/live.ts +2 -1
- package/src/session-hooks.ts +6 -1
- package/src/tools/decision-log.ts +4 -6
- package/src/working-directory.ts +126 -0
package/lib/client.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* iterate-plugin client source-digest: 7da1ef5af84458a763f4b0ad8cd75ba2de3fb16b9831e00c0a9767bc16fece65 */
|
|
1
2
|
window.__ModuleLoader__.load({ id: "iterate-plugin", factory: (require) => {
|
|
2
3
|
var module = { exports: {} };
|
|
3
4
|
var exports = module.exports;
|
|
@@ -62,10 +63,10 @@ function safeKeys(o) {
|
|
|
62
63
|
}
|
|
63
64
|
function coerceJsonNode(v) {
|
|
64
65
|
if (typeof v !== "string") return v;
|
|
65
|
-
const
|
|
66
|
-
if (!
|
|
66
|
+
const t2 = v.trim();
|
|
67
|
+
if (!t2.startsWith("{") && !t2.startsWith("[")) return v;
|
|
67
68
|
try {
|
|
68
|
-
return JSON.parse(
|
|
69
|
+
return JSON.parse(t2);
|
|
69
70
|
} catch {
|
|
70
71
|
return v;
|
|
71
72
|
}
|
|
@@ -175,7 +176,8 @@ function isReviewReport(obj) {
|
|
|
175
176
|
obj
|
|
176
177
|
);
|
|
177
178
|
const convergence = safeGet(o, "convergence");
|
|
178
|
-
|
|
179
|
+
if (!convergence || typeof convergence !== "object" || Array.isArray(convergence)) return false;
|
|
180
|
+
return Array.isArray(safeGet(o, "findings")) && Array.isArray(safeGet(o, "rounds"));
|
|
179
181
|
}
|
|
180
182
|
function findReportInObject(obj, seen, maxDepth = 20) {
|
|
181
183
|
if (maxDepth <= 0) return null;
|
|
@@ -338,11 +340,11 @@ function extractTranscript(obj, seen, depth) {
|
|
|
338
340
|
obj
|
|
339
341
|
);
|
|
340
342
|
if (safeGet(o, "operation") === "capture") {
|
|
341
|
-
const
|
|
342
|
-
if (
|
|
343
|
+
const t2 = safeGet(o, "transcript");
|
|
344
|
+
if (t2 && typeof t2 === "object" && isTranscriptManifest(t2)) {
|
|
343
345
|
return attachLive(
|
|
344
346
|
/** @type {Record<string, unknown>} */
|
|
345
|
-
|
|
347
|
+
t2,
|
|
346
348
|
o
|
|
347
349
|
);
|
|
348
350
|
}
|
|
@@ -457,7 +459,11 @@ function scanSessionForTranscript(session) {
|
|
|
457
459
|
if (found) return found;
|
|
458
460
|
}
|
|
459
461
|
}
|
|
460
|
-
|
|
462
|
+
const loose = findFirstInObject(session, isTranscriptManifest);
|
|
463
|
+
return loose ? (
|
|
464
|
+
/** @type {Record<string, unknown>} */
|
|
465
|
+
loose
|
|
466
|
+
) : null;
|
|
461
467
|
}
|
|
462
468
|
function normalizeValidations(raw) {
|
|
463
469
|
if (!Array.isArray(raw)) return [];
|
|
@@ -502,12 +508,12 @@ function normalizeTranscript(manifest) {
|
|
|
502
508
|
) : [];
|
|
503
509
|
const rounds = asArray(safeGet(src, "rounds")).map((r) => ({
|
|
504
510
|
round: asNum(safeGet(r, "round")),
|
|
505
|
-
threads: asArray(safeGet(r, "threads")).map((
|
|
506
|
-
dimension: asStr(safeGet(
|
|
507
|
-
attempt: asNum(safeGet(
|
|
508
|
-
messages: asArray(safeGet(
|
|
509
|
-
readFiles: asArray(safeGet(
|
|
510
|
-
findings: asArray(safeGet(
|
|
511
|
+
threads: asArray(safeGet(r, "threads")).map((t2) => ({
|
|
512
|
+
dimension: asStr(safeGet(t2, "dimension")),
|
|
513
|
+
attempt: asNum(safeGet(t2, "attempt")),
|
|
514
|
+
messages: asArray(safeGet(t2, "messages")).map((m) => typeof m === "string" ? m : ""),
|
|
515
|
+
readFiles: asArray(safeGet(t2, "readFiles")).map((f) => typeof f === "string" ? f : ""),
|
|
516
|
+
findings: asArray(safeGet(t2, "findings")).map((f) => ({ ...f }))
|
|
511
517
|
}))
|
|
512
518
|
}));
|
|
513
519
|
const cp = safeGet(src, "checkpoint");
|
|
@@ -550,7 +556,7 @@ function normalizeTranscript(manifest) {
|
|
|
550
556
|
target: asStr(safeGet(e, "target"))
|
|
551
557
|
})),
|
|
552
558
|
checkpoint,
|
|
553
|
-
timeline: asArray(safeGet(src, "timeline")).map((
|
|
559
|
+
timeline: asArray(safeGet(src, "timeline")).map((t2) => ({ ...t2 })),
|
|
554
560
|
// #6: per-round validation rows (command / exitCode / allowed), captured
|
|
555
561
|
// by the workflow and persisted through `iterate_transcript capture`.
|
|
556
562
|
validations: normalizeValidations(safeGet(src, "validations")),
|
|
@@ -731,10 +737,12 @@ function normalizeQualityGateSnapshot(raw) {
|
|
|
731
737
|
}
|
|
732
738
|
function scanSessionForQualityGate(session) {
|
|
733
739
|
const node = latestToolResultNode(session, "iterate_quality_gate", findQualityGateInObject);
|
|
734
|
-
if (node
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
740
|
+
if (node !== null) {
|
|
741
|
+
const found = findQualityGateInObject(node);
|
|
742
|
+
if (found) return normalizeQualityGateSnapshot(found);
|
|
743
|
+
}
|
|
744
|
+
const loose = findFirstInObject(session, isQualityGateSnapshot);
|
|
745
|
+
return loose ? normalizeQualityGateSnapshot(loose) : null;
|
|
738
746
|
}
|
|
739
747
|
function normalizeExperienceBankResult(raw) {
|
|
740
748
|
const src = raw && typeof raw === "object" ? (
|
|
@@ -774,17 +782,19 @@ function normalizeExperienceBankResult(raw) {
|
|
|
774
782
|
hitCount: asNum(safeGet(rec, "hitCount")),
|
|
775
783
|
lastHitAt: asStr(safeGet(rec, "lastHitAt")) || null,
|
|
776
784
|
files: asArr(safeGet(rec, "files")).map((f) => typeof f === "string" ? f : ""),
|
|
777
|
-
tags: asArr(safeGet(rec, "tags")).map((
|
|
785
|
+
tags: asArr(safeGet(rec, "tags")).map((t2) => typeof t2 === "string" ? t2 : "")
|
|
778
786
|
};
|
|
779
787
|
})
|
|
780
788
|
};
|
|
781
789
|
}
|
|
782
790
|
function scanSessionForExperienceBank(session) {
|
|
783
791
|
const node = latestToolResultNode(session, "iterate_experience", findExperienceResultInObject);
|
|
784
|
-
if (node
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
792
|
+
if (node !== null) {
|
|
793
|
+
const found = findExperienceResultInObject(node);
|
|
794
|
+
if (found) return normalizeExperienceBankResult(found);
|
|
795
|
+
}
|
|
796
|
+
const loose = findFirstInObject(session, isExperienceBankResult);
|
|
797
|
+
return loose ? normalizeExperienceBankResult(loose) : null;
|
|
788
798
|
}
|
|
789
799
|
function normalizeDefenseEventsResult(raw) {
|
|
790
800
|
const src = raw && typeof raw === "object" ? (
|
|
@@ -837,10 +847,12 @@ function normalizeDefenseEventsResult(raw) {
|
|
|
837
847
|
}
|
|
838
848
|
function scanSessionForDefenseEvents(session) {
|
|
839
849
|
const node = latestToolResultNode(session, "iterate_defense_events", findDefenseResultInObject);
|
|
840
|
-
if (node
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
850
|
+
if (node !== null) {
|
|
851
|
+
const found = findDefenseResultInObject(node);
|
|
852
|
+
if (found) return normalizeDefenseEventsResult(found);
|
|
853
|
+
}
|
|
854
|
+
const loose = findFirstInObject(session, isDefenseEventsResult);
|
|
855
|
+
return loose ? normalizeDefenseEventsResult(loose) : null;
|
|
844
856
|
}
|
|
845
857
|
function isRunSummary(obj) {
|
|
846
858
|
if (!obj || typeof obj !== "object") return false;
|
|
@@ -1321,12 +1333,12 @@ function toolCalledInSession(session, toolName) {
|
|
|
1321
1333
|
toolCalls
|
|
1322
1334
|
) {
|
|
1323
1335
|
if (!call || typeof call !== "object") continue;
|
|
1324
|
-
const
|
|
1336
|
+
const t2 = String(safeGet(
|
|
1325
1337
|
/** @type {Record<string, unknown>} */
|
|
1326
1338
|
call,
|
|
1327
1339
|
"tool"
|
|
1328
1340
|
) ?? "");
|
|
1329
|
-
if (
|
|
1341
|
+
if (t2 === toolName || t2.endsWith(toolName)) return true;
|
|
1330
1342
|
}
|
|
1331
1343
|
}
|
|
1332
1344
|
const messages = safeGet(s, "messages");
|
|
@@ -1368,8 +1380,11 @@ function toolCalledInSession(session, toolName) {
|
|
|
1368
1380
|
}
|
|
1369
1381
|
return false;
|
|
1370
1382
|
}
|
|
1371
|
-
function diskEmptyStateText(pulled, topic) {
|
|
1372
|
-
const subject = topic || "\u6570\u636E";
|
|
1383
|
+
function diskEmptyStateText(pulled, topic, lang = "zh") {
|
|
1384
|
+
const subject = topic || (lang === "en" ? "data" : "\u6570\u636E");
|
|
1385
|
+
if (lang === "en") {
|
|
1386
|
+
return pulled ? `Pulled from disk: ${subject} has no records yet (the disk is empty).` : `Not pulled from disk yet: ${subject} lives under the project's .iterate/ \u2014 copy the "Pull disk snapshot" instruction back into the session and it will fill in.`;
|
|
1387
|
+
}
|
|
1373
1388
|
return pulled ? `\u5DF2\u4ECE\u78C1\u76D8\u62C9\u53D6\uFF1A${subject}\u6682\u65E0\u8BB0\u5F55\uFF08\u78C1\u76D8\u65E0\u6570\u636E\uFF09\u3002` : `\u5C1A\u672A\u4ECE\u78C1\u76D8\u62C9\u53D6${subject}\uFF1A\u6570\u636E\u5B58\u653E\u5728\u9879\u76EE .iterate/ \u4E0B\uFF0C\u70B9\u300C\u62C9\u53D6\u78C1\u76D8\u5FEB\u7167\u300D\u590D\u5236\u6307\u4EE4\u53D1\u56DE\u4F1A\u8BDD\u5373\u53EF\u56DE\u586B\u3002`;
|
|
1374
1389
|
}
|
|
1375
1390
|
function normalizeFindingFilter(filter) {
|
|
@@ -1505,27 +1520,29 @@ function trendMax(points) {
|
|
|
1505
1520
|
}
|
|
1506
1521
|
return max;
|
|
1507
1522
|
}
|
|
1508
|
-
function stoppedReasonLabel(reason) {
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
}
|
|
1523
|
+
function stoppedReasonLabel(reason, lang = "zh") {
|
|
1524
|
+
const zh = {
|
|
1525
|
+
converged: "\u5DF2\u7ED3\u675F \xB7 \u5DF2\u6536\u655B\uFF08\u65E0\u65B0\u53D1\u73B0\uFF09",
|
|
1526
|
+
max_rounds_reached: "\u5DF2\u7ED3\u675F \xB7 \u8FBE\u5230\u8F6E\u6570\u4E0A\u9650",
|
|
1527
|
+
aborted_by_validation: "\u5DF2\u7ED3\u675F \xB7 \u9A8C\u8BC1\u5931\u8D25\u540E\u56DE\u6EDA\u505C\u6B62",
|
|
1528
|
+
aborted_by_config: "\u5DF2\u7ED3\u675F \xB7 \u9A8C\u8BC1\u547D\u4EE4\u4E0D\u5728\u767D\u540D\u5355\uFF08\u914D\u7F6E\u9700\u4FEE\u590D\uFF09",
|
|
1529
|
+
inconclusive: "\u5DF2\u7ED3\u675F \xB7 \u8F6E\u6B21\u7ED3\u8BBA\u4E0D\u660E\uFF08\u5BA1\u67E5\u8F93\u51FA\u65E0\u6548\uFF09",
|
|
1530
|
+
schema_invalid: "\u5DF2\u7ED3\u675F \xB7 \u5BA1\u67E5\u8F93\u51FA\u8FDE\u7EED schema \u6821\u9A8C\u5931\u8D25",
|
|
1531
|
+
no_usable_reviewer_output: "\u5DF2\u7ED3\u675F \xB7 \u65E0\u53EF\u7528\u5BA1\u67E5\u8F93\u51FA"
|
|
1532
|
+
};
|
|
1533
|
+
const en = {
|
|
1534
|
+
converged: "Done \xB7 converged (no new findings)",
|
|
1535
|
+
max_rounds_reached: "Done \xB7 reached the round limit",
|
|
1536
|
+
aborted_by_validation: "Done \xB7 rolled back after a validation failure",
|
|
1537
|
+
aborted_by_config: "Done \xB7 validation command not allow-listed (config needs fixing)",
|
|
1538
|
+
inconclusive: "Done \xB7 inconclusive rounds (invalid review output)",
|
|
1539
|
+
schema_invalid: "Done \xB7 repeated schema validation failures in review output",
|
|
1540
|
+
no_usable_reviewer_output: "Done \xB7 no usable review output"
|
|
1541
|
+
};
|
|
1542
|
+
if (lang === "en") return en[reason] ?? (reason ? `Done \xB7 ${reason}` : "Done");
|
|
1543
|
+
return zh[reason] ?? (reason ? `\u5DF2\u7ED3\u675F \xB7 ${reason}` : "\u5DF2\u7ED3\u675F");
|
|
1527
1544
|
}
|
|
1528
|
-
function buildCompletionSummary(report) {
|
|
1545
|
+
function buildCompletionSummary(report, lang = "zh") {
|
|
1529
1546
|
const conv = (
|
|
1530
1547
|
/** @type {Record<string, unknown>} */
|
|
1531
1548
|
report.convergence ?? {}
|
|
@@ -1534,33 +1551,74 @@ function buildCompletionSummary(report) {
|
|
|
1534
1551
|
const total = getTotalRounds(report);
|
|
1535
1552
|
const stats = severityStats(report);
|
|
1536
1553
|
const converged = conv.converged === true;
|
|
1537
|
-
const reason = converged ? "\u5DF2\u6536\u655B" : `\u5DF2\u8FBE\u6700\u5927\u8F6E\u6570 ${total}`;
|
|
1538
1554
|
const totalFindings = stats.critical + stats.high + stats.medium + stats.low;
|
|
1555
|
+
if (lang === "en") {
|
|
1556
|
+
const reason2 = converged ? "converged" : `reached the round limit ${total}`;
|
|
1557
|
+
return `iterate review complete \xB7 ${rounds}/${total} rounds \xB7 ${totalFindings} findings \xB7 ${reason2}`;
|
|
1558
|
+
}
|
|
1559
|
+
const reason = converged ? "\u5DF2\u6536\u655B" : `\u5DF2\u8FBE\u6700\u5927\u8F6E\u6570 ${total}`;
|
|
1539
1560
|
return `iterate \u8BC4\u5BA1\u5B8C\u6210 \xB7 ${rounds}/${total} \u8F6E \xB7 ${totalFindings} \u9879\u53D1\u73B0 \xB7 ${reason}`;
|
|
1540
1561
|
}
|
|
1541
1562
|
var CONFIG_EDIT_FIELDS = [
|
|
1542
|
-
{
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1563
|
+
{
|
|
1564
|
+
key: "goal",
|
|
1565
|
+
label: { zh: "\u76EE\u6807", en: "Goal" },
|
|
1566
|
+
hint: { zh: "\u4E00\u53E5\u8BDD\u63CF\u8FF0\u672C\u6B21\u8FED\u4EE3\u76EE\u6807\uFF08\u5B57\u7B26\u4E32\uFF09", en: "One-sentence description of this iteration's goal (a string)" }
|
|
1567
|
+
},
|
|
1568
|
+
{
|
|
1569
|
+
key: "dimensions",
|
|
1570
|
+
label: { zh: "\u5BA1\u67E5\u7EF4\u5EA6", en: "Review dimensions" },
|
|
1571
|
+
hint: { zh: '\u6570\u7EC4\uFF0C\u5982 ["correctness","security"]', en: 'Array, e.g. ["correctness","security"]' }
|
|
1572
|
+
},
|
|
1573
|
+
{
|
|
1574
|
+
key: "max_rounds",
|
|
1575
|
+
label: { zh: "\u6700\u5927\u8F6E\u6570", en: "Max rounds" },
|
|
1576
|
+
hint: { zh: "\u6B63\u6574\u6570", en: "Positive integer" }
|
|
1577
|
+
},
|
|
1578
|
+
{
|
|
1579
|
+
key: "review.scope",
|
|
1580
|
+
label: { zh: "\u5BA1\u67E5\u8303\u56F4", en: "Review scope" },
|
|
1581
|
+
hint: { zh: '"full" \u6216 "changed-only"', en: '"full" or "changed-only"' }
|
|
1582
|
+
},
|
|
1583
|
+
{
|
|
1584
|
+
key: "reasoning_effort",
|
|
1585
|
+
label: { zh: "\u5BA1\u67E5\u63A8\u7406\u5F3A\u5EA6", en: "Review reasoning effort" },
|
|
1586
|
+
hint: { zh: '"low" / "medium" / "high"\uFF0C\u7F3A\u7701\u8DDF\u968F\u6A21\u578B\u9ED8\u8BA4', en: '"low" / "medium" / "high"; omitted = follow the model default' }
|
|
1587
|
+
},
|
|
1547
1588
|
{
|
|
1548
1589
|
key: "validation.commands",
|
|
1549
|
-
label: "\u9A8C\u8BC1\u547D\u4EE4",
|
|
1550
|
-
hint:
|
|
1590
|
+
label: { zh: "\u9A8C\u8BC1\u547D\u4EE4", en: "Validation commands" },
|
|
1591
|
+
hint: {
|
|
1592
|
+
zh: '\u6570\u7EC4\uFF0C\u6BCF\u9879\u662F\u4E00\u6761\u767D\u540D\u5355\u547D\u4EE4\u5B57\u7B26\u4E32\uFF0C\u5982 ["npm test","npm run lint"]\uFF1B\u6BCF\u8F6E\u9A8C\u8BC1\u9010\u6761\u6267\u884C\u3002\u7559\u7A7A\u6570\u7EC4 = \u4E0D\u9A8C\u8BC1\uFF08\u672C\u8F6E\u8FED\u4EE3\u4E0D\u53D7\u4EFB\u4F55\u6D4B\u8BD5\u4FDD\u62A4\uFF09',
|
|
1593
|
+
en: 'Array of allow-listed command strings, e.g. ["npm test","npm run lint"]; run one by one every round. An empty array = no verification (this iteration runs with no test protection)'
|
|
1594
|
+
}
|
|
1551
1595
|
},
|
|
1552
1596
|
{
|
|
1553
1597
|
key: "language",
|
|
1554
|
-
label: "\u754C\u9762\u8BED\u8A00",
|
|
1555
|
-
hint:
|
|
1598
|
+
label: { zh: "\u754C\u9762\u8BED\u8A00", en: "Interface language" },
|
|
1599
|
+
hint: {
|
|
1600
|
+
zh: '"zh" \u6216 "en"\uFF08\u9ED8\u8BA4 "en"\uFF09\uFF1A\u63A7\u5236\u5BA1\u6279\u7406\u7531\u3001\u9632\u5FA1\u4E8B\u4EF6\u6807\u7B7E\u7B49\u9762\u5411\u4EBA\u6587\u6848\u7684\u8BED\u8A00',
|
|
1601
|
+
en: '"zh" or "en" (default "en"): language of human-facing copy such as approval rationales and defense-event labels'
|
|
1602
|
+
}
|
|
1556
1603
|
},
|
|
1557
1604
|
{
|
|
1558
1605
|
key: "personalization.known_intentional",
|
|
1559
|
-
label: "\u5DF2\u77E5\u6709\u610F\u95EE\u9898",
|
|
1560
|
-
hint:
|
|
1606
|
+
label: { zh: "\u5DF2\u77E5\u6709\u610F\u95EE\u9898", en: "Known intentional issues" },
|
|
1607
|
+
hint: {
|
|
1608
|
+
zh: "\u6570\u7EC4\uFF0C\u6BCF\u9879 {file, line?, dimension, reason}\uFF1B\u547D\u4E2D\u6761\u76EE\u5728\u8BC4\u5BA1\u4E2D\u88AB\u8DF3\u8FC7\u3002\u53EF\u7528\u5206\u8BCA\u9762\u677F\u7684\u300C\u56DE\u8BFB\u5DF2\u5199\u5165\u6761\u76EE\u300D\u6838\u5BF9",
|
|
1609
|
+
en: `Array of {file, line?, dimension, reason}; findings hitting an entry are skipped in review. Verify via the triage panel's "read back written entries"`
|
|
1610
|
+
}
|
|
1611
|
+
},
|
|
1612
|
+
{
|
|
1613
|
+
key: "atomic.max_lines",
|
|
1614
|
+
label: { zh: "\u539F\u5B50\u4FEE\u590D\u4E0A\u9650\u884C\u6570", en: "Atomic fix line cap" },
|
|
1615
|
+
hint: { zh: "\u6B63\u6574\u6570", en: "Positive integer" }
|
|
1561
1616
|
},
|
|
1562
|
-
{
|
|
1563
|
-
|
|
1617
|
+
{
|
|
1618
|
+
key: "git.push_per_round",
|
|
1619
|
+
label: { zh: "\u6BCF\u8F6E\u63A8\u9001", en: "Push per round" },
|
|
1620
|
+
hint: { zh: "true / false", en: "true / false" }
|
|
1621
|
+
}
|
|
1564
1622
|
];
|
|
1565
1623
|
function buildConfigEditGuide() {
|
|
1566
1624
|
const lines = [
|
|
@@ -1573,7 +1631,7 @@ function buildConfigEditGuide() {
|
|
|
1573
1631
|
" \u8BF7\u5148\u7ED9 validation.commands \u914D\u4E0A\u81F3\u5C11\u4E00\u6761\u771F\u5B9E\u547D\u4EE4\uFF08\u5982 npm test\uFF09\u3002",
|
|
1574
1632
|
"",
|
|
1575
1633
|
"\u53EF\u7F16\u8F91\u5B57\u6BB5\uFF1A",
|
|
1576
|
-
...CONFIG_EDIT_FIELDS.map((f) => `- ${f.key}\uFF08${f.label}\uFF09\uFF1A${f.hint}`),
|
|
1634
|
+
...CONFIG_EDIT_FIELDS.map((f) => `- ${f.key}\uFF08${f.label.zh}\uFF09\uFF1A${f.hint.zh}`),
|
|
1577
1635
|
"",
|
|
1578
1636
|
"\u8BA9\u6A21\u578B\u5E2E\u4F60\u6539\uFF1A",
|
|
1579
1637
|
'1. \u8C03\u7528 iterate_config({ operation: "read" }) \u67E5\u770B\u5F53\u524D\u914D\u7F6E\uFF1B',
|
|
@@ -1599,8 +1657,8 @@ function configFieldByKey(key) {
|
|
|
1599
1657
|
}
|
|
1600
1658
|
function buildConfigFieldInstruction(key, value) {
|
|
1601
1659
|
const field = configFieldByKey(key);
|
|
1602
|
-
const label = field ? field.label : key;
|
|
1603
|
-
const hint = field ? field.hint : "\u89C1 iterate.config.yaml";
|
|
1660
|
+
const label = field ? field.label.zh : key;
|
|
1661
|
+
const hint = field ? field.hint.zh : "\u89C1 iterate.config.yaml";
|
|
1604
1662
|
const updates = { [key]: value === void 0 ? CONFIG_VALUE_PLACEHOLDER : value };
|
|
1605
1663
|
const payload = buildConfigEditInstruction(updates);
|
|
1606
1664
|
return [
|
|
@@ -1612,6 +1670,71 @@ function buildConfigFieldInstruction(key, value) {
|
|
|
1612
1670
|
'\u5199\u5165\u524D\u8BF7\u5148 `operation: "read"` \u5C55\u793A\u5F53\u524D\u503C\uFF1B\u5199\u5165\u7531\u5DE5\u5177\u81EA\u52A8\u5907\u4EFD\uFF0C\u5931\u8D25\u81EA\u52A8\u56DE\u6EDA\u3002'
|
|
1613
1671
|
].join("\n");
|
|
1614
1672
|
}
|
|
1673
|
+
function buildConfigReadInstruction() {
|
|
1674
|
+
return `\u8BF7\u8C03\u7528 \`iterate_config\` \u56DE\u8BFB\u5F53\u524D\u751F\u6548\u914D\u7F6E\uFF0C\u5E76\u628A\u5B8C\u6574\u7ED3\u679C\uFF08\u542B config \u5B57\u6BB5\uFF09\u539F\u6837\u56DE\u663E\uFF0C\u4F9B\u6211\u6838\u5BF9\u754C\u9762\u4E0A\u5C55\u793A\u7684\u5F53\u524D\u503C\uFF1A
|
|
1675
|
+
|
|
1676
|
+
\`\`\`json
|
|
1677
|
+
${JSON.stringify({ operation: "read" }, null, 2)}
|
|
1678
|
+
\`\`\``;
|
|
1679
|
+
}
|
|
1680
|
+
var CONFIG_TOP_LEVEL_KEYS = [...new Set(CONFIG_EDIT_FIELDS.map((f) => f.key.split(".")[0]))];
|
|
1681
|
+
function isEffectiveConfig(v) {
|
|
1682
|
+
if (!v || typeof v !== "object" || Array.isArray(v)) return false;
|
|
1683
|
+
const rec = (
|
|
1684
|
+
/** @type {Record<string, unknown>} */
|
|
1685
|
+
v
|
|
1686
|
+
);
|
|
1687
|
+
let hits = 0;
|
|
1688
|
+
for (const key of CONFIG_TOP_LEVEL_KEYS) {
|
|
1689
|
+
if (Object.hasOwn(rec, key)) hits += 1;
|
|
1690
|
+
if (hits >= 3) return true;
|
|
1691
|
+
}
|
|
1692
|
+
return false;
|
|
1693
|
+
}
|
|
1694
|
+
function findConfigInResult(v) {
|
|
1695
|
+
if (!v || typeof v !== "object" || Array.isArray(v)) return null;
|
|
1696
|
+
const rec = (
|
|
1697
|
+
/** @type {Record<string, unknown>} */
|
|
1698
|
+
v
|
|
1699
|
+
);
|
|
1700
|
+
const cfg = safeGet(rec, "config");
|
|
1701
|
+
if (isEffectiveConfig(cfg)) return (
|
|
1702
|
+
/** @type {Record<string, unknown>} */
|
|
1703
|
+
cfg
|
|
1704
|
+
);
|
|
1705
|
+
return isEffectiveConfig(v) ? rec : null;
|
|
1706
|
+
}
|
|
1707
|
+
function scanSessionForConfigRead(session) {
|
|
1708
|
+
const node = latestToolResultNode(session, "iterate_config", findConfigInResult);
|
|
1709
|
+
if (node !== null) {
|
|
1710
|
+
const cfg = findConfigInResult(node);
|
|
1711
|
+
if (cfg) return cfg;
|
|
1712
|
+
}
|
|
1713
|
+
const loose = findFirstInObject(session, isEffectiveConfig);
|
|
1714
|
+
return loose ? (
|
|
1715
|
+
/** @type {Record<string, unknown>} */
|
|
1716
|
+
loose
|
|
1717
|
+
) : null;
|
|
1718
|
+
}
|
|
1719
|
+
function configValueByPath(config, key) {
|
|
1720
|
+
if (!config || typeof config !== "object" || typeof key !== "string" || !key) {
|
|
1721
|
+
return { resolved: false, value: void 0 };
|
|
1722
|
+
}
|
|
1723
|
+
let node = (
|
|
1724
|
+
/** @type {unknown} */
|
|
1725
|
+
config
|
|
1726
|
+
);
|
|
1727
|
+
for (const part of key.split(".")) {
|
|
1728
|
+
if (!node || typeof node !== "object" || Array.isArray(node)) return { resolved: false, value: void 0 };
|
|
1729
|
+
const rec = (
|
|
1730
|
+
/** @type {Record<string, unknown>} */
|
|
1731
|
+
node
|
|
1732
|
+
);
|
|
1733
|
+
if (!Object.hasOwn(rec, part)) return { resolved: false, value: void 0 };
|
|
1734
|
+
node = rec[part];
|
|
1735
|
+
}
|
|
1736
|
+
return { resolved: true, value: node };
|
|
1737
|
+
}
|
|
1615
1738
|
var VERDICT_SHORTCUTS = {
|
|
1616
1739
|
y: "keep",
|
|
1617
1740
|
Y: "keep",
|
|
@@ -1668,9 +1791,9 @@ function buildRuntimeStatusGuide() {
|
|
|
1668
1791
|
}
|
|
1669
1792
|
function filterLiveEntries(entries, type) {
|
|
1670
1793
|
const list = Array.isArray(entries) ? entries : [];
|
|
1671
|
-
const
|
|
1672
|
-
if (!
|
|
1673
|
-
return list.filter((e) => e && typeof e === "object" && String(e.type ?? "") ===
|
|
1794
|
+
const t2 = typeof type === "string" ? type.trim() : "";
|
|
1795
|
+
if (!t2) return list.slice();
|
|
1796
|
+
return list.filter((e) => e && typeof e === "object" && String(e.type ?? "") === t2);
|
|
1674
1797
|
}
|
|
1675
1798
|
function filterTimelineEntries(entries, opts) {
|
|
1676
1799
|
const list = Array.isArray(entries) ? entries : [];
|
|
@@ -1678,18 +1801,18 @@ function filterTimelineEntries(entries, opts) {
|
|
|
1678
1801
|
const type = typeof o.type === "string" ? o.type : "";
|
|
1679
1802
|
const round = typeof o.round === "string" ? o.round : "";
|
|
1680
1803
|
const q = typeof o.search === "string" ? o.search.trim().toLowerCase() : "";
|
|
1681
|
-
const filtered = list.filter((
|
|
1682
|
-
if (!
|
|
1683
|
-
if (type && String(
|
|
1684
|
-
if (round && String(
|
|
1804
|
+
const filtered = list.filter((t2) => {
|
|
1805
|
+
if (!t2 || typeof t2 !== "object") return false;
|
|
1806
|
+
if (type && String(t2.type ?? "") !== type) return false;
|
|
1807
|
+
if (round && String(t2.round ?? "") !== round) return false;
|
|
1685
1808
|
if (q) {
|
|
1686
1809
|
let dataText = "";
|
|
1687
1810
|
try {
|
|
1688
|
-
dataText = JSON.stringify(
|
|
1811
|
+
dataText = JSON.stringify(t2.data ?? {});
|
|
1689
1812
|
} catch {
|
|
1690
|
-
dataText =
|
|
1813
|
+
dataText = t2.data === void 0 ? "{}" : String(t2.data);
|
|
1691
1814
|
}
|
|
1692
|
-
const hay = [String(
|
|
1815
|
+
const hay = [String(t2.type ?? ""), String(t2.round ?? ""), dataText].join(" ").toLowerCase();
|
|
1693
1816
|
if (hay.indexOf(q) < 0) return false;
|
|
1694
1817
|
}
|
|
1695
1818
|
return true;
|
|
@@ -1753,15 +1876,15 @@ function buildRoundComparison(report, validations) {
|
|
|
1753
1876
|
return [...rounds.values()].filter((r) => r.round > 0).sort((a, b) => a.round - b.round).map((r) => ({ ...r, severities: { ...r.severities } }));
|
|
1754
1877
|
}
|
|
1755
1878
|
function dashboardRunState(transcript) {
|
|
1756
|
-
const
|
|
1757
|
-
if (!
|
|
1758
|
-
const rawRound = Number(
|
|
1879
|
+
const t2 = transcript && typeof transcript === "object" ? transcript : null;
|
|
1880
|
+
if (!t2) return { state: "empty", round: 0, phase: "", stoppedReason: "" };
|
|
1881
|
+
const rawRound = Number(t2.round);
|
|
1759
1882
|
const round = Number.isFinite(rawRound) && rawRound > 0 ? Math.floor(rawRound) : 1;
|
|
1760
|
-
const stoppedReason = typeof
|
|
1883
|
+
const stoppedReason = typeof t2.stoppedReason === "string" ? t2.stoppedReason.trim() : "";
|
|
1761
1884
|
return {
|
|
1762
|
-
state:
|
|
1885
|
+
state: t2.active === true ? "running" : "done",
|
|
1763
1886
|
round,
|
|
1764
|
-
phase: latestPhase(
|
|
1887
|
+
phase: latestPhase(t2.phases),
|
|
1765
1888
|
stoppedReason
|
|
1766
1889
|
};
|
|
1767
1890
|
}
|
|
@@ -1774,6 +1897,387 @@ function latestPhase(phases) {
|
|
|
1774
1897
|
return latest;
|
|
1775
1898
|
}
|
|
1776
1899
|
|
|
1900
|
+
// src/client/i18n.ts
|
|
1901
|
+
var LANG_STORAGE_KEY = "iterate-ui-lang";
|
|
1902
|
+
var LANG_NAMES = {
|
|
1903
|
+
zh: "\u7B80\u4F53\u4E2D\u6587",
|
|
1904
|
+
en: "English"
|
|
1905
|
+
};
|
|
1906
|
+
var EN = {
|
|
1907
|
+
// ── run state / dashboard ────────────────────────────────────────────────
|
|
1908
|
+
\u8FD0\u884C\u4E2D: "Running",
|
|
1909
|
+
\u5DF2\u7ED3\u675F: "Finished",
|
|
1910
|
+
"Round {a0}\uFF1A{a1} \u9879": "Round {a0}: {a1} findings",
|
|
1911
|
+
"\u5404\u8F6E\u53D1\u73B0\u6570\u91CF\u8D8B\u52BF\uFF1A{a0}": "Findings per round: {a0}",
|
|
1912
|
+
\u5B8C\u6574\u8FED\u4EE3: "Full iteration",
|
|
1913
|
+
"\u590D\u5236\u542F\u52A8\u6307\u4EE4\uFF1A\u5B8C\u6574\u300C\u5BA1\u67E5 \u2192 \u4FEE\u590D \u2192 \u9A8C\u8BC1 \u2192 \u590D\u76D8\u300D\u95ED\u73AF\uFF08\u7C98\u8D34\u7ED9\u6A21\u578B\u5373\u53EF\uFF09": 'Copy the start instruction: the full "review \u2192 fix \u2192 validate \u2192 debrief" loop (paste it to the model)',
|
|
1914
|
+
\u4EC5\u8BC4\u5BA1: "Review only",
|
|
1915
|
+
"\u590D\u5236\u542F\u52A8\u6307\u4EE4\uFF1A\u53EA\u5BA1\u67E5\u4E0D\u4FEE\u6539\uFF08dry-run\uFF09\uFF08\u7C98\u8D34\u7ED9\u6A21\u578B\u5373\u53EF\uFF09": "Copy the start instruction: review without changing anything (dry-run) \u2014 paste it to the model",
|
|
1916
|
+
"\u7B2C {a0} \u8F6E\u8FDB\u884C\u4E2D{a1}\u2014\u2014\u9996\u8F6E\u6C47\u603B\u62A5\u544A\u843D\u5730\u540E\uFF0C\u8FD9\u91CC\u4F1A\u663E\u793A\u6536\u655B\u8FDB\u5EA6\u4E0E\u53D1\u73B0\u7EDF\u8BA1\u3002": "Round {a0} in progress{a1} \u2014 convergence progress and finding stats appear here once the first aggregated report lands.",
|
|
1917
|
+
" \xB7 \u9636\u6BB5\u300C{a0}\u300D": ' \xB7 phase "{a0}"',
|
|
1918
|
+
"\u4E0A\u6B21\u8FED\u4EE3\u5728\u7B2C {a0} \u8F6E\u540E\u505C\u6B62{a1}\uFF0C\u4F46\u6CA1\u6709\u53EF\u5C55\u793A\u7684\u6C47\u603B\u62A5\u544A\u3002": "The last iteration stopped at round {a0}{a1}, but there is no report to show.",
|
|
1919
|
+
"\u8FD0\u884C\u4E00\u6B21\u8BC4\u5BA1\u540E\uFF0C\u8FD9\u91CC\u4F1A\u663E\u793A\u6536\u655B\u8FDB\u5EA6\u4E0E\u53D1\u73B0\u7EDF\u8BA1\u3002": "Run a review and convergence progress and finding stats will show up here.",
|
|
1920
|
+
\u672C\u6B21\u8FED\u4EE3\u4ECE\u4E0A\u4E00\u6B21\u4E2D\u65AD\u7684\u65AD\u70B9\u7EE7\u7EED\u6267\u884C: "This run resumed from the previous interrupted checkpoint",
|
|
1921
|
+
"\u5DF2\u4E2D\u65AD\u6062\u590D \xD7{a0}": "Resumed \xD7{a0}",
|
|
1922
|
+
"\u4F1A\u8BDD\u4E2D\u68C0\u6D4B\u5230\u7528\u6237\u9644\u5E26\u7684\u56FE\u7247\uFF0C\u8BC4\u5BA1\u5C06\u4F5C\u4E3A\u89C6\u89C9\u8BC1\u636E\u53C2\u8003": "Images attached by the user were detected in this session; the review treats them as visual evidence",
|
|
1923
|
+
"\u9644\u4EF6\u56FE\u7247 {a0}": "Attached images {a0}",
|
|
1924
|
+
"\u5F53\u524D\u5904\u4E8E\u300C{a0}\u300D\u9636\u6BB5\uFF08\u8FD0\u884C\u4E2D\uFF09": 'Currently in the "{a0}" phase (running)',
|
|
1925
|
+
"\u6700\u8FD1\u4E00\u6B21\u6267\u884C\u505C\u7559\u5728\u300C{a0}\u300D\u9636\u6BB5\uFF08\u5DF2\u7ED3\u675F\uFF09": 'The last run stopped in the "{a0}" phase (finished)',
|
|
1926
|
+
"\u4EE3\u7801\u6A21\u5F0F\uFF1A\u76F4\u63A5\u4FEE\u6539\u6587\u4EF6": "Code mode: edits files directly",
|
|
1927
|
+
"\u8FED\u4EE3\u6A21\u5F0F\uFF1A\u5BA1\u67E5-\u4FEE\u590D\u5FAA\u73AF": "Iterate mode: review \u2192 fix loop",
|
|
1928
|
+
"+{a0} \u66F4\u591A": "+{a0} more",
|
|
1929
|
+
"\u672C\u8F6E\u5DF2\u5E94\u7528\u7684\u539F\u5B50\u4FEE\u590D\u6570\uFF08\u6B63\u5E38\u6A21\u5F0F\uFF09": "Atomic fixes applied this round (normal mode)",
|
|
1930
|
+
"\u5BA1\u67E5\u5DF2\u6536\u655B\uFF1A\u6700\u540E\u4E00\u8F6E\u672A\u53D1\u73B0\u65B0\u95EE\u9898": "Review converged: the final round found nothing new",
|
|
1931
|
+
"\u2713 \u5DF2\u6536\u655B": "\u2713 Converged",
|
|
1932
|
+
"\u9996\u8F6E {a0} \u2192 \u672B\u8F6E {a1} \u9879\uFF0C\u964D\u5E45 {a2}%{a3}": "Round {a0} \u2192 round {a1} findings, down {a2}%{a3}",
|
|
1933
|
+
"\uFF0C\u5DF2\u6536\u655B": ", converged",
|
|
1934
|
+
"Iterate \xB7 \u6536\u655B\u7EDF\u8BA1": "Iterate \xB7 Convergence stats",
|
|
1935
|
+
\u6536\u8D77\u5386\u53F2: "Collapse history",
|
|
1936
|
+
"\u5386\u53F2 / \u8D8B\u52BF": "History / trend",
|
|
1937
|
+
\u8F6E\u6B21: "Round",
|
|
1938
|
+
\u53D1\u73B0: "Findings",
|
|
1939
|
+
\u8BF7\u7EE7\u7EED\u6267\u884C\u4E0B\u4E00\u8F6E\u8FED\u4EE3\u5BA1\u67E5: "Please continue with the next review round",
|
|
1940
|
+
"\u8BF7\u56DE\u6EDA\u4E0A\u4E00\u8F6E\u8FED\u4EE3\u7684\u4FEE\u590D\uFF1A\u8C03\u7528 `iterate_history` \u67E5\u770B\u672C\u8F6E fix id\uFF0C\u518D\u7528 `iterate_rollback` \u9010\u4E2A\u64A4\u9500\u8FD9\u4E9B\u4FEE\u590D": "Please roll back the fixes from the last round: call `iterate_history` for this round\u2019s fix ids, then `iterate_rollback` to undo them one by one",
|
|
1941
|
+
"y \u4FEE\u590D": "y fix",
|
|
1942
|
+
"\u4FDD\u7559\u8BE5 finding\uFF0C\u8FDB\u5165\u4FEE\u590D": "Keep this finding and move it to fixing",
|
|
1943
|
+
"n \u8DF3\u8FC7": "n skip",
|
|
1944
|
+
"\u8DF3\u8FC7\u8BE5 finding": "Skip this finding",
|
|
1945
|
+
"a \u5DF2\u77E5\u6709\u610F": "a known-intentional",
|
|
1946
|
+
"\u6807\u8BB0\u4E3A\u5DF2\u77E5\u6709\u610F\u5E76\u5199\u5165 known_intentional": "Mark as known-intentional and write it into known_intentional",
|
|
1947
|
+
// ── triage panel ─────────────────────────────────────────────────────────
|
|
1948
|
+
"Iterate \xB7 Findings \u5206\u8BCA ({a0}/{a1})": "Iterate \xB7 Findings triage ({a0}/{a1})",
|
|
1949
|
+
"y=\u4FEE\u590D \xB7 n=\u8DF3\u8FC7 \xB7 a=\u5DF2\u77E5\u6709\u610F \xB7 \u2191/\u2193 \u9009\u62E9": "y=fix \xB7 n=skip \xB7 a=known-intentional \xB7 \u2191/\u2193 to move",
|
|
1950
|
+
\u6309\u4E25\u91CD\u5EA6\u7B5B\u9009: "Filter by severity",
|
|
1951
|
+
\u5168\u90E8\u4E25\u91CD\u5EA6: "All severities",
|
|
1952
|
+
\u6309\u7EF4\u5EA6\u7B5B\u9009: "Filter by dimension",
|
|
1953
|
+
\u5168\u90E8\u7EF4\u5EA6: "All dimensions",
|
|
1954
|
+
"\u641C\u7D22\u6587\u4EF6 / \u6458\u8981\u2026": "Search file / summary\u2026",
|
|
1955
|
+
\u641C\u7D22\u6587\u4EF6\u6216\u6458\u8981: "Search file or summary",
|
|
1956
|
+
"\u6E05\u9664\u7B5B\u9009\uFF08\u663E\u793A {a0}\uFF09": "Clear filters (showing {a0})",
|
|
1957
|
+
"\u5171 {a0} \u9879": "{a0} in total",
|
|
1958
|
+
"\u6279\u91CF\u4F5C\u7528\u4E8E\uFF1A": "Batch applies to:",
|
|
1959
|
+
"\u6279\u91CF\u6309\u94AE\u4EC5\u4F5C\u7528\u4E8E\u5F53\u524D\u7B5B\u9009\u53EF\u89C1\u7684 findings": "Batch buttons only apply to the findings visible under the current filter",
|
|
1960
|
+
"\u53EF\u89C1 {a0}": "Visible {a0}",
|
|
1961
|
+
"\u6279\u91CF\u6309\u94AE\u4F5C\u7528\u4E8E\u5168\u90E8 findings": "Batch buttons apply to every finding",
|
|
1962
|
+
"\u5168\u90E8 {a0}": "All {a0}",
|
|
1963
|
+
"\u628A\u6240\u6709\u5224\u5B9A\u6062\u590D\u4E3A\u9ED8\u8BA4 y\uFF08\u4FEE\u590D\uFF09": "Reset every verdict to the default y (fix)",
|
|
1964
|
+
\u91CD\u7F6E: "Reset",
|
|
1965
|
+
"y {a0} \xB7 n {a1} \xB7 a {a2} \xB7 \u5F85\u5199\u56DE known_intentional\uFF1A{a3} \u6761": "y {a0} \xB7 n {a1} \xB7 a {a2} \xB7 pending known_intentional write-back: {a3}",
|
|
1966
|
+
"\u5F53\u524D\u6CA1\u6709\u6807\u8BB0\u4E3A\u300C\u5DF2\u77E5\u6709\u610F\u300D\u7684 finding": "No finding is marked known-intentional yet",
|
|
1967
|
+
"\u590D\u5236\u5E94\u7528\u6307\u4EE4\uFF1A\u7C98\u8D34\u540E\u6A21\u578B\u4F1A\u8C03\u7528 iterate_triage apply\uFF08\u6821\u9A8C\u3001\u53BB\u91CD\u3001\u5199\u5165\u524D\u5907\u4EFD\u3001\u5931\u8D25\u81EA\u52A8\u56DE\u6EDA\uFF09": "Copy the apply instruction: once pasted, the model calls iterate_triage apply (validates, dedupes, backs up before writing, rolls back on failure)",
|
|
1968
|
+
"\u751F\u6210\u5E94\u7528\u6307\u4EE4{a0}": "Generate apply instruction{a0}",
|
|
1969
|
+
"\u53EA\u590D\u5236 known_intentional YAML \u7247\u6BB5\uFF08\u9700\u81EA\u884C\u7C98\u5230 iterate.config.yaml \u7684 personalization.known_intentional \u4E0B\uFF09": "Copy only the known_intentional YAML fragment (you must paste it under personalization.known_intentional in iterate.config.yaml yourself)",
|
|
1970
|
+
"\u4EC5\u590D\u5236 YAML \u7247\u6BB5": "Copy YAML fragment only",
|
|
1971
|
+
"\u590D\u5236 iterate_triage list \u6307\u4EE4\uFF0C\u6838\u5BF9\u5DF2\u7ECF\u5199\u5165\u7684 known_intentional \u6761\u76EE\uFF08\u5199\u56DE\u95ED\u73AF\u786E\u8BA4\uFF09": "Copy the iterate_triage list instruction to check which known_intentional entries actually landed (write-back \u2192 readback)",
|
|
1972
|
+
\u56DE\u8BFB\u5DF2\u5199\u5165\u6761\u76EE: "Read back written entries",
|
|
1973
|
+
"\u5DF2\u590D\u5236\u5E94\u7528\u6307\u4EE4\u2014\u2014\u7C98\u8D34\u56DE\u4F1A\u8BDD\uFF0C\u6A21\u578B\u5C06\u8C03\u7528 iterate_triage apply \u5E76\u56DE\u62A5\u5199\u5165\u6761\u6570\u3002": "Apply instruction copied \u2014 paste it back into the chat and the model will call iterate_triage apply and report how many entries were written.",
|
|
1974
|
+
"\u5DF2\u590D\u5236\u56DE\u8BFB\u6307\u4EE4\u2014\u2014\u7C98\u8D34\u56DE\u4F1A\u8BDD\u53EF\u5217\u51FA\u5F53\u524D\u5DF2\u5199\u5165\u7684 known_intentional\u3002": "Readback instruction copied \u2014 paste it back to list the known_intentional entries currently written.",
|
|
1975
|
+
// ── command actions ──────────────────────────────────────────────────────
|
|
1976
|
+
\u6307\u6325\u64CD\u4F5C: "Command actions",
|
|
1977
|
+
"\u6279\u51C6\u67B6\u6784\u4FEE\u590D\uFF08\u590D\u5236\u6307\u4EE4\u6587\u672C\uFF1Aiterate_fix force:true\uFF0C\u542B\u5168\u90E8\u5FC5\u586B\u53C2\u6570\uFF09": "Approve the architectural fix (copies the instruction text: iterate_fix with force:true and every required argument)",
|
|
1978
|
+
\u6279\u51C6\u67B6\u6784\u4FEE\u590D: "Approve architectural fix",
|
|
1979
|
+
\u89E6\u53D1\u65B0\u4E00\u8F6E\u8FED\u4EE3\u5BA1\u67E5: "Trigger the next review round",
|
|
1980
|
+
\u89E6\u53D1\u65B0\u4E00\u8F6E: "New round",
|
|
1981
|
+
"\u6307\u6D3E\u5168\u90E8 {a0} \u4E2A findings \u4FEE\u590D\uFF08\u9010\u4E2A iterate_fix\uFF09": "Assign all {a0} findings for fixing (one iterate_fix each)",
|
|
1982
|
+
"\u6307\u6D3E\u5F53\u524D\u53EF\u89C1 {a0} \u4E2A findings \u4FEE\u590D\uFF08\u9010\u4E2A iterate_fix\uFF09": "Assign the {a0} visible findings for fixing (one iterate_fix each)",
|
|
1983
|
+
\u6307\u6D3E\u4FEE\u590D: "Assign fixes",
|
|
1984
|
+
\u56DE\u6EDA\u5230\u4E0A\u4E00\u4E2A\u68C0\u67E5\u70B9: "Roll back to the previous checkpoint",
|
|
1985
|
+
\u56DE\u6EDA\u68C0\u67E5\u70B9: "Rollback to checkpoint",
|
|
1986
|
+
// ── verdict banner / stats card ──────────────────────────────────────────
|
|
1987
|
+
\u62A5\u544A\u5DF2\u6279\u51C6: "Report approved",
|
|
1988
|
+
\u62A5\u544A\u9700\u4FEE\u8BA2: "Report needs revision",
|
|
1989
|
+
\u9879\u53D1\u73B0: " findings",
|
|
1990
|
+
\u8F6E: " rounds",
|
|
1991
|
+
\u9879\u5BA1\u67E5: " reviews",
|
|
1992
|
+
\u62A5\u544A\u901A\u8FC7\u5168\u90E8\u4E00\u81F4\u6027\u68C0\u67E5: "The report passed every consistency check",
|
|
1993
|
+
\u5904\u62A5\u544A\u7F3A\u9677: " report defects found",
|
|
1994
|
+
\u5DF2\u6536\u655B: "Converged",
|
|
1995
|
+
\u672A\u6536\u655B: "Not converged",
|
|
1996
|
+
"Round {a0} \u5B8C\u6210 \xB7 \u5DF2\u6536\u655B": "Round {a0} complete \xB7 converged",
|
|
1997
|
+
"Round {a0} \u5B8C\u6210": "Round {a0} complete",
|
|
1998
|
+
// ── settings ─────────────────────────────────────────────────────────────
|
|
1999
|
+
"\u5DF2\u6E05\u9664 {a0} \u6761": "Cleared {a0}",
|
|
2000
|
+
\u518D\u6B21\u70B9\u51FB\u4EE5\u786E\u8BA4\u6E05\u9664\u5168\u90E8\u5224\u5B9A: "Click again to confirm clearing every verdict",
|
|
2001
|
+
"\u6E05\u9664\u6240\u6709\u5206\u8BCA\u5224\u5B9A\u8BB0\u5F55\uFF08\u9700\u8981\u4E8C\u6B21\u786E\u8BA4\uFF09": "Clear every triage verdict (requires a second click)",
|
|
2002
|
+
"\u786E\u8BA4\u6E05\u9664\uFF1F": "Confirm clear?",
|
|
2003
|
+
\u6E05\u9664\u5206\u8BCA: "Clear triage",
|
|
2004
|
+
\u8FED\u4EE3\u4E3B\u9898: "Iterate theme",
|
|
2005
|
+
"\u542F\u7528\u6696\u7425\u73C0\u914D\u8272\u7684 iterate \u4E13\u5C5E\u76AE\u80A4\uFF0C\u8986\u76D6 dsh \u9ED8\u8BA4\u4E3B\u9898\u4EE4\u724C\u3002": "Enables the warm-amber iterate skin, overriding the default dsh theme tokens.",
|
|
2006
|
+
\u5DF2\u542F\u7528: "Enabled",
|
|
2007
|
+
\u5DF2\u5173\u95ED: "Off",
|
|
2008
|
+
"\u5F00\u5173 iterate \u4E3B\u9898": "Toggle the iterate theme",
|
|
2009
|
+
\u5206\u8BCA\u6301\u4E45\u5316: "Triage persistence",
|
|
2010
|
+
"y / n / a \u5224\u5B9A\u4FDD\u5B58\u5728\u672C\u5730\u6D4F\u89C8\u5668\uFF08localStorage\uFF09\uFF0C\u5237\u65B0\u4F1A\u8BDD\u540E\u4ECD\u4FDD\u7559\u3002": "y / n / a verdicts are stored in your browser (localStorage) and survive a session refresh.",
|
|
2011
|
+
\u672C\u5730\u4FDD\u5B58: "Stored locally",
|
|
2012
|
+
\u914D\u7F6E\u7BA1\u7406: "Configuration",
|
|
2013
|
+
"\u76EE\u6807 / \u7EF4\u5EA6 / \u6700\u5927\u8F6E\u6570 / validation.commands \u5199\u5728\u9879\u76EE\u7684 iterate.config.yaml\uFF0C\u590D\u5236\u6307\u5F15\u53EF\u8BA9\u6A21\u578B\u6309\u9700\u8C03\u6574\u3002": "Goal / dimensions / max rounds / validation.commands live in the project\u2019s iterate.config.yaml; copy the guide to let the model adjust them on demand.",
|
|
2014
|
+
\u590D\u5236\u6307\u5F15: "Copy guide",
|
|
2015
|
+
\u6536\u8D77: "Collapse",
|
|
2016
|
+
\u5C55\u5F00: "Expand",
|
|
2017
|
+
\u9009\u62E9\u8981\u4FEE\u6539\u7684\u914D\u7F6E\u5B57\u6BB5: "Pick the config field to edit",
|
|
2018
|
+
"\u751F\u6210\u5E76\u590D\u5236\u8BE5\u5B57\u6BB5\u7684 iterate_config \u5199\u5165\u6307\u4EE4\uFF08\u5199\u5165\u524D\u81EA\u52A8\u5907\u4EFD\u3001\u5931\u8D25\u81EA\u52A8\u56DE\u6EDA\uFF09": "Build and copy the iterate_config write instruction for this field (backs up first, rolls back on failure)",
|
|
2019
|
+
\u751F\u6210\u5199\u5165\u6307\u4EE4: "Build write instruction",
|
|
2020
|
+
"\u526A\u8D34\u677F\u88AB\u62D2\u7EDD\u2014\u2014\u6307\u4EE4\u5DF2\u5C55\u793A\u5728\u4E0B\u65B9\uFF0C\u8BF7\u624B\u52A8\u590D\u5236\u3002": "The clipboard write was refused \u2014 the instruction is shown below, copy it manually.",
|
|
2021
|
+
"\u5199\u5165\u6307\u4EE4\uFF08\u7C98\u8D34\u7ED9\u6A21\u578B\uFF09": "Write instruction (paste to the model)",
|
|
2022
|
+
"\u5C1A\u672A\u56DE\u8BFB\u5F53\u524D\u914D\u7F6E\u2014\u2014\u70B9\u300C\u56DE\u8BFB\u5F53\u524D\u914D\u7F6E\u300D\u590D\u5236\u6307\u4EE4\u53D1\u7ED9\u6A21\u578B\uFF0C\u56DE\u663E\u540E\u5373\u53EF\u5728\u6B64\u770B\u5230\u5F53\u524D\u503C\u3002": "No config read back yet \u2014 press \u201CRead back current config\u201D, send the instruction to the model, and the current value shows up here.",
|
|
2023
|
+
"\u5F53\u524D\u503C {a0}\uFF1A{a1}": "Current value for {a0}: {a1}",
|
|
2024
|
+
"\u56DE\u8BFB\u7ED3\u679C\u4E2D\u6CA1\u6709 {a0}\uFF08\u8BE5\u5B57\u6BB5\u53EF\u80FD\u5C1A\u672A\u5199\u5165\u914D\u7F6E\u6587\u4EF6\uFF09\u3002": "The read-back does not contain {a0} (it may not have been written to the config file yet).",
|
|
2025
|
+
'\u590D\u5236\u56DE\u8BFB\u6307\u4EE4\uFF1A\u8BA9\u6A21\u578B\u8C03\u7528 iterate_config(operation:"read") \u5E76\u56DE\u663E\u7ED3\u679C': 'Copy the read-back instruction: have the model call iterate_config(operation:"read") and echo the result',
|
|
2026
|
+
\u56DE\u8BFB\u5F53\u524D\u914D\u7F6E: "Read back current config",
|
|
2027
|
+
"\u56DE\u8BFB\u6307\u4EE4\uFF08\u7C98\u8D34\u7ED9\u6A21\u578B\uFF09": "Read-back instruction (paste to the model)",
|
|
2028
|
+
\u590D\u5236: "Copy",
|
|
2029
|
+
"iterate.config.yaml \u53EF\u7F16\u8F91\u5B57\u6BB5": "Editable iterate.config.yaml fields",
|
|
2030
|
+
"\u4E2D\u6587\uFF08\u7C98\u8D34\u7ED9\u6A21\u578B\u7684\u5951\u7EA6\u6587\u6848\uFF09": "Chinese (contract text to paste to the model)",
|
|
2031
|
+
\u72B6\u6001\u6982\u89C8: "Runtime status",
|
|
2032
|
+
"\u67E5\u770B\u8FD0\u884C\u65F6\u4EA7\u7269\u5E03\u5C40\u4E0E\u6E05\u7406\u6307\u5F15\u3002iterate_status / iterate_history / iterate_prune \u5DE5\u5177\u7528\u4E8E\u67E5\u770B\u548C\u7BA1\u7406\u3002": "The runtime artifact layout and cleanup guide. Use iterate_status / iterate_history / iterate_prune to inspect and manage them.",
|
|
2033
|
+
\u62C9\u53D6\u78C1\u76D8\u5FEB\u7167: "Pull disk snapshot",
|
|
2034
|
+
\u8FD0\u884C\u65F6\u5E03\u5C40\u4E0E\u6E05\u7406: "Runtime layout & cleanup",
|
|
2035
|
+
"\u4E3A\u6BCF\u6B21\u4EE3\u7801\u8BC4\u5BA1\u751F\u6210 Review \u62A5\u544A\u4E0E\u4EA4\u4E92\u5F0F\u5206\u8BCA\u89C6\u56FE\uFF0C\u4E13\u6CE8 AI \u81EA\u6211\u5BA1\u67E5\u4E0E\u4FEE\u6B63\u3002": "Generates a review report and an interactive triage view for every code review, focused on AI self-review and correction.",
|
|
2036
|
+
\u5C31\u7EEA: "Ready",
|
|
2037
|
+
"iterate \u8BBE\u7F6E": "iterate settings",
|
|
2038
|
+
"\u526A\u8D34\u677F\u5199\u5165\u88AB\u62D2\u7EDD\uFF0C\u590D\u5236\u672A\u751F\u6548\u2014\u2014\u8BF7\u5C55\u5F00\u5BF9\u5E94\u533A\u5757\u624B\u52A8\u9009\u4E2D\u6587\u672C\u590D\u5236\u3002": "The clipboard write was refused, so nothing was copied \u2014 expand the section and copy the text manually.",
|
|
2039
|
+
"\u754C\u9762\u8BED\u8A00": "Interface language",
|
|
2040
|
+
"\u9762\u677F\u6587\u6848\u7684\u663E\u793A\u8BED\u8A00\uFF1B\u590D\u5236\u7ED9\u6A21\u578B\u7684\u6307\u4EE4\u4FDD\u6301\u4E2D\u6587\uFF0C\u4E0E SKILL.md \u7684\u5DE5\u4F5C\u6D41\u5951\u7EA6\u4E00\u81F4\u3002": "The language of the panel copy. Instructions copied for the model stay Chinese \u2014 they mirror the SKILL.md workflow contract.",
|
|
2041
|
+
"\u5207\u6362\u754C\u9762\u8BED\u8A00": "Switch the interface language",
|
|
2042
|
+
// ── observatory shell / live feed ────────────────────────────────────────
|
|
2043
|
+
"{a0} \u9875 \xB7 \u6309 1-9/0 \u5207 Fn\u3001- \u56DE\u5B9E\u65F6\u6D41": "{a0} tabs \xB7 keys 1-9/0 switch Fn, - returns to the live feed",
|
|
2044
|
+
"\u590D\u5236\u62C9\u53D6\u78C1\u76D8\u5FEB\u7167\u6307\u4EE4\uFF1A\u8BA9\u6A21\u578B\u9010\u4E2A\u8C03\u7528 {a0} \u5E76\u56DE\u663E\u5B8C\u6574\u7ED3\u679C": "Copy the disk-snapshot instruction: have the model call {a0} and echo the full results",
|
|
2045
|
+
"iterate \u89C2\u6D4B\u53F0": "iterate observatory",
|
|
2046
|
+
"\u6682\u65E0\u8FD0\u884C\u65F6\u89C2\u6D4B\u6570\u636E \xB7 {a0}": "No runtime observations yet \xB7 {a0}",
|
|
2047
|
+
"\u590D\u5236\u62C9\u53D6\u78C1\u76D8\u5FEB\u7167\u6307\u4EE4\uFF1A\u78C1\u76D8\u4E0A\u53EF\u80FD\u5DF2\u6709\u5386\u53F2\u4EA7\u7269\uFF0C\u56DE\u663E\u8FDB\u4F1A\u8BDD\u540E\u89C2\u6D4B\u53F0\u5373\u53EF\u586B\u5145": "Copy the disk-snapshot instruction: older artifacts may already be on disk; once echoed back into the chat the observatory fills up",
|
|
2048
|
+
"\u5B9E\u65F6\u6D3B\u52A8\u6D41\u4EC5\u5728\u8FD0\u884C\u671F\u95F4\u8BB0\u5F55\uFF0C\u5F53\u524D\u5DF2\u5B8C\u6210\u3002": "The live activity stream is only recorded while a run is active; this run has finished.",
|
|
2049
|
+
\u67E5\u770B\u5BA1\u67E5\u7EBF\u7A0B: "View review threads",
|
|
2050
|
+
\u67E5\u770B\u53D1\u73B0: "View findings",
|
|
2051
|
+
\u6682\u65E0\u5B9E\u65F6\u6D3B\u52A8: "No live activity yet",
|
|
2052
|
+
\u5B9E\u65F6\u6D3B\u52A8: "Live activity",
|
|
2053
|
+
\u6309\u6D3B\u52A8\u7C7B\u578B\u7B5B\u9009: "Filter by activity type",
|
|
2054
|
+
\u5168\u90E8\u6D3B\u52A8: "All activity",
|
|
2055
|
+
\u65E0\u5339\u914D\u7684\u5B9E\u65F6\u6D3B\u52A8: "No matching live activity",
|
|
2056
|
+
\u590D\u5236\u672A\u6210\u529F: "Copy failed",
|
|
2057
|
+
"\u526A\u8D34\u677F\u5199\u5165\u88AB\u62D2\u7EDD\uFF0C\u8BF7\u624B\u52A8\u9009\u4E2D\u4E0B\u65B9\u6307\u4EE4\u590D\u5236": "The clipboard write was refused \u2014 select the instruction below and copy it manually",
|
|
2058
|
+
\u5173\u95ED\u590D\u5236\u5931\u8D25\u63D0\u793A: "Dismiss the copy-failure notice",
|
|
2059
|
+
\u5173\u95ED: "Dismiss",
|
|
2060
|
+
"\u5C06\u89C2\u6D4B\u53F0\u5168\u90E8\u6570\u636E\u5BFC\u51FA\u4E3A JSON\uFF08\u4F18\u5148\u4E0B\u8F7D\uFF0C\u5931\u8D25\u5219\u590D\u5236\uFF09": "Export every observatory panel as JSON (downloads first, falls back to copying)",
|
|
2061
|
+
\u5DF2\u5BFC\u51FA: "Exported",
|
|
2062
|
+
"\u5BFC\u51FA JSON": "Export JSON",
|
|
2063
|
+
"\u89C2\u6D4B\u53F0\u9875\u7B7E\uFF08\u5FEB\u6377\u952E 1-9 / 0 / -\uFF09": "Observatory tabs (keys 1-9 / 0 / -)",
|
|
2064
|
+
"{a0}\uFF08\u6309 {a1} \u5207\u6362\uFF09": "{a0} (press {a1})",
|
|
2065
|
+
"{a0}\uFF08\u6309 - \u5207\u6362\uFF09": "{a0} (press -)",
|
|
2066
|
+
// ── F1 review threads ────────────────────────────────────────────────────
|
|
2067
|
+
\u6682\u65E0\u5BA1\u67E5\u7EBF\u7A0B: "No review threads yet",
|
|
2068
|
+
\u5BA1\u67E5\u7EBF\u7A0B: "Review threads",
|
|
2069
|
+
\u5C55\u5F00\u5168\u90E8\u7EBF\u7A0B: "Expand all threads",
|
|
2070
|
+
\u5168\u90E8\u5C55\u5F00: "Expand all",
|
|
2071
|
+
\u6536\u8D77\u5168\u90E8\u7EBF\u7A0B: "Collapse all threads",
|
|
2072
|
+
\u5168\u90E8\u6536\u8D77: "Collapse all",
|
|
2073
|
+
"{a0} \xB7 {a1} \u8F6E": "{a0} \xB7 {a1} rounds",
|
|
2074
|
+
\u81EA\u7531\u5207\u6362: "Mixed",
|
|
2075
|
+
\u672C\u8F6E\u65E0\u7EBF\u7A0B: "No threads in this round",
|
|
2076
|
+
\u672A\u547D\u540D\u7EF4\u5EA6: "Unnamed dimension",
|
|
2077
|
+
\u6536\u8D77\u7EBF\u7A0B: "Collapse thread",
|
|
2078
|
+
\u5C55\u5F00\u7EBF\u7A0B: "Expand thread",
|
|
2079
|
+
\u53D9\u8FF0: "Narration",
|
|
2080
|
+
"{a0} \u6761": "{a0}",
|
|
2081
|
+
\u65E0\u7EBF\u7D22\u53D9\u8FF0: "No narration recorded",
|
|
2082
|
+
\u8BFB\u53D6\u6587\u4EF6: "Files read",
|
|
2083
|
+
\u672C\u7EBF\u7A0B\u65E0\u53D1\u73B0: "This thread found nothing",
|
|
2084
|
+
"{a0} \u7EBF\u7A0B": "{a0} threads",
|
|
2085
|
+
// ── F2 convergence trend ─────────────────────────────────────────────────
|
|
2086
|
+
\u6682\u65E0\u6536\u655B\u6570\u636E: "No convergence data yet",
|
|
2087
|
+
\u5DF2\u4FEE\u590D: "Fixed",
|
|
2088
|
+
\u4E25\u91CD\u5EA6\u5206\u5E03: "Severity mix",
|
|
2089
|
+
\u9A8C\u8BC1: "Validation",
|
|
2090
|
+
"{a0}/{a1} \u901A\u8FC7{a2}": "{a0}/{a1} passed{a2}",
|
|
2091
|
+
"\uFF08\u542B\u5931\u8D25\uFF09": " (failures included)",
|
|
2092
|
+
"\u5404\u8F6E\u53D1\u73B0\u6570\u91CF\uFF1A{a0}{a1}": "Findings per round: {a0}{a1}",
|
|
2093
|
+
" \xB7 \u5F53\u524D Round {a0}": " \xB7 current round {a0}",
|
|
2094
|
+
"\u8DE8\u8F6E\u5BF9\u6BD4\uFF08\u672C\u4F1A\u8BDD\uFF09": "Cross-round comparison (this session)",
|
|
2095
|
+
"\u8DE8\u4F1A\u8BDD\u5BF9\u6BD4\uFF1A\u672C\u8868\u53EA\u8986\u76D6\u5F53\u524D\u4F1A\u8BDD\uFF1B\u70B9\u300C\u62C9\u53D6\u78C1\u76D8\u5FEB\u7167\u300D\u8BA9\u6A21\u578B\u56DE\u663E iterate_history\uFF0C\u518D\u7528\u300C\u5BFC\u51FA JSON\u300D\u5E76\u6392\u6BD4\u8F83\u4E24\u6B21\u8FD0\u884C": 'Cross-session comparison: this table only covers the current session \u2014 click "Pull disk snapshot" to have the model echo iterate_history, then use "Export JSON" to compare two runs side by side',
|
|
2096
|
+
// ── F3 finding locations ─────────────────────────────────────────────────
|
|
2097
|
+
\u6682\u65E0\u53D1\u73B0: "No findings",
|
|
2098
|
+
"{a0}\uFF08{a1} \u9879\uFF09": "{a0} ({a1} findings)",
|
|
2099
|
+
"\u641C\u7D22\u53D1\u73B0\u2026": "Search findings\u2026",
|
|
2100
|
+
\u641C\u7D22\u53D1\u73B0: "Search findings",
|
|
2101
|
+
\u6E05\u9664\u5168\u90E8\u7B5B\u9009: "Clear all filters",
|
|
2102
|
+
\u6E05\u9664\u7B5B\u9009: "Clear filters",
|
|
2103
|
+
\u5DF2\u786E\u8BA4: "Acknowledged",
|
|
2104
|
+
"\u590D\u5236\u8BE5 finding \u7684\u5EFA\u8BAE\u4FEE\u590D\u6587\u672C": "Copy this finding\u2019s suggested fix text",
|
|
2105
|
+
"\u590D\u5236 suggested_fix": "Copy suggested_fix",
|
|
2106
|
+
"\u590D\u5236 iterate_triage \u6307\u4EE4\u6587\u672C\uFF08\u6807\u8BB0\u4E3A known_intentional\uFF09": "Copy the iterate_triage instruction text (mark as known_intentional)",
|
|
2107
|
+
"\u590D\u5236 iterate_fix \u6307\u4EE4\u6587\u672C": "Copy the iterate_fix instruction text",
|
|
2108
|
+
\u590D\u5236\u4FEE\u590D\u6307\u4EE4: "Copy fix instruction",
|
|
2109
|
+
\u65E0\u5339\u914D\u7684\u53D1\u73B0: "No matching findings",
|
|
2110
|
+
// ── F4 fixes & rollback ──────────────────────────────────────────────────
|
|
2111
|
+
\u6682\u65E0\u4FEE\u590D\u8BB0\u5F55: "No fixes recorded yet",
|
|
2112
|
+
\u6210\u529F: "Success",
|
|
2113
|
+
\u5931\u8D25: "Failed",
|
|
2114
|
+
"\u590D\u5236 iterate_rollback \u6307\u4EE4\u6587\u672C": "Copy the iterate_rollback instruction text",
|
|
2115
|
+
\u56DE\u6EDA: "Rollback",
|
|
2116
|
+
// ── F5 checkpoint ────────────────────────────────────────────────────────
|
|
2117
|
+
\u65AD\u70B9: "Checkpoint",
|
|
2118
|
+
"\u590D\u5236 iterate_checkpoint resume \u6307\u4EE4\u6587\u672C\uFF08\u52A0\u8F7D\u65AD\u70B9\u5E76\u8BA1\u6570\u4E00\u6B21\u6062\u590D\uFF09": "Copy the iterate_checkpoint resume instruction (loads the checkpoint and counts one resume)",
|
|
2119
|
+
\u590D\u5236\u6062\u590D\u6307\u4EE4: "Copy resume instruction",
|
|
2120
|
+
"\u590D\u5236 iterate_checkpoint clear \u6307\u4EE4\u6587\u672C\uFF08\u6E05\u9664\u5F53\u524D\u65AD\u70B9\uFF0C\u4F9B\u91CD\u65B0\u5F00\u59CB\uFF09": "Copy the iterate_checkpoint clear instruction (drops the current checkpoint so you can start over)",
|
|
2121
|
+
\u6E05\u9664\u65AD\u70B9: "Clear checkpoint",
|
|
2122
|
+
// ── F6 run console ───────────────────────────────────────────────────────
|
|
2123
|
+
\u8BE2\u95EE\u7528\u6237: "Ask the user",
|
|
2124
|
+
\u62D2\u7EDD: "Deny",
|
|
2125
|
+
\u76F4\u63A5\u6267\u884C: "Run directly",
|
|
2126
|
+
"\u8BF7\u8C03\u7528 `iterate_transcript` \u5199\u5165 nudge \u6307\u4EE4\uFF1A\n\n```json\n{a0}\n```": "Please call `iterate_transcript` to write this nudge instruction:\n\n```json\n{a0}\n```",
|
|
2127
|
+
"\u8BF7\u8C03\u7528 `iterate_transcript` \u6E05\u9664\u5F53\u524D nudge\uFF1A\n\n```json\n{a0}\n```": "Please call `iterate_transcript` to clear the current nudge:\n\n```json\n{a0}\n```",
|
|
2128
|
+
\u901A\u8FC7: "Passed",
|
|
2129
|
+
\u5BFC\u81F4\u4E2D\u6B62: " aborted the run",
|
|
2130
|
+
\u9A8C\u8BC1\u7ED3\u679C: "Validation results",
|
|
2131
|
+
\u672C\u8F6E\u5C1A\u65E0\u9A8C\u8BC1\u8BB0\u5F55: "No validation was recorded in this round",
|
|
2132
|
+
"{a0} \u6761\u547D\u4EE4": "{a0} commands",
|
|
2133
|
+
\u56E0\u9A8C\u8BC1\u5931\u8D25\u4E2D\u6B62: "Stopped because validation failed",
|
|
2134
|
+
"\u5C1A\u672A\u62C9\u53D6\u9A8C\u8BC1\u7ED3\u679C\uFF1A\u6570\u636E\u5728\u78C1\u76D8 transcript \u91CC\uFF0C\u70B9\u300C\u62C9\u53D6\u78C1\u76D8\u5FEB\u7167\u300D\u590D\u5236\u6307\u4EE4\u53D1\u56DE\u4F1A\u8BDD\u5373\u53EF\u56DE\u586B\u3002": 'Validation results have not been pulled yet: they live in the transcript on disk \u2014 click "Pull disk snapshot", paste the instruction back into the chat, and this panel fills.',
|
|
2135
|
+
\u8FD0\u884C\u63A7\u5236\u53F0: "Run console",
|
|
2136
|
+
"\u6279\u51C6\u7B56\u7565\uFF1A{a0}": "Approval policy: {a0}",
|
|
2137
|
+
"\u5F53\u524D nudge": "Current nudge",
|
|
2138
|
+
"\u590D\u5236\u6E05\u9664 nudge \u6307\u4EE4\uFF08\u5199 text:null\uFF09\uFF0C\u5728\u8FD0\u884C\u63A7\u5236\u53F0\u63D0\u793A\u6E05\u9664\u5DF2\u6301\u4E45\u5316\u7684 nudge": "Copy the clear-nudge instruction (writes text:null) to ask the model to drop the persisted nudge",
|
|
2139
|
+
\u5DF2\u590D\u5236\u6E05\u9664\u6307\u4EE4: "Clear instruction copied",
|
|
2140
|
+
\u590D\u5236\u6E05\u9664\u6307\u4EE4: "Copy clear instruction",
|
|
2141
|
+
"\u8D77\u8349\u4E00\u6761 nudge \u65B9\u5411\u6307\u4EE4\u2026": "Draft a nudge to steer the run\u2026",
|
|
2142
|
+
"nudge \u8349\u7A3F": "Nudge draft",
|
|
2143
|
+
"\u590D\u5236 iterate_transcript nudge \u6307\u4EE4\u6587\u672C": "Copy the iterate_transcript nudge instruction text",
|
|
2144
|
+
"\u590D\u5236 nudge \u6307\u4EE4": "Copy nudge instruction",
|
|
2145
|
+
// ── F7 decision timeline ─────────────────────────────────────────────────
|
|
2146
|
+
\u6682\u65E0\u65F6\u95F4\u7EBF\u6761\u76EE: "No timeline entries yet",
|
|
2147
|
+
\u65F6\u95F4\u7EBF: "Timeline",
|
|
2148
|
+
\u6309\u65F6\u95F4\u7EBF\u7C7B\u578B\u7B5B\u9009: "Filter the timeline by type",
|
|
2149
|
+
\u5168\u90E8\u7C7B\u578B: "All types",
|
|
2150
|
+
\u6309\u8F6E\u6B21\u7B5B\u9009: "Filter by round",
|
|
2151
|
+
\u5168\u90E8\u8F6E\u6B21: "All rounds",
|
|
2152
|
+
"\u641C\u7D22\u65F6\u95F4\u7EBF\u2026": "Search timeline\u2026",
|
|
2153
|
+
\u641C\u7D22\u65F6\u95F4\u7EBF: "Search timeline",
|
|
2154
|
+
\u6E05\u9664: "Clear",
|
|
2155
|
+
\u65E0\u5339\u914D\u7684\u65F6\u95F4\u7EBF\u6761\u76EE: "No matching timeline entries",
|
|
2156
|
+
// ── F8 quality gate ──────────────────────────────────────────────────────
|
|
2157
|
+
\u8D28\u91CF\u95E8\u7981: "Quality gate",
|
|
2158
|
+
"\u590D\u5236 iterate_quality_gate \u67E5\u8BE2\u6307\u4EE4\uFF08\u542B JSON \u53C2\u6570\uFF09": "Copy the iterate_quality_gate query instruction (JSON arguments included)",
|
|
2159
|
+
\u67E5\u8BE2\u95E8\u7981: "Query gate",
|
|
2160
|
+
"\u590D\u5236 iterate_quality_gate clear \u6307\u4EE4\u6587\u672C\uFF08\u91CD\u7F6E\u9648\u65E7\u7684 FAIL \u8BC1\u4E66\uFF09": "Copy the iterate_quality_gate clear instruction (resets a stale FAIL certificate)",
|
|
2161
|
+
\u6E05\u9664\u95E8\u7981: "Clear gate",
|
|
2162
|
+
"\u590D\u5236\u62C9\u53D6\u78C1\u76D8\u5FEB\u7167\u6307\u4EE4\uFF1A\u8BA9\u6A21\u578B\u56DE\u663E .iterate/ \u4E0B\u7684\u95E8\u7981\u3001\u7ECF\u9A8C\u3001\u9632\u5FA1\u4E8B\u4EF6\u4E0E transcript": "Copy the disk-snapshot instruction: have the model echo the gate, experience, defense events and transcript artifacts under .iterate/",
|
|
2163
|
+
\u8D28\u91CF\u95E8\u7981\u89C6\u56FE: "Quality gate view",
|
|
2164
|
+
\u8D28\u91CF\u95E8\u7981\u8BC1\u4E66: "Quality gate certificate",
|
|
2165
|
+
"\u8D28\u91CF\u95E8\u7981\u663E\u793A\u5404\u7EF4\u5EA6\u6536\u655B\u5EA6\u3001\u9A8C\u8BC1\u901A\u8FC7\u7387\u548C\u6574\u4F53 PASS/FAIL \u72B6\u6001\u3002": "The quality gate shows per-dimension convergence, the validation pass rate and the overall PASS/FAIL state.",
|
|
2166
|
+
\u590D\u5236\u67E5\u8BE2\u6307\u4EE4: "Copy query instruction",
|
|
2167
|
+
\u590D\u5236\u62C9\u53D6\u78C1\u76D8\u5FEB\u7167\u6307\u4EE4: "Copy disk-snapshot instruction",
|
|
2168
|
+
"\u6574\u4F53\u8BC4\u5206 {a0} \xB7 \u9A8C\u8BC1 {a1}/{a2} \xB7 \u901A\u8FC7\u7387 {a3}%": "Overall score {a0} \xB7 validation {a1}/{a2} \xB7 pass rate {a3}%",
|
|
2169
|
+
"{a0} \xB7 \u6536\u655B {a1}% \xB7 \u8BC4\u5206 {a2}": "{a0} \xB7 convergence {a1}% \xB7 score {a2}",
|
|
2170
|
+
"\u8BC4\u5206 {a0} \xB7 \u53D1\u73B0 {a1} \xB7 \u5DF2\u4FEE\u590D {a2}": "Score {a0} \xB7 findings {a1} \xB7 fixed {a2}",
|
|
2171
|
+
"\u5931\u8D25\u539F\u56E0\uFF1A{a0}": "Failure reason: {a0}",
|
|
2172
|
+
// ── F9 experience bank ───────────────────────────────────────────────────
|
|
2173
|
+
"\u8BF7\u8C03\u7528 `iterate_experience` \u641C\u7D22\u7ECF\u9A8C\uFF1A\n\n```json\n{a0}\n```": "Please call `iterate_experience` to search the experience bank:\n\n```json\n{a0}\n```",
|
|
2174
|
+
"\u8BF7\u8C03\u7528 `iterate_experience` \u91C7\u7EB3\u7ECF\u9A8C\u5E76\u5E94\u7528\u5DF2\u9A8C\u8BC1\u4FEE\u6CD5\uFF1A\n\n```json\n{a0}\n```": "Please call `iterate_experience` to adopt this entry and apply its verified fix:\n\n```json\n{a0}\n```",
|
|
2175
|
+
"\u547D\u4E2D {a0} \u6B21": "Hit {a0} times",
|
|
2176
|
+
"\u590D\u5236\u91C7\u7EB3\u6307\u4EE4\uFF08\u67E5\u8BE2\u8BE5\u7ECF\u9A8C\u5E76\u5E94\u7528\u5230\u5F53\u524D\u4E0A\u4E0B\u6587\uFF09": "Copy the adopt instruction (queries this entry and applies it to the current context)",
|
|
2177
|
+
\u91C7\u7EB3: "Adopt",
|
|
2178
|
+
\u7ECF\u9A8C\u94F6\u884C: "Experience bank",
|
|
2179
|
+
"\u4F1A\u8BDD\u5185 {a0} \u6761": "{a0} in this session",
|
|
2180
|
+
"\u590D\u5236\u5217\u51FA\u7ECF\u9A8C\u6307\u4EE4\uFF08\u542B JSON \u53C2\u6570\uFF09": "Copy the list-experience instruction (JSON arguments included)",
|
|
2181
|
+
\u5217\u51FA\u7ECF\u9A8C: "List experiences",
|
|
2182
|
+
"\u590D\u5236\u62C9\u53D6\u78C1\u76D8\u5FEB\u7167\u6307\u4EE4\uFF1A\u628A .iterate/ \u4E0B\u7684\u7ECF\u9A8C\u94F6\u884C\u7B49\u4EA7\u7269\u56DE\u663E\u8FDB\u4F1A\u8BDD": "Copy the disk-snapshot instruction: echo the experience bank and other .iterate/ artifacts back into the chat",
|
|
2183
|
+
"\u641C\u7D22\u7ECF\u9A8C\u6A21\u5F0F\u2026": "Search experience patterns\u2026",
|
|
2184
|
+
\u641C\u7D22\u7ECF\u9A8C: "Search experiences",
|
|
2185
|
+
\u590D\u5236\u641C\u7D22\u6307\u4EE4: "Copy search instruction",
|
|
2186
|
+
\u641C\u7D22: "Search",
|
|
2187
|
+
"\u6CA1\u6709\u5339\u914D\u300C": "No experience matches \u201C",
|
|
2188
|
+
"\u300D\u7684\u7ECF\u9A8C": "\u201D",
|
|
2189
|
+
"\u4E5F\u53EF\u70B9\u300C\u5217\u51FA\u7ECF\u9A8C\u300D\u67E5\u8BE2\u78C1\u76D8\u4E0A\u7684\u5168\u90E8\u5386\u53F2\u7ECF\u9A8C\u3002": 'You can also click "List experiences" to query every historical entry on disk.',
|
|
2190
|
+
// ── F10 defense events ───────────────────────────────────────────────────
|
|
2191
|
+
"\u8BF7\u8C03\u7528 `iterate_defense_events` \u67E5\u8BE2\u9632\u5FA1\u4E8B\u4EF6\uFF1A\n\n```json\n{a0}\n```": "Please call `iterate_defense_events` to query defense events:\n\n```json\n{a0}\n```",
|
|
2192
|
+
\u524D\u7F6E\u6821\u9A8C\u5931\u8D25: "Precondition failed",
|
|
2193
|
+
\u4E0D\u53D8\u91CF\u8FDD\u53CD: "Invariant violated",
|
|
2194
|
+
\u5047\u8BBE\u88AB\u8BC1\u4F2A: "Assumption falsified",
|
|
2195
|
+
\u9632\u5FA1\u4E8B\u4EF6: "Defense events",
|
|
2196
|
+
"\u4F1A\u8BDD\u5185 {a0} \u6761 / \u7D2F\u8BA1 {a1}": "{a0} in this session / {a1} total",
|
|
2197
|
+
"\u590D\u5236\u5217\u51FA\u9632\u5FA1\u4E8B\u4EF6\u6307\u4EE4\uFF08\u542B JSON \u53C2\u6570\uFF09": "Copy the list-defense-events instruction (JSON arguments included)",
|
|
2198
|
+
\u5217\u51FA\u4E8B\u4EF6: "List events",
|
|
2199
|
+
"\u590D\u5236\u62C9\u53D6\u78C1\u76D8\u5FEB\u7167\u6307\u4EE4\uFF1A\u628A .iterate/ \u4E0B\u7684\u9632\u5FA1\u4E8B\u4EF6\u6D41\u56DE\u663E\u8FDB\u4F1A\u8BDD": "Copy the disk-snapshot instruction: echo the defense event stream under .iterate/ back into the chat",
|
|
2200
|
+
"\u8BF7\u8C03\u7528 `iterate_defense_events` \u67E5\u8BE2\u4E8B\u4EF6\u7EDF\u8BA1\uFF1A\n\n```json\n{a0}\n```": "Please call `iterate_defense_events` for the event counts:\n\n```json\n{a0}\n```",
|
|
2201
|
+
"\u590D\u5236\u7EDF\u8BA1\u6307\u4EE4\uFF08\u542B JSON \u53C2\u6570\uFF09": "Copy the counts instruction (JSON arguments included)",
|
|
2202
|
+
\u7EDF\u8BA1: "Counts",
|
|
2203
|
+
"\u8BF7\u8C03\u7528 `iterate_defense_events` \u6E05\u9664\u9632\u5FA1\u4E8B\u4EF6\u6D41\uFF1A\n\n```json\n{a0}\n```": "Please call `iterate_defense_events` to clear the defense event stream:\n\n```json\n{a0}\n```",
|
|
2204
|
+
"\u590D\u5236 iterate_defense_events clear \u6307\u4EE4\u6587\u672C\uFF08\u91CD\u7F6E\u9648\u65E7\u4E8B\u4EF6\u6D41\uFF09": "Copy the iterate_defense_events clear instruction (resets a stale event stream)",
|
|
2205
|
+
\u6E05\u9664\u4E8B\u4EF6: "Clear events",
|
|
2206
|
+
\u9632\u5FA1\u4E8B\u4EF6\u6D41: "Defense event stream",
|
|
2207
|
+
"\u9632\u5FA1\u4E8B\u4EF6\u5305\u62EC\uFF1A\u524D\u7F6E\u6821\u9A8C\u5931\u8D25\u3001\u56DE\u6EDA\u3001\u4E0D\u53D8\u91CF\u8FDD\u53CD\u3001\u5047\u8BBE\u88AB\u8BC1\u4F2A\u3002": "Defense events cover failed preconditions, rollbacks, violated invariants and falsified assumptions.",
|
|
2208
|
+
\u6309\u4E8B\u4EF6\u7C7B\u578B\u7B5B\u9009: "Filter by event type",
|
|
2209
|
+
\u6E05\u9664\u7C7B\u578B\u7B5B\u9009: "Clear type filter",
|
|
2210
|
+
"\u9632\u7EBF\uFF1A{a0}": "Defense: {a0}",
|
|
2211
|
+
\u6CA1\u6709\u5339\u914D\u8BE5\u7C7B\u578B\u7684\u9632\u5FA1\u4E8B\u4EF6: "No defense events of this type",
|
|
2212
|
+
// ── copy feedback ────────────────────────────────────────────────────────
|
|
2213
|
+
\u5DF2\u590D\u5236: "Copied",
|
|
2214
|
+
\u590D\u5236\u5931\u8D25: "Copy failed"
|
|
2215
|
+
};
|
|
2216
|
+
var current = "zh";
|
|
2217
|
+
var storage = null;
|
|
2218
|
+
var listeners = /* @__PURE__ */ new Set();
|
|
2219
|
+
function getLang() {
|
|
2220
|
+
return current;
|
|
2221
|
+
}
|
|
2222
|
+
function setLang(next, persist = true) {
|
|
2223
|
+
if (next !== current) {
|
|
2224
|
+
current = next;
|
|
2225
|
+
if (persist) {
|
|
2226
|
+
try {
|
|
2227
|
+
storage?.set(LANG_STORAGE_KEY, next);
|
|
2228
|
+
} catch {
|
|
2229
|
+
}
|
|
2230
|
+
}
|
|
2231
|
+
for (const listener of [...listeners]) {
|
|
2232
|
+
try {
|
|
2233
|
+
listener(next);
|
|
2234
|
+
} catch {
|
|
2235
|
+
}
|
|
2236
|
+
}
|
|
2237
|
+
}
|
|
2238
|
+
}
|
|
2239
|
+
function subscribeLang(listener) {
|
|
2240
|
+
listeners.add(listener);
|
|
2241
|
+
return () => {
|
|
2242
|
+
listeners.delete(listener);
|
|
2243
|
+
};
|
|
2244
|
+
}
|
|
2245
|
+
function configureLangStorage(next) {
|
|
2246
|
+
storage = next;
|
|
2247
|
+
}
|
|
2248
|
+
function detectLang(stored, navigatorLanguage) {
|
|
2249
|
+
if (stored === "en" || stored === "zh") return stored;
|
|
2250
|
+
return /^zh\b/i.test(navigatorLanguage ?? "") ? "zh" : "en";
|
|
2251
|
+
}
|
|
2252
|
+
function t(key) {
|
|
2253
|
+
return current === "en" ? EN[key] ?? key : key;
|
|
2254
|
+
}
|
|
2255
|
+
function tf(template, params = {}) {
|
|
2256
|
+
const translated = current === "en" ? EN[template] ?? template : template;
|
|
2257
|
+
return translated.replace(
|
|
2258
|
+
/\{([A-Za-z0-9_]+)\}/g,
|
|
2259
|
+
(whole, name2) => Object.prototype.hasOwnProperty.call(params, name2) ? String(params[name2]) : whole
|
|
2260
|
+
);
|
|
2261
|
+
}
|
|
2262
|
+
|
|
2263
|
+
// src/client/session-cache.ts
|
|
2264
|
+
var current2 = null;
|
|
2265
|
+
var listeners2 = /* @__PURE__ */ new Set();
|
|
2266
|
+
function noteSession(session) {
|
|
2267
|
+
if (Object.is(session, current2)) return;
|
|
2268
|
+
current2 = session;
|
|
2269
|
+
for (const listener of [...listeners2]) listener();
|
|
2270
|
+
}
|
|
2271
|
+
function readSession() {
|
|
2272
|
+
return current2;
|
|
2273
|
+
}
|
|
2274
|
+
function subscribeSession(listener) {
|
|
2275
|
+
listeners2.add(listener);
|
|
2276
|
+
return () => {
|
|
2277
|
+
listeners2.delete(listener);
|
|
2278
|
+
};
|
|
2279
|
+
}
|
|
2280
|
+
|
|
1777
2281
|
// src/client/index.ts
|
|
1778
2282
|
var React = require("react");
|
|
1779
2283
|
var name = "iterate-plugin";
|
|
@@ -2106,12 +2610,12 @@ function createStorage() {
|
|
|
2106
2610
|
}
|
|
2107
2611
|
}
|
|
2108
2612
|
function removeStorageByPrefix(prefix) {
|
|
2109
|
-
if (!
|
|
2613
|
+
if (!storage2) return 0;
|
|
2110
2614
|
let removed = 0;
|
|
2111
2615
|
try {
|
|
2112
|
-
for (const key of
|
|
2616
|
+
for (const key of storage2.keys()) {
|
|
2113
2617
|
if (key.startsWith(prefix)) {
|
|
2114
|
-
|
|
2618
|
+
storage2.remove(key);
|
|
2115
2619
|
removed++;
|
|
2116
2620
|
}
|
|
2117
2621
|
}
|
|
@@ -2120,6 +2624,20 @@ function removeStorageByPrefix(prefix) {
|
|
|
2120
2624
|
}
|
|
2121
2625
|
return removed;
|
|
2122
2626
|
}
|
|
2627
|
+
function useLang() {
|
|
2628
|
+
const [lang, set] = React.useState(getLang());
|
|
2629
|
+
React.useEffect(() => subscribeLang(set), []);
|
|
2630
|
+
return lang;
|
|
2631
|
+
}
|
|
2632
|
+
function useSessionSnapshot() {
|
|
2633
|
+
return React.useSyncExternalStore(subscribeSession, readSession, readSession);
|
|
2634
|
+
}
|
|
2635
|
+
function withLang(Component) {
|
|
2636
|
+
return function LangScoped(props) {
|
|
2637
|
+
useLang();
|
|
2638
|
+
return React.createElement(Component, props);
|
|
2639
|
+
};
|
|
2640
|
+
}
|
|
2123
2641
|
function copyText(text) {
|
|
2124
2642
|
if (typeof navigator !== "undefined" && navigator.clipboard && typeof navigator.clipboard.writeText === "function") {
|
|
2125
2643
|
return navigator.clipboard.writeText(text).then(
|
|
@@ -2157,10 +2675,23 @@ function severityColor(severity) {
|
|
|
2157
2675
|
function severityLabel(severity) {
|
|
2158
2676
|
return SEVERITY_LABEL[coerceSeverity(severity)];
|
|
2159
2677
|
}
|
|
2678
|
+
function formatConfigValue(value) {
|
|
2679
|
+
if (typeof value === "string") return value;
|
|
2680
|
+
if (value === void 0) return "\u2014";
|
|
2681
|
+
if (value === null) return "null";
|
|
2682
|
+
try {
|
|
2683
|
+
return JSON.stringify(value) ?? String(value);
|
|
2684
|
+
} catch {
|
|
2685
|
+
return String(value);
|
|
2686
|
+
}
|
|
2687
|
+
}
|
|
2688
|
+
function parenthesize(label) {
|
|
2689
|
+
return getLang() === "en" ? ` (${label})` : `\uFF08${label}\uFF09`;
|
|
2690
|
+
}
|
|
2160
2691
|
function runStatusText(live, manifest) {
|
|
2161
|
-
if (live) return "\u8FD0\u884C\u4E2D";
|
|
2692
|
+
if (live) return t("\u8FD0\u884C\u4E2D");
|
|
2162
2693
|
const reason = manifest && typeof manifest.stoppedReason === "string" ? manifest.stoppedReason : "";
|
|
2163
|
-
return reason ? stoppedReasonLabel(reason) : "\u5DF2\u7ED3\u675F";
|
|
2694
|
+
return reason ? stoppedReasonLabel(reason, getLang()) : t("\u5DF2\u7ED3\u675F");
|
|
2164
2695
|
}
|
|
2165
2696
|
function readSlots(ctx) {
|
|
2166
2697
|
if (ctx && ctx.slots && typeof ctx.slots.inject === "function" && typeof ctx.slots.register === "function") {
|
|
@@ -2184,7 +2715,7 @@ function readTheme(ctx) {
|
|
|
2184
2715
|
}
|
|
2185
2716
|
var slotsSvc = void 0;
|
|
2186
2717
|
var themeSvc = void 0;
|
|
2187
|
-
var
|
|
2718
|
+
var storage2 = null;
|
|
2188
2719
|
var themeDisposer = null;
|
|
2189
2720
|
var themeListener = null;
|
|
2190
2721
|
var themeEnabled = true;
|
|
@@ -2235,7 +2766,7 @@ function registerThemeListener(ctx) {
|
|
|
2235
2766
|
}
|
|
2236
2767
|
function setThemeEnabled(enabled) {
|
|
2237
2768
|
themeEnabled = enabled;
|
|
2238
|
-
if (
|
|
2769
|
+
if (storage2) storage2.set(THEME_STORAGE_KEY, enabled ? "1" : "0");
|
|
2239
2770
|
if (enabled) applyThemeSkin();
|
|
2240
2771
|
else clearThemeSkin();
|
|
2241
2772
|
}
|
|
@@ -2252,7 +2783,7 @@ function TrendChart({ points }) {
|
|
|
2252
2783
|
key: p.round,
|
|
2253
2784
|
className: "iterate-trend-bar",
|
|
2254
2785
|
"data-hot": p.count > 0 ? "" : void 0,
|
|
2255
|
-
title: `Round
|
|
2786
|
+
title: tf(`Round {a0}\uFF1A{a1} \u9879`, { a0: p.round, a1: p.count }),
|
|
2256
2787
|
style: { height: `${Math.max(4, Math.round(p.count / max * 24))}px` }
|
|
2257
2788
|
})
|
|
2258
2789
|
);
|
|
@@ -2260,7 +2791,7 @@ function TrendChart({ points }) {
|
|
|
2260
2791
|
return React.createElement("div", {
|
|
2261
2792
|
className: "iterate-trend",
|
|
2262
2793
|
role: "img",
|
|
2263
|
-
"aria-label": `\u5404\u8F6E\u53D1\u73B0\u6570\u91CF\u8D8B\u52BF\uFF1A
|
|
2794
|
+
"aria-label": tf(`\u5404\u8F6E\u53D1\u73B0\u6570\u91CF\u8D8B\u52BF\uFF1A{a0}`, { a0: summary })
|
|
2264
2795
|
}, ...bars);
|
|
2265
2796
|
}
|
|
2266
2797
|
function StartIterationButton() {
|
|
@@ -2269,7 +2800,7 @@ function StartIterationButton() {
|
|
|
2269
2800
|
const timers = React.useRef([]);
|
|
2270
2801
|
React.useEffect(
|
|
2271
2802
|
() => () => {
|
|
2272
|
-
for (const
|
|
2803
|
+
for (const t2 of timers.current) clearTimeout(t2);
|
|
2273
2804
|
timers.current = [];
|
|
2274
2805
|
},
|
|
2275
2806
|
[]
|
|
@@ -2279,8 +2810,8 @@ function StartIterationButton() {
|
|
|
2279
2810
|
if (ok) {
|
|
2280
2811
|
setFailed(null);
|
|
2281
2812
|
setCopied(key);
|
|
2282
|
-
const
|
|
2283
|
-
timers.current.push(
|
|
2813
|
+
const t2 = window.setTimeout(() => setCopied((cur) => cur === key ? null : cur), 1600);
|
|
2814
|
+
timers.current.push(t2);
|
|
2284
2815
|
} else {
|
|
2285
2816
|
setCopied(null);
|
|
2286
2817
|
setFailed(key);
|
|
@@ -2295,17 +2826,20 @@ function StartIterationButton() {
|
|
|
2295
2826
|
"data-failed": failed === key ? "" : void 0,
|
|
2296
2827
|
onClick: () => copy(key, command),
|
|
2297
2828
|
title
|
|
2298
|
-
}, copied === key ? "\u5DF2\u590D\u5236" : failed === key ? "\u590D\u5236\u5931\u8D25" : label);
|
|
2829
|
+
}, copied === key ? t("\u5DF2\u590D\u5236") : failed === key ? t("\u590D\u5236\u5931\u8D25") : label);
|
|
2299
2830
|
return React.createElement(
|
|
2300
2831
|
"span",
|
|
2301
2832
|
{ className: "iterate-dashboard-launch" },
|
|
2302
|
-
btn("start-full", "\u5B8C\u6574\u8FED\u4EE3", START_INSTRUCTIONS.full, true, "\u590D\u5236\u542F\u52A8\u6307\u4EE4\uFF1A\u5B8C\u6574\u300C\u5BA1\u67E5 \u2192 \u4FEE\u590D \u2192 \u9A8C\u8BC1 \u2192 \u590D\u76D8\u300D\u95ED\u73AF\uFF08\u7C98\u8D34\u7ED9\u6A21\u578B\u5373\u53EF\uFF09"),
|
|
2303
|
-
btn("start-review", "\u4EC5\u8BC4\u5BA1", START_INSTRUCTIONS.reviewOnly, false, "\u590D\u5236\u542F\u52A8\u6307\u4EE4\uFF1A\u53EA\u5BA1\u67E5\u4E0D\u4FEE\u6539\uFF08dry-run\uFF09\uFF08\u7C98\u8D34\u7ED9\u6A21\u578B\u5373\u53EF\uFF09")
|
|
2833
|
+
btn("start-full", t("\u5B8C\u6574\u8FED\u4EE3"), START_INSTRUCTIONS.full, true, t("\u590D\u5236\u542F\u52A8\u6307\u4EE4\uFF1A\u5B8C\u6574\u300C\u5BA1\u67E5 \u2192 \u4FEE\u590D \u2192 \u9A8C\u8BC1 \u2192 \u590D\u76D8\u300D\u95ED\u73AF\uFF08\u7C98\u8D34\u7ED9\u6A21\u578B\u5373\u53EF\uFF09")),
|
|
2834
|
+
btn("start-review", t("\u4EC5\u8BC4\u5BA1"), START_INSTRUCTIONS.reviewOnly, false, t("\u590D\u5236\u542F\u52A8\u6307\u4EE4\uFF1A\u53EA\u5BA1\u67E5\u4E0D\u4FEE\u6539\uFF08dry-run\uFF09\uFF08\u7C98\u8D34\u7ED9\u6A21\u578B\u5373\u53EF\uFF09"))
|
|
2304
2835
|
);
|
|
2305
2836
|
}
|
|
2306
2837
|
function ConvergenceDashboard(props) {
|
|
2307
2838
|
const [pulseKey, setPulseKey] = React.useState(0);
|
|
2308
2839
|
const session = props && props.session ? props.session : null;
|
|
2840
|
+
React.useEffect(() => {
|
|
2841
|
+
noteSession(session);
|
|
2842
|
+
}, [session]);
|
|
2309
2843
|
const report = latestReport(session);
|
|
2310
2844
|
React.useEffect(() => {
|
|
2311
2845
|
if (!report) return;
|
|
@@ -2320,11 +2854,11 @@ function ConvergenceDashboard(props) {
|
|
|
2320
2854
|
return React.createElement(
|
|
2321
2855
|
"div",
|
|
2322
2856
|
{ "data-iterate-root": "", "data-iterate": "dashboard", "data-run-state": "running", className: "iterate-dashboard iterate-dashboard-empty" },
|
|
2323
|
-
React.createElement("span", { className: "iterate-round-badge", "data-live": "" }, "\u8FD0\u884C\u4E2D"),
|
|
2857
|
+
React.createElement("span", { className: "iterate-round-badge", "data-live": "" }, t("\u8FD0\u884C\u4E2D")),
|
|
2324
2858
|
React.createElement(
|
|
2325
2859
|
"span",
|
|
2326
2860
|
{ className: "iterate-empty-hint" },
|
|
2327
|
-
`\u7B2C
|
|
2861
|
+
tf(`\u7B2C {a0} \u8F6E\u8FDB\u884C\u4E2D{a1}\u2014\u2014\u9996\u8F6E\u6C47\u603B\u62A5\u544A\u843D\u5730\u540E\uFF0C\u8FD9\u91CC\u4F1A\u663E\u793A\u6536\u655B\u8FDB\u5EA6\u4E0E\u53D1\u73B0\u7EDF\u8BA1\u3002`, { a0: String(runState.round), a1: runState.phase ? tf(` \xB7 \u9636\u6BB5\u300C{a0}\u300D`, { a0: runState.phase }) : "" })
|
|
2328
2862
|
)
|
|
2329
2863
|
// No start button while a run is active.
|
|
2330
2864
|
);
|
|
@@ -2333,11 +2867,11 @@ function ConvergenceDashboard(props) {
|
|
|
2333
2867
|
return React.createElement(
|
|
2334
2868
|
"div",
|
|
2335
2869
|
{ "data-iterate-root": "", "data-iterate": "dashboard", "data-run-state": "done", className: "iterate-dashboard iterate-dashboard-empty" },
|
|
2336
|
-
React.createElement("span", { className: "iterate-round-badge" }, "\u5DF2\u7ED3\u675F"),
|
|
2870
|
+
React.createElement("span", { className: "iterate-round-badge" }, t("\u5DF2\u7ED3\u675F")),
|
|
2337
2871
|
React.createElement(
|
|
2338
2872
|
"span",
|
|
2339
2873
|
{ className: "iterate-empty-hint" },
|
|
2340
|
-
`\u4E0A\u6B21\u8FED\u4EE3\u5728\u7B2C
|
|
2874
|
+
tf(`\u4E0A\u6B21\u8FED\u4EE3\u5728\u7B2C {a0} \u8F6E\u540E\u505C\u6B62{a1}\uFF0C\u4F46\u6CA1\u6709\u53EF\u5C55\u793A\u7684\u6C47\u603B\u62A5\u544A\u3002`, { a0: String(runState.round), a1: runState.stoppedReason ? parenthesize(stoppedReasonLabel(runState.stoppedReason, getLang())) : "" })
|
|
2341
2875
|
),
|
|
2342
2876
|
React.createElement(StartIterationButton, null)
|
|
2343
2877
|
);
|
|
@@ -2346,7 +2880,7 @@ function ConvergenceDashboard(props) {
|
|
|
2346
2880
|
"div",
|
|
2347
2881
|
{ "data-iterate-root": "", "data-iterate": "dashboard", "data-run-state": "empty", className: "iterate-dashboard iterate-dashboard-empty" },
|
|
2348
2882
|
React.createElement("span", { className: "iterate-round-badge" }, "iterate"),
|
|
2349
|
-
React.createElement("span", { className: "iterate-empty-hint" }, "\u8FD0\u884C\u4E00\u6B21\u8BC4\u5BA1\u540E\uFF0C\u8FD9\u91CC\u4F1A\u663E\u793A\u6536\u655B\u8FDB\u5EA6\u4E0E\u53D1\u73B0\u7EDF\u8BA1\u3002"),
|
|
2883
|
+
React.createElement("span", { className: "iterate-empty-hint" }, t("\u8FD0\u884C\u4E00\u6B21\u8BC4\u5BA1\u540E\uFF0C\u8FD9\u91CC\u4F1A\u663E\u793A\u6536\u655B\u8FDB\u5EA6\u4E0E\u53D1\u73B0\u7EDF\u8BA1\u3002")),
|
|
2350
2884
|
React.createElement(StartIterationButton, null)
|
|
2351
2885
|
);
|
|
2352
2886
|
}
|
|
@@ -2361,20 +2895,20 @@ function ConvergenceDashboard(props) {
|
|
|
2361
2895
|
const resumeChip = resumeCount > 0 ? React.createElement("span", {
|
|
2362
2896
|
className: "iterate-chip-resume",
|
|
2363
2897
|
key: "resume",
|
|
2364
|
-
title: "\u672C\u6B21\u8FED\u4EE3\u4ECE\u4E0A\u4E00\u6B21\u4E2D\u65AD\u7684\u65AD\u70B9\u7EE7\u7EED\u6267\u884C"
|
|
2365
|
-
}, `\u5DF2\u4E2D\u65AD\u6062\u590D \xD7
|
|
2898
|
+
title: t("\u672C\u6B21\u8FED\u4EE3\u4ECE\u4E0A\u4E00\u6B21\u4E2D\u65AD\u7684\u65AD\u70B9\u7EE7\u7EED\u6267\u884C")
|
|
2899
|
+
}, tf(`\u5DF2\u4E2D\u65AD\u6062\u590D \xD7{a0}`, { a0: String(resumeCount) })) : null;
|
|
2366
2900
|
const imageChip = imageCount > 0 ? React.createElement("span", {
|
|
2367
2901
|
className: "iterate-chip-images",
|
|
2368
2902
|
key: "images",
|
|
2369
|
-
title: "\u4F1A\u8BDD\u4E2D\u68C0\u6D4B\u5230\u7528\u6237\u9644\u5E26\u7684\u56FE\u7247\uFF0C\u8BC4\u5BA1\u5C06\u4F5C\u4E3A\u89C6\u89C9\u8BC1\u636E\u53C2\u8003"
|
|
2370
|
-
}, `\u9644\u4EF6\u56FE\u7247
|
|
2903
|
+
title: t("\u4F1A\u8BDD\u4E2D\u68C0\u6D4B\u5230\u7528\u6237\u9644\u5E26\u7684\u56FE\u7247\uFF0C\u8BC4\u5BA1\u5C06\u4F5C\u4E3A\u89C6\u89C9\u8BC1\u636E\u53C2\u8003")
|
|
2904
|
+
}, tf(`\u9644\u4EF6\u56FE\u7247 {a0}`, { a0: String(imageCount) })) : null;
|
|
2371
2905
|
const transcript = latestTranscript(session);
|
|
2372
2906
|
const phase = transcript ? latestPhase(transcript.phases) : "";
|
|
2373
2907
|
const liveChip = transcript && phase ? React.createElement("span", {
|
|
2374
2908
|
className: "iterate-chip-phase",
|
|
2375
2909
|
key: "phase",
|
|
2376
2910
|
"data-live": transcript.active === true ? "" : void 0,
|
|
2377
|
-
title: transcript.active === true ? `\u5F53\u524D\u5904\u4E8E\u300C
|
|
2911
|
+
title: transcript.active === true ? tf(`\u5F53\u524D\u5904\u4E8E\u300C{a0}\u300D\u9636\u6BB5\uFF08\u8FD0\u884C\u4E2D\uFF09`, { a0: phase }) : tf(`\u6700\u8FD1\u4E00\u6B21\u6267\u884C\u505C\u7559\u5728\u300C{a0}\u300D\u9636\u6BB5\uFF08\u5DF2\u7ED3\u675F\uFF09`, { a0: phase })
|
|
2378
2912
|
}, `${phase} \xB7 ${runStatusText(transcript.active === true, transcript)}`) : null;
|
|
2379
2913
|
const taskModeTranscript = latestTranscript(session);
|
|
2380
2914
|
const taskMode = taskModeTranscript?.taskMode;
|
|
@@ -2382,7 +2916,7 @@ function ConvergenceDashboard(props) {
|
|
|
2382
2916
|
className: "iterate-chip-taskmode",
|
|
2383
2917
|
key: "taskmode",
|
|
2384
2918
|
"data-mode": taskMode,
|
|
2385
|
-
title: taskMode === "code" ? "\u4EE3\u7801\u6A21\u5F0F\uFF1A\u76F4\u63A5\u4FEE\u6539\u6587\u4EF6" : "\u8FED\u4EE3\u6A21\u5F0F\uFF1A\u5BA1\u67E5-\u4FEE\u590D\u5FAA\u73AF"
|
|
2919
|
+
title: taskMode === "code" ? t("\u4EE3\u7801\u6A21\u5F0F\uFF1A\u76F4\u63A5\u4FEE\u6539\u6587\u4EF6") : t("\u8FED\u4EE3\u6A21\u5F0F\uFF1A\u5BA1\u67E5-\u4FEE\u590D\u5FAA\u73AF")
|
|
2386
2920
|
}, taskMode === "code" ? "\u25CF code" : "\u25CF iterate") : null;
|
|
2387
2921
|
const dimNames = Object.keys(dims);
|
|
2388
2922
|
const dimBadges = dimNames.slice(0, 6).map(
|
|
@@ -2398,7 +2932,7 @@ function ConvergenceDashboard(props) {
|
|
|
2398
2932
|
React.createElement(
|
|
2399
2933
|
"span",
|
|
2400
2934
|
{ key: "+more", className: "iterate-dim-badge iterate-dim-more", title: dimNames.slice(6).join(", ") },
|
|
2401
|
-
|
|
2935
|
+
tf(`+{a0} \u66F4\u591A`, { a0: overflow })
|
|
2402
2936
|
)
|
|
2403
2937
|
);
|
|
2404
2938
|
}
|
|
@@ -2409,14 +2943,14 @@ function ConvergenceDashboard(props) {
|
|
|
2409
2943
|
const fixBadge = fixCount !== null ? React.createElement("span", {
|
|
2410
2944
|
className: "iterate-metric",
|
|
2411
2945
|
key: "fixes",
|
|
2412
|
-
title: "\u672C\u8F6E\u5DF2\u5E94\u7528\u7684\u539F\u5B50\u4FEE\u590D\u6570\uFF08\u6B63\u5E38\u6A21\u5F0F\uFF09"
|
|
2946
|
+
title: t("\u672C\u8F6E\u5DF2\u5E94\u7528\u7684\u539F\u5B50\u4FEE\u590D\u6570\uFF08\u6B63\u5E38\u6A21\u5F0F\uFF09")
|
|
2413
2947
|
}, `${String(fixCount)} fixes`) : null;
|
|
2414
2948
|
const converged = report.convergence && report.convergence.converged === true;
|
|
2415
2949
|
const convChip = converged ? React.createElement("span", {
|
|
2416
2950
|
className: "iterate-chip-resume",
|
|
2417
2951
|
key: "converged",
|
|
2418
|
-
title: "\u5BA1\u67E5\u5DF2\u6536\u655B\uFF1A\u6700\u540E\u4E00\u8F6E\u672A\u53D1\u73B0\u65B0\u95EE\u9898"
|
|
2419
|
-
}, "\u2713 \u5DF2\u6536\u655B") : null;
|
|
2952
|
+
title: t("\u5BA1\u67E5\u5DF2\u6536\u655B\uFF1A\u6700\u540E\u4E00\u8F6E\u672A\u53D1\u73B0\u65B0\u95EE\u9898")
|
|
2953
|
+
}, t("\u2713 \u5DF2\u6536\u655B")) : null;
|
|
2420
2954
|
const sevMetric = (key, label) => React.createElement(
|
|
2421
2955
|
"span",
|
|
2422
2956
|
{ className: "iterate-metric", key, title: label },
|
|
@@ -2485,19 +3019,19 @@ function StatsCard(props) {
|
|
|
2485
3019
|
React.createElement("td", { style: { color: SEVERITY_COLOR.low } }, String(h.low))
|
|
2486
3020
|
)
|
|
2487
3021
|
);
|
|
2488
|
-
const trendLine = `\u9996\u8F6E
|
|
2489
|
-
const completion = buildCompletionSummary(report);
|
|
3022
|
+
const trendLine = tf(`\u9996\u8F6E {a0} \u2192 \u672B\u8F6E {a1} \u9879\uFF0C\u964D\u5E45 {a2}%{a3}`, { a0: trend.firstRound, a1: trend.lastRound, a2: trend.reductionPercent, a3: trend.converged ? t("\uFF0C\u5DF2\u6536\u655B") : "" });
|
|
3023
|
+
const completion = buildCompletionSummary(report, getLang());
|
|
2490
3024
|
return React.createElement(
|
|
2491
3025
|
"div",
|
|
2492
3026
|
{ "data-iterate-root": "", "data-iterate": "stats", className: "iterate-stats" },
|
|
2493
3027
|
React.createElement(
|
|
2494
3028
|
"div",
|
|
2495
3029
|
{ className: "iterate-triage-head" },
|
|
2496
|
-
React.createElement("span", {}, "Iterate \xB7 \u6536\u655B\u7EDF\u8BA1"),
|
|
3030
|
+
React.createElement("span", {}, t("Iterate \xB7 \u6536\u655B\u7EDF\u8BA1")),
|
|
2497
3031
|
React.createElement(
|
|
2498
3032
|
"span",
|
|
2499
3033
|
{ className: "iterate-triage-hint" },
|
|
2500
|
-
`Round ${getCurrentRound(report)}/${getTotalRounds(report)} \xB7 ${total} findings \xB7 ${report.convergence && report.convergence.converged ? "\u5DF2\u6536\u655B" : "\u672A\u6536\u655B"}`
|
|
3034
|
+
`Round ${getCurrentRound(report)}/${getTotalRounds(report)} \xB7 ${total} findings \xB7 ${report.convergence && report.convergence.converged ? t("\u5DF2\u6536\u655B") : t("\u672A\u6536\u655B")}`
|
|
2501
3035
|
)
|
|
2502
3036
|
),
|
|
2503
3037
|
React.createElement("div", { className: "iterate-stats-grid" }, ...rows),
|
|
@@ -2510,7 +3044,7 @@ function StatsCard(props) {
|
|
|
2510
3044
|
className: "iterate-btn",
|
|
2511
3045
|
"data-primary": showHistory ? "" : void 0,
|
|
2512
3046
|
onClick: () => setShowHistory((v) => !v)
|
|
2513
|
-
}, showHistory ? "\u6536\u8D77\u5386\u53F2" : "\u5386\u53F2 / \u8D8B\u52BF")
|
|
3047
|
+
}, showHistory ? t("\u6536\u8D77\u5386\u53F2") : t("\u5386\u53F2 / \u8D8B\u52BF"))
|
|
2514
3048
|
),
|
|
2515
3049
|
showHistory ? React.createElement(
|
|
2516
3050
|
"div",
|
|
@@ -2524,8 +3058,8 @@ function StatsCard(props) {
|
|
|
2524
3058
|
React.createElement(
|
|
2525
3059
|
"tr",
|
|
2526
3060
|
{},
|
|
2527
|
-
React.createElement("th", {}, "\u8F6E\u6B21"),
|
|
2528
|
-
React.createElement("th", {}, "\u53D1\u73B0"),
|
|
3061
|
+
React.createElement("th", {}, t("\u8F6E\u6B21")),
|
|
3062
|
+
React.createElement("th", {}, t("\u53D1\u73B0")),
|
|
2529
3063
|
React.createElement("th", { style: { color: SEVERITY_COLOR.critical } }, "CRIT"),
|
|
2530
3064
|
React.createElement("th", { style: { color: SEVERITY_COLOR.high } }, "HIGH"),
|
|
2531
3065
|
React.createElement("th", { style: { color: SEVERITY_COLOR.medium } }, "MED"),
|
|
@@ -2548,7 +3082,7 @@ function TriagePanel(props) {
|
|
|
2548
3082
|
const storageKey = TRIAGE_STORAGE_PREFIX + hashReport(report);
|
|
2549
3083
|
const [verdicts, setVerdicts] = React.useState(() => {
|
|
2550
3084
|
const initial = buildTriageState(report);
|
|
2551
|
-
const saved =
|
|
3085
|
+
const saved = storage2 ? storage2.get(storageKey) : null;
|
|
2552
3086
|
if (saved) {
|
|
2553
3087
|
try {
|
|
2554
3088
|
const parsed = JSON.parse(saved);
|
|
@@ -2573,7 +3107,7 @@ function TriagePanel(props) {
|
|
|
2573
3107
|
const [cmdFailed, setCmdFailed] = React.useState(null);
|
|
2574
3108
|
const cmdTimers = React.useRef([]);
|
|
2575
3109
|
React.useEffect(() => () => {
|
|
2576
|
-
for (const
|
|
3110
|
+
for (const t2 of cmdTimers.current) clearTimeout(t2);
|
|
2577
3111
|
cmdTimers.current = [];
|
|
2578
3112
|
}, []);
|
|
2579
3113
|
const copyWithFeedback = (text, key) => {
|
|
@@ -2590,7 +3124,7 @@ function TriagePanel(props) {
|
|
|
2590
3124
|
});
|
|
2591
3125
|
};
|
|
2592
3126
|
React.useEffect(() => {
|
|
2593
|
-
if (
|
|
3127
|
+
if (storage2) storage2.set(storageKey, JSON.stringify(verdicts));
|
|
2594
3128
|
}, [storageKey, verdicts]);
|
|
2595
3129
|
const setVerdict = (index, verdict) => {
|
|
2596
3130
|
setVerdicts((prev) => ({ ...prev, [String(index)]: verdict }));
|
|
@@ -2617,9 +3151,9 @@ function TriagePanel(props) {
|
|
|
2617
3151
|
if (!doc) return;
|
|
2618
3152
|
const onKeyDown = (ev) => {
|
|
2619
3153
|
if (ev.metaKey || ev.ctrlKey || ev.altKey) return;
|
|
2620
|
-
const
|
|
2621
|
-
if (
|
|
2622
|
-
if (
|
|
3154
|
+
const t2 = ev.target;
|
|
3155
|
+
if (t2 && (t2.tagName === "INPUT" || t2.tagName === "TEXTAREA" || t2.tagName === "SELECT")) return;
|
|
3156
|
+
if (t2 && typeof t2.isContentEditable === "boolean" && t2.isContentEditable) return;
|
|
2623
3157
|
const rootEl = doc.querySelector('[data-iterate="triage"]');
|
|
2624
3158
|
if (!rootEl) return;
|
|
2625
3159
|
const activeEl = doc.activeElement;
|
|
@@ -2658,11 +3192,11 @@ function TriagePanel(props) {
|
|
|
2658
3192
|
copyWithFeedback(cmd, "approve-arch");
|
|
2659
3193
|
};
|
|
2660
3194
|
const doTriggerNewRound = () => {
|
|
2661
|
-
const cmd = "\u8BF7\u7EE7\u7EED\u6267\u884C\u4E0B\u4E00\u8F6E\u8FED\u4EE3\u5BA1\u67E5";
|
|
3195
|
+
const cmd = t("\u8BF7\u7EE7\u7EED\u6267\u884C\u4E0B\u4E00\u8F6E\u8FED\u4EE3\u5BA1\u67E5");
|
|
2662
3196
|
copyWithFeedback(cmd, "new-round");
|
|
2663
3197
|
};
|
|
2664
3198
|
const doRollbackToCheckpoint = () => {
|
|
2665
|
-
const cmd = "\u8BF7\u56DE\u6EDA\u4E0A\u4E00\u8F6E\u8FED\u4EE3\u7684\u4FEE\u590D\uFF1A\u8C03\u7528 `iterate_history` \u67E5\u770B\u672C\u8F6E fix id\uFF0C\u518D\u7528 `iterate_rollback` \u9010\u4E2A\u64A4\u9500\u8FD9\u4E9B\u4FEE\u590D";
|
|
3199
|
+
const cmd = t("\u8BF7\u56DE\u6EDA\u4E0A\u4E00\u8F6E\u8FED\u4EE3\u7684\u4FEE\u590D\uFF1A\u8C03\u7528 `iterate_history` \u67E5\u770B\u672C\u8F6E fix id\uFF0C\u518D\u7528 `iterate_rollback` \u9010\u4E2A\u64A4\u9500\u8FD9\u4E9B\u4FEE\u590D");
|
|
2666
3200
|
copyWithFeedback(cmd, "rollback");
|
|
2667
3201
|
};
|
|
2668
3202
|
const doAssignFindings = () => {
|
|
@@ -2750,9 +3284,9 @@ function TriagePanel(props) {
|
|
|
2750
3284
|
React.createElement(
|
|
2751
3285
|
"div",
|
|
2752
3286
|
{ className: "iterate-finding-actions" },
|
|
2753
|
-
btn("y \u4FEE\u590D", "keep", "\u4FDD\u7559\u8BE5 finding\uFF0C\u8FDB\u5165\u4FEE\u590D"),
|
|
2754
|
-
btn("n \u8DF3\u8FC7", "skip", "\u8DF3\u8FC7\u8BE5 finding"),
|
|
2755
|
-
btn("a \u5DF2\u77E5\u6709\u610F", "ignore", "\u6807\u8BB0\u4E3A\u5DF2\u77E5\u6709\u610F\u5E76\u5199\u5165 known_intentional")
|
|
3287
|
+
btn(t("y \u4FEE\u590D"), "keep", t("\u4FDD\u7559\u8BE5 finding\uFF0C\u8FDB\u5165\u4FEE\u590D")),
|
|
3288
|
+
btn(t("n \u8DF3\u8FC7"), "skip", t("\u8DF3\u8FC7\u8BE5 finding")),
|
|
3289
|
+
btn(t("a \u5DF2\u77E5\u6709\u610F"), "ignore", t("\u6807\u8BB0\u4E3A\u5DF2\u77E5\u6709\u610F\u5E76\u5199\u5165 known_intentional"))
|
|
2756
3290
|
)
|
|
2757
3291
|
);
|
|
2758
3292
|
});
|
|
@@ -2762,24 +3296,24 @@ function TriagePanel(props) {
|
|
|
2762
3296
|
React.createElement(
|
|
2763
3297
|
"div",
|
|
2764
3298
|
{ className: "iterate-triage-head" },
|
|
2765
|
-
React.createElement("span", { role: "heading", "aria-level": 3 }, `Iterate \xB7 Findings \u5206\u8BCA (
|
|
2766
|
-
React.createElement("span", { className: "iterate-triage-hint" }, "y=\u4FEE\u590D \xB7 n=\u8DF3\u8FC7 \xB7 a=\u5DF2\u77E5\u6709\u610F \xB7 \u2191/\u2193 \u9009\u62E9")
|
|
3299
|
+
React.createElement("span", { role: "heading", "aria-level": 3 }, tf(`Iterate \xB7 Findings \u5206\u8BCA ({a0}/{a1})`, { a0: filtered.length, a1: findings.length })),
|
|
3300
|
+
React.createElement("span", { className: "iterate-triage-hint" }, t("y=\u4FEE\u590D \xB7 n=\u8DF3\u8FC7 \xB7 a=\u5DF2\u77E5\u6709\u610F \xB7 \u2191/\u2193 \u9009\u62E9"))
|
|
2767
3301
|
),
|
|
2768
3302
|
React.createElement(
|
|
2769
3303
|
"div",
|
|
2770
3304
|
{ className: "iterate-filter" },
|
|
2771
3305
|
React.createElement(
|
|
2772
3306
|
"select",
|
|
2773
|
-
{ className: "iterate-filter-select", value: filter.severities[0] || "", onChange: (e) => setSeverityFilter(e.target.value), "aria-label": "\u6309\u4E25\u91CD\u5EA6\u7B5B\u9009" },
|
|
2774
|
-
React.createElement("option", { value: "" }, "\u5168\u90E8\u4E25\u91CD\u5EA6"),
|
|
3307
|
+
{ className: "iterate-filter-select", value: filter.severities[0] || "", onChange: (e) => setSeverityFilter(e.target.value), "aria-label": t("\u6309\u4E25\u91CD\u5EA6\u7B5B\u9009") },
|
|
3308
|
+
React.createElement("option", { value: "" }, t("\u5168\u90E8\u4E25\u91CD\u5EA6")),
|
|
2775
3309
|
...options.severities.map(
|
|
2776
3310
|
(s) => React.createElement("option", { key: s.value, value: s.value }, `${severityLabel(s.value)} (${s.count})`)
|
|
2777
3311
|
)
|
|
2778
3312
|
),
|
|
2779
3313
|
React.createElement(
|
|
2780
3314
|
"select",
|
|
2781
|
-
{ className: "iterate-filter-select", value: filter.dimensions[0] || "", onChange: (e) => setDimensionFilter(e.target.value), "aria-label": "\u6309\u7EF4\u5EA6\u7B5B\u9009" },
|
|
2782
|
-
React.createElement("option", { value: "" }, "\u5168\u90E8\u7EF4\u5EA6"),
|
|
3315
|
+
{ className: "iterate-filter-select", value: filter.dimensions[0] || "", onChange: (e) => setDimensionFilter(e.target.value), "aria-label": t("\u6309\u7EF4\u5EA6\u7B5B\u9009") },
|
|
3316
|
+
React.createElement("option", { value: "" }, t("\u5168\u90E8\u7EF4\u5EA6")),
|
|
2783
3317
|
...options.dimensions.map(
|
|
2784
3318
|
(d) => React.createElement("option", { key: d.value, value: d.value }, `${d.value} (${d.count})`)
|
|
2785
3319
|
)
|
|
@@ -2787,41 +3321,41 @@ function TriagePanel(props) {
|
|
|
2787
3321
|
React.createElement("input", {
|
|
2788
3322
|
className: "iterate-filter-search",
|
|
2789
3323
|
type: "search",
|
|
2790
|
-
placeholder: "\u641C\u7D22\u6587\u4EF6 / \u6458\u8981\u2026",
|
|
2791
|
-
"aria-label": "\u641C\u7D22\u6587\u4EF6\u6216\u6458\u8981",
|
|
3324
|
+
placeholder: t("\u641C\u7D22\u6587\u4EF6 / \u6458\u8981\u2026"),
|
|
3325
|
+
"aria-label": t("\u641C\u7D22\u6587\u4EF6\u6216\u6458\u8981"),
|
|
2792
3326
|
value: filter.search,
|
|
2793
3327
|
onChange: (e) => setSearchFilter(e.target.value)
|
|
2794
3328
|
}),
|
|
2795
3329
|
React.createElement(
|
|
2796
3330
|
"span",
|
|
2797
3331
|
{ className: "iterate-filter-count" },
|
|
2798
|
-
isFilterActive ? React.createElement("button", { className: "iterate-batch-btn", onClick: clearFilter }, `\u6E05\u9664\u7B5B\u9009\uFF08\u663E\u793A
|
|
3332
|
+
isFilterActive ? React.createElement("button", { className: "iterate-batch-btn", onClick: clearFilter }, tf(`\u6E05\u9664\u7B5B\u9009\uFF08\u663E\u793A {a0}\uFF09`, { a0: filtered.length })) : tf(`\u5171 {a0} \u9879`, { a0: findings.length })
|
|
2799
3333
|
)
|
|
2800
3334
|
),
|
|
2801
3335
|
React.createElement(
|
|
2802
3336
|
"div",
|
|
2803
3337
|
{ className: "iterate-batch" },
|
|
2804
|
-
React.createElement("span", { className: "iterate-batch-label" }, "\u6279\u91CF\u4F5C\u7528\u4E8E\uFF1A"),
|
|
3338
|
+
React.createElement("span", { className: "iterate-batch-label" }, t("\u6279\u91CF\u4F5C\u7528\u4E8E\uFF1A")),
|
|
2805
3339
|
React.createElement("button", {
|
|
2806
3340
|
className: selectAll ? "iterate-batch-btn iterate-batch-scope" : "iterate-batch-btn iterate-batch-scope iterate-batch-scope-on",
|
|
2807
3341
|
onClick: () => setSelectAll(false),
|
|
2808
|
-
title: "\u6279\u91CF\u6309\u94AE\u4EC5\u4F5C\u7528\u4E8E\u5F53\u524D\u7B5B\u9009\u53EF\u89C1\u7684 findings"
|
|
2809
|
-
}, `\u53EF\u89C1
|
|
3342
|
+
title: t("\u6279\u91CF\u6309\u94AE\u4EC5\u4F5C\u7528\u4E8E\u5F53\u524D\u7B5B\u9009\u53EF\u89C1\u7684 findings")
|
|
3343
|
+
}, tf(`\u53EF\u89C1 {a0}`, { a0: indices.length })),
|
|
2810
3344
|
React.createElement("button", {
|
|
2811
3345
|
className: selectAll ? "iterate-batch-btn iterate-batch-scope iterate-batch-scope-on" : "iterate-batch-btn iterate-batch-scope",
|
|
2812
3346
|
onClick: () => setSelectAll(true),
|
|
2813
|
-
title: "\u6279\u91CF\u6309\u94AE\u4F5C\u7528\u4E8E\u5168\u90E8 findings"
|
|
2814
|
-
}, `\u5168\u90E8
|
|
3347
|
+
title: t("\u6279\u91CF\u6309\u94AE\u4F5C\u7528\u4E8E\u5168\u90E8 findings")
|
|
3348
|
+
}, tf(`\u5168\u90E8 {a0}`, { a0: allIndices.length })),
|
|
2815
3349
|
React.createElement("button", { className: "iterate-batch-btn", onClick: () => applyBatch("keep") }, "y"),
|
|
2816
3350
|
React.createElement("button", { className: "iterate-batch-btn", onClick: () => applyBatch("skip") }, "n"),
|
|
2817
3351
|
React.createElement("button", { className: "iterate-batch-btn", onClick: () => applyBatch("ignore") }, "a"),
|
|
2818
|
-
React.createElement("button", { className: "iterate-batch-btn", onClick: doResetVerdicts, title: "\u628A\u6240\u6709\u5224\u5B9A\u6062\u590D\u4E3A\u9ED8\u8BA4 y\uFF08\u4FEE\u590D\uFF09" }, "\u91CD\u7F6E")
|
|
3352
|
+
React.createElement("button", { className: "iterate-batch-btn", onClick: doResetVerdicts, title: t("\u628A\u6240\u6709\u5224\u5B9A\u6062\u590D\u4E3A\u9ED8\u8BA4 y\uFF08\u4FEE\u590D\uFF09") }, t("\u91CD\u7F6E"))
|
|
2819
3353
|
),
|
|
2820
3354
|
...rows,
|
|
2821
3355
|
React.createElement(
|
|
2822
3356
|
"div",
|
|
2823
3357
|
{ className: "iterate-triage-foot" },
|
|
2824
|
-
React.createElement("span", {}, `y
|
|
3358
|
+
React.createElement("span", {}, tf(`y {a0} \xB7 n {a1} \xB7 a {a2} \xB7 \u5F85\u5199\u56DE known_intentional\uFF1A{a3} \u6761`, { a0: counts.keep, a1: counts.skip, a2: counts.ignore, a3: ignoredCount })),
|
|
2825
3359
|
React.createElement(
|
|
2826
3360
|
"span",
|
|
2827
3361
|
{ style: { display: "flex", gap: 6, flexWrap: "wrap" } },
|
|
@@ -2834,31 +3368,31 @@ function TriagePanel(props) {
|
|
|
2834
3368
|
"data-failed": cmdFailed === "apply" ? "" : void 0,
|
|
2835
3369
|
onClick: doBuildInstruction,
|
|
2836
3370
|
disabled: ignoredCount === 0,
|
|
2837
|
-
title: ignoredCount === 0 ? "\u5F53\u524D\u6CA1\u6709\u6807\u8BB0\u4E3A\u300C\u5DF2\u77E5\u6709\u610F\u300D\u7684 finding" : "\u590D\u5236\u5E94\u7528\u6307\u4EE4\uFF1A\u7C98\u8D34\u540E\u6A21\u578B\u4F1A\u8C03\u7528 iterate_triage apply\uFF08\u6821\u9A8C\u3001\u53BB\u91CD\u3001\u5199\u5165\u524D\u5907\u4EFD\u3001\u5931\u8D25\u81EA\u52A8\u56DE\u6EDA\uFF09"
|
|
2838
|
-
}, cmdCopied === "apply" ? "\u5DF2\u590D\u5236" : cmdFailed === "apply" ? "\u590D\u5236\u5931\u8D25" : `\u751F\u6210\u5E94\u7528\u6307\u4EE4
|
|
3371
|
+
title: ignoredCount === 0 ? t("\u5F53\u524D\u6CA1\u6709\u6807\u8BB0\u4E3A\u300C\u5DF2\u77E5\u6709\u610F\u300D\u7684 finding") : t("\u590D\u5236\u5E94\u7528\u6307\u4EE4\uFF1A\u7C98\u8D34\u540E\u6A21\u578B\u4F1A\u8C03\u7528 iterate_triage apply\uFF08\u6821\u9A8C\u3001\u53BB\u91CD\u3001\u5199\u5165\u524D\u5907\u4EFD\u3001\u5931\u8D25\u81EA\u52A8\u56DE\u6EDA\uFF09")
|
|
3372
|
+
}, cmdCopied === "apply" ? t("\u5DF2\u590D\u5236") : cmdFailed === "apply" ? t("\u590D\u5236\u5931\u8D25") : tf(`\u751F\u6210\u5E94\u7528\u6307\u4EE4{a0}`, { a0: ignoredCount > 0 ? `\uFF08${ignoredCount}\uFF09` : "" })),
|
|
2839
3373
|
React.createElement("button", {
|
|
2840
3374
|
className: "iterate-btn",
|
|
2841
3375
|
"data-copied": copied ? "" : void 0,
|
|
2842
3376
|
"data-failed": cmdFailed === "yaml" ? "" : void 0,
|
|
2843
3377
|
onClick: doCopyYaml,
|
|
2844
3378
|
disabled: ignoredCount === 0,
|
|
2845
|
-
title: ignoredCount === 0 ? "\u5F53\u524D\u6CA1\u6709\u6807\u8BB0\u4E3A\u300C\u5DF2\u77E5\u6709\u610F\u300D\u7684 finding" : "\u53EA\u590D\u5236 known_intentional YAML \u7247\u6BB5\uFF08\u9700\u81EA\u884C\u7C98\u5230 iterate.config.yaml \u7684 personalization.known_intentional \u4E0B\uFF09"
|
|
2846
|
-
}, copied ? "\u5DF2\u590D\u5236" : cmdFailed === "yaml" ? "\u590D\u5236\u5931\u8D25" : "\u4EC5\u590D\u5236 YAML \u7247\u6BB5"),
|
|
3379
|
+
title: ignoredCount === 0 ? t("\u5F53\u524D\u6CA1\u6709\u6807\u8BB0\u4E3A\u300C\u5DF2\u77E5\u6709\u610F\u300D\u7684 finding") : t("\u53EA\u590D\u5236 known_intentional YAML \u7247\u6BB5\uFF08\u9700\u81EA\u884C\u7C98\u5230 iterate.config.yaml \u7684 personalization.known_intentional \u4E0B\uFF09")
|
|
3380
|
+
}, copied ? t("\u5DF2\u590D\u5236") : cmdFailed === "yaml" ? t("\u590D\u5236\u5931\u8D25") : t("\u4EC5\u590D\u5236 YAML \u7247\u6BB5")),
|
|
2847
3381
|
React.createElement("button", {
|
|
2848
3382
|
className: "iterate-btn",
|
|
2849
3383
|
"data-copied": cmdCopied === "readback" ? "" : void 0,
|
|
2850
3384
|
"data-failed": cmdFailed === "readback" ? "" : void 0,
|
|
2851
3385
|
onClick: doReadback,
|
|
2852
|
-
title: "\u590D\u5236 iterate_triage list \u6307\u4EE4\uFF0C\u6838\u5BF9\u5DF2\u7ECF\u5199\u5165\u7684 known_intentional \u6761\u76EE\uFF08\u5199\u56DE\u95ED\u73AF\u786E\u8BA4\uFF09"
|
|
2853
|
-
}, cmdCopied === "readback" ? "\u5DF2\u590D\u5236" : cmdFailed === "readback" ? "\u590D\u5236\u5931\u8D25" : "\u56DE\u8BFB\u5DF2\u5199\u5165\u6761\u76EE")
|
|
3386
|
+
title: t("\u590D\u5236 iterate_triage list \u6307\u4EE4\uFF0C\u6838\u5BF9\u5DF2\u7ECF\u5199\u5165\u7684 known_intentional \u6761\u76EE\uFF08\u5199\u56DE\u95ED\u73AF\u786E\u8BA4\uFF09")
|
|
3387
|
+
}, cmdCopied === "readback" ? t("\u5DF2\u590D\u5236") : cmdFailed === "readback" ? t("\u590D\u5236\u5931\u8D25") : t("\u56DE\u8BFB\u5DF2\u5199\u5165\u6761\u76EE"))
|
|
2854
3388
|
),
|
|
2855
|
-
cmdCopied === "apply" ? React.createElement("span", { className: "iterate-triage-hint", role: "status" }, "\u5DF2\u590D\u5236\u5E94\u7528\u6307\u4EE4\u2014\u2014\u7C98\u8D34\u56DE\u4F1A\u8BDD\uFF0C\u6A21\u578B\u5C06\u8C03\u7528 iterate_triage apply \u5E76\u56DE\u62A5\u5199\u5165\u6761\u6570\u3002") : cmdCopied === "readback" ? React.createElement("span", { className: "iterate-triage-hint", role: "status" }, "\u5DF2\u590D\u5236\u56DE\u8BFB\u6307\u4EE4\u2014\u2014\u7C98\u8D34\u56DE\u4F1A\u8BDD\u53EF\u5217\u51FA\u5F53\u524D\u5DF2\u5199\u5165\u7684 known_intentional\u3002") : null
|
|
3389
|
+
cmdCopied === "apply" ? React.createElement("span", { className: "iterate-triage-hint", role: "status" }, t("\u5DF2\u590D\u5236\u5E94\u7528\u6307\u4EE4\u2014\u2014\u7C98\u8D34\u56DE\u4F1A\u8BDD\uFF0C\u6A21\u578B\u5C06\u8C03\u7528 iterate_triage apply \u5E76\u56DE\u62A5\u5199\u5165\u6761\u6570\u3002")) : cmdCopied === "readback" ? React.createElement("span", { className: "iterate-triage-hint", role: "status" }, t("\u5DF2\u590D\u5236\u56DE\u8BFB\u6307\u4EE4\u2014\u2014\u7C98\u8D34\u56DE\u4F1A\u8BDD\u53EF\u5217\u51FA\u5F53\u524D\u5DF2\u5199\u5165\u7684 known_intentional\u3002")) : null
|
|
2856
3390
|
),
|
|
2857
3391
|
// v3.0: Command buttons for native actions (§8)
|
|
2858
3392
|
React.createElement(
|
|
2859
3393
|
"div",
|
|
2860
3394
|
{ className: "iterate-triage-foot", style: { borderTop: "1px solid var(--dsw-alias-border-l1)" } },
|
|
2861
|
-
React.createElement("span", { style: { fontSize: 11, fontWeight: 600, color: "var(--dsw-alias-label-secondary)" } }, "\u6307\u6325\u64CD\u4F5C"),
|
|
3395
|
+
React.createElement("span", { style: { fontSize: 11, fontWeight: 600, color: "var(--dsw-alias-label-secondary)" } }, t("\u6307\u6325\u64CD\u4F5C")),
|
|
2862
3396
|
React.createElement(
|
|
2863
3397
|
"span",
|
|
2864
3398
|
{ style: { display: "flex", gap: 6, flexWrap: "wrap" } },
|
|
@@ -2868,15 +3402,15 @@ function TriagePanel(props) {
|
|
|
2868
3402
|
"data-copied": cmdCopied === "approve-arch" ? "" : void 0,
|
|
2869
3403
|
"data-failed": cmdFailed === "approve-arch" ? "" : void 0,
|
|
2870
3404
|
onClick: doApproveArchitecturalFix,
|
|
2871
|
-
title: "\u6279\u51C6\u67B6\u6784\u4FEE\u590D\uFF08\u590D\u5236\u6307\u4EE4\u6587\u672C\uFF1Aiterate_fix force:true\uFF0C\u542B\u5168\u90E8\u5FC5\u586B\u53C2\u6570\uFF09"
|
|
2872
|
-
}, cmdCopied === "approve-arch" ? "\u5DF2\u590D\u5236" : cmdFailed === "approve-arch" ? "\u590D\u5236\u5931\u8D25" : "\u6279\u51C6\u67B6\u6784\u4FEE\u590D"),
|
|
3405
|
+
title: t("\u6279\u51C6\u67B6\u6784\u4FEE\u590D\uFF08\u590D\u5236\u6307\u4EE4\u6587\u672C\uFF1Aiterate_fix force:true\uFF0C\u542B\u5168\u90E8\u5FC5\u586B\u53C2\u6570\uFF09")
|
|
3406
|
+
}, cmdCopied === "approve-arch" ? t("\u5DF2\u590D\u5236") : cmdFailed === "approve-arch" ? t("\u590D\u5236\u5931\u8D25") : t("\u6279\u51C6\u67B6\u6784\u4FEE\u590D")),
|
|
2873
3407
|
React.createElement("button", {
|
|
2874
3408
|
className: "iterate-cmd",
|
|
2875
3409
|
"data-copied": cmdCopied === "new-round" ? "" : void 0,
|
|
2876
3410
|
"data-failed": cmdFailed === "new-round" ? "" : void 0,
|
|
2877
3411
|
onClick: doTriggerNewRound,
|
|
2878
|
-
title: "\u89E6\u53D1\u65B0\u4E00\u8F6E\u8FED\u4EE3\u5BA1\u67E5"
|
|
2879
|
-
}, cmdCopied === "new-round" ? "\u5DF2\u590D\u5236" : cmdFailed === "new-round" ? "\u590D\u5236\u5931\u8D25" : "\u89E6\u53D1\u65B0\u4E00\u8F6E"),
|
|
3412
|
+
title: t("\u89E6\u53D1\u65B0\u4E00\u8F6E\u8FED\u4EE3\u5BA1\u67E5")
|
|
3413
|
+
}, cmdCopied === "new-round" ? t("\u5DF2\u590D\u5236") : cmdFailed === "new-round" ? t("\u590D\u5236\u5931\u8D25") : t("\u89E6\u53D1\u65B0\u4E00\u8F6E")),
|
|
2880
3414
|
React.createElement("button", {
|
|
2881
3415
|
className: "iterate-cmd",
|
|
2882
3416
|
"data-primary": "",
|
|
@@ -2884,16 +3418,16 @@ function TriagePanel(props) {
|
|
|
2884
3418
|
"data-failed": cmdFailed === "assign" ? "" : void 0,
|
|
2885
3419
|
onClick: doAssignFindings,
|
|
2886
3420
|
disabled: (selectAll ? allIndices : indices).length === 0,
|
|
2887
|
-
title: selectAll ? `\u6307\u6D3E\u5168\u90E8
|
|
2888
|
-
}, cmdCopied === "assign" ? "\u5DF2\u590D\u5236" : cmdFailed === "assign" ? "\u590D\u5236\u5931\u8D25" : "\u6307\u6D3E\u4FEE\u590D"),
|
|
3421
|
+
title: selectAll ? tf(`\u6307\u6D3E\u5168\u90E8 {a0} \u4E2A findings \u4FEE\u590D\uFF08\u9010\u4E2A iterate_fix\uFF09`, { a0: allIndices.length }) : tf(`\u6307\u6D3E\u5F53\u524D\u53EF\u89C1 {a0} \u4E2A findings \u4FEE\u590D\uFF08\u9010\u4E2A iterate_fix\uFF09`, { a0: indices.length })
|
|
3422
|
+
}, cmdCopied === "assign" ? t("\u5DF2\u590D\u5236") : cmdFailed === "assign" ? t("\u590D\u5236\u5931\u8D25") : t("\u6307\u6D3E\u4FEE\u590D")),
|
|
2889
3423
|
React.createElement("button", {
|
|
2890
3424
|
className: "iterate-cmd",
|
|
2891
3425
|
"data-danger": "",
|
|
2892
3426
|
"data-copied": cmdCopied === "rollback" ? "" : void 0,
|
|
2893
3427
|
"data-failed": cmdFailed === "rollback" ? "" : void 0,
|
|
2894
3428
|
onClick: doRollbackToCheckpoint,
|
|
2895
|
-
title: "\u56DE\u6EDA\u5230\u4E0A\u4E00\u4E2A\u68C0\u67E5\u70B9"
|
|
2896
|
-
}, cmdCopied === "rollback" ? "\u5DF2\u590D\u5236" : cmdFailed === "rollback" ? "\u590D\u5236\u5931\u8D25" : "\u56DE\u6EDA\u68C0\u67E5\u70B9")
|
|
3429
|
+
title: t("\u56DE\u6EDA\u5230\u4E0A\u4E00\u4E2A\u68C0\u67E5\u70B9")
|
|
3430
|
+
}, cmdCopied === "rollback" ? t("\u5DF2\u590D\u5236") : cmdFailed === "rollback" ? t("\u590D\u5236\u5931\u8D25") : t("\u56DE\u6EDA\u68C0\u67E5\u70B9"))
|
|
2897
3431
|
)
|
|
2898
3432
|
),
|
|
2899
3433
|
payload ? React.createElement("div", { className: "iterate-payload" }, payload) : null
|
|
@@ -2916,16 +3450,16 @@ function VerdictBanner(props) {
|
|
|
2916
3450
|
React.createElement(
|
|
2917
3451
|
"span",
|
|
2918
3452
|
{ className: "iterate-verdict-tag", "data-ok": ok ? "" : void 0, "data-warn": ok ? void 0 : "" },
|
|
2919
|
-
ok ? "\u62A5\u544A\u5DF2\u6279\u51C6" : "\u62A5\u544A\u9700\u4FEE\u8BA2"
|
|
3453
|
+
ok ? t("\u62A5\u544A\u5DF2\u6279\u51C6") : t("\u62A5\u544A\u9700\u4FEE\u8BA2")
|
|
2920
3454
|
),
|
|
2921
3455
|
React.createElement(
|
|
2922
3456
|
"span",
|
|
2923
3457
|
{ className: "iterate-verdict-detail" },
|
|
2924
|
-
item(verdict.totalFindings, "\u9879\u53D1\u73B0"),
|
|
2925
|
-
item(verdict.totalRounds, "\u8F6E"),
|
|
2926
|
-
item(verdict.checksRun, "\u9879\u5BA1\u67E5"),
|
|
2927
|
-
ok ? phrase("\u62A5\u544A\u901A\u8FC7\u5168\u90E8\u4E00\u81F4\u6027\u68C0\u67E5") : item(verdict.reportIssues, "\u5904\u62A5\u544A\u7F3A\u9677"),
|
|
2928
|
-
phrase(verdict.converged ? "\u5DF2\u6536\u655B" : "\u672A\u6536\u655B")
|
|
3458
|
+
item(verdict.totalFindings, t("\u9879\u53D1\u73B0")),
|
|
3459
|
+
item(verdict.totalRounds, t("\u8F6E")),
|
|
3460
|
+
item(verdict.checksRun, t("\u9879\u5BA1\u67E5")),
|
|
3461
|
+
ok ? phrase(t("\u62A5\u544A\u901A\u8FC7\u5168\u90E8\u4E00\u81F4\u6027\u68C0\u67E5")) : item(verdict.reportIssues, t("\u5904\u62A5\u544A\u7F3A\u9677")),
|
|
3462
|
+
phrase(verdict.converged ? t("\u5DF2\u6536\u655B") : t("\u672A\u6536\u655B"))
|
|
2929
3463
|
)
|
|
2930
3464
|
);
|
|
2931
3465
|
}
|
|
@@ -2967,7 +3501,7 @@ function ProgressCapsule() {
|
|
|
2967
3501
|
const listener = (payload) => {
|
|
2968
3502
|
const converged = payload && payload.converged === true;
|
|
2969
3503
|
const round = payload && typeof payload.round === "number" ? payload.round : "?";
|
|
2970
|
-
setInfo({ text: converged ? `Round
|
|
3504
|
+
setInfo({ text: converged ? tf(`Round {a0} \u5B8C\u6210 \xB7 \u5DF2\u6536\u655B`, { a0: round }) : tf(`Round {a0} \u5B8C\u6210`, { a0: round }), ok: converged });
|
|
2971
3505
|
if (timer) clearTimeout(timer);
|
|
2972
3506
|
timer = setTimeout(() => setInfo(null), converged ? 3600 : 2400);
|
|
2973
3507
|
};
|
|
@@ -2987,7 +3521,10 @@ function ProgressCapsule() {
|
|
|
2987
3521
|
"aria-live": "polite"
|
|
2988
3522
|
}, info.text);
|
|
2989
3523
|
}
|
|
2990
|
-
function SettingsPanel(
|
|
3524
|
+
function SettingsPanel(props) {
|
|
3525
|
+
const lang = useLang();
|
|
3526
|
+
const cachedSession = useSessionSnapshot();
|
|
3527
|
+
const session = props && props.session ? props.session : cachedSession;
|
|
2991
3528
|
const [enabled, setEnabled] = React.useState(themeEnabled);
|
|
2992
3529
|
const [guideCopied, setGuideCopied] = React.useState(false);
|
|
2993
3530
|
const [statusCopied, setStatusCopied] = React.useState(false);
|
|
@@ -3001,13 +3538,19 @@ function SettingsPanel(_props) {
|
|
|
3001
3538
|
const [cfgCopied, setCfgCopied] = React.useState(false);
|
|
3002
3539
|
const [cfgFailed, setCfgFailed] = React.useState(false);
|
|
3003
3540
|
const [cfgText, setCfgText] = React.useState(null);
|
|
3541
|
+
const [cfgReadCopied, setCfgReadCopied] = React.useState(false);
|
|
3542
|
+
const [cfgReadText, setCfgReadText] = React.useState(null);
|
|
3004
3543
|
const [pullCopied, setPullCopied] = React.useState(false);
|
|
3005
3544
|
const [copyError, setCopyError] = React.useState(null);
|
|
3006
3545
|
const guide = buildConfigEditGuide();
|
|
3007
3546
|
const statusGuide = buildRuntimeStatusGuide();
|
|
3547
|
+
const cfgMeta = configFieldByKey(cfgField);
|
|
3548
|
+
const cfgRead = scanSessionForConfigRead(session);
|
|
3549
|
+
const cfgCurrent = cfgRead ? configValueByPath(cfgRead, cfgField) : null;
|
|
3550
|
+
const cfgFieldLabel = cfgMeta ? cfgMeta.label[getLang()] : cfgField;
|
|
3008
3551
|
const cfgTimers = React.useRef([]);
|
|
3009
3552
|
React.useEffect(() => () => {
|
|
3010
|
-
for (const
|
|
3553
|
+
for (const t2 of cfgTimers.current) clearTimeout(t2);
|
|
3011
3554
|
cfgTimers.current = [];
|
|
3012
3555
|
}, []);
|
|
3013
3556
|
const toggleTheme = () => {
|
|
@@ -3016,7 +3559,7 @@ function SettingsPanel(_props) {
|
|
|
3016
3559
|
setThemeEnabled(next);
|
|
3017
3560
|
};
|
|
3018
3561
|
const flashCopied = (slot) => {
|
|
3019
|
-
const setter = slot === "guide" ? setGuideCopied : slot === "status" ? setStatusCopied : setPullCopied;
|
|
3562
|
+
const setter = slot === "guide" ? setGuideCopied : slot === "status" ? setStatusCopied : slot === "pull" ? setPullCopied : setCfgReadCopied;
|
|
3020
3563
|
setter(true);
|
|
3021
3564
|
cfgTimers.current.push(window.setTimeout(() => setter(false), 1600));
|
|
3022
3565
|
};
|
|
@@ -3036,6 +3579,17 @@ function SettingsPanel(_props) {
|
|
|
3036
3579
|
if (!ok) return;
|
|
3037
3580
|
});
|
|
3038
3581
|
};
|
|
3582
|
+
const doCopyConfigRead = () => {
|
|
3583
|
+
const text = buildConfigReadInstruction();
|
|
3584
|
+
copyText(text).then((ok) => {
|
|
3585
|
+
setCopyError(ok ? null : "cfgRead");
|
|
3586
|
+
if (ok) {
|
|
3587
|
+
flashCopied("cfgRead");
|
|
3588
|
+
return;
|
|
3589
|
+
}
|
|
3590
|
+
setCfgReadText(text);
|
|
3591
|
+
});
|
|
3592
|
+
};
|
|
3039
3593
|
const requestClear = () => {
|
|
3040
3594
|
if (confirming) {
|
|
3041
3595
|
const count = removeStorageByPrefix(TRIAGE_STORAGE_PREFIX);
|
|
@@ -3047,13 +3601,13 @@ function SettingsPanel(_props) {
|
|
|
3047
3601
|
setConfirming(true);
|
|
3048
3602
|
cfgTimers.current.push(window.setTimeout(() => setConfirming(false), 3e3));
|
|
3049
3603
|
};
|
|
3050
|
-
const clearButton = clearedInfo !== null ? React.createElement("button", { className: "iterate-btn", "data-copied": "", disabled: true }, `\u5DF2\u6E05\u9664
|
|
3604
|
+
const clearButton = clearedInfo !== null ? React.createElement("button", { className: "iterate-btn", "data-copied": "", disabled: true }, tf(`\u5DF2\u6E05\u9664 {a0} \u6761`, { a0: clearedInfo })) : React.createElement("button", {
|
|
3051
3605
|
className: "iterate-btn",
|
|
3052
3606
|
"data-danger": confirming ? void 0 : "",
|
|
3053
3607
|
"data-confirm": confirming ? "" : void 0,
|
|
3054
3608
|
onClick: requestClear,
|
|
3055
|
-
title: confirming ? "\u518D\u6B21\u70B9\u51FB\u4EE5\u786E\u8BA4\u6E05\u9664\u5168\u90E8\u5224\u5B9A" : "\u6E05\u9664\u6240\u6709\u5206\u8BCA\u5224\u5B9A\u8BB0\u5F55\uFF08\u9700\u8981\u4E8C\u6B21\u786E\u8BA4\uFF09"
|
|
3056
|
-
}, confirming ? "\u786E\u8BA4\u6E05\u9664\uFF1F" : "\u6E05\u9664\u5206\u8BCA");
|
|
3609
|
+
title: confirming ? t("\u518D\u6B21\u70B9\u51FB\u4EE5\u786E\u8BA4\u6E05\u9664\u5168\u90E8\u5224\u5B9A") : t("\u6E05\u9664\u6240\u6709\u5206\u8BCA\u5224\u5B9A\u8BB0\u5F55\uFF08\u9700\u8981\u4E8C\u6B21\u786E\u8BA4\uFF09")
|
|
3610
|
+
}, confirming ? t("\u786E\u8BA4\u6E05\u9664\uFF1F") : t("\u6E05\u9664\u5206\u8BCA"));
|
|
3057
3611
|
const themeCard = React.createElement(
|
|
3058
3612
|
"div",
|
|
3059
3613
|
{ key: "theme", className: "iterate-scard" },
|
|
@@ -3063,17 +3617,17 @@ function SettingsPanel(_props) {
|
|
|
3063
3617
|
React.createElement(
|
|
3064
3618
|
"div",
|
|
3065
3619
|
{},
|
|
3066
|
-
React.createElement("div", { className: "iterate-settings-title" }, "\u8FED\u4EE3\u4E3B\u9898"),
|
|
3067
|
-
React.createElement("div", { className: "iterate-settings-desc" }, "\u542F\u7528\u6696\u7425\u73C0\u914D\u8272\u7684 iterate \u4E13\u5C5E\u76AE\u80A4\uFF0C\u8986\u76D6 dsh \u9ED8\u8BA4\u4E3B\u9898\u4EE4\u724C\u3002")
|
|
3620
|
+
React.createElement("div", { className: "iterate-settings-title" }, t("\u8FED\u4EE3\u4E3B\u9898")),
|
|
3621
|
+
React.createElement("div", { className: "iterate-settings-desc" }, t("\u542F\u7528\u6696\u7425\u73C0\u914D\u8272\u7684 iterate \u4E13\u5C5E\u76AE\u80A4\uFF0C\u8986\u76D6 dsh \u9ED8\u8BA4\u4E3B\u9898\u4EE4\u724C\u3002"))
|
|
3068
3622
|
),
|
|
3069
3623
|
React.createElement(
|
|
3070
3624
|
"div",
|
|
3071
3625
|
{ className: "iterate-scard-actions" },
|
|
3072
|
-
React.createElement("span", { className: "iterate-chip", "data-ok": enabled ? "" : void 0 }, enabled ? "\u5DF2\u542F\u7528" : "\u5DF2\u5173\u95ED"),
|
|
3626
|
+
React.createElement("span", { className: "iterate-chip", "data-ok": enabled ? "" : void 0 }, enabled ? t("\u5DF2\u542F\u7528") : t("\u5DF2\u5173\u95ED")),
|
|
3073
3627
|
React.createElement("button", {
|
|
3074
3628
|
role: "switch",
|
|
3075
3629
|
"aria-checked": enabled,
|
|
3076
|
-
"aria-label": "\u5F00\u5173 iterate \u4E3B\u9898",
|
|
3630
|
+
"aria-label": t("\u5F00\u5173 iterate \u4E3B\u9898"),
|
|
3077
3631
|
className: "iterate-switch",
|
|
3078
3632
|
"data-on": enabled ? "" : void 0,
|
|
3079
3633
|
onClick: toggleTheme
|
|
@@ -3081,6 +3635,37 @@ function SettingsPanel(_props) {
|
|
|
3081
3635
|
)
|
|
3082
3636
|
)
|
|
3083
3637
|
);
|
|
3638
|
+
const langCard = React.createElement(
|
|
3639
|
+
"div",
|
|
3640
|
+
{ key: "lang", className: "iterate-scard" },
|
|
3641
|
+
React.createElement(
|
|
3642
|
+
"div",
|
|
3643
|
+
{ className: "iterate-scard-head" },
|
|
3644
|
+
React.createElement(
|
|
3645
|
+
"div",
|
|
3646
|
+
{},
|
|
3647
|
+
React.createElement("div", { className: "iterate-settings-title" }, t("\u754C\u9762\u8BED\u8A00")),
|
|
3648
|
+
React.createElement(
|
|
3649
|
+
"div",
|
|
3650
|
+
{ className: "iterate-settings-desc" },
|
|
3651
|
+
t("\u9762\u677F\u6587\u6848\u7684\u663E\u793A\u8BED\u8A00\uFF1B\u590D\u5236\u7ED9\u6A21\u578B\u7684\u6307\u4EE4\u4FDD\u6301\u4E2D\u6587\uFF0C\u4E0E SKILL.md \u7684\u5DE5\u4F5C\u6D41\u5951\u7EA6\u4E00\u81F4\u3002")
|
|
3652
|
+
)
|
|
3653
|
+
),
|
|
3654
|
+
React.createElement(
|
|
3655
|
+
"div",
|
|
3656
|
+
{ className: "iterate-scard-actions" },
|
|
3657
|
+
React.createElement("span", { className: "iterate-chip", "data-ok": "" }, LANG_NAMES[lang]),
|
|
3658
|
+
React.createElement("button", {
|
|
3659
|
+
role: "switch",
|
|
3660
|
+
"aria-checked": lang === "en",
|
|
3661
|
+
"aria-label": t("\u5207\u6362\u754C\u9762\u8BED\u8A00"),
|
|
3662
|
+
className: "iterate-switch",
|
|
3663
|
+
"data-on": lang === "en" ? "" : void 0,
|
|
3664
|
+
onClick: () => setLang(lang === "en" ? "zh" : "en")
|
|
3665
|
+
}, React.createElement("span", { className: "iterate-switch-knob" }))
|
|
3666
|
+
)
|
|
3667
|
+
)
|
|
3668
|
+
);
|
|
3084
3669
|
const dataCard = React.createElement(
|
|
3085
3670
|
"div",
|
|
3086
3671
|
{ key: "data", className: "iterate-scard" },
|
|
@@ -3090,13 +3675,13 @@ function SettingsPanel(_props) {
|
|
|
3090
3675
|
React.createElement(
|
|
3091
3676
|
"div",
|
|
3092
3677
|
{},
|
|
3093
|
-
React.createElement("div", { className: "iterate-settings-title" }, "\u5206\u8BCA\u6301\u4E45\u5316"),
|
|
3094
|
-
React.createElement("div", { className: "iterate-settings-desc" }, "y / n / a \u5224\u5B9A\u4FDD\u5B58\u5728\u672C\u5730\u6D4F\u89C8\u5668\uFF08localStorage\uFF09\uFF0C\u5237\u65B0\u4F1A\u8BDD\u540E\u4ECD\u4FDD\u7559\u3002")
|
|
3678
|
+
React.createElement("div", { className: "iterate-settings-title" }, t("\u5206\u8BCA\u6301\u4E45\u5316")),
|
|
3679
|
+
React.createElement("div", { className: "iterate-settings-desc" }, t("y / n / a \u5224\u5B9A\u4FDD\u5B58\u5728\u672C\u5730\u6D4F\u89C8\u5668\uFF08localStorage\uFF09\uFF0C\u5237\u65B0\u4F1A\u8BDD\u540E\u4ECD\u4FDD\u7559\u3002"))
|
|
3095
3680
|
),
|
|
3096
3681
|
React.createElement(
|
|
3097
3682
|
"div",
|
|
3098
3683
|
{ className: "iterate-scard-actions" },
|
|
3099
|
-
React.createElement("span", { className: "iterate-chip" }, "\u672C\u5730\u4FDD\u5B58"),
|
|
3684
|
+
React.createElement("span", { className: "iterate-chip" }, t("\u672C\u5730\u4FDD\u5B58")),
|
|
3100
3685
|
clearButton
|
|
3101
3686
|
)
|
|
3102
3687
|
)
|
|
@@ -3110,14 +3695,14 @@ function SettingsPanel(_props) {
|
|
|
3110
3695
|
React.createElement(
|
|
3111
3696
|
"div",
|
|
3112
3697
|
{},
|
|
3113
|
-
React.createElement("div", { className: "iterate-settings-title" }, "\u914D\u7F6E\u7BA1\u7406"),
|
|
3114
|
-
React.createElement("div", { className: "iterate-settings-desc" }, "\u76EE\u6807 / \u7EF4\u5EA6 / \u6700\u5927\u8F6E\u6570 / validation.commands \u5199\u5728\u9879\u76EE\u7684 iterate.config.yaml\uFF0C\u590D\u5236\u6307\u5F15\u53EF\u8BA9\u6A21\u578B\u6309\u9700\u8C03\u6574\u3002")
|
|
3698
|
+
React.createElement("div", { className: "iterate-settings-title" }, t("\u914D\u7F6E\u7BA1\u7406")),
|
|
3699
|
+
React.createElement("div", { className: "iterate-settings-desc" }, t("\u76EE\u6807 / \u7EF4\u5EA6 / \u6700\u5927\u8F6E\u6570 / validation.commands \u5199\u5728\u9879\u76EE\u7684 iterate.config.yaml\uFF0C\u590D\u5236\u6307\u5F15\u53EF\u8BA9\u6A21\u578B\u6309\u9700\u8C03\u6574\u3002"))
|
|
3115
3700
|
),
|
|
3116
3701
|
React.createElement(
|
|
3117
3702
|
"div",
|
|
3118
3703
|
{ className: "iterate-scard-actions" },
|
|
3119
|
-
React.createElement("button", { className: "iterate-btn", "data-primary": "", "data-copied": guideCopied ? "" : void 0, onClick: () => doCopy(guide, "guide") }, guideCopied ? "\u5DF2\u590D\u5236" : "\u590D\u5236\u6307\u5F15"),
|
|
3120
|
-
React.createElement("button", { className: "iterate-btn", "data-ghost": "", onClick: () => setShowGuide((v) => !v) }, showGuide ? "\u6536\u8D77" : "\u5C55\u5F00")
|
|
3704
|
+
React.createElement("button", { className: "iterate-btn", "data-primary": "", "data-copied": guideCopied ? "" : void 0, onClick: () => doCopy(guide, "guide") }, guideCopied ? t("\u5DF2\u590D\u5236") : t("\u590D\u5236\u6307\u5F15")),
|
|
3705
|
+
React.createElement("button", { className: "iterate-btn", "data-ghost": "", onClick: () => setShowGuide((v) => !v) }, showGuide ? t("\u6536\u8D77") : t("\u5C55\u5F00"))
|
|
3121
3706
|
)
|
|
3122
3707
|
),
|
|
3123
3708
|
// Gap #8: wire up the previously-dead `buildConfigFieldInstruction` — pick
|
|
@@ -3131,17 +3716,17 @@ function SettingsPanel(_props) {
|
|
|
3131
3716
|
{
|
|
3132
3717
|
className: "iterate-filter-select",
|
|
3133
3718
|
value: cfgField,
|
|
3134
|
-
"aria-label": "\u9009\u62E9\u8981\u4FEE\u6539\u7684\u914D\u7F6E\u5B57\u6BB5",
|
|
3719
|
+
"aria-label": t("\u9009\u62E9\u8981\u4FEE\u6539\u7684\u914D\u7F6E\u5B57\u6BB5"),
|
|
3135
3720
|
onChange: (e) => setCfgField(e.target.value)
|
|
3136
3721
|
},
|
|
3137
3722
|
...CONFIG_EDIT_FIELDS.map(
|
|
3138
|
-
(f) => React.createElement("option", { key: f.key, value: f.key }, `${f.label}\uFF08${f.key}\uFF09`)
|
|
3723
|
+
(f) => React.createElement("option", { key: f.key, value: f.key }, getLang() === "en" ? `${f.label.en} (${f.key})` : `${f.label.zh}\uFF08${f.key}\uFF09`)
|
|
3139
3724
|
)
|
|
3140
3725
|
),
|
|
3141
3726
|
React.createElement(
|
|
3142
3727
|
"span",
|
|
3143
3728
|
{ className: "iterate-settings-desc" },
|
|
3144
|
-
|
|
3729
|
+
cfgMeta?.hint[getLang()] ?? ""
|
|
3145
3730
|
),
|
|
3146
3731
|
React.createElement("button", {
|
|
3147
3732
|
className: "iterate-btn",
|
|
@@ -3149,18 +3734,48 @@ function SettingsPanel(_props) {
|
|
|
3149
3734
|
"data-copied": cfgCopied ? "" : void 0,
|
|
3150
3735
|
"data-failed": cfgFailed ? "" : void 0,
|
|
3151
3736
|
onClick: doBuildConfigInstruction,
|
|
3152
|
-
title: "\u751F\u6210\u5E76\u590D\u5236\u8BE5\u5B57\u6BB5\u7684 iterate_config \u5199\u5165\u6307\u4EE4\uFF08\u5199\u5165\u524D\u81EA\u52A8\u5907\u4EFD\u3001\u5931\u8D25\u81EA\u52A8\u56DE\u6EDA\uFF09"
|
|
3153
|
-
}, cfgCopied ? "\u5DF2\u590D\u5236" : cfgFailed ? "\u590D\u5236\u5931\u8D25" : "\u751F\u6210\u5199\u5165\u6307\u4EE4"),
|
|
3154
|
-
cfgFailed ? React.createElement("span", { className: "iterate-settings-desc" }, "\u526A\u8D34\u677F\u88AB\u62D2\u7EDD\u2014\u2014\u6307\u4EE4\u5DF2\u5C55\u793A\u5728\u4E0B\u65B9\uFF0C\u8BF7\u624B\u52A8\u590D\u5236\u3002") : null
|
|
3737
|
+
title: t("\u751F\u6210\u5E76\u590D\u5236\u8BE5\u5B57\u6BB5\u7684 iterate_config \u5199\u5165\u6307\u4EE4\uFF08\u5199\u5165\u524D\u81EA\u52A8\u5907\u4EFD\u3001\u5931\u8D25\u81EA\u52A8\u56DE\u6EDA\uFF09")
|
|
3738
|
+
}, cfgCopied ? t("\u5DF2\u590D\u5236") : cfgFailed ? t("\u590D\u5236\u5931\u8D25") : t("\u751F\u6210\u5199\u5165\u6307\u4EE4")),
|
|
3739
|
+
cfgFailed ? React.createElement("span", { className: "iterate-settings-desc" }, t("\u526A\u8D34\u677F\u88AB\u62D2\u7EDD\u2014\u2014\u6307\u4EE4\u5DF2\u5C55\u793A\u5728\u4E0B\u65B9\uFF0C\u8BF7\u624B\u52A8\u590D\u5236\u3002")) : null
|
|
3155
3740
|
),
|
|
3741
|
+
// Gap #1 (3.7.0): close the write -> read-back loop. Three honest states:
|
|
3742
|
+
// nothing echoed yet, the value the model read back, or a read-back that
|
|
3743
|
+
// never contained this field (defaults are in play — say so, don't blank).
|
|
3744
|
+
React.createElement(
|
|
3745
|
+
"div",
|
|
3746
|
+
{ className: "iterate-guide-bar", style: { marginTop: 8, flexWrap: "wrap" } },
|
|
3747
|
+
React.createElement(
|
|
3748
|
+
"span",
|
|
3749
|
+
{ className: "iterate-settings-desc" },
|
|
3750
|
+
!cfgRead ? t("\u5C1A\u672A\u56DE\u8BFB\u5F53\u524D\u914D\u7F6E\u2014\u2014\u70B9\u300C\u56DE\u8BFB\u5F53\u524D\u914D\u7F6E\u300D\u590D\u5236\u6307\u4EE4\u53D1\u7ED9\u6A21\u578B\uFF0C\u56DE\u663E\u540E\u5373\u53EF\u5728\u6B64\u770B\u5230\u5F53\u524D\u503C\u3002") : cfgCurrent && cfgCurrent.resolved ? tf("\u5F53\u524D\u503C {a0}\uFF1A{a1}", { a0: cfgFieldLabel, a1: formatConfigValue(cfgCurrent.value) }) : tf("\u56DE\u8BFB\u7ED3\u679C\u4E2D\u6CA1\u6709 {a0}\uFF08\u8BE5\u5B57\u6BB5\u53EF\u80FD\u5C1A\u672A\u5199\u5165\u914D\u7F6E\u6587\u4EF6\uFF09\u3002", { a0: cfgFieldLabel })
|
|
3751
|
+
),
|
|
3752
|
+
React.createElement("button", {
|
|
3753
|
+
className: "iterate-btn",
|
|
3754
|
+
"data-primary": "",
|
|
3755
|
+
"data-copied": cfgReadCopied ? "" : void 0,
|
|
3756
|
+
onClick: doCopyConfigRead,
|
|
3757
|
+
title: t('\u590D\u5236\u56DE\u8BFB\u6307\u4EE4\uFF1A\u8BA9\u6A21\u578B\u8C03\u7528 iterate_config(operation:"read") \u5E76\u56DE\u663E\u7ED3\u679C')
|
|
3758
|
+
}, cfgReadCopied ? t("\u5DF2\u590D\u5236") : t("\u56DE\u8BFB\u5F53\u524D\u914D\u7F6E"))
|
|
3759
|
+
),
|
|
3760
|
+
cfgReadText ? React.createElement(
|
|
3761
|
+
"div",
|
|
3762
|
+
{ className: "iterate-guide" },
|
|
3763
|
+
React.createElement(
|
|
3764
|
+
"div",
|
|
3765
|
+
{ className: "iterate-guide-bar" },
|
|
3766
|
+
React.createElement("span", {}, t("\u56DE\u8BFB\u6307\u4EE4\uFF08\u7C98\u8D34\u7ED9\u6A21\u578B\uFF09")),
|
|
3767
|
+
React.createElement("button", { className: "iterate-btn", "data-ghost": "", onClick: () => doCopy(cfgReadText, "cfgRead") }, t("\u590D\u5236"))
|
|
3768
|
+
),
|
|
3769
|
+
React.createElement("div", { className: "iterate-guide-body" }, cfgReadText)
|
|
3770
|
+
) : null,
|
|
3156
3771
|
cfgText ? React.createElement(
|
|
3157
3772
|
"div",
|
|
3158
3773
|
{ className: "iterate-guide" },
|
|
3159
3774
|
React.createElement(
|
|
3160
3775
|
"div",
|
|
3161
3776
|
{ className: "iterate-guide-bar" },
|
|
3162
|
-
React.createElement("span", {}, "\u5199\u5165\u6307\u4EE4\uFF08\u7C98\u8D34\u7ED9\u6A21\u578B\uFF09"),
|
|
3163
|
-
React.createElement("button", { className: "iterate-btn", "data-ghost": "", onClick: () => doCopy(cfgText, "guide") }, "\u590D\u5236")
|
|
3777
|
+
React.createElement("span", {}, t("\u5199\u5165\u6307\u4EE4\uFF08\u7C98\u8D34\u7ED9\u6A21\u578B\uFF09")),
|
|
3778
|
+
React.createElement("button", { className: "iterate-btn", "data-ghost": "", onClick: () => doCopy(cfgText, "guide") }, t("\u590D\u5236"))
|
|
3164
3779
|
),
|
|
3165
3780
|
React.createElement("div", { className: "iterate-guide-body" }, cfgText)
|
|
3166
3781
|
) : null,
|
|
@@ -3170,8 +3785,9 @@ function SettingsPanel(_props) {
|
|
|
3170
3785
|
React.createElement(
|
|
3171
3786
|
"div",
|
|
3172
3787
|
{ className: "iterate-guide-bar" },
|
|
3173
|
-
React.createElement("span", {}, "iterate.config.yaml \u53EF\u7F16\u8F91\u5B57\u6BB5"),
|
|
3174
|
-
React.createElement("
|
|
3788
|
+
React.createElement("span", {}, t("iterate.config.yaml \u53EF\u7F16\u8F91\u5B57\u6BB5")),
|
|
3789
|
+
React.createElement("span", { className: "iterate-chip" }, t("\u4E2D\u6587\uFF08\u7C98\u8D34\u7ED9\u6A21\u578B\u7684\u5951\u7EA6\u6587\u6848\uFF09")),
|
|
3790
|
+
React.createElement("button", { className: "iterate-btn", "data-ghost": "", onClick: () => doCopy(guide, "guide") }, t("\u590D\u5236"))
|
|
3175
3791
|
),
|
|
3176
3792
|
React.createElement("div", { className: "iterate-guide-body" }, guide)
|
|
3177
3793
|
) : null
|
|
@@ -3185,13 +3801,13 @@ function SettingsPanel(_props) {
|
|
|
3185
3801
|
React.createElement(
|
|
3186
3802
|
"div",
|
|
3187
3803
|
{},
|
|
3188
|
-
React.createElement("div", { className: "iterate-settings-title" }, "\u72B6\u6001\u6982\u89C8"),
|
|
3189
|
-
React.createElement("div", { className: "iterate-settings-desc" }, "\u67E5\u770B\u8FD0\u884C\u65F6\u4EA7\u7269\u5E03\u5C40\u4E0E\u6E05\u7406\u6307\u5F15\u3002iterate_status / iterate_history / iterate_prune \u5DE5\u5177\u7528\u4E8E\u67E5\u770B\u548C\u7BA1\u7406\u3002")
|
|
3804
|
+
React.createElement("div", { className: "iterate-settings-title" }, t("\u72B6\u6001\u6982\u89C8")),
|
|
3805
|
+
React.createElement("div", { className: "iterate-settings-desc" }, t("\u67E5\u770B\u8FD0\u884C\u65F6\u4EA7\u7269\u5E03\u5C40\u4E0E\u6E05\u7406\u6307\u5F15\u3002iterate_status / iterate_history / iterate_prune \u5DE5\u5177\u7528\u4E8E\u67E5\u770B\u548C\u7BA1\u7406\u3002"))
|
|
3190
3806
|
),
|
|
3191
3807
|
React.createElement(
|
|
3192
3808
|
"div",
|
|
3193
3809
|
{ className: "iterate-scard-actions" },
|
|
3194
|
-
React.createElement("button", { className: "iterate-btn", "data-primary": "", "data-copied": statusCopied ? "" : void 0, onClick: () => doCopy(statusGuide, "status") }, statusCopied ? "\u5DF2\u590D\u5236" : "\u590D\u5236\u6307\u5F15"),
|
|
3810
|
+
React.createElement("button", { className: "iterate-btn", "data-primary": "", "data-copied": statusCopied ? "" : void 0, onClick: () => doCopy(statusGuide, "status") }, statusCopied ? t("\u5DF2\u590D\u5236") : t("\u590D\u5236\u6307\u5F15")),
|
|
3195
3811
|
// Gap #4: RUNTIME_ARTIFACTS stops being documentation-only — this
|
|
3196
3812
|
// copies the instruction that makes the model echo those artifacts
|
|
3197
3813
|
// into the session so the observatory panels can read them.
|
|
@@ -3199,8 +3815,8 @@ function SettingsPanel(_props) {
|
|
|
3199
3815
|
className: "iterate-btn",
|
|
3200
3816
|
"data-copied": pullCopied ? "" : void 0,
|
|
3201
3817
|
onClick: () => doCopy(buildDiskSnapshotInstruction(), "pull")
|
|
3202
|
-
}, pullCopied ? "\u5DF2\u590D\u5236" : "\u62C9\u53D6\u78C1\u76D8\u5FEB\u7167"),
|
|
3203
|
-
React.createElement("button", { className: "iterate-btn", "data-ghost": "", onClick: () => setShowStatus((v) => !v) }, showStatus ? "\u6536\u8D77" : "\u5C55\u5F00")
|
|
3818
|
+
}, pullCopied ? t("\u5DF2\u590D\u5236") : t("\u62C9\u53D6\u78C1\u76D8\u5FEB\u7167")),
|
|
3819
|
+
React.createElement("button", { className: "iterate-btn", "data-ghost": "", onClick: () => setShowStatus((v) => !v) }, showStatus ? t("\u6536\u8D77") : t("\u5C55\u5F00"))
|
|
3204
3820
|
)
|
|
3205
3821
|
),
|
|
3206
3822
|
showStatus ? React.createElement(
|
|
@@ -3209,8 +3825,9 @@ function SettingsPanel(_props) {
|
|
|
3209
3825
|
React.createElement(
|
|
3210
3826
|
"div",
|
|
3211
3827
|
{ className: "iterate-guide-bar" },
|
|
3212
|
-
React.createElement("span", {}, "\u8FD0\u884C\u65F6\u5E03\u5C40\u4E0E\u6E05\u7406"),
|
|
3213
|
-
React.createElement("
|
|
3828
|
+
React.createElement("span", {}, t("\u8FD0\u884C\u65F6\u5E03\u5C40\u4E0E\u6E05\u7406")),
|
|
3829
|
+
React.createElement("span", { className: "iterate-chip" }, t("\u4E2D\u6587\uFF08\u7C98\u8D34\u7ED9\u6A21\u578B\u7684\u5951\u7EA6\u6587\u6848\uFF09")),
|
|
3830
|
+
React.createElement("button", { className: "iterate-btn", "data-ghost": "", onClick: () => doCopy(statusGuide, "status") }, t("\u590D\u5236"))
|
|
3214
3831
|
),
|
|
3215
3832
|
React.createElement("div", { className: "iterate-guide-body" }, statusGuide)
|
|
3216
3833
|
) : null
|
|
@@ -3225,20 +3842,20 @@ function SettingsPanel(_props) {
|
|
|
3225
3842
|
"div",
|
|
3226
3843
|
{},
|
|
3227
3844
|
React.createElement("div", { className: "iterate-settings-title" }, "iterate"),
|
|
3228
|
-
React.createElement("div", { className: "iterate-settings-desc" }, "\u4E3A\u6BCF\u6B21\u4EE3\u7801\u8BC4\u5BA1\u751F\u6210 Review \u62A5\u544A\u4E0E\u4EA4\u4E92\u5F0F\u5206\u8BCA\u89C6\u56FE\uFF0C\u4E13\u6CE8 AI \u81EA\u6211\u5BA1\u67E5\u4E0E\u4FEE\u6B63\u3002")
|
|
3845
|
+
React.createElement("div", { className: "iterate-settings-desc" }, t("\u4E3A\u6BCF\u6B21\u4EE3\u7801\u8BC4\u5BA1\u751F\u6210 Review \u62A5\u544A\u4E0E\u4EA4\u4E92\u5F0F\u5206\u8BCA\u89C6\u56FE\uFF0C\u4E13\u6CE8 AI \u81EA\u6211\u5BA1\u67E5\u4E0E\u4FEE\u6B63\u3002"))
|
|
3229
3846
|
),
|
|
3230
3847
|
React.createElement(
|
|
3231
3848
|
"span",
|
|
3232
3849
|
{ className: "iterate-pill" },
|
|
3233
3850
|
React.createElement("span", { className: "iterate-pill-dot" }),
|
|
3234
|
-
"\u5C31\u7EEA"
|
|
3851
|
+
t("\u5C31\u7EEA")
|
|
3235
3852
|
)
|
|
3236
3853
|
)
|
|
3237
3854
|
);
|
|
3238
3855
|
return React.createElement(
|
|
3239
3856
|
"div",
|
|
3240
3857
|
{ "data-iterate-root": "", "data-iterate": "settings", className: "iterate-settings" },
|
|
3241
|
-
React.createElement("div", { className: "iterate-settings-title", style: { fontSize: 15, fontWeight: 700 } }, "iterate \u8BBE\u7F6E"),
|
|
3858
|
+
React.createElement("div", { className: "iterate-settings-title", style: { fontSize: 15, fontWeight: 700 } }, t("iterate \u8BBE\u7F6E")),
|
|
3242
3859
|
banner,
|
|
3243
3860
|
copyError ? React.createElement(
|
|
3244
3861
|
"div",
|
|
@@ -3246,9 +3863,10 @@ function SettingsPanel(_props) {
|
|
|
3246
3863
|
React.createElement(
|
|
3247
3864
|
"div",
|
|
3248
3865
|
{ className: "iterate-settings-desc" },
|
|
3249
|
-
"\u526A\u8D34\u677F\u5199\u5165\u88AB\u62D2\u7EDD\uFF0C\u590D\u5236\u672A\u751F\u6548\u2014\u2014\u8BF7\u5C55\u5F00\u5BF9\u5E94\u533A\u5757\u624B\u52A8\u9009\u4E2D\u6587\u672C\u590D\u5236\u3002"
|
|
3866
|
+
t("\u526A\u8D34\u677F\u5199\u5165\u88AB\u62D2\u7EDD\uFF0C\u590D\u5236\u672A\u751F\u6548\u2014\u2014\u8BF7\u5C55\u5F00\u5BF9\u5E94\u533A\u5757\u624B\u52A8\u9009\u4E2D\u6587\u672C\u590D\u5236\u3002")
|
|
3250
3867
|
)
|
|
3251
3868
|
) : null,
|
|
3869
|
+
langCard,
|
|
3252
3870
|
themeCard,
|
|
3253
3871
|
dataCard,
|
|
3254
3872
|
guideCard,
|
|
@@ -3256,18 +3874,18 @@ function SettingsPanel(_props) {
|
|
|
3256
3874
|
);
|
|
3257
3875
|
}
|
|
3258
3876
|
var OBS_TABS = [
|
|
3259
|
-
{ key: "live", label: "\u5B9E\u65F6\u6D3B\u52A8\u6D41", hotkey: "" },
|
|
3260
|
-
{ key: "f1", label: "\u5BA1\u67E5\u7EBF\u7A0B", hotkey: "1" },
|
|
3261
|
-
{ key: "f2", label: "\u6536\u655B\u8D8B\u52BF", hotkey: "2" },
|
|
3262
|
-
{ key: "f3", label: "\u53D1\u73B0\u5B9A\u4F4D", hotkey: "3" },
|
|
3263
|
-
{ key: "f4", label: "\u4FEE\u590D\u4E0E\u56DE\u6EDA", hotkey: "4" },
|
|
3264
|
-
{ key: "f5", label: "\u65AD\u70B9\u6062\u590D", hotkey: "5" },
|
|
3265
|
-
{ key: "f6", label: "\u8FD0\u884C\u63A7\u5236\u53F0", hotkey: "6" },
|
|
3266
|
-
{ key: "f7", label: "\u51B3\u7B56\u65F6\u95F4\u7EBF", hotkey: "7" },
|
|
3877
|
+
{ key: "live", label: { zh: "\u5B9E\u65F6\u6D3B\u52A8\u6D41", en: "Live activity" }, hotkey: "" },
|
|
3878
|
+
{ key: "f1", label: { zh: "\u5BA1\u67E5\u7EBF\u7A0B", en: "Review threads" }, hotkey: "1" },
|
|
3879
|
+
{ key: "f2", label: { zh: "\u6536\u655B\u8D8B\u52BF", en: "Convergence trend" }, hotkey: "2" },
|
|
3880
|
+
{ key: "f3", label: { zh: "\u53D1\u73B0\u5B9A\u4F4D", en: "Finding locations" }, hotkey: "3" },
|
|
3881
|
+
{ key: "f4", label: { zh: "\u4FEE\u590D\u4E0E\u56DE\u6EDA", en: "Fixes & rollback" }, hotkey: "4" },
|
|
3882
|
+
{ key: "f5", label: { zh: "\u65AD\u70B9\u6062\u590D", en: "Checkpoint resume" }, hotkey: "5" },
|
|
3883
|
+
{ key: "f6", label: { zh: "\u8FD0\u884C\u63A7\u5236\u53F0", en: "Run console" }, hotkey: "6" },
|
|
3884
|
+
{ key: "f7", label: { zh: "\u51B3\u7B56\u65F6\u95F4\u7EBF", en: "Decision timeline" }, hotkey: "7" },
|
|
3267
3885
|
// v3.0: Quality Command Center tabs
|
|
3268
|
-
{ key: "f8", label: "\u8D28\u91CF\u95E8\u7981", hotkey: "8" },
|
|
3269
|
-
{ key: "f9", label: "\u7ECF\u9A8C\u94F6\u884C", hotkey: "9" },
|
|
3270
|
-
{ key: "f10", label: "\u9632\u5FA1\u4E8B\u4EF6", hotkey: "0" }
|
|
3886
|
+
{ key: "f8", label: { zh: "\u8D28\u91CF\u95E8\u7981", en: "Quality gate" }, hotkey: "8" },
|
|
3887
|
+
{ key: "f9", label: { zh: "\u7ECF\u9A8C\u94F6\u884C", en: "Experience bank" }, hotkey: "9" },
|
|
3888
|
+
{ key: "f10", label: { zh: "\u9632\u5FA1\u4E8B\u4EF6", en: "Defense events" }, hotkey: "0" }
|
|
3271
3889
|
];
|
|
3272
3890
|
var OBS_HOTKEY_TABS = {
|
|
3273
3891
|
1: "f1",
|
|
@@ -3282,23 +3900,26 @@ var OBS_HOTKEY_TABS = {
|
|
|
3282
3900
|
0: "f10",
|
|
3283
3901
|
"-": "live"
|
|
3284
3902
|
};
|
|
3285
|
-
function obsTabLabel(
|
|
3286
|
-
|
|
3287
|
-
|
|
3903
|
+
function obsTabLabel(t2) {
|
|
3904
|
+
const label = t2.label[getLang()];
|
|
3905
|
+
if (t2.key === "live") return label;
|
|
3906
|
+
return `${t2.key.toUpperCase()} ${label}`;
|
|
3907
|
+
}
|
|
3908
|
+
function obsHotkeyHint() {
|
|
3909
|
+
return getLang() === "en" ? `${String(OBS_TABS.length)} tabs \xB7 keys 1-9/0 switch Fn, - returns to the live feed` : tf(`{a0} \u9875 \xB7 \u6309 1-9/0 \u5207 Fn\u3001- \u56DE\u5B9E\u65F6\u6D41`, { a0: String(OBS_TABS.length) });
|
|
3288
3910
|
}
|
|
3289
|
-
var OBS_HOTKEY_HINT = `${String(OBS_TABS.length)} \u9875 \xB7 \u6309 1-9/0 \u5207 Fn\u3001- \u56DE\u5B9E\u65F6\u6D41`;
|
|
3290
3911
|
var OBS_LIVE_META = {
|
|
3291
|
-
read: { label: "\u9605\u8BFB", color: "var(--dsw-alias-brand-primary)" },
|
|
3292
|
-
fix: { label: "\u4FEE\u590D", color: "var(--dsw-alias-state-success-primary)" },
|
|
3293
|
-
rollback: { label: "\u56DE\u6EDA", color: "var(--dsw-alias-state-error-primary)" },
|
|
3294
|
-
diff: { label: "\u5DEE\u5F02", color: "var(--dsw-alias-state-warn-primary)" },
|
|
3295
|
-
review: { label: "\u5BA1\u67E5", color: "var(--dsw-alias-brand-primary)" },
|
|
3296
|
-
triage: { label: "\u5206\u6D41", color: "var(--dsw-alias-state-warn-primary)" },
|
|
3297
|
-
checkpoint: { label: "\u65AD\u70B9", color: "var(--dsw-alias-brand-primary)" },
|
|
3298
|
-
validate: { label: "\u6821\u9A8C", color: "var(--dsw-alias-state-success-primary)" },
|
|
3299
|
-
log: { label: "\u8BB0\u5F55", color: "var(--dsw-alias-label-secondary)" },
|
|
3300
|
-
prune: { label: "\u6E05\u7406", color: "var(--dsw-alias-state-warn-primary)" },
|
|
3301
|
-
info: { label: "\u4FE1\u606F", color: "var(--dsw-alias-label-secondary)" }
|
|
3912
|
+
read: { label: { zh: "\u9605\u8BFB", en: "Read" }, color: "var(--dsw-alias-brand-primary)" },
|
|
3913
|
+
fix: { label: { zh: "\u4FEE\u590D", en: "Fix" }, color: "var(--dsw-alias-state-success-primary)" },
|
|
3914
|
+
rollback: { label: { zh: "\u56DE\u6EDA", en: "Rollback" }, color: "var(--dsw-alias-state-error-primary)" },
|
|
3915
|
+
diff: { label: { zh: "\u5DEE\u5F02", en: "Diff" }, color: "var(--dsw-alias-state-warn-primary)" },
|
|
3916
|
+
review: { label: { zh: "\u5BA1\u67E5", en: "Review" }, color: "var(--dsw-alias-brand-primary)" },
|
|
3917
|
+
triage: { label: { zh: "\u5206\u6D41", en: "Triage" }, color: "var(--dsw-alias-state-warn-primary)" },
|
|
3918
|
+
checkpoint: { label: { zh: "\u65AD\u70B9", en: "Checkpoint" }, color: "var(--dsw-alias-brand-primary)" },
|
|
3919
|
+
validate: { label: { zh: "\u6821\u9A8C", en: "Validate" }, color: "var(--dsw-alias-state-success-primary)" },
|
|
3920
|
+
log: { label: { zh: "\u8BB0\u5F55", en: "Log" }, color: "var(--dsw-alias-label-secondary)" },
|
|
3921
|
+
prune: { label: { zh: "\u6E05\u7406", en: "Prune" }, color: "var(--dsw-alias-state-warn-primary)" },
|
|
3922
|
+
info: { label: { zh: "\u4FE1\u606F", en: "Info" }, color: "var(--dsw-alias-label-secondary)" }
|
|
3302
3923
|
};
|
|
3303
3924
|
var OBS_LIVE_FALLBACK_COLOR = "var(--dsw-alias-label-secondary)";
|
|
3304
3925
|
function formatObsLiveTime(ts) {
|
|
@@ -3340,6 +3961,9 @@ function buildObsFixInstruction(f) {
|
|
|
3340
3961
|
}
|
|
3341
3962
|
function ObservatoryPanel(props) {
|
|
3342
3963
|
const session = props && props.session ? props.session : null;
|
|
3964
|
+
React.useEffect(() => {
|
|
3965
|
+
noteSession(session);
|
|
3966
|
+
}, [session]);
|
|
3343
3967
|
const manifest = latestTranscript(session);
|
|
3344
3968
|
const qualityGate = latestQualityGate(session);
|
|
3345
3969
|
const experienceBank = latestExperienceBank(session);
|
|
@@ -3369,9 +3993,9 @@ function ObservatoryPanel(props) {
|
|
|
3369
3993
|
if (!doc || !open) return;
|
|
3370
3994
|
const onKeyDown = (ev) => {
|
|
3371
3995
|
if (ev.metaKey || ev.ctrlKey || ev.altKey || ev.shiftKey) return;
|
|
3372
|
-
const
|
|
3373
|
-
if (
|
|
3374
|
-
if (
|
|
3996
|
+
const t2 = ev.target;
|
|
3997
|
+
if (t2 && (t2.tagName === "INPUT" || t2.tagName === "TEXTAREA" || t2.tagName === "SELECT")) return;
|
|
3998
|
+
if (t2 && typeof t2.isContentEditable === "boolean" && t2.isContentEditable) return;
|
|
3375
3999
|
const rootEl = doc.querySelector('[data-iterate="obs"]');
|
|
3376
4000
|
if (!rootEl) return;
|
|
3377
4001
|
const activeEl = doc.activeElement;
|
|
@@ -3399,7 +4023,7 @@ function ObservatoryPanel(props) {
|
|
|
3399
4023
|
});
|
|
3400
4024
|
};
|
|
3401
4025
|
const pullInstruction = buildDiskSnapshotInstruction();
|
|
3402
|
-
const pullTitle = `\u590D\u5236\u62C9\u53D6\u78C1\u76D8\u5FEB\u7167\u6307\u4EE4\uFF1A\u8BA9\u6A21\u578B\u9010\u4E2A\u8C03\u7528
|
|
4026
|
+
const pullTitle = tf(`\u590D\u5236\u62C9\u53D6\u78C1\u76D8\u5FEB\u7167\u6307\u4EE4\uFF1A\u8BA9\u6A21\u578B\u9010\u4E2A\u8C03\u7528 {a0} \u5E76\u56DE\u663E\u5B8C\u6574\u7ED3\u679C`, { a0: DISK_SNAPSHOT_SOURCES.map((s) => s.tool).join(" / ") });
|
|
3403
4027
|
const toggleThread = (key) => {
|
|
3404
4028
|
setThreadMode("auto");
|
|
3405
4029
|
setExpandedThreads((prev) => {
|
|
@@ -3451,8 +4075,8 @@ function ObservatoryPanel(props) {
|
|
|
3451
4075
|
React.createElement(
|
|
3452
4076
|
"div",
|
|
3453
4077
|
{ className: "iterate-obs-head", "data-closed": "" },
|
|
3454
|
-
React.createElement("span", { className: "iterate-obs-title" }, "iterate \u89C2\u6D4B\u53F0"),
|
|
3455
|
-
React.createElement("span", { className: "iterate-obs-head-meta" }, `\u6682\u65E0\u8FD0\u884C\u65F6\u89C2\u6D4B\u6570\u636E \xB7
|
|
4078
|
+
React.createElement("span", { className: "iterate-obs-title" }, t("iterate \u89C2\u6D4B\u53F0")),
|
|
4079
|
+
React.createElement("span", { className: "iterate-obs-head-meta" }, tf(`\u6682\u65E0\u8FD0\u884C\u65F6\u89C2\u6D4B\u6570\u636E \xB7 {a0}`, { a0: obsHotkeyHint() })),
|
|
3456
4080
|
React.createElement("button", {
|
|
3457
4081
|
className: "iterate-btn",
|
|
3458
4082
|
"data-copied": copiedKey === "pull-snapshot" ? "" : void 0,
|
|
@@ -3460,8 +4084,8 @@ function ObservatoryPanel(props) {
|
|
|
3460
4084
|
e.stopPropagation();
|
|
3461
4085
|
copyInstruction("pull-snapshot", pullInstruction);
|
|
3462
4086
|
},
|
|
3463
|
-
title: "\u590D\u5236\u62C9\u53D6\u78C1\u76D8\u5FEB\u7167\u6307\u4EE4\uFF1A\u78C1\u76D8\u4E0A\u53EF\u80FD\u5DF2\u6709\u5386\u53F2\u4EA7\u7269\uFF0C\u56DE\u663E\u8FDB\u4F1A\u8BDD\u540E\u89C2\u6D4B\u53F0\u5373\u53EF\u586B\u5145"
|
|
3464
|
-
}, copiedKey === "pull-snapshot" ? "\u5DF2\u590D\u5236" : "\u62C9\u53D6\u78C1\u76D8\u5FEB\u7167")
|
|
4087
|
+
title: t("\u590D\u5236\u62C9\u53D6\u78C1\u76D8\u5FEB\u7167\u6307\u4EE4\uFF1A\u78C1\u76D8\u4E0A\u53EF\u80FD\u5DF2\u6709\u5386\u53F2\u4EA7\u7269\uFF0C\u56DE\u663E\u8FDB\u4F1A\u8BDD\u540E\u89C2\u6D4B\u53F0\u5373\u53EF\u586B\u5145")
|
|
4088
|
+
}, copiedKey === "pull-snapshot" ? t("\u5DF2\u590D\u5236") : t("\u62C9\u53D6\u78C1\u76D8\u5FEB\u7167"))
|
|
3465
4089
|
)
|
|
3466
4090
|
);
|
|
3467
4091
|
}
|
|
@@ -3483,7 +4107,7 @@ function ObservatoryPanel(props) {
|
|
|
3483
4107
|
const renderThreads = () => {
|
|
3484
4108
|
const rounds = manifest.rounds || [];
|
|
3485
4109
|
if (rounds.length === 0) {
|
|
3486
|
-
return React.createElement("div", { className: "iterate-obs-empty" }, "\u6682\u65E0\u5BA1\u67E5\u7EBF\u7A0B");
|
|
4110
|
+
return React.createElement("div", { className: "iterate-obs-empty" }, t("\u6682\u65E0\u5BA1\u67E5\u7EBF\u7A0B"));
|
|
3487
4111
|
}
|
|
3488
4112
|
return React.createElement(
|
|
3489
4113
|
"div",
|
|
@@ -3491,34 +4115,34 @@ function ObservatoryPanel(props) {
|
|
|
3491
4115
|
React.createElement(
|
|
3492
4116
|
"div",
|
|
3493
4117
|
{ className: "iterate-obs-bar", style: { marginBottom: 8, flexWrap: "wrap" } },
|
|
3494
|
-
React.createElement("b", {}, "\u5BA1\u67E5\u7EBF\u7A0B"),
|
|
3495
|
-
React.createElement("button", { className: "iterate-btn", onClick: () => setAllThreads("all"), title: "\u5C55\u5F00\u5168\u90E8\u7EBF\u7A0B" }, "\u5168\u90E8\u5C55\u5F00"),
|
|
3496
|
-
React.createElement("button", { className: "iterate-btn", onClick: () => setAllThreads("none"), title: "\u6536\u8D77\u5168\u90E8\u7EBF\u7A0B" }, "\u5168\u90E8\u6536\u8D77"),
|
|
4118
|
+
React.createElement("b", {}, t("\u5BA1\u67E5\u7EBF\u7A0B")),
|
|
4119
|
+
React.createElement("button", { className: "iterate-btn", onClick: () => setAllThreads("all"), title: t("\u5C55\u5F00\u5168\u90E8\u7EBF\u7A0B") }, t("\u5168\u90E8\u5C55\u5F00")),
|
|
4120
|
+
React.createElement("button", { className: "iterate-btn", onClick: () => setAllThreads("none"), title: t("\u6536\u8D77\u5168\u90E8\u7EBF\u7A0B") }, t("\u5168\u90E8\u6536\u8D77")),
|
|
3497
4121
|
React.createElement(
|
|
3498
4122
|
"span",
|
|
3499
4123
|
{ className: "iterate-filter-count" },
|
|
3500
|
-
|
|
4124
|
+
tf(`{a0} \xB7 {a1} \u8F6E`, { a0: threadMode === "all" ? t("\u5168\u90E8\u5C55\u5F00") : threadMode === "none" ? t("\u5168\u90E8\u6536\u8D77") : t("\u81EA\u7531\u5207\u6362"), a1: rounds.length })
|
|
3501
4125
|
)
|
|
3502
4126
|
),
|
|
3503
4127
|
...rounds.map((r, ri) => {
|
|
3504
4128
|
const threads = r.threads || [];
|
|
3505
|
-
const fCount = threads.reduce((sum,
|
|
3506
|
-
const threadBlocks = threads.length === 0 ? [React.createElement("div", { key: "none", className: "iterate-obs-empty" }, "\u672C\u8F6E\u65E0\u7EBF\u7A0B")] : threads.map((
|
|
4129
|
+
const fCount = threads.reduce((sum, t2) => sum + (t2.findings ? t2.findings.length : 0), 0);
|
|
4130
|
+
const threadBlocks = threads.length === 0 ? [React.createElement("div", { key: "none", className: "iterate-obs-empty" }, t("\u672C\u8F6E\u65E0\u7EBF\u7A0B"))] : threads.map((th, ti) => {
|
|
3507
4131
|
const key = `${ri}-${ti}`;
|
|
3508
4132
|
const expanded = isThreadExpanded(key);
|
|
3509
|
-
const dim =
|
|
3510
|
-
const tFindings =
|
|
3511
|
-
const files =
|
|
3512
|
-
const msgs =
|
|
4133
|
+
const dim = th.dimension || t("\u672A\u547D\u540D\u7EF4\u5EA6");
|
|
4134
|
+
const tFindings = th.findings || [];
|
|
4135
|
+
const files = th.readFiles || [];
|
|
4136
|
+
const msgs = th.messages || [];
|
|
3513
4137
|
return React.createElement(
|
|
3514
4138
|
"div",
|
|
3515
4139
|
{ key, className: "iterate-obs-block" },
|
|
3516
4140
|
React.createElement(
|
|
3517
4141
|
"div",
|
|
3518
|
-
{ className: "iterate-obs-block-head", "data-click": "", onClick: () => toggleThread(key), title: expanded ? "\u6536\u8D77\u7EBF\u7A0B" : "\u5C55\u5F00\u7EBF\u7A0B" },
|
|
4142
|
+
{ className: "iterate-obs-block-head", "data-click": "", onClick: () => toggleThread(key), title: expanded ? t("\u6536\u8D77\u7EBF\u7A0B") : t("\u5C55\u5F00\u7EBF\u7A0B") },
|
|
3519
4143
|
React.createElement("span", {}, expanded ? "\u2212" : "+"),
|
|
3520
4144
|
React.createElement("b", {}, dim),
|
|
3521
|
-
React.createElement("span", { className: "iterate-obs-chip" }, `attempt ${typeof
|
|
4145
|
+
React.createElement("span", { className: "iterate-obs-chip" }, `attempt ${typeof th.attempt === "number" ? th.attempt : "?"}`),
|
|
3522
4146
|
React.createElement("span", { className: "iterate-obs-chip" }, `${tFindings.length} findings`)
|
|
3523
4147
|
),
|
|
3524
4148
|
expanded ? React.createElement(
|
|
@@ -3527,15 +4151,15 @@ function ObservatoryPanel(props) {
|
|
|
3527
4151
|
React.createElement(
|
|
3528
4152
|
"div",
|
|
3529
4153
|
{ className: "iterate-obs-bar" },
|
|
3530
|
-
React.createElement("b", {}, "\u53D9\u8FF0"),
|
|
3531
|
-
React.createElement("span", { className: "iterate-obs-head-meta" },
|
|
4154
|
+
React.createElement("b", {}, t("\u53D9\u8FF0")),
|
|
4155
|
+
React.createElement("span", { className: "iterate-obs-head-meta" }, tf(`{a0} \u6761`, { a0: msgs.length }))
|
|
3532
4156
|
),
|
|
3533
|
-
...msgs.length === 0 ? [React.createElement("div", { key: "msg-none", className: "iterate-obs-empty" }, "\u65E0\u7EBF\u7D22\u53D9\u8FF0")] : msgs.map((m, mi) => React.createElement("div", { key: mi, className: "iterate-obs-msg" }, String(m))),
|
|
4157
|
+
...msgs.length === 0 ? [React.createElement("div", { key: "msg-none", className: "iterate-obs-empty" }, t("\u65E0\u7EBF\u7D22\u53D9\u8FF0"))] : msgs.map((m, mi) => React.createElement("div", { key: mi, className: "iterate-obs-msg" }, String(m))),
|
|
3534
4158
|
...files.length > 0 ? [
|
|
3535
4159
|
React.createElement(
|
|
3536
4160
|
"div",
|
|
3537
4161
|
{ key: "files-h", className: "iterate-obs-bar", style: { marginTop: 6 } },
|
|
3538
|
-
React.createElement("b", {}, "\u8BFB\u53D6\u6587\u4EF6")
|
|
4162
|
+
React.createElement("b", {}, t("\u8BFB\u53D6\u6587\u4EF6"))
|
|
3539
4163
|
),
|
|
3540
4164
|
...files.map(
|
|
3541
4165
|
(f, fi) => React.createElement("div", { key: `f${fi}`, className: "iterate-obs-file" }, String(f))
|
|
@@ -3544,9 +4168,9 @@ function ObservatoryPanel(props) {
|
|
|
3544
4168
|
React.createElement(
|
|
3545
4169
|
"div",
|
|
3546
4170
|
{ className: "iterate-obs-bar", style: { marginTop: 6 } },
|
|
3547
|
-
React.createElement("b", {}, "\u53D1\u73B0")
|
|
4171
|
+
React.createElement("b", {}, t("\u53D1\u73B0"))
|
|
3548
4172
|
),
|
|
3549
|
-
...tFindings.length === 0 ? [React.createElement("div", { key: "finding-none", className: "iterate-obs-empty" }, "\u672C\u7EBF\u7A0B\u65E0\u53D1\u73B0")] : tFindings.map((f, fi) => threadFindingPill(f, `tf${fi}`))
|
|
4173
|
+
...tFindings.length === 0 ? [React.createElement("div", { key: "finding-none", className: "iterate-obs-empty" }, t("\u672C\u7EBF\u7A0B\u65E0\u53D1\u73B0"))] : tFindings.map((f, fi) => threadFindingPill(f, `tf${fi}`))
|
|
3550
4174
|
) : null
|
|
3551
4175
|
);
|
|
3552
4176
|
});
|
|
@@ -3557,7 +4181,7 @@ function ObservatoryPanel(props) {
|
|
|
3557
4181
|
"div",
|
|
3558
4182
|
{ className: "iterate-obs-block-head" },
|
|
3559
4183
|
React.createElement("b", {}, `Round ${typeof r.round === "number" ? r.round : ri + 1}`),
|
|
3560
|
-
React.createElement("span", { className: "iterate-obs-chip" },
|
|
4184
|
+
React.createElement("span", { className: "iterate-obs-chip" }, tf(`{a0} \u7EBF\u7A0B`, { a0: threads.length })),
|
|
3561
4185
|
React.createElement("span", { className: "iterate-obs-head-meta" }, `${fCount} findings`)
|
|
3562
4186
|
),
|
|
3563
4187
|
React.createElement("div", { className: "iterate-obs-block-body" }, ...threadBlocks)
|
|
@@ -3568,7 +4192,7 @@ function ObservatoryPanel(props) {
|
|
|
3568
4192
|
const renderTrend = () => {
|
|
3569
4193
|
const conv = manifest.convergence || [];
|
|
3570
4194
|
if (conv.length === 0) {
|
|
3571
|
-
return React.createElement("div", { className: "iterate-obs-empty" }, "\u6682\u65E0\u6536\u655B\u6570\u636E");
|
|
4195
|
+
return React.createElement("div", { className: "iterate-obs-empty" }, t("\u6682\u65E0\u6536\u655B\u6570\u636E"));
|
|
3572
4196
|
}
|
|
3573
4197
|
const points = conv.map((n, i) => ({ round: i + 1, count: n }));
|
|
3574
4198
|
const report = latestReport(session);
|
|
@@ -3582,11 +4206,11 @@ function ObservatoryPanel(props) {
|
|
|
3582
4206
|
React.createElement(
|
|
3583
4207
|
"tr",
|
|
3584
4208
|
{},
|
|
3585
|
-
React.createElement("th", {}, "\u8F6E\u6B21"),
|
|
3586
|
-
React.createElement("th", {}, "\u53D1\u73B0"),
|
|
3587
|
-
React.createElement("th", {}, "\u5DF2\u4FEE\u590D"),
|
|
3588
|
-
React.createElement("th", {}, "\u4E25\u91CD\u5EA6\u5206\u5E03"),
|
|
3589
|
-
React.createElement("th", {}, "\u9A8C\u8BC1")
|
|
4209
|
+
React.createElement("th", {}, t("\u8F6E\u6B21")),
|
|
4210
|
+
React.createElement("th", {}, t("\u53D1\u73B0")),
|
|
4211
|
+
React.createElement("th", {}, t("\u5DF2\u4FEE\u590D")),
|
|
4212
|
+
React.createElement("th", {}, t("\u4E25\u91CD\u5EA6\u5206\u5E03")),
|
|
4213
|
+
React.createElement("th", {}, t("\u9A8C\u8BC1"))
|
|
3590
4214
|
)
|
|
3591
4215
|
),
|
|
3592
4216
|
React.createElement(
|
|
@@ -3595,7 +4219,7 @@ function ObservatoryPanel(props) {
|
|
|
3595
4219
|
...comparison.map((row) => {
|
|
3596
4220
|
const sevText = Object.entries(row.severities).map(([k, v]) => `${k}:${v}`).join(" \xB7 ");
|
|
3597
4221
|
const anyFailed = row.validations.some((v) => v.allowed !== true);
|
|
3598
|
-
const valText = row.validations.length === 0 ? "\u2014" :
|
|
4222
|
+
const valText = row.validations.length === 0 ? "\u2014" : tf(`{a0}/{a1} \u901A\u8FC7{a2}`, { a0: row.validations.filter((v) => v.allowed === true).length, a1: row.validations.length, a2: anyFailed ? t("\uFF08\u542B\u5931\u8D25\uFF09") : "" });
|
|
3599
4223
|
return React.createElement(
|
|
3600
4224
|
"tr",
|
|
3601
4225
|
{ key: `cmp-${row.round}` },
|
|
@@ -3617,7 +4241,7 @@ function ObservatoryPanel(props) {
|
|
|
3617
4241
|
React.createElement(
|
|
3618
4242
|
"div",
|
|
3619
4243
|
{ className: "iterate-obs-bar", style: { marginTop: 6 } },
|
|
3620
|
-
`\u5404\u8F6E\u53D1\u73B0\u6570\u91CF\uFF1A
|
|
4244
|
+
tf(`\u5404\u8F6E\u53D1\u73B0\u6570\u91CF\uFF1A{a0}{a1}`, { a0: conv.join(" \u2192 "), a1: typeof manifest.round === "number" ? tf(` \xB7 \u5F53\u524D Round {a0}`, { a0: manifest.round }) : "" })
|
|
3621
4245
|
),
|
|
3622
4246
|
comparisonTable ? React.createElement(
|
|
3623
4247
|
"div",
|
|
@@ -3625,11 +4249,11 @@ function ObservatoryPanel(props) {
|
|
|
3625
4249
|
React.createElement(
|
|
3626
4250
|
"div",
|
|
3627
4251
|
{ className: "iterate-obs-block-head" },
|
|
3628
|
-
React.createElement("span", {}, "\u8DE8\u8F6E\u5BF9\u6BD4\uFF08\u672C\u4F1A\u8BDD\uFF09"),
|
|
4252
|
+
React.createElement("span", {}, t("\u8DE8\u8F6E\u5BF9\u6BD4\uFF08\u672C\u4F1A\u8BDD\uFF09")),
|
|
3629
4253
|
React.createElement(
|
|
3630
4254
|
"span",
|
|
3631
4255
|
{ className: "iterate-obs-head-meta" },
|
|
3632
|
-
"\u8DE8\u4F1A\u8BDD\u5BF9\u6BD4\uFF1A\u672C\u8868\u53EA\u8986\u76D6\u5F53\u524D\u4F1A\u8BDD\uFF1B\u70B9\u300C\u62C9\u53D6\u78C1\u76D8\u5FEB\u7167\u300D\u8BA9\u6A21\u578B\u56DE\u663E iterate_history\uFF0C\u518D\u7528\u300C\u5BFC\u51FA JSON\u300D\u5E76\u6392\u6BD4\u8F83\u4E24\u6B21\u8FD0\u884C"
|
|
4256
|
+
t("\u8DE8\u4F1A\u8BDD\u5BF9\u6BD4\uFF1A\u672C\u8868\u53EA\u8986\u76D6\u5F53\u524D\u4F1A\u8BDD\uFF1B\u70B9\u300C\u62C9\u53D6\u78C1\u76D8\u5FEB\u7167\u300D\u8BA9\u6A21\u578B\u56DE\u663E iterate_history\uFF0C\u518D\u7528\u300C\u5BFC\u51FA JSON\u300D\u5E76\u6392\u6BD4\u8F83\u4E24\u6B21\u8FD0\u884C")
|
|
3633
4257
|
)
|
|
3634
4258
|
),
|
|
3635
4259
|
React.createElement("div", { className: "iterate-obs-block-body" }, comparisonTable)
|
|
@@ -3639,7 +4263,7 @@ function ObservatoryPanel(props) {
|
|
|
3639
4263
|
const renderFindings = () => {
|
|
3640
4264
|
const findings = manifest.findings || [];
|
|
3641
4265
|
if (findings.length === 0) {
|
|
3642
|
-
return React.createElement("div", { className: "iterate-obs-empty" }, "\u6682\u65E0\u53D1\u73B0");
|
|
4266
|
+
return React.createElement("div", { className: "iterate-obs-empty" }, t("\u6682\u65E0\u53D1\u73B0"));
|
|
3643
4267
|
}
|
|
3644
4268
|
const opts = buildFilterOptions(findings);
|
|
3645
4269
|
const { filtered } = filterFindingsWithIndices(findings, f3Filter);
|
|
@@ -3653,13 +4277,13 @@ function ObservatoryPanel(props) {
|
|
|
3653
4277
|
const filterBar = React.createElement(
|
|
3654
4278
|
"div",
|
|
3655
4279
|
{ className: "iterate-obs-bar", style: { marginBottom: 8, flexWrap: "wrap" } },
|
|
3656
|
-
React.createElement("b", {}, "\u53D1\u73B0"),
|
|
4280
|
+
React.createElement("b", {}, t("\u53D1\u73B0")),
|
|
3657
4281
|
...opts.severities.map(
|
|
3658
4282
|
(s) => React.createElement("button", {
|
|
3659
4283
|
key: `sev-${s.value}`,
|
|
3660
4284
|
className: "iterate-filter-chip",
|
|
3661
4285
|
"data-active": f3Filter.severities.includes(s.value) ? "" : void 0,
|
|
3662
|
-
title:
|
|
4286
|
+
title: tf(`{a0}\uFF08{a1} \u9879\uFF09`, { a0: s.value, a1: s.count }),
|
|
3663
4287
|
onClick: () => toggleSeverity(s.value)
|
|
3664
4288
|
}, `${s.value} ${s.count}`)
|
|
3665
4289
|
),
|
|
@@ -3668,13 +4292,13 @@ function ObservatoryPanel(props) {
|
|
|
3668
4292
|
{
|
|
3669
4293
|
className: "iterate-filter-select",
|
|
3670
4294
|
value: f3Filter.dimensions[0] || "",
|
|
3671
|
-
"aria-label": "\u6309\u7EF4\u5EA6\u7B5B\u9009",
|
|
4295
|
+
"aria-label": t("\u6309\u7EF4\u5EA6\u7B5B\u9009"),
|
|
3672
4296
|
onChange: (e) => {
|
|
3673
4297
|
const v = e.target.value;
|
|
3674
4298
|
setF3Filter((prev) => ({ ...prev, dimensions: v ? [v] : [] }));
|
|
3675
4299
|
}
|
|
3676
4300
|
},
|
|
3677
|
-
React.createElement("option", { value: "" }, "\u5168\u90E8\u7EF4\u5EA6"),
|
|
4301
|
+
React.createElement("option", { value: "" }, t("\u5168\u90E8\u7EF4\u5EA6")),
|
|
3678
4302
|
...opts.dimensions.map(
|
|
3679
4303
|
(d) => React.createElement("option", { key: d.value, value: d.value }, `${d.value} (${d.count})`)
|
|
3680
4304
|
)
|
|
@@ -3682,16 +4306,16 @@ function ObservatoryPanel(props) {
|
|
|
3682
4306
|
React.createElement("input", {
|
|
3683
4307
|
className: "iterate-filter-search",
|
|
3684
4308
|
type: "search",
|
|
3685
|
-
placeholder: "\u641C\u7D22\u53D1\u73B0\u2026",
|
|
3686
|
-
"aria-label": "\u641C\u7D22\u53D1\u73B0",
|
|
4309
|
+
placeholder: t("\u641C\u7D22\u53D1\u73B0\u2026"),
|
|
4310
|
+
"aria-label": t("\u641C\u7D22\u53D1\u73B0"),
|
|
3687
4311
|
value: f3Filter.search,
|
|
3688
4312
|
onChange: (e) => setF3Filter((prev) => ({ ...prev, search: e.target.value }))
|
|
3689
4313
|
}),
|
|
3690
4314
|
filterActive ? React.createElement("button", {
|
|
3691
4315
|
className: "iterate-filter-clear",
|
|
3692
4316
|
onClick: () => setF3Filter({ severities: [], dimensions: [], search: "" }),
|
|
3693
|
-
title: "\u6E05\u9664\u5168\u90E8\u7B5B\u9009"
|
|
3694
|
-
}, "\u6E05\u9664\u7B5B\u9009") : null,
|
|
4317
|
+
title: t("\u6E05\u9664\u5168\u90E8\u7B5B\u9009")
|
|
4318
|
+
}, t("\u6E05\u9664\u7B5B\u9009")) : null,
|
|
3695
4319
|
React.createElement("span", { className: "iterate-filter-count" }, `${filtered.length}/${findings.length}`)
|
|
3696
4320
|
);
|
|
3697
4321
|
const findingBlocks = filtered.map((f, i) => {
|
|
@@ -3716,7 +4340,7 @@ function ObservatoryPanel(props) {
|
|
|
3716
4340
|
React.createElement("span", {}, severityLabel(finding.severity)),
|
|
3717
4341
|
React.createElement("span", { className: "iterate-obs-file" }, loc),
|
|
3718
4342
|
React.createElement("span", {}, String(finding.dimension || "")),
|
|
3719
|
-
finding.acknowledged === true ? React.createElement("span", { className: "iterate-obs-chip" }, "\u5DF2\u786E\u8BA4") : null
|
|
4343
|
+
finding.acknowledged === true ? React.createElement("span", { className: "iterate-obs-chip" }, t("\u5DF2\u786E\u8BA4")) : null
|
|
3720
4344
|
),
|
|
3721
4345
|
React.createElement(
|
|
3722
4346
|
"div",
|
|
@@ -3729,21 +4353,21 @@ function ObservatoryPanel(props) {
|
|
|
3729
4353
|
className: "iterate-btn",
|
|
3730
4354
|
"data-copied": copiedKey === `${k}-fix` ? "" : void 0,
|
|
3731
4355
|
onClick: () => copyInstruction(`${k}-fix`, String(finding.suggested_fix || "")),
|
|
3732
|
-
title: "\u590D\u5236\u8BE5 finding \u7684\u5EFA\u8BAE\u4FEE\u590D\u6587\u672C"
|
|
3733
|
-
}, copiedKey === `${k}-fix` ? "\u5DF2\u590D\u5236" : "\u590D\u5236 suggested_fix"),
|
|
4356
|
+
title: t("\u590D\u5236\u8BE5 finding \u7684\u5EFA\u8BAE\u4FEE\u590D\u6587\u672C")
|
|
4357
|
+
}, copiedKey === `${k}-fix` ? t("\u5DF2\u590D\u5236") : t("\u590D\u5236 suggested_fix")),
|
|
3734
4358
|
React.createElement("button", {
|
|
3735
4359
|
className: "iterate-btn",
|
|
3736
4360
|
"data-copied": copiedKey === `${k}-known` ? "" : void 0,
|
|
3737
4361
|
onClick: () => copyInstruction(`${k}-known`, knownInstruction),
|
|
3738
|
-
title: "\u590D\u5236 iterate_triage \u6307\u4EE4\u6587\u672C\uFF08\u6807\u8BB0\u4E3A known_intentional\uFF09"
|
|
3739
|
-
}, copiedKey === `${k}-known` ? "\u5DF2\u590D\u5236" : "known_intentional"),
|
|
4362
|
+
title: t("\u590D\u5236 iterate_triage \u6307\u4EE4\u6587\u672C\uFF08\u6807\u8BB0\u4E3A known_intentional\uFF09")
|
|
4363
|
+
}, copiedKey === `${k}-known` ? t("\u5DF2\u590D\u5236") : "known_intentional"),
|
|
3740
4364
|
React.createElement("button", {
|
|
3741
4365
|
className: "iterate-btn",
|
|
3742
4366
|
"data-primary": "",
|
|
3743
4367
|
"data-copied": copiedKey === `${k}-repair` ? "" : void 0,
|
|
3744
4368
|
onClick: () => copyInstruction(`${k}-repair`, fixInstruction),
|
|
3745
|
-
title: "\u590D\u5236 iterate_fix \u6307\u4EE4\u6587\u672C"
|
|
3746
|
-
}, copiedKey === `${k}-repair` ? "\u5DF2\u590D\u5236" : "\u590D\u5236\u4FEE\u590D\u6307\u4EE4")
|
|
4369
|
+
title: t("\u590D\u5236 iterate_fix \u6307\u4EE4\u6587\u672C")
|
|
4370
|
+
}, copiedKey === `${k}-repair` ? t("\u5DF2\u590D\u5236") : t("\u590D\u5236\u4FEE\u590D\u6307\u4EE4"))
|
|
3747
4371
|
)
|
|
3748
4372
|
)
|
|
3749
4373
|
);
|
|
@@ -3753,7 +4377,7 @@ function ObservatoryPanel(props) {
|
|
|
3753
4377
|
"div",
|
|
3754
4378
|
{},
|
|
3755
4379
|
filterBar,
|
|
3756
|
-
React.createElement("div", { className: "iterate-obs-empty" }, "\u65E0\u5339\u914D\u7684\u53D1\u73B0")
|
|
4380
|
+
React.createElement("div", { className: "iterate-obs-empty" }, t("\u65E0\u5339\u914D\u7684\u53D1\u73B0"))
|
|
3757
4381
|
);
|
|
3758
4382
|
}
|
|
3759
4383
|
return React.createElement("div", {}, filterBar, ...findingBlocks);
|
|
@@ -3761,7 +4385,7 @@ function ObservatoryPanel(props) {
|
|
|
3761
4385
|
const renderFixes = () => {
|
|
3762
4386
|
const fixes = manifest.fixes || [];
|
|
3763
4387
|
if (fixes.length === 0) {
|
|
3764
|
-
return React.createElement("div", { className: "iterate-obs-empty" }, "\u6682\u65E0\u4FEE\u590D\u8BB0\u5F55");
|
|
4388
|
+
return React.createElement("div", { className: "iterate-obs-empty" }, t("\u6682\u65E0\u4FEE\u590D\u8BB0\u5F55"));
|
|
3765
4389
|
}
|
|
3766
4390
|
return React.createElement("div", {}, ...fixes.map((f, i) => {
|
|
3767
4391
|
const k = `f4-${i}`;
|
|
@@ -3777,7 +4401,7 @@ function ObservatoryPanel(props) {
|
|
|
3777
4401
|
{ className: "iterate-obs-block-head" },
|
|
3778
4402
|
React.createElement("b", {}, id),
|
|
3779
4403
|
React.createElement("span", { className: "iterate-obs-file" }, String(f.file || "?")),
|
|
3780
|
-
React.createElement("span", { className: "iterate-obs-chip" }, f.success === true ? "\u6210\u529F" : "\u5931\u8D25"),
|
|
4404
|
+
React.createElement("span", { className: "iterate-obs-chip" }, f.success === true ? t("\u6210\u529F") : t("\u5931\u8D25")),
|
|
3781
4405
|
typeof f.round === "number" ? React.createElement("span", { className: "iterate-obs-head-meta" }, `Round ${f.round}`) : null
|
|
3782
4406
|
),
|
|
3783
4407
|
React.createElement(
|
|
@@ -3794,8 +4418,8 @@ function ObservatoryPanel(props) {
|
|
|
3794
4418
|
"data-danger": "",
|
|
3795
4419
|
"data-copied": copiedKey === `${k}-rb` ? "" : void 0,
|
|
3796
4420
|
onClick: () => copyInstruction(`${k}-rb`, rollbackText),
|
|
3797
|
-
title: "\u590D\u5236 iterate_rollback \u6307\u4EE4\u6587\u672C"
|
|
3798
|
-
}, copiedKey === `${k}-rb` ? "\u5DF2\u590D\u5236" : "\u56DE\u6EDA")
|
|
4421
|
+
title: t("\u590D\u5236 iterate_rollback \u6307\u4EE4\u6587\u672C")
|
|
4422
|
+
}, copiedKey === `${k}-rb` ? t("\u5DF2\u590D\u5236") : t("\u56DE\u6EDA"))
|
|
3799
4423
|
)
|
|
3800
4424
|
)
|
|
3801
4425
|
);
|
|
@@ -3807,7 +4431,7 @@ function ObservatoryPanel(props) {
|
|
|
3807
4431
|
return React.createElement(
|
|
3808
4432
|
"div",
|
|
3809
4433
|
{ className: "iterate-obs-empty" },
|
|
3810
|
-
diskEmptyStateText(toolCalledInSession(session, "iterate_transcript"), "\u65AD\u70B9")
|
|
4434
|
+
diskEmptyStateText(toolCalledInSession(session, "iterate_transcript"), t("\u65AD\u70B9"), getLang())
|
|
3811
4435
|
);
|
|
3812
4436
|
}
|
|
3813
4437
|
const resumeText = buildCheckpointResumeInstruction();
|
|
@@ -3819,7 +4443,7 @@ function ObservatoryPanel(props) {
|
|
|
3819
4443
|
React.createElement(
|
|
3820
4444
|
"div",
|
|
3821
4445
|
{ className: "iterate-obs-block-head" },
|
|
3822
|
-
React.createElement("b", {}, "\u65AD\u70B9"),
|
|
4446
|
+
React.createElement("b", {}, t("\u65AD\u70B9")),
|
|
3823
4447
|
React.createElement("span", { className: "iterate-obs-head-meta" }, String(cp.updatedAt || ""))
|
|
3824
4448
|
),
|
|
3825
4449
|
React.createElement(
|
|
@@ -3842,36 +4466,36 @@ function ObservatoryPanel(props) {
|
|
|
3842
4466
|
"data-primary": "",
|
|
3843
4467
|
"data-copied": copiedKey === "cp-resume" ? "" : void 0,
|
|
3844
4468
|
onClick: () => copyInstruction("cp-resume", resumeText),
|
|
3845
|
-
title: "\u590D\u5236 iterate_checkpoint resume \u6307\u4EE4\u6587\u672C\uFF08\u52A0\u8F7D\u65AD\u70B9\u5E76\u8BA1\u6570\u4E00\u6B21\u6062\u590D\uFF09"
|
|
3846
|
-
}, copiedKey === "cp-resume" ? "\u5DF2\u590D\u5236" : "\u590D\u5236\u6062\u590D\u6307\u4EE4"),
|
|
4469
|
+
title: t("\u590D\u5236 iterate_checkpoint resume \u6307\u4EE4\u6587\u672C\uFF08\u52A0\u8F7D\u65AD\u70B9\u5E76\u8BA1\u6570\u4E00\u6B21\u6062\u590D\uFF09")
|
|
4470
|
+
}, copiedKey === "cp-resume" ? t("\u5DF2\u590D\u5236") : t("\u590D\u5236\u6062\u590D\u6307\u4EE4")),
|
|
3847
4471
|
React.createElement("button", {
|
|
3848
4472
|
className: "iterate-btn",
|
|
3849
4473
|
"data-danger": "",
|
|
3850
4474
|
"data-copied": copiedKey === "cp-clear" ? "" : void 0,
|
|
3851
4475
|
onClick: () => copyInstruction("cp-clear", clearText),
|
|
3852
|
-
title: "\u590D\u5236 iterate_checkpoint clear \u6307\u4EE4\u6587\u672C\uFF08\u6E05\u9664\u5F53\u524D\u65AD\u70B9\uFF0C\u4F9B\u91CD\u65B0\u5F00\u59CB\uFF09"
|
|
3853
|
-
}, copiedKey === "cp-clear" ? "\u5DF2\u590D\u5236" : "\u6E05\u9664\u65AD\u70B9")
|
|
4476
|
+
title: t("\u590D\u5236 iterate_checkpoint clear \u6307\u4EE4\u6587\u672C\uFF08\u6E05\u9664\u5F53\u524D\u65AD\u70B9\uFF0C\u4F9B\u91CD\u65B0\u5F00\u59CB\uFF09")
|
|
4477
|
+
}, copiedKey === "cp-clear" ? t("\u5DF2\u590D\u5236") : t("\u6E05\u9664\u65AD\u70B9"))
|
|
3854
4478
|
)
|
|
3855
4479
|
)
|
|
3856
4480
|
);
|
|
3857
4481
|
};
|
|
3858
4482
|
const renderConsole = () => {
|
|
3859
4483
|
const approval = manifest.approval || { policy: "ask" };
|
|
3860
|
-
const policyLabelMap = { ask: "\u8BE2\u95EE\u7528\u6237", deny: "\u62D2\u7EDD", allow: "\u76F4\u63A5\u6267\u884C" };
|
|
4484
|
+
const policyLabelMap = { ask: t("\u8BE2\u95EE\u7528\u6237"), deny: t("\u62D2\u7EDD"), allow: t("\u76F4\u63A5\u6267\u884C") };
|
|
3861
4485
|
const policyLabel = policyLabelMap[String(approval.policy || "ask")] || String(approval.policy || "ask");
|
|
3862
4486
|
const nudge = manifest.nudge || null;
|
|
3863
4487
|
const present = Boolean(nudge && nudge.text);
|
|
3864
4488
|
const activeNudgeText = nudge && nudge.text ? nudge.text : "";
|
|
3865
|
-
const nudgeInstruction = `\u8BF7\u8C03\u7528 \`iterate_transcript\` \u5199\u5165 nudge \u6307\u4EE4\uFF1A
|
|
4489
|
+
const nudgeInstruction = tf(`\u8BF7\u8C03\u7528 \`iterate_transcript\` \u5199\u5165 nudge \u6307\u4EE4\uFF1A
|
|
3866
4490
|
|
|
3867
4491
|
\`\`\`json
|
|
3868
|
-
|
|
3869
|
-
|
|
3870
|
-
const activeClearInstruction = `\u8BF7\u8C03\u7528 \`iterate_transcript\` \u6E05\u9664\u5F53\u524D nudge\uFF1A
|
|
4492
|
+
{a0}
|
|
4493
|
+
\`\`\``, { a0: JSON.stringify({ operation: "nudge", text: nudgeText }, null, 2) });
|
|
4494
|
+
const activeClearInstruction = tf(`\u8BF7\u8C03\u7528 \`iterate_transcript\` \u6E05\u9664\u5F53\u524D nudge\uFF1A
|
|
3871
4495
|
|
|
3872
4496
|
\`\`\`json
|
|
3873
|
-
|
|
3874
|
-
|
|
4497
|
+
{a0}
|
|
4498
|
+
\`\`\``, { a0: JSON.stringify({ operation: "nudge", text: null }, null, 2) });
|
|
3875
4499
|
const validations = Array.isArray(manifest.validations) ? manifest.validations : [];
|
|
3876
4500
|
const abortedByValidation = String(manifest.stoppedReason || "") === "aborted_by_validation";
|
|
3877
4501
|
const validationRows = validations.map((v, i) => {
|
|
@@ -3893,10 +4517,10 @@ ${JSON.stringify({ operation: "nudge", text: null }, null, 2)}
|
|
|
3893
4517
|
React.createElement(
|
|
3894
4518
|
"span",
|
|
3895
4519
|
{ className: "iterate-obs-chip", "data-status": allowed ? "pass" : "fail" },
|
|
3896
|
-
allowed ? "\u901A\u8FC7" : "\u5931\u8D25"
|
|
4520
|
+
allowed ? t("\u901A\u8FC7") : t("\u5931\u8D25")
|
|
3897
4521
|
),
|
|
3898
4522
|
React.createElement("span", { className: "iterate-obs-head-meta" }, exit),
|
|
3899
|
-
highlight ? React.createElement("span", { className: "iterate-obs-chip", "data-status": "fail" }, "\u5BFC\u81F4\u4E2D\u6B62") : null
|
|
4523
|
+
highlight ? React.createElement("span", { className: "iterate-obs-chip", "data-status": "fail" }, t("\u5BFC\u81F4\u4E2D\u6B62")) : null
|
|
3900
4524
|
);
|
|
3901
4525
|
});
|
|
3902
4526
|
const validationsBlock = React.createElement(
|
|
@@ -3905,9 +4529,9 @@ ${JSON.stringify({ operation: "nudge", text: null }, null, 2)}
|
|
|
3905
4529
|
React.createElement(
|
|
3906
4530
|
"div",
|
|
3907
4531
|
{ className: "iterate-obs-block-head" },
|
|
3908
|
-
React.createElement("span", {}, "\u9A8C\u8BC1\u7ED3\u679C"),
|
|
3909
|
-
validations.length === 0 ? React.createElement("span", { className: "iterate-obs-head-meta" }, "\u672C\u8F6E\u5C1A\u65E0\u9A8C\u8BC1\u8BB0\u5F55") : React.createElement("span", { className: "iterate-obs-head-meta" },
|
|
3910
|
-
abortedByValidation ? React.createElement("span", { className: "iterate-obs-badge", "data-status": "fail" }, "\u56E0\u9A8C\u8BC1\u5931\u8D25\u4E2D\u6B62") : null
|
|
4532
|
+
React.createElement("span", {}, t("\u9A8C\u8BC1\u7ED3\u679C")),
|
|
4533
|
+
validations.length === 0 ? React.createElement("span", { className: "iterate-obs-head-meta" }, t("\u672C\u8F6E\u5C1A\u65E0\u9A8C\u8BC1\u8BB0\u5F55")) : React.createElement("span", { className: "iterate-obs-head-meta" }, tf(`{a0} \u6761\u547D\u4EE4`, { a0: validations.length })),
|
|
4534
|
+
abortedByValidation ? React.createElement("span", { className: "iterate-obs-badge", "data-status": "fail" }, t("\u56E0\u9A8C\u8BC1\u5931\u8D25\u4E2D\u6B62")) : null
|
|
3911
4535
|
),
|
|
3912
4536
|
React.createElement(
|
|
3913
4537
|
"div",
|
|
@@ -3915,7 +4539,7 @@ ${JSON.stringify({ operation: "nudge", text: null }, null, 2)}
|
|
|
3915
4539
|
validations.length === 0 ? React.createElement(
|
|
3916
4540
|
"div",
|
|
3917
4541
|
{ className: "iterate-obs-empty" },
|
|
3918
|
-
"\u5C1A\u672A\u62C9\u53D6\u9A8C\u8BC1\u7ED3\u679C\uFF1A\u6570\u636E\u5728\u78C1\u76D8 transcript \u91CC\uFF0C\u70B9\u300C\u62C9\u53D6\u78C1\u76D8\u5FEB\u7167\u300D\u590D\u5236\u6307\u4EE4\u53D1\u56DE\u4F1A\u8BDD\u5373\u53EF\u56DE\u586B\u3002"
|
|
4542
|
+
t("\u5C1A\u672A\u62C9\u53D6\u9A8C\u8BC1\u7ED3\u679C\uFF1A\u6570\u636E\u5728\u78C1\u76D8 transcript \u91CC\uFF0C\u70B9\u300C\u62C9\u53D6\u78C1\u76D8\u5FEB\u7167\u300D\u590D\u5236\u6307\u4EE4\u53D1\u56DE\u4F1A\u8BDD\u5373\u53EF\u56DE\u586B\u3002")
|
|
3919
4543
|
) : React.createElement(React.Fragment, null, ...validationRows)
|
|
3920
4544
|
)
|
|
3921
4545
|
);
|
|
@@ -3925,9 +4549,9 @@ ${JSON.stringify({ operation: "nudge", text: null }, null, 2)}
|
|
|
3925
4549
|
React.createElement(
|
|
3926
4550
|
"div",
|
|
3927
4551
|
{ className: "iterate-obs-block-head" },
|
|
3928
|
-
React.createElement("span", {}, "\u8FD0\u884C\u63A7\u5236\u53F0"),
|
|
4552
|
+
React.createElement("span", {}, t("\u8FD0\u884C\u63A7\u5236\u53F0")),
|
|
3929
4553
|
React.createElement("span", { className: "iterate-obs-badge", "data-live": live ? "" : void 0 }, runStatusText(live, manifest)),
|
|
3930
|
-
React.createElement("span", { className: "iterate-obs-head-meta" }, `\u6279\u51C6\u7B56\u7565\uFF1A
|
|
4554
|
+
React.createElement("span", { className: "iterate-obs-head-meta" }, tf(`\u6279\u51C6\u7B56\u7565\uFF1A{a0}`, { a0: policyLabel }))
|
|
3931
4555
|
),
|
|
3932
4556
|
React.createElement(
|
|
3933
4557
|
"div",
|
|
@@ -3935,21 +4559,21 @@ ${JSON.stringify({ operation: "nudge", text: null }, null, 2)}
|
|
|
3935
4559
|
present ? React.createElement(
|
|
3936
4560
|
"div",
|
|
3937
4561
|
{ className: "iterate-obs-bar", style: { marginBottom: 6 } },
|
|
3938
|
-
React.createElement("b", {}, "\u5F53\u524D nudge"),
|
|
4562
|
+
React.createElement("b", {}, t("\u5F53\u524D nudge")),
|
|
3939
4563
|
React.createElement("span", { className: "iterate-obs-msg" }, activeNudgeText),
|
|
3940
4564
|
React.createElement("button", {
|
|
3941
4565
|
className: "iterate-btn",
|
|
3942
4566
|
"data-copied": copiedKey === "nudge-clear" ? "" : void 0,
|
|
3943
4567
|
onClick: () => copyInstruction("nudge-clear", activeClearInstruction),
|
|
3944
|
-
title: "\u590D\u5236\u6E05\u9664 nudge \u6307\u4EE4\uFF08\u5199 text:null\uFF09\uFF0C\u5728\u8FD0\u884C\u63A7\u5236\u53F0\u63D0\u793A\u6E05\u9664\u5DF2\u6301\u4E45\u5316\u7684 nudge"
|
|
3945
|
-
}, copiedKey === "nudge-clear" ? "\u5DF2\u590D\u5236\u6E05\u9664\u6307\u4EE4" : "\u590D\u5236\u6E05\u9664\u6307\u4EE4")
|
|
4568
|
+
title: t("\u590D\u5236\u6E05\u9664 nudge \u6307\u4EE4\uFF08\u5199 text:null\uFF09\uFF0C\u5728\u8FD0\u884C\u63A7\u5236\u53F0\u63D0\u793A\u6E05\u9664\u5DF2\u6301\u4E45\u5316\u7684 nudge")
|
|
4569
|
+
}, copiedKey === "nudge-clear" ? t("\u5DF2\u590D\u5236\u6E05\u9664\u6307\u4EE4") : t("\u590D\u5236\u6E05\u9664\u6307\u4EE4"))
|
|
3946
4570
|
) : null,
|
|
3947
4571
|
React.createElement("textarea", {
|
|
3948
4572
|
className: "iterate-obs-input iterate-obs-mono",
|
|
3949
4573
|
rows: 3,
|
|
3950
|
-
placeholder: "\u8D77\u8349\u4E00\u6761 nudge \u65B9\u5411\u6307\u4EE4\u2026",
|
|
4574
|
+
placeholder: t("\u8D77\u8349\u4E00\u6761 nudge \u65B9\u5411\u6307\u4EE4\u2026"),
|
|
3951
4575
|
value: nudgeText,
|
|
3952
|
-
"aria-label": "nudge \u8349\u7A3F",
|
|
4576
|
+
"aria-label": t("nudge \u8349\u7A3F"),
|
|
3953
4577
|
onChange: (e) => setNudgeText(e.target.value)
|
|
3954
4578
|
}),
|
|
3955
4579
|
React.createElement(
|
|
@@ -3961,8 +4585,8 @@ ${JSON.stringify({ operation: "nudge", text: null }, null, 2)}
|
|
|
3961
4585
|
"data-copied": copiedKey === "nudge" ? "" : void 0,
|
|
3962
4586
|
disabled: !nudgeText,
|
|
3963
4587
|
onClick: () => copyInstruction("nudge", nudgeInstruction),
|
|
3964
|
-
title: "\u590D\u5236 iterate_transcript nudge \u6307\u4EE4\u6587\u672C"
|
|
3965
|
-
}, copiedKey === "nudge" ? "\u5DF2\u590D\u5236" : "\u590D\u5236 nudge \u6307\u4EE4")
|
|
4588
|
+
title: t("\u590D\u5236 iterate_transcript nudge \u6307\u4EE4\u6587\u672C")
|
|
4589
|
+
}, copiedKey === "nudge" ? t("\u5DF2\u590D\u5236") : t("\u590D\u5236 nudge \u6307\u4EE4"))
|
|
3966
4590
|
),
|
|
3967
4591
|
validationsBlock
|
|
3968
4592
|
)
|
|
@@ -3971,11 +4595,11 @@ ${JSON.stringify({ operation: "nudge", text: null }, null, 2)}
|
|
|
3971
4595
|
const renderTimeline = () => {
|
|
3972
4596
|
const entries = manifest.timeline || [];
|
|
3973
4597
|
if (entries.length === 0) {
|
|
3974
|
-
return React.createElement("div", { className: "iterate-obs-empty" }, "\u6682\u65E0\u65F6\u95F4\u7EBF\u6761\u76EE");
|
|
4598
|
+
return React.createElement("div", { className: "iterate-obs-empty" }, t("\u6682\u65E0\u65F6\u95F4\u7EBF\u6761\u76EE"));
|
|
3975
4599
|
}
|
|
3976
|
-
const types = Array.from(new Set(entries.map((
|
|
4600
|
+
const types = Array.from(new Set(entries.map((t2) => String(t2.type || "unknown")).filter(Boolean))).sort();
|
|
3977
4601
|
const rounds = Array.from(
|
|
3978
|
-
new Set(entries.map((
|
|
4602
|
+
new Set(entries.map((t2) => typeof t2.round === "number" ? String(t2.round) : "").filter(Boolean))
|
|
3979
4603
|
).sort((a, b) => Number(a) - Number(b));
|
|
3980
4604
|
const filtered = filterTimelineEntries(entries, {
|
|
3981
4605
|
type: timelineType,
|
|
@@ -3989,14 +4613,14 @@ ${JSON.stringify({ operation: "nudge", text: null }, null, 2)}
|
|
|
3989
4613
|
setTimelineSearch("");
|
|
3990
4614
|
};
|
|
3991
4615
|
const sorted = filtered.slice();
|
|
3992
|
-
const rows = sorted.map((
|
|
4616
|
+
const rows = sorted.map((t2, i) => {
|
|
3993
4617
|
const k = `f7-${i}`;
|
|
3994
4618
|
let dataText = "";
|
|
3995
|
-
if (
|
|
4619
|
+
if (t2.data && typeof t2.data === "object") {
|
|
3996
4620
|
try {
|
|
3997
|
-
dataText = JSON.stringify(
|
|
4621
|
+
dataText = JSON.stringify(t2.data);
|
|
3998
4622
|
} catch {
|
|
3999
|
-
dataText = String(
|
|
4623
|
+
dataText = String(t2.data);
|
|
4000
4624
|
}
|
|
4001
4625
|
}
|
|
4002
4626
|
return React.createElement(
|
|
@@ -4005,11 +4629,11 @@ ${JSON.stringify({ operation: "nudge", text: null }, null, 2)}
|
|
|
4005
4629
|
React.createElement(
|
|
4006
4630
|
"div",
|
|
4007
4631
|
{ className: "iterate-obs-bar", style: { width: "100%" } },
|
|
4008
|
-
React.createElement("span", { className: "iterate-obs-chip" }, String(
|
|
4632
|
+
React.createElement("span", { className: "iterate-obs-chip" }, String(t2.type || "?")),
|
|
4009
4633
|
React.createElement(
|
|
4010
4634
|
"span",
|
|
4011
4635
|
{ className: "iterate-obs-head-meta" },
|
|
4012
|
-
`${typeof
|
|
4636
|
+
`${typeof t2.round === "number" ? `Round ${t2.round} \xB7 ` : ""}${String(t2.timestamp || "")}`
|
|
4013
4637
|
)
|
|
4014
4638
|
),
|
|
4015
4639
|
dataText ? React.createElement("div", { className: "iterate-obs-code" }, dataText) : null
|
|
@@ -4018,42 +4642,42 @@ ${JSON.stringify({ operation: "nudge", text: null }, null, 2)}
|
|
|
4018
4642
|
const filterBar = React.createElement(
|
|
4019
4643
|
"div",
|
|
4020
4644
|
{ className: "iterate-obs-bar", style: { marginBottom: 8 } },
|
|
4021
|
-
React.createElement("b", {}, "\u65F6\u95F4\u7EBF"),
|
|
4645
|
+
React.createElement("b", {}, t("\u65F6\u95F4\u7EBF")),
|
|
4022
4646
|
React.createElement(
|
|
4023
4647
|
"select",
|
|
4024
4648
|
{
|
|
4025
4649
|
className: "iterate-filter-select",
|
|
4026
4650
|
value: timelineType,
|
|
4027
|
-
"aria-label": "\u6309\u65F6\u95F4\u7EBF\u7C7B\u578B\u7B5B\u9009",
|
|
4651
|
+
"aria-label": t("\u6309\u65F6\u95F4\u7EBF\u7C7B\u578B\u7B5B\u9009"),
|
|
4028
4652
|
onChange: (e) => setTimelineType(e.target.value)
|
|
4029
4653
|
},
|
|
4030
|
-
React.createElement("option", { value: "" }, "\u5168\u90E8\u7C7B\u578B"),
|
|
4031
|
-
...types.map((
|
|
4654
|
+
React.createElement("option", { value: "" }, t("\u5168\u90E8\u7C7B\u578B")),
|
|
4655
|
+
...types.map((t2) => React.createElement("option", { key: t2, value: t2 }, t2))
|
|
4032
4656
|
),
|
|
4033
4657
|
React.createElement(
|
|
4034
4658
|
"select",
|
|
4035
4659
|
{
|
|
4036
4660
|
className: "iterate-filter-select",
|
|
4037
4661
|
value: timelineRound,
|
|
4038
|
-
"aria-label": "\u6309\u8F6E\u6B21\u7B5B\u9009",
|
|
4662
|
+
"aria-label": t("\u6309\u8F6E\u6B21\u7B5B\u9009"),
|
|
4039
4663
|
onChange: (e) => setTimelineRound(e.target.value)
|
|
4040
4664
|
},
|
|
4041
|
-
React.createElement("option", { value: "" }, "\u5168\u90E8\u8F6E\u6B21"),
|
|
4665
|
+
React.createElement("option", { value: "" }, t("\u5168\u90E8\u8F6E\u6B21")),
|
|
4042
4666
|
...rounds.map((r) => React.createElement("option", { key: r, value: r }, `Round ${r}`))
|
|
4043
4667
|
),
|
|
4044
4668
|
React.createElement("input", {
|
|
4045
4669
|
className: "iterate-filter-search",
|
|
4046
4670
|
type: "search",
|
|
4047
|
-
placeholder: "\u641C\u7D22\u65F6\u95F4\u7EBF\u2026",
|
|
4048
|
-
"aria-label": "\u641C\u7D22\u65F6\u95F4\u7EBF",
|
|
4671
|
+
placeholder: t("\u641C\u7D22\u65F6\u95F4\u7EBF\u2026"),
|
|
4672
|
+
"aria-label": t("\u641C\u7D22\u65F6\u95F4\u7EBF"),
|
|
4049
4673
|
value: timelineSearch,
|
|
4050
4674
|
onChange: (e) => setTimelineSearch(e.target.value)
|
|
4051
4675
|
}),
|
|
4052
4676
|
filterActive ? React.createElement("button", {
|
|
4053
4677
|
className: "iterate-filter-clear",
|
|
4054
4678
|
onClick: clearTimelineFilter,
|
|
4055
|
-
title: "\u6E05\u9664\u5168\u90E8\u7B5B\u9009"
|
|
4056
|
-
}, "\u6E05\u9664") : null,
|
|
4679
|
+
title: t("\u6E05\u9664\u5168\u90E8\u7B5B\u9009")
|
|
4680
|
+
}, t("\u6E05\u9664")) : null,
|
|
4057
4681
|
React.createElement("span", { className: "iterate-filter-count" }, `${filtered.length}/${entries.length}`)
|
|
4058
4682
|
);
|
|
4059
4683
|
if (rows.length === 0) {
|
|
@@ -4061,7 +4685,7 @@ ${JSON.stringify({ operation: "nudge", text: null }, null, 2)}
|
|
|
4061
4685
|
"div",
|
|
4062
4686
|
{},
|
|
4063
4687
|
filterBar,
|
|
4064
|
-
React.createElement("div", { className: "iterate-obs-empty" }, "\u65E0\u5339\u914D\u7684\u65F6\u95F4\u7EBF\u6761\u76EE")
|
|
4688
|
+
React.createElement("div", { className: "iterate-obs-empty" }, t("\u65E0\u5339\u914D\u7684\u65F6\u95F4\u7EBF\u6761\u76EE"))
|
|
4065
4689
|
);
|
|
4066
4690
|
}
|
|
4067
4691
|
return React.createElement("div", {}, filterBar, ...rows);
|
|
@@ -4079,29 +4703,29 @@ ${JSON.stringify({ operation: "nudge", text: null }, null, 2)}
|
|
|
4079
4703
|
const headerBar = React.createElement(
|
|
4080
4704
|
"div",
|
|
4081
4705
|
{ className: "iterate-obs-bar", style: { marginBottom: 8 } },
|
|
4082
|
-
React.createElement("b", {}, "\u8D28\u91CF\u95E8\u7981"),
|
|
4706
|
+
React.createElement("b", {}, t("\u8D28\u91CF\u95E8\u7981")),
|
|
4083
4707
|
React.createElement("button", {
|
|
4084
4708
|
className: "iterate-btn",
|
|
4085
4709
|
"data-primary": "",
|
|
4086
4710
|
"data-copied": copiedKey === "qgate" ? "" : void 0,
|
|
4087
4711
|
onClick: () => copyInstruction("qgate", gateInstruction),
|
|
4088
|
-
title: "\u590D\u5236 iterate_quality_gate \u67E5\u8BE2\u6307\u4EE4\uFF08\u542B JSON \u53C2\u6570\uFF09"
|
|
4089
|
-
}, copiedKey === "qgate" ? "\u5DF2\u590D\u5236" : "\u67E5\u8BE2\u95E8\u7981"),
|
|
4712
|
+
title: t("\u590D\u5236 iterate_quality_gate \u67E5\u8BE2\u6307\u4EE4\uFF08\u542B JSON \u53C2\u6570\uFF09")
|
|
4713
|
+
}, copiedKey === "qgate" ? t("\u5DF2\u590D\u5236") : t("\u67E5\u8BE2\u95E8\u7981")),
|
|
4090
4714
|
React.createElement("button", {
|
|
4091
4715
|
className: "iterate-btn",
|
|
4092
4716
|
"data-danger": "",
|
|
4093
4717
|
"data-copied": copiedKey === "qgate-clear" ? "" : void 0,
|
|
4094
4718
|
onClick: () => copyInstruction("qgate-clear", gateClearInstruction),
|
|
4095
|
-
title: "\u590D\u5236 iterate_quality_gate clear \u6307\u4EE4\u6587\u672C\uFF08\u91CD\u7F6E\u9648\u65E7\u7684 FAIL \u8BC1\u4E66\uFF09"
|
|
4096
|
-
}, copiedKey === "qgate-clear" ? "\u5DF2\u590D\u5236" : "\u6E05\u9664\u95E8\u7981"),
|
|
4719
|
+
title: t("\u590D\u5236 iterate_quality_gate clear \u6307\u4EE4\u6587\u672C\uFF08\u91CD\u7F6E\u9648\u65E7\u7684 FAIL \u8BC1\u4E66\uFF09")
|
|
4720
|
+
}, copiedKey === "qgate-clear" ? t("\u5DF2\u590D\u5236") : t("\u6E05\u9664\u95E8\u7981")),
|
|
4097
4721
|
// Gap #4: the browser cannot read `.iterate/` directly — one click
|
|
4098
4722
|
// copies the pull instruction that makes the model echo it into the stream.
|
|
4099
4723
|
React.createElement("button", {
|
|
4100
4724
|
className: "iterate-btn",
|
|
4101
4725
|
"data-copied": copiedKey === "disk-snapshot" ? "" : void 0,
|
|
4102
4726
|
onClick: () => copyInstruction("disk-snapshot", pullInstruction),
|
|
4103
|
-
title: "\u590D\u5236\u62C9\u53D6\u78C1\u76D8\u5FEB\u7167\u6307\u4EE4\uFF1A\u8BA9\u6A21\u578B\u56DE\u663E .iterate/ \u4E0B\u7684\u95E8\u7981\u3001\u7ECF\u9A8C\u3001\u9632\u5FA1\u4E8B\u4EF6\u4E0E transcript"
|
|
4104
|
-
}, copiedKey === "disk-snapshot" ? "\u5DF2\u590D\u5236" : "\u62C9\u53D6\u78C1\u76D8\u5FEB\u7167")
|
|
4727
|
+
title: t("\u590D\u5236\u62C9\u53D6\u78C1\u76D8\u5FEB\u7167\u6307\u4EE4\uFF1A\u8BA9\u6A21\u578B\u56DE\u663E .iterate/ \u4E0B\u7684\u95E8\u7981\u3001\u7ECF\u9A8C\u3001\u9632\u5FA1\u4E8B\u4EF6\u4E0E transcript")
|
|
4728
|
+
}, copiedKey === "disk-snapshot" ? t("\u5DF2\u590D\u5236") : t("\u62C9\u53D6\u78C1\u76D8\u5FEB\u7167"))
|
|
4105
4729
|
);
|
|
4106
4730
|
if (!hasGate) {
|
|
4107
4731
|
return React.createElement(
|
|
@@ -4114,7 +4738,7 @@ ${JSON.stringify({ operation: "nudge", text: null }, null, 2)}
|
|
|
4114
4738
|
React.createElement(
|
|
4115
4739
|
"div",
|
|
4116
4740
|
{ className: "iterate-obs-block-head" },
|
|
4117
|
-
React.createElement("span", {}, "\u8D28\u91CF\u95E8\u7981\u89C6\u56FE"),
|
|
4741
|
+
React.createElement("span", {}, t("\u8D28\u91CF\u95E8\u7981\u89C6\u56FE")),
|
|
4118
4742
|
React.createElement("span", { className: "iterate-obs-badge" }, "v3.0")
|
|
4119
4743
|
),
|
|
4120
4744
|
React.createElement(
|
|
@@ -4125,12 +4749,12 @@ ${JSON.stringify({ operation: "nudge", text: null }, null, 2)}
|
|
|
4125
4749
|
{ className: "iterate-obs-msg" },
|
|
4126
4750
|
// Gap #4: distinguish "we pulled it and it is empty" from "we
|
|
4127
4751
|
// never asked the model to read the disk".
|
|
4128
|
-
diskEmptyStateText(pulled, "\u8D28\u91CF\u95E8\u7981\u8BC1\u4E66")
|
|
4752
|
+
diskEmptyStateText(pulled, t("\u8D28\u91CF\u95E8\u7981\u8BC1\u4E66"), getLang())
|
|
4129
4753
|
),
|
|
4130
4754
|
React.createElement(
|
|
4131
4755
|
"div",
|
|
4132
4756
|
{ className: "iterate-obs-msg", style: { marginTop: 6 } },
|
|
4133
|
-
"\u8D28\u91CF\u95E8\u7981\u663E\u793A\u5404\u7EF4\u5EA6\u6536\u655B\u5EA6\u3001\u9A8C\u8BC1\u901A\u8FC7\u7387\u548C\u6574\u4F53 PASS/FAIL \u72B6\u6001\u3002"
|
|
4757
|
+
t("\u8D28\u91CF\u95E8\u7981\u663E\u793A\u5404\u7EF4\u5EA6\u6536\u655B\u5EA6\u3001\u9A8C\u8BC1\u901A\u8FC7\u7387\u548C\u6574\u4F53 PASS/FAIL \u72B6\u6001\u3002")
|
|
4134
4758
|
),
|
|
4135
4759
|
React.createElement(
|
|
4136
4760
|
"div",
|
|
@@ -4139,14 +4763,14 @@ ${JSON.stringify({ operation: "nudge", text: null }, null, 2)}
|
|
|
4139
4763
|
className: "iterate-btn",
|
|
4140
4764
|
"data-copied": copiedKey === "qgate-instr" ? "" : void 0,
|
|
4141
4765
|
onClick: () => copyInstruction("qgate-instr", gateInstruction),
|
|
4142
|
-
title: "\u590D\u5236\u67E5\u8BE2\u6307\u4EE4"
|
|
4143
|
-
}, copiedKey === "qgate-instr" ? "\u5DF2\u590D\u5236" : "\u590D\u5236\u67E5\u8BE2\u6307\u4EE4"),
|
|
4766
|
+
title: t("\u590D\u5236\u67E5\u8BE2\u6307\u4EE4")
|
|
4767
|
+
}, copiedKey === "qgate-instr" ? t("\u5DF2\u590D\u5236") : t("\u590D\u5236\u67E5\u8BE2\u6307\u4EE4")),
|
|
4144
4768
|
React.createElement("button", {
|
|
4145
4769
|
className: "iterate-btn",
|
|
4146
4770
|
"data-copied": copiedKey === "disk-snapshot-2" ? "" : void 0,
|
|
4147
4771
|
onClick: () => copyInstruction("disk-snapshot-2", pullInstruction),
|
|
4148
|
-
title: "\u590D\u5236\u62C9\u53D6\u78C1\u76D8\u5FEB\u7167\u6307\u4EE4"
|
|
4149
|
-
}, copiedKey === "disk-snapshot-2" ? "\u5DF2\u590D\u5236" : "\u62C9\u53D6\u78C1\u76D8\u5FEB\u7167")
|
|
4772
|
+
title: t("\u590D\u5236\u62C9\u53D6\u78C1\u76D8\u5FEB\u7167\u6307\u4EE4")
|
|
4773
|
+
}, copiedKey === "disk-snapshot-2" ? t("\u5DF2\u590D\u5236") : t("\u62C9\u53D6\u78C1\u76D8\u5FEB\u7167"))
|
|
4150
4774
|
)
|
|
4151
4775
|
)
|
|
4152
4776
|
)
|
|
@@ -4166,7 +4790,7 @@ ${JSON.stringify({ operation: "nudge", text: null }, null, 2)}
|
|
|
4166
4790
|
React.createElement(
|
|
4167
4791
|
"span",
|
|
4168
4792
|
{ className: "iterate-obs-head-meta" },
|
|
4169
|
-
`\u6574\u4F53\u8BC4\u5206
|
|
4793
|
+
tf(`\u6574\u4F53\u8BC4\u5206 {a0} \xB7 \u9A8C\u8BC1 {a1}/{a2} \xB7 \u901A\u8FC7\u7387 {a3}%`, { a0: num(gate && gate.overallScore), a1: num(gate && gate.passedChecks), a2: num(gate && gate.totalChecks), a3: num(gate && gate.verificationPassRate) })
|
|
4170
4794
|
)
|
|
4171
4795
|
),
|
|
4172
4796
|
React.createElement(
|
|
@@ -4179,7 +4803,7 @@ ${JSON.stringify({ operation: "nudge", text: null }, null, 2)}
|
|
|
4179
4803
|
(d, i) => React.createElement(
|
|
4180
4804
|
"span",
|
|
4181
4805
|
{ key: `gdim-${i}`, className: "iterate-obs-chip" },
|
|
4182
|
-
|
|
4806
|
+
tf(`{a0} \xB7 \u6536\u655B {a1}% \xB7 \u8BC4\u5206 {a2}`, { a0: String(d.dimension || "?"), a1: num(d.convergenceRate), a2: num(d.score) })
|
|
4183
4807
|
)
|
|
4184
4808
|
)
|
|
4185
4809
|
) : null,
|
|
@@ -4201,33 +4825,33 @@ ${JSON.stringify({ operation: "nudge", text: null }, null, 2)}
|
|
|
4201
4825
|
style: { width: `${fill}%` }
|
|
4202
4826
|
})
|
|
4203
4827
|
),
|
|
4204
|
-
React.createElement("span", {}, `\u8BC4\u5206
|
|
4828
|
+
React.createElement("span", {}, tf(`\u8BC4\u5206 {a0} \xB7 \u53D1\u73B0 {a1} \xB7 \u5DF2\u4FEE\u590D {a2}`, { a0: num(d.score), a1: num(d.findingsCount), a2: num(d.fixedCount) }))
|
|
4205
4829
|
);
|
|
4206
4830
|
})
|
|
4207
4831
|
),
|
|
4208
|
-
gate && gate.failReason ? React.createElement("div", { className: "iterate-obs-msg", style: { marginTop: 6 } }, `\u5931\u8D25\u539F\u56E0\uFF1A
|
|
4832
|
+
gate && gate.failReason ? React.createElement("div", { className: "iterate-obs-msg", style: { marginTop: 6 } }, tf(`\u5931\u8D25\u539F\u56E0\uFF1A{a0}`, { a0: String(gate.failReason) })) : null
|
|
4209
4833
|
)
|
|
4210
4834
|
)
|
|
4211
4835
|
);
|
|
4212
4836
|
};
|
|
4213
4837
|
const renderExperienceBank = () => {
|
|
4214
|
-
const expInstruction = expSearch ? `\u8BF7\u8C03\u7528 \`iterate_experience\` \u641C\u7D22\u7ECF\u9A8C\uFF1A
|
|
4838
|
+
const expInstruction = expSearch ? tf(`\u8BF7\u8C03\u7528 \`iterate_experience\` \u641C\u7D22\u7ECF\u9A8C\uFF1A
|
|
4215
4839
|
|
|
4216
4840
|
\`\`\`json
|
|
4217
|
-
|
|
4218
|
-
|
|
4841
|
+
{a0}
|
|
4842
|
+
\`\`\``, { a0: JSON.stringify({ operation: "search", query: expSearch }, null, 2) }) : buildExperienceListInstruction();
|
|
4219
4843
|
const expEntries = experienceBank && experienceBank.entries ? experienceBank.entries : [];
|
|
4220
4844
|
const query = expSearch.trim().toLowerCase();
|
|
4221
4845
|
const visible = query ? expEntries.filter(
|
|
4222
|
-
(e) => [e.pattern, e.description, e.id, e.dimension, e.severity, ...e.tags || []].filter(Boolean).some((
|
|
4846
|
+
(e) => [e.pattern, e.description, e.id, e.dimension, e.severity, ...e.tags || []].filter(Boolean).some((t2) => String(t2).toLowerCase().includes(query))
|
|
4223
4847
|
) : expEntries;
|
|
4224
4848
|
const pulled = toolCalledInSession(session, "iterate_experience");
|
|
4225
4849
|
const resultRows = visible.map((e, i) => {
|
|
4226
|
-
const adoptInstruction = `\u8BF7\u8C03\u7528 \`iterate_experience\` \u91C7\u7EB3\u7ECF\u9A8C\u5E76\u5E94\u7528\u5DF2\u9A8C\u8BC1\u4FEE\u6CD5\uFF1A
|
|
4850
|
+
const adoptInstruction = tf(`\u8BF7\u8C03\u7528 \`iterate_experience\` \u91C7\u7EB3\u7ECF\u9A8C\u5E76\u5E94\u7528\u5DF2\u9A8C\u8BC1\u4FEE\u6CD5\uFF1A
|
|
4227
4851
|
|
|
4228
4852
|
\`\`\`json
|
|
4229
|
-
|
|
4230
|
-
|
|
4853
|
+
{a0}
|
|
4854
|
+
\`\`\``, { a0: JSON.stringify({ operation: "get", id: e.id }, null, 2) });
|
|
4231
4855
|
return React.createElement(
|
|
4232
4856
|
"div",
|
|
4233
4857
|
{ key: `exp-${i}`, className: "iterate-obs-block" },
|
|
@@ -4236,7 +4860,7 @@ ${JSON.stringify({ operation: "get", id: e.id }, null, 2)}
|
|
|
4236
4860
|
{ className: "iterate-obs-block-head" },
|
|
4237
4861
|
React.createElement("span", { className: "iterate-obs-chip" }, String(e.dimension || "")),
|
|
4238
4862
|
React.createElement("span", {}, String(e.pattern || "?")),
|
|
4239
|
-
React.createElement("span", { className: "iterate-exp-hit" }, `\u547D\u4E2D
|
|
4863
|
+
React.createElement("span", { className: "iterate-exp-hit" }, tf(`\u547D\u4E2D {a0} \u6B21`, { a0: e.hitCount ?? 0 }))
|
|
4240
4864
|
),
|
|
4241
4865
|
React.createElement(
|
|
4242
4866
|
"div",
|
|
@@ -4250,8 +4874,8 @@ ${JSON.stringify({ operation: "get", id: e.id }, null, 2)}
|
|
|
4250
4874
|
"data-primary": "",
|
|
4251
4875
|
"data-copied": copiedKey === `exp-adopt-${i}` ? "" : void 0,
|
|
4252
4876
|
onClick: () => copyInstruction(`exp-adopt-${i}`, adoptInstruction),
|
|
4253
|
-
title: "\u590D\u5236\u91C7\u7EB3\u6307\u4EE4\uFF08\u67E5\u8BE2\u8BE5\u7ECF\u9A8C\u5E76\u5E94\u7528\u5230\u5F53\u524D\u4E0A\u4E0B\u6587\uFF09"
|
|
4254
|
-
}, copiedKey === `exp-adopt-${i}` ? "\u5DF2\u590D\u5236" : "\u91C7\u7EB3") : null
|
|
4877
|
+
title: t("\u590D\u5236\u91C7\u7EB3\u6307\u4EE4\uFF08\u67E5\u8BE2\u8BE5\u7ECF\u9A8C\u5E76\u5E94\u7528\u5230\u5F53\u524D\u4E0A\u4E0B\u6587\uFF09")
|
|
4878
|
+
}, copiedKey === `exp-adopt-${i}` ? t("\u5DF2\u590D\u5236") : t("\u91C7\u7EB3")) : null
|
|
4255
4879
|
)
|
|
4256
4880
|
)
|
|
4257
4881
|
);
|
|
@@ -4262,21 +4886,21 @@ ${JSON.stringify({ operation: "get", id: e.id }, null, 2)}
|
|
|
4262
4886
|
React.createElement(
|
|
4263
4887
|
"div",
|
|
4264
4888
|
{ className: "iterate-obs-bar", style: { marginBottom: 8 } },
|
|
4265
|
-
React.createElement("b", {}, "\u7ECF\u9A8C\u94F6\u884C"),
|
|
4266
|
-
React.createElement("span", { className: "iterate-obs-head-meta" }, `\u4F1A\u8BDD\u5185
|
|
4889
|
+
React.createElement("b", {}, t("\u7ECF\u9A8C\u94F6\u884C")),
|
|
4890
|
+
React.createElement("span", { className: "iterate-obs-head-meta" }, tf(`\u4F1A\u8BDD\u5185 {a0} \u6761`, { a0: expEntries.length })),
|
|
4267
4891
|
React.createElement("button", {
|
|
4268
4892
|
className: "iterate-btn",
|
|
4269
4893
|
"data-primary": "",
|
|
4270
4894
|
"data-copied": copiedKey === "exp-list" ? "" : void 0,
|
|
4271
4895
|
onClick: () => copyInstruction("exp-list", buildExperienceListInstruction()),
|
|
4272
|
-
title: "\u590D\u5236\u5217\u51FA\u7ECF\u9A8C\u6307\u4EE4\uFF08\u542B JSON \u53C2\u6570\uFF09"
|
|
4273
|
-
}, copiedKey === "exp-list" ? "\u5DF2\u590D\u5236" : "\u5217\u51FA\u7ECF\u9A8C"),
|
|
4896
|
+
title: t("\u590D\u5236\u5217\u51FA\u7ECF\u9A8C\u6307\u4EE4\uFF08\u542B JSON \u53C2\u6570\uFF09")
|
|
4897
|
+
}, copiedKey === "exp-list" ? t("\u5DF2\u590D\u5236") : t("\u5217\u51FA\u7ECF\u9A8C")),
|
|
4274
4898
|
React.createElement("button", {
|
|
4275
4899
|
className: "iterate-btn",
|
|
4276
4900
|
"data-copied": copiedKey === "exp-snapshot" ? "" : void 0,
|
|
4277
4901
|
onClick: () => copyInstruction("exp-snapshot", pullInstruction),
|
|
4278
|
-
title: "\u590D\u5236\u62C9\u53D6\u78C1\u76D8\u5FEB\u7167\u6307\u4EE4\uFF1A\u628A .iterate/ \u4E0B\u7684\u7ECF\u9A8C\u94F6\u884C\u7B49\u4EA7\u7269\u56DE\u663E\u8FDB\u4F1A\u8BDD"
|
|
4279
|
-
}, copiedKey === "exp-snapshot" ? "\u5DF2\u590D\u5236" : "\u62C9\u53D6\u78C1\u76D8\u5FEB\u7167")
|
|
4902
|
+
title: t("\u590D\u5236\u62C9\u53D6\u78C1\u76D8\u5FEB\u7167\u6307\u4EE4\uFF1A\u628A .iterate/ \u4E0B\u7684\u7ECF\u9A8C\u94F6\u884C\u7B49\u4EA7\u7269\u56DE\u663E\u8FDB\u4F1A\u8BDD")
|
|
4903
|
+
}, copiedKey === "exp-snapshot" ? t("\u5DF2\u590D\u5236") : t("\u62C9\u53D6\u78C1\u76D8\u5FEB\u7167"))
|
|
4280
4904
|
),
|
|
4281
4905
|
React.createElement(
|
|
4282
4906
|
"div",
|
|
@@ -4284,8 +4908,8 @@ ${JSON.stringify({ operation: "get", id: e.id }, null, 2)}
|
|
|
4284
4908
|
React.createElement("input", {
|
|
4285
4909
|
className: "iterate-filter-search",
|
|
4286
4910
|
type: "search",
|
|
4287
|
-
placeholder: "\u641C\u7D22\u7ECF\u9A8C\u6A21\u5F0F\u2026",
|
|
4288
|
-
"aria-label": "\u641C\u7D22\u7ECF\u9A8C",
|
|
4911
|
+
placeholder: t("\u641C\u7D22\u7ECF\u9A8C\u6A21\u5F0F\u2026"),
|
|
4912
|
+
"aria-label": t("\u641C\u7D22\u7ECF\u9A8C"),
|
|
4289
4913
|
value: expSearch,
|
|
4290
4914
|
onChange: (e) => setExpSearch(e.target.value)
|
|
4291
4915
|
}),
|
|
@@ -4294,36 +4918,36 @@ ${JSON.stringify({ operation: "get", id: e.id }, null, 2)}
|
|
|
4294
4918
|
"data-copied": copiedKey === "exp-search" ? "" : void 0,
|
|
4295
4919
|
disabled: !expSearch,
|
|
4296
4920
|
onClick: () => copyInstruction("exp-search", expInstruction),
|
|
4297
|
-
title: "\u590D\u5236\u641C\u7D22\u6307\u4EE4"
|
|
4298
|
-
}, copiedKey === "exp-search" ? "\u5DF2\u590D\u5236" : "\u641C\u7D22")
|
|
4921
|
+
title: t("\u590D\u5236\u641C\u7D22\u6307\u4EE4")
|
|
4922
|
+
}, copiedKey === "exp-search" ? t("\u5DF2\u590D\u5236") : t("\u641C\u7D22"))
|
|
4299
4923
|
),
|
|
4300
|
-
resultRows.length > 0 ? React.createElement("div", {}, ...resultRows) : expEntries.length > 0 ? React.createElement("div", { className: "iterate-obs-empty" }, "\u6CA1\u6709\u5339\u914D\u300C" + expSearch + "\u300D\u7684\u7ECF\u9A8C") : React.createElement(
|
|
4924
|
+
resultRows.length > 0 ? React.createElement("div", {}, ...resultRows) : expEntries.length > 0 ? React.createElement("div", { className: "iterate-obs-empty" }, t("\u6CA1\u6709\u5339\u914D\u300C") + expSearch + t("\u300D\u7684\u7ECF\u9A8C")) : React.createElement(
|
|
4301
4925
|
"div",
|
|
4302
4926
|
{},
|
|
4303
4927
|
// Gap #4: separate "pulled and empty" from "never pulled".
|
|
4304
|
-
React.createElement("div", { className: "iterate-obs-empty" }, diskEmptyStateText(pulled, "\u7ECF\u9A8C\u94F6\u884C")),
|
|
4305
|
-
React.createElement("div", { className: "iterate-obs-empty" }, "\u4E5F\u53EF\u70B9\u300C\u5217\u51FA\u7ECF\u9A8C\u300D\u67E5\u8BE2\u78C1\u76D8\u4E0A\u7684\u5168\u90E8\u5386\u53F2\u7ECF\u9A8C\u3002")
|
|
4928
|
+
React.createElement("div", { className: "iterate-obs-empty" }, diskEmptyStateText(pulled, t("\u7ECF\u9A8C\u94F6\u884C"), getLang())),
|
|
4929
|
+
React.createElement("div", { className: "iterate-obs-empty" }, t("\u4E5F\u53EF\u70B9\u300C\u5217\u51FA\u7ECF\u9A8C\u300D\u67E5\u8BE2\u78C1\u76D8\u4E0A\u7684\u5168\u90E8\u5386\u53F2\u7ECF\u9A8C\u3002"))
|
|
4306
4930
|
)
|
|
4307
4931
|
);
|
|
4308
4932
|
};
|
|
4309
4933
|
const renderDefenseEvents = () => {
|
|
4310
|
-
const defenseInstruction = defenseFilter ? `\u8BF7\u8C03\u7528 \`iterate_defense_events\` \u67E5\u8BE2\u9632\u5FA1\u4E8B\u4EF6\uFF1A
|
|
4934
|
+
const defenseInstruction = defenseFilter ? tf(`\u8BF7\u8C03\u7528 \`iterate_defense_events\` \u67E5\u8BE2\u9632\u5FA1\u4E8B\u4EF6\uFF1A
|
|
4311
4935
|
|
|
4312
4936
|
\`\`\`json
|
|
4313
|
-
|
|
4314
|
-
|
|
4937
|
+
{a0}
|
|
4938
|
+
\`\`\``, { a0: JSON.stringify({ operation: "list", type: defenseFilter || void 0 }, null, 2) }) : buildDefenseEventsListInstruction();
|
|
4315
4939
|
const typeOptions = [
|
|
4316
|
-
{ value: "", label: "\u5168\u90E8\u7C7B\u578B" },
|
|
4317
|
-
{ value: "precondition_failed", label: "\u524D\u7F6E\u6821\u9A8C\u5931\u8D25" },
|
|
4318
|
-
{ value: "rollback", label: "\u56DE\u6EDA" },
|
|
4319
|
-
{ value: "invariant_violated", label: "\u4E0D\u53D8\u91CF\u8FDD\u53CD" },
|
|
4320
|
-
{ value: "assumption_falsified", label: "\u5047\u8BBE\u88AB\u8BC1\u4F2A" }
|
|
4940
|
+
{ value: "", label: t("\u5168\u90E8\u7C7B\u578B") },
|
|
4941
|
+
{ value: "precondition_failed", label: t("\u524D\u7F6E\u6821\u9A8C\u5931\u8D25") },
|
|
4942
|
+
{ value: "rollback", label: t("\u56DE\u6EDA") },
|
|
4943
|
+
{ value: "invariant_violated", label: t("\u4E0D\u53D8\u91CF\u8FDD\u53CD") },
|
|
4944
|
+
{ value: "assumption_falsified", label: t("\u5047\u8BBE\u88AB\u8BC1\u4F2A") }
|
|
4321
4945
|
];
|
|
4322
4946
|
const TYPE_LABEL = {
|
|
4323
|
-
precondition_failed: "\u524D\u7F6E\u6821\u9A8C\u5931\u8D25",
|
|
4324
|
-
rollback: "\u56DE\u6EDA",
|
|
4325
|
-
invariant_violated: "\u4E0D\u53D8\u91CF\u8FDD\u53CD",
|
|
4326
|
-
assumption_falsified: "\u5047\u8BBE\u88AB\u8BC1\u4F2A"
|
|
4947
|
+
precondition_failed: t("\u524D\u7F6E\u6821\u9A8C\u5931\u8D25"),
|
|
4948
|
+
rollback: t("\u56DE\u6EDA"),
|
|
4949
|
+
invariant_violated: t("\u4E0D\u53D8\u91CF\u8FDD\u53CD"),
|
|
4950
|
+
assumption_falsified: t("\u5047\u8BBE\u88AB\u8BC1\u4F2A")
|
|
4327
4951
|
};
|
|
4328
4952
|
const counts = defenseEvents && defenseEvents.counts || {};
|
|
4329
4953
|
const allEvents = defenseEvents && defenseEvents.events ? defenseEvents.events : [];
|
|
@@ -4332,42 +4956,42 @@ ${JSON.stringify({ operation: "list", type: defenseFilter || void 0 }, null, 2)}
|
|
|
4332
4956
|
const headerBar = React.createElement(
|
|
4333
4957
|
"div",
|
|
4334
4958
|
{ className: "iterate-obs-bar", style: { marginBottom: 8 } },
|
|
4335
|
-
React.createElement("b", {}, "\u9632\u5FA1\u4E8B\u4EF6"),
|
|
4336
|
-
React.createElement("span", { className: "iterate-obs-head-meta" }, `\u4F1A\u8BDD\u5185
|
|
4959
|
+
React.createElement("b", {}, t("\u9632\u5FA1\u4E8B\u4EF6")),
|
|
4960
|
+
React.createElement("span", { className: "iterate-obs-head-meta" }, tf(`\u4F1A\u8BDD\u5185 {a0} \u6761 / \u7D2F\u8BA1 {a1}`, { a0: allEvents.length, a1: totalCount })),
|
|
4337
4961
|
React.createElement("button", {
|
|
4338
4962
|
className: "iterate-btn",
|
|
4339
4963
|
"data-primary": "",
|
|
4340
4964
|
"data-copied": copiedKey === "defense-list" ? "" : void 0,
|
|
4341
4965
|
onClick: () => copyInstruction("defense-list", buildDefenseEventsListInstruction()),
|
|
4342
|
-
title: "\u590D\u5236\u5217\u51FA\u9632\u5FA1\u4E8B\u4EF6\u6307\u4EE4\uFF08\u542B JSON \u53C2\u6570\uFF09"
|
|
4343
|
-
}, copiedKey === "defense-list" ? "\u5DF2\u590D\u5236" : "\u5217\u51FA\u4E8B\u4EF6"),
|
|
4966
|
+
title: t("\u590D\u5236\u5217\u51FA\u9632\u5FA1\u4E8B\u4EF6\u6307\u4EE4\uFF08\u542B JSON \u53C2\u6570\uFF09")
|
|
4967
|
+
}, copiedKey === "defense-list" ? t("\u5DF2\u590D\u5236") : t("\u5217\u51FA\u4E8B\u4EF6")),
|
|
4344
4968
|
React.createElement("button", {
|
|
4345
4969
|
className: "iterate-btn",
|
|
4346
4970
|
"data-copied": copiedKey === "defense-snapshot" ? "" : void 0,
|
|
4347
4971
|
onClick: () => copyInstruction("defense-snapshot", pullInstruction),
|
|
4348
|
-
title: "\u590D\u5236\u62C9\u53D6\u78C1\u76D8\u5FEB\u7167\u6307\u4EE4\uFF1A\u628A .iterate/ \u4E0B\u7684\u9632\u5FA1\u4E8B\u4EF6\u6D41\u56DE\u663E\u8FDB\u4F1A\u8BDD"
|
|
4349
|
-
}, copiedKey === "defense-snapshot" ? "\u5DF2\u590D\u5236" : "\u62C9\u53D6\u78C1\u76D8\u5FEB\u7167"),
|
|
4972
|
+
title: t("\u590D\u5236\u62C9\u53D6\u78C1\u76D8\u5FEB\u7167\u6307\u4EE4\uFF1A\u628A .iterate/ \u4E0B\u7684\u9632\u5FA1\u4E8B\u4EF6\u6D41\u56DE\u663E\u8FDB\u4F1A\u8BDD")
|
|
4973
|
+
}, copiedKey === "defense-snapshot" ? t("\u5DF2\u590D\u5236") : t("\u62C9\u53D6\u78C1\u76D8\u5FEB\u7167")),
|
|
4350
4974
|
React.createElement("button", {
|
|
4351
4975
|
className: "iterate-btn",
|
|
4352
4976
|
"data-copied": copiedKey === "defense-counts" ? "" : void 0,
|
|
4353
|
-
onClick: () => copyInstruction("defense-counts", `\u8BF7\u8C03\u7528 \`iterate_defense_events\` \u67E5\u8BE2\u4E8B\u4EF6\u7EDF\u8BA1\uFF1A
|
|
4977
|
+
onClick: () => copyInstruction("defense-counts", tf(`\u8BF7\u8C03\u7528 \`iterate_defense_events\` \u67E5\u8BE2\u4E8B\u4EF6\u7EDF\u8BA1\uFF1A
|
|
4354
4978
|
|
|
4355
4979
|
\`\`\`json
|
|
4356
|
-
|
|
4357
|
-
|
|
4358
|
-
title: "\u590D\u5236\u7EDF\u8BA1\u6307\u4EE4\uFF08\u542B JSON \u53C2\u6570\uFF09"
|
|
4359
|
-
}, copiedKey === "defense-counts" ? "\u5DF2\u590D\u5236" : "\u7EDF\u8BA1"),
|
|
4980
|
+
{a0}
|
|
4981
|
+
\`\`\``, { a0: JSON.stringify({ operation: "counts" }, null, 2) })),
|
|
4982
|
+
title: t("\u590D\u5236\u7EDF\u8BA1\u6307\u4EE4\uFF08\u542B JSON \u53C2\u6570\uFF09")
|
|
4983
|
+
}, copiedKey === "defense-counts" ? t("\u5DF2\u590D\u5236") : t("\u7EDF\u8BA1")),
|
|
4360
4984
|
React.createElement("button", {
|
|
4361
4985
|
className: "iterate-btn",
|
|
4362
4986
|
"data-danger": "",
|
|
4363
4987
|
"data-copied": copiedKey === "defense-clear" ? "" : void 0,
|
|
4364
|
-
onClick: () => copyInstruction("defense-clear", `\u8BF7\u8C03\u7528 \`iterate_defense_events\` \u6E05\u9664\u9632\u5FA1\u4E8B\u4EF6\u6D41\uFF1A
|
|
4988
|
+
onClick: () => copyInstruction("defense-clear", tf(`\u8BF7\u8C03\u7528 \`iterate_defense_events\` \u6E05\u9664\u9632\u5FA1\u4E8B\u4EF6\u6D41\uFF1A
|
|
4365
4989
|
|
|
4366
4990
|
\`\`\`json
|
|
4367
|
-
|
|
4368
|
-
|
|
4369
|
-
title: "\u590D\u5236 iterate_defense_events clear \u6307\u4EE4\u6587\u672C\uFF08\u91CD\u7F6E\u9648\u65E7\u4E8B\u4EF6\u6D41\uFF09"
|
|
4370
|
-
}, copiedKey === "defense-clear" ? "\u5DF2\u590D\u5236" : "\u6E05\u9664\u4E8B\u4EF6")
|
|
4991
|
+
{a0}
|
|
4992
|
+
\`\`\``, { a0: JSON.stringify({ operation: "clear" }, null, 2) })),
|
|
4993
|
+
title: t("\u590D\u5236 iterate_defense_events clear \u6307\u4EE4\u6587\u672C\uFF08\u91CD\u7F6E\u9648\u65E7\u4E8B\u4EF6\u6D41\uFF09")
|
|
4994
|
+
}, copiedKey === "defense-clear" ? t("\u5DF2\u590D\u5236") : t("\u6E05\u9664\u4E8B\u4EF6"))
|
|
4371
4995
|
);
|
|
4372
4996
|
if (allEvents.length === 0 && totalCount === 0) {
|
|
4373
4997
|
return React.createElement(
|
|
@@ -4380,7 +5004,7 @@ ${JSON.stringify({ operation: "clear" }, null, 2)}
|
|
|
4380
5004
|
React.createElement(
|
|
4381
5005
|
"div",
|
|
4382
5006
|
{ className: "iterate-obs-block-head" },
|
|
4383
|
-
React.createElement("span", {}, "\u9632\u5FA1\u4E8B\u4EF6\u6D41"),
|
|
5007
|
+
React.createElement("span", {}, t("\u9632\u5FA1\u4E8B\u4EF6\u6D41")),
|
|
4384
5008
|
React.createElement("span", { className: "iterate-obs-badge" }, "v3.0")
|
|
4385
5009
|
),
|
|
4386
5010
|
React.createElement(
|
|
@@ -4389,12 +5013,12 @@ ${JSON.stringify({ operation: "clear" }, null, 2)}
|
|
|
4389
5013
|
React.createElement(
|
|
4390
5014
|
"div",
|
|
4391
5015
|
{ className: "iterate-obs-msg" },
|
|
4392
|
-
diskEmptyStateText(toolCalledInSession(session, "iterate_defense_events"), "\u9632\u5FA1\u4E8B\u4EF6\u6D41")
|
|
5016
|
+
diskEmptyStateText(toolCalledInSession(session, "iterate_defense_events"), t("\u9632\u5FA1\u4E8B\u4EF6\u6D41"), getLang())
|
|
4393
5017
|
),
|
|
4394
5018
|
React.createElement(
|
|
4395
5019
|
"div",
|
|
4396
5020
|
{ className: "iterate-obs-msg", style: { marginTop: 6 } },
|
|
4397
|
-
"\u9632\u5FA1\u4E8B\u4EF6\u5305\u62EC\uFF1A\u524D\u7F6E\u6821\u9A8C\u5931\u8D25\u3001\u56DE\u6EDA\u3001\u4E0D\u53D8\u91CF\u8FDD\u53CD\u3001\u5047\u8BBE\u88AB\u8BC1\u4F2A\u3002"
|
|
5021
|
+
t("\u9632\u5FA1\u4E8B\u4EF6\u5305\u62EC\uFF1A\u524D\u7F6E\u6821\u9A8C\u5931\u8D25\u3001\u56DE\u6EDA\u3001\u4E0D\u53D8\u91CF\u8FDD\u53CD\u3001\u5047\u8BBE\u88AB\u8BC1\u4F2A\u3002")
|
|
4398
5022
|
),
|
|
4399
5023
|
React.createElement(
|
|
4400
5024
|
"div",
|
|
@@ -4403,8 +5027,8 @@ ${JSON.stringify({ operation: "clear" }, null, 2)}
|
|
|
4403
5027
|
className: "iterate-btn",
|
|
4404
5028
|
"data-copied": copiedKey === "defense-instr" ? "" : void 0,
|
|
4405
5029
|
onClick: () => copyInstruction("defense-instr", defenseInstruction),
|
|
4406
|
-
title: "\u590D\u5236\u67E5\u8BE2\u6307\u4EE4"
|
|
4407
|
-
}, copiedKey === "defense-instr" ? "\u5DF2\u590D\u5236" : "\u590D\u5236\u67E5\u8BE2\u6307\u4EE4")
|
|
5030
|
+
title: t("\u590D\u5236\u67E5\u8BE2\u6307\u4EE4")
|
|
5031
|
+
}, copiedKey === "defense-instr" ? t("\u5DF2\u590D\u5236") : t("\u590D\u5236\u67E5\u8BE2\u6307\u4EE4"))
|
|
4408
5032
|
)
|
|
4409
5033
|
)
|
|
4410
5034
|
)
|
|
@@ -4418,7 +5042,7 @@ ${JSON.stringify({ operation: "clear" }, null, 2)}
|
|
|
4418
5042
|
{
|
|
4419
5043
|
className: "iterate-filter-select",
|
|
4420
5044
|
value: defenseFilter,
|
|
4421
|
-
"aria-label": "\u6309\u4E8B\u4EF6\u7C7B\u578B\u7B5B\u9009",
|
|
5045
|
+
"aria-label": t("\u6309\u4E8B\u4EF6\u7C7B\u578B\u7B5B\u9009"),
|
|
4422
5046
|
onChange: (e) => setDefenseFilter(e.target.value)
|
|
4423
5047
|
},
|
|
4424
5048
|
...typeOptions.map((opt) => React.createElement("option", { key: opt.value, value: opt.value }, opt.label))
|
|
@@ -4426,8 +5050,8 @@ ${JSON.stringify({ operation: "clear" }, null, 2)}
|
|
|
4426
5050
|
defenseFilter ? React.createElement("button", {
|
|
4427
5051
|
className: "iterate-filter-clear",
|
|
4428
5052
|
onClick: () => setDefenseFilter(""),
|
|
4429
|
-
title: "\u6E05\u9664\u7C7B\u578B\u7B5B\u9009"
|
|
4430
|
-
}, "\u6E05\u9664") : null
|
|
5053
|
+
title: t("\u6E05\u9664\u7C7B\u578B\u7B5B\u9009")
|
|
5054
|
+
}, t("\u6E05\u9664")) : null
|
|
4431
5055
|
);
|
|
4432
5056
|
let eventRows = [];
|
|
4433
5057
|
if (visibleEvents.length > 0) {
|
|
@@ -4448,7 +5072,7 @@ ${JSON.stringify({ operation: "clear" }, null, 2)}
|
|
|
4448
5072
|
"div",
|
|
4449
5073
|
{ className: "iterate-obs-block-body" },
|
|
4450
5074
|
React.createElement("div", { className: "iterate-obs-msg" }, String(e.description || "")),
|
|
4451
|
-
e.defense ? React.createElement("div", { className: "iterate-obs-msg", style: { marginTop: 4 } }, `\u9632\u7EBF\uFF1A
|
|
5075
|
+
e.defense ? React.createElement("div", { className: "iterate-obs-msg", style: { marginTop: 4 } }, tf(`\u9632\u7EBF\uFF1A{a0}`, { a0: String(e.defense) })) : null
|
|
4452
5076
|
)
|
|
4453
5077
|
);
|
|
4454
5078
|
});
|
|
@@ -4469,7 +5093,7 @@ ${JSON.stringify({ operation: "clear" }, null, 2)}
|
|
|
4469
5093
|
)
|
|
4470
5094
|
)
|
|
4471
5095
|
),
|
|
4472
|
-
eventRows.length > 0 ? React.createElement("div", {}, ...eventRows) : React.createElement("div", { className: "iterate-obs-empty" }, "\u6CA1\u6709\u5339\u914D\u8BE5\u7C7B\u578B\u7684\u9632\u5FA1\u4E8B\u4EF6")
|
|
5096
|
+
eventRows.length > 0 ? React.createElement("div", {}, ...eventRows) : React.createElement("div", { className: "iterate-obs-empty" }, t("\u6CA1\u6709\u5339\u914D\u8BE5\u7C7B\u578B\u7684\u9632\u5FA1\u4E8B\u4EF6"))
|
|
4473
5097
|
);
|
|
4474
5098
|
};
|
|
4475
5099
|
const renderLive = () => {
|
|
@@ -4481,29 +5105,31 @@ ${JSON.stringify({ operation: "clear" }, null, 2)}
|
|
|
4481
5105
|
return React.createElement(
|
|
4482
5106
|
"div",
|
|
4483
5107
|
{ className: "iterate-obs-empty" },
|
|
4484
|
-
React.createElement("div", {}, "\u5B9E\u65F6\u6D3B\u52A8\u6D41\u4EC5\u5728\u8FD0\u884C\u671F\u95F4\u8BB0\u5F55\uFF0C\u5F53\u524D\u5DF2\u5B8C\u6210\u3002"),
|
|
5108
|
+
React.createElement("div", {}, t("\u5B9E\u65F6\u6D3B\u52A8\u6D41\u4EC5\u5728\u8FD0\u884C\u671F\u95F4\u8BB0\u5F55\uFF0C\u5F53\u524D\u5DF2\u5B8C\u6210\u3002")),
|
|
4485
5109
|
React.createElement(
|
|
4486
5110
|
"div",
|
|
4487
5111
|
{ className: "iterate-obs-bar", style: { marginTop: 8 } },
|
|
4488
|
-
React.createElement("button", { className: "iterate-btn", onClick: () => setTab("f1") }, "\u67E5\u770B\u5BA1\u67E5\u7EBF\u7A0B"),
|
|
4489
|
-
React.createElement("button", { className: "iterate-btn", onClick: () => setTab("f3") }, "\u67E5\u770B\u53D1\u73B0")
|
|
5112
|
+
React.createElement("button", { className: "iterate-btn", onClick: () => setTab("f1") }, t("\u67E5\u770B\u5BA1\u67E5\u7EBF\u7A0B")),
|
|
5113
|
+
React.createElement("button", { className: "iterate-btn", onClick: () => setTab("f3") }, t("\u67E5\u770B\u53D1\u73B0"))
|
|
4490
5114
|
)
|
|
4491
5115
|
);
|
|
4492
5116
|
}
|
|
4493
|
-
return React.createElement("div", { className: "iterate-obs-empty" }, "\u6682\u65E0\u5B9E\u65F6\u6D3B\u52A8");
|
|
5117
|
+
return React.createElement("div", { className: "iterate-obs-empty" }, t("\u6682\u65E0\u5B9E\u65F6\u6D3B\u52A8"));
|
|
4494
5118
|
}
|
|
4495
5119
|
const types = Array.from(new Set(liveEntries.map((e) => String(e.type || "unknown")).filter(Boolean))).sort();
|
|
4496
5120
|
const filtered = filterLiveEntries(liveEntries, liveType);
|
|
4497
5121
|
const rows = filtered.map((e, i) => {
|
|
4498
5122
|
const type = String(e.type || "unknown");
|
|
4499
|
-
const meta = OBS_LIVE_META[type]
|
|
5123
|
+
const meta = OBS_LIVE_META[type];
|
|
5124
|
+
const typeLabel = meta ? meta.label[getLang()] : String(e.type || "?");
|
|
5125
|
+
const typeColor = meta ? meta.color : OBS_LIVE_FALLBACK_COLOR;
|
|
4500
5126
|
const tool = String(e.tool || "");
|
|
4501
5127
|
const target = String(e.target || "");
|
|
4502
5128
|
const time = formatObsLiveTime(String(e.ts || ""));
|
|
4503
5129
|
return React.createElement(
|
|
4504
5130
|
"div",
|
|
4505
5131
|
{ key: `live-${i}`, className: "iterate-obs-row" },
|
|
4506
|
-
React.createElement("span", { className: "iterate-obs-livebadge", style: { color:
|
|
5132
|
+
React.createElement("span", { className: "iterate-obs-livebadge", style: { color: typeColor } }, typeLabel),
|
|
4507
5133
|
tool ? React.createElement("span", { className: "iterate-obs-chip" }, tool) : null,
|
|
4508
5134
|
React.createElement("span", { className: "iterate-obs-msg" }, target || "\u2014"),
|
|
4509
5135
|
React.createElement("span", { className: "iterate-obs-head-meta" }, time)
|
|
@@ -4512,23 +5138,23 @@ ${JSON.stringify({ operation: "clear" }, null, 2)}
|
|
|
4512
5138
|
const filterBar = React.createElement(
|
|
4513
5139
|
"div",
|
|
4514
5140
|
{ className: "iterate-obs-bar", style: { marginBottom: 8 } },
|
|
4515
|
-
React.createElement("b", {}, "\u5B9E\u65F6\u6D3B\u52A8"),
|
|
5141
|
+
React.createElement("b", {}, t("\u5B9E\u65F6\u6D3B\u52A8")),
|
|
4516
5142
|
React.createElement(
|
|
4517
5143
|
"select",
|
|
4518
5144
|
{
|
|
4519
5145
|
className: "iterate-filter-select",
|
|
4520
5146
|
value: liveType,
|
|
4521
|
-
"aria-label": "\u6309\u6D3B\u52A8\u7C7B\u578B\u7B5B\u9009",
|
|
5147
|
+
"aria-label": t("\u6309\u6D3B\u52A8\u7C7B\u578B\u7B5B\u9009"),
|
|
4522
5148
|
onChange: (e) => setLiveType(e.target.value)
|
|
4523
5149
|
},
|
|
4524
|
-
React.createElement("option", { value: "" }, "\u5168\u90E8\u6D3B\u52A8"),
|
|
4525
|
-
...types.map((
|
|
5150
|
+
React.createElement("option", { value: "" }, t("\u5168\u90E8\u6D3B\u52A8")),
|
|
5151
|
+
...types.map((t2) => React.createElement("option", { key: t2, value: t2 }, t2))
|
|
4526
5152
|
),
|
|
4527
5153
|
liveType ? React.createElement("button", {
|
|
4528
5154
|
className: "iterate-filter-clear",
|
|
4529
5155
|
onClick: () => setLiveType(""),
|
|
4530
|
-
title: "\u6E05\u9664\u7C7B\u578B\u7B5B\u9009"
|
|
4531
|
-
}, "\u6E05\u9664") : null,
|
|
5156
|
+
title: t("\u6E05\u9664\u7C7B\u578B\u7B5B\u9009")
|
|
5157
|
+
}, t("\u6E05\u9664")) : null,
|
|
4532
5158
|
React.createElement("span", { className: "iterate-filter-count" }, `${filtered.length}/${liveEntries.length}`)
|
|
4533
5159
|
);
|
|
4534
5160
|
if (rows.length === 0) {
|
|
@@ -4536,7 +5162,7 @@ ${JSON.stringify({ operation: "clear" }, null, 2)}
|
|
|
4536
5162
|
"div",
|
|
4537
5163
|
{},
|
|
4538
5164
|
filterBar,
|
|
4539
|
-
React.createElement("div", { className: "iterate-obs-empty" }, "\u65E0\u5339\u914D\u7684\u5B9E\u65F6\u6D3B\u52A8")
|
|
5165
|
+
React.createElement("div", { className: "iterate-obs-empty" }, t("\u65E0\u5339\u914D\u7684\u5B9E\u65F6\u6D3B\u52A8"))
|
|
4540
5166
|
);
|
|
4541
5167
|
}
|
|
4542
5168
|
return React.createElement("div", {}, filterBar, ...rows);
|
|
@@ -4576,14 +5202,14 @@ ${JSON.stringify({ operation: "clear" }, null, 2)}
|
|
|
4576
5202
|
React.createElement(
|
|
4577
5203
|
"div",
|
|
4578
5204
|
{ className: "iterate-obs-head", "data-closed": open ? void 0 : "", onClick: () => setOpen((v) => !v) },
|
|
4579
|
-
React.createElement("span", { className: "iterate-obs-title" }, "iterate \u89C2\u6D4B\u53F0"),
|
|
5205
|
+
React.createElement("span", { className: "iterate-obs-title" }, t("iterate \u89C2\u6D4B\u53F0")),
|
|
4580
5206
|
React.createElement("span", { className: "iterate-obs-badge", "data-live": live ? "" : void 0 }, runStatusText(live, manifest)),
|
|
4581
5207
|
React.createElement("span", { className: "iterate-obs-head-meta" }, headMeta || "runtime"),
|
|
4582
5208
|
// Gap #14: make the tab system discoverable without expanding it.
|
|
4583
5209
|
React.createElement("span", {
|
|
4584
5210
|
className: "iterate-obs-head-meta",
|
|
4585
|
-
title:
|
|
4586
|
-
},
|
|
5211
|
+
title: obsHotkeyHint()
|
|
5212
|
+
}, obsHotkeyHint()),
|
|
4587
5213
|
React.createElement("button", {
|
|
4588
5214
|
className: "iterate-btn",
|
|
4589
5215
|
"data-ghost": "",
|
|
@@ -4591,7 +5217,7 @@ ${JSON.stringify({ operation: "clear" }, null, 2)}
|
|
|
4591
5217
|
e.stopPropagation();
|
|
4592
5218
|
setOpen((v) => !v);
|
|
4593
5219
|
}
|
|
4594
|
-
}, open ? "\u6536\u8D77" : "\u5C55\u5F00")
|
|
5220
|
+
}, open ? t("\u6536\u8D77") : t("\u5C55\u5F00"))
|
|
4595
5221
|
),
|
|
4596
5222
|
open ? React.createElement(
|
|
4597
5223
|
"div",
|
|
@@ -4602,14 +5228,14 @@ ${JSON.stringify({ operation: "clear" }, null, 2)}
|
|
|
4602
5228
|
React.createElement(
|
|
4603
5229
|
"div",
|
|
4604
5230
|
{ className: "iterate-obs-block-head" },
|
|
4605
|
-
React.createElement("b", {}, "\u590D\u5236\u672A\u6210\u529F"),
|
|
4606
|
-
React.createElement("span", { className: "iterate-obs-head-meta" }, "\u526A\u8D34\u677F\u5199\u5165\u88AB\u62D2\u7EDD\uFF0C\u8BF7\u624B\u52A8\u9009\u4E2D\u4E0B\u65B9\u6307\u4EE4\u590D\u5236"),
|
|
5231
|
+
React.createElement("b", {}, t("\u590D\u5236\u672A\u6210\u529F")),
|
|
5232
|
+
React.createElement("span", { className: "iterate-obs-head-meta" }, t("\u526A\u8D34\u677F\u5199\u5165\u88AB\u62D2\u7EDD\uFF0C\u8BF7\u624B\u52A8\u9009\u4E2D\u4E0B\u65B9\u6307\u4EE4\u590D\u5236")),
|
|
4607
5233
|
React.createElement("button", {
|
|
4608
5234
|
className: "iterate-btn",
|
|
4609
5235
|
"data-ghost": "",
|
|
4610
|
-
"aria-label": "\u5173\u95ED\u590D\u5236\u5931\u8D25\u63D0\u793A",
|
|
5236
|
+
"aria-label": t("\u5173\u95ED\u590D\u5236\u5931\u8D25\u63D0\u793A"),
|
|
4611
5237
|
onClick: () => setCopyFailText(null)
|
|
4612
|
-
}, "\u5173\u95ED")
|
|
5238
|
+
}, t("\u5173\u95ED"))
|
|
4613
5239
|
),
|
|
4614
5240
|
React.createElement("div", { className: "iterate-obs-code" }, copyFailText)
|
|
4615
5241
|
) : null,
|
|
@@ -4626,8 +5252,8 @@ ${JSON.stringify({ operation: "clear" }, null, 2)}
|
|
|
4626
5252
|
"data-primary": "",
|
|
4627
5253
|
"data-copied": copiedKey === "export" ? "" : void 0,
|
|
4628
5254
|
onClick: exportObservatory,
|
|
4629
|
-
title: "\u5C06\u89C2\u6D4B\u53F0\u5168\u90E8\u6570\u636E\u5BFC\u51FA\u4E3A JSON\uFF08\u4F18\u5148\u4E0B\u8F7D\uFF0C\u5931\u8D25\u5219\u590D\u5236\uFF09"
|
|
4630
|
-
}, copiedKey === "export" ? "\u5DF2\u5BFC\u51FA" : "\u5BFC\u51FA JSON"),
|
|
5255
|
+
title: t("\u5C06\u89C2\u6D4B\u53F0\u5168\u90E8\u6570\u636E\u5BFC\u51FA\u4E3A JSON\uFF08\u4F18\u5148\u4E0B\u8F7D\uFF0C\u5931\u8D25\u5219\u590D\u5236\uFF09")
|
|
5256
|
+
}, copiedKey === "export" ? t("\u5DF2\u5BFC\u51FA") : t("\u5BFC\u51FA JSON")),
|
|
4631
5257
|
// Gap #4: `.iterate/` artifacts are unreachable from the browser;
|
|
4632
5258
|
// this copies the one instruction that makes the model echo them
|
|
4633
5259
|
// into the session stream (which is what every panel scans).
|
|
@@ -4636,21 +5262,21 @@ ${JSON.stringify({ operation: "clear" }, null, 2)}
|
|
|
4636
5262
|
"data-copied": copiedKey === "pull-snapshot" ? "" : void 0,
|
|
4637
5263
|
onClick: () => copyInstruction("pull-snapshot", pullInstruction),
|
|
4638
5264
|
title: pullTitle
|
|
4639
|
-
}, copiedKey === "pull-snapshot" ? "\u5DF2\u590D\u5236" : "\u62C9\u53D6\u78C1\u76D8\u5FEB\u7167")
|
|
5265
|
+
}, copiedKey === "pull-snapshot" ? t("\u5DF2\u590D\u5236") : t("\u62C9\u53D6\u78C1\u76D8\u5FEB\u7167"))
|
|
4640
5266
|
),
|
|
4641
5267
|
React.createElement(
|
|
4642
5268
|
"div",
|
|
4643
|
-
{ className: "iterate-obs-tabs", role: "tablist", "aria-label": "\u89C2\u6D4B\u53F0\u9875\u7B7E\uFF08\u5FEB\u6377\u952E 1-9 / 0 / -\uFF09" },
|
|
5269
|
+
{ className: "iterate-obs-tabs", role: "tablist", "aria-label": t("\u89C2\u6D4B\u53F0\u9875\u7B7E\uFF08\u5FEB\u6377\u952E 1-9 / 0 / -\uFF09") },
|
|
4644
5270
|
...OBS_TABS.map(
|
|
4645
|
-
(
|
|
4646
|
-
key:
|
|
5271
|
+
(t2) => React.createElement("button", {
|
|
5272
|
+
key: t2.key,
|
|
4647
5273
|
className: "iterate-obs-tab",
|
|
4648
5274
|
role: "tab",
|
|
4649
|
-
"aria-selected": tab ===
|
|
4650
|
-
"data-active": tab ===
|
|
4651
|
-
onClick: () => setTab(
|
|
4652
|
-
title:
|
|
4653
|
-
}, obsTabLabel(
|
|
5275
|
+
"aria-selected": tab === t2.key,
|
|
5276
|
+
"data-active": tab === t2.key ? "" : void 0,
|
|
5277
|
+
onClick: () => setTab(t2.key),
|
|
5278
|
+
title: t2.hotkey ? tf(`{a0}\uFF08\u6309 {a1} \u5207\u6362\uFF09`, { a0: obsTabLabel(t2), a1: t2.hotkey }) : tf(`{a0}\uFF08\u6309 - \u5207\u6362\uFF09`, { a0: obsTabLabel(t2) })
|
|
5279
|
+
}, obsTabLabel(t2))
|
|
4654
5280
|
)
|
|
4655
5281
|
),
|
|
4656
5282
|
React.createElement("div", { className: "iterate-obs-body" }, renderBody())
|
|
@@ -4663,11 +5289,21 @@ function selectTurnTail(owner) {
|
|
|
4663
5289
|
if (scanSessionForRunSummary(owner.turn)) return { matched: true };
|
|
4664
5290
|
return null;
|
|
4665
5291
|
}
|
|
5292
|
+
var LangDashboard = withLang(ConvergenceDashboard);
|
|
5293
|
+
var LangObservatory = withLang(ObservatoryPanel);
|
|
5294
|
+
var LangTurnTail = withLang(TurnTailEntry);
|
|
5295
|
+
var LangProgress = withLang(ProgressCapsule);
|
|
5296
|
+
var LangSettings = withLang(SettingsPanel);
|
|
4666
5297
|
function apply(ctx) {
|
|
4667
5298
|
slotsSvc = readSlots(ctx);
|
|
4668
5299
|
themeSvc = readTheme(ctx);
|
|
4669
|
-
|
|
4670
|
-
|
|
5300
|
+
storage2 = createStorage();
|
|
5301
|
+
configureLangStorage(storage2);
|
|
5302
|
+
setLang(
|
|
5303
|
+
detectLang(storage2.get(LANG_STORAGE_KEY), typeof navigator !== "undefined" ? navigator.language : ""),
|
|
5304
|
+
false
|
|
5305
|
+
);
|
|
5306
|
+
const savedTheme = storage2.get(THEME_STORAGE_KEY);
|
|
4671
5307
|
themeEnabled = savedTheme === null ? true : savedTheme === "1";
|
|
4672
5308
|
if (themeEnabled) applyThemeSkin();
|
|
4673
5309
|
if (typeof document !== "undefined" && document.createElement && document.head) {
|
|
@@ -4697,35 +5333,35 @@ function apply(ctx) {
|
|
|
4697
5333
|
"conversation.input.dock",
|
|
4698
5334
|
() => slotsSvc?.register(
|
|
4699
5335
|
{ name: "conversation.input.dock", id: "iterate-dashboard", order: 90 },
|
|
4700
|
-
(props) => React.createElement(
|
|
5336
|
+
(props) => React.createElement(LangDashboard, props)
|
|
4701
5337
|
)
|
|
4702
5338
|
);
|
|
4703
5339
|
slotsSvc.inject(
|
|
4704
5340
|
"conversation.input.dock",
|
|
4705
5341
|
() => slotsSvc?.register(
|
|
4706
5342
|
{ name: "conversation.input.dock", id: "iterate-observatory", order: 91 },
|
|
4707
|
-
(props) => React.createElement(
|
|
5343
|
+
(props) => React.createElement(LangObservatory, props)
|
|
4708
5344
|
)
|
|
4709
5345
|
);
|
|
4710
5346
|
slotsSvc.inject(
|
|
4711
5347
|
"conversation.chat.turnTail",
|
|
4712
5348
|
() => slotsSvc?.register(
|
|
4713
5349
|
{ name: "conversation.chat.turnTail", id: "iterate-turn-tail", select: selectTurnTail },
|
|
4714
|
-
(props) => React.createElement(
|
|
5350
|
+
(props) => React.createElement(LangTurnTail, props)
|
|
4715
5351
|
)
|
|
4716
5352
|
);
|
|
4717
5353
|
slotsSvc.inject(
|
|
4718
5354
|
"shell.overlay",
|
|
4719
5355
|
() => slotsSvc?.register(
|
|
4720
5356
|
{ name: "shell.overlay", id: "iterate-progress", order: 0 },
|
|
4721
|
-
(props) => React.createElement(
|
|
5357
|
+
(props) => React.createElement(LangProgress, props)
|
|
4722
5358
|
)
|
|
4723
5359
|
);
|
|
4724
5360
|
slotsSvc.inject(
|
|
4725
5361
|
"settings.section",
|
|
4726
5362
|
() => slotsSvc?.register(
|
|
4727
5363
|
{ name: "settings.section", id: "iterate-settings", order: 30, label: () => "iterate" },
|
|
4728
|
-
(props) => React.createElement(
|
|
5364
|
+
(props) => React.createElement(LangSettings, props)
|
|
4729
5365
|
)
|
|
4730
5366
|
);
|
|
4731
5367
|
}
|