vibe-coding-master 0.3.21 → 0.3.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/backend/api/artifact-routes.js +8 -1
- package/dist/backend/api/project-routes.js +3 -1
- package/dist/backend/api/task-routes.js +3 -1
- package/dist/backend/server.js +9 -1
- package/dist/backend/services/artifact-service.js +10 -3
- package/dist/backend/services/codex-translation-service.js +169 -42
- package/dist/backend/services/session-service.js +2 -27
- package/dist/backend/services/status-service.js +3 -1
- package/dist-frontend/assets/{index-DOKW0Y5n.js → index-CEB6Bssn.js} +1 -1
- package/dist-frontend/index.html +1 -1
- package/docs/codex-translation-plan.md +80 -62
- package/package.json +1 -1
|
@@ -64,11 +64,18 @@ export function registerArtifactRoutes(app, deps) {
|
|
|
64
64
|
const task = await deps.taskService.loadTask(project.repoRoot, request.params.taskSlug);
|
|
65
65
|
const taskRepoRoot = getTaskRuntimeRepoRoot(task);
|
|
66
66
|
const paths = deps.artifactService.getHandoffPaths(taskRepoRoot, task.handoffDir);
|
|
67
|
+
const artifactPath = paths.roleLogPaths[request.params.role];
|
|
68
|
+
if (!artifactPath) {
|
|
69
|
+
return {
|
|
70
|
+
role: request.params.role,
|
|
71
|
+
content: ""
|
|
72
|
+
};
|
|
73
|
+
}
|
|
67
74
|
return {
|
|
68
75
|
role: request.params.role,
|
|
69
76
|
content: await deps.artifactService.readArtifact({
|
|
70
77
|
repoRoot: taskRepoRoot,
|
|
71
|
-
artifactPath
|
|
78
|
+
artifactPath
|
|
72
79
|
})
|
|
73
80
|
};
|
|
74
81
|
});
|
|
@@ -4,7 +4,9 @@ export function registerProjectRoutes(app, deps) {
|
|
|
4
4
|
return deps.projectService.getRecentRepositoryPaths();
|
|
5
5
|
});
|
|
6
6
|
app.post("/api/projects/connect", async (request) => {
|
|
7
|
-
|
|
7
|
+
const project = await deps.projectService.connectProject(request.body);
|
|
8
|
+
await deps.codexTranslationService?.cleanupStartupRuntime(project.repoRoot);
|
|
9
|
+
return project;
|
|
8
10
|
});
|
|
9
11
|
app.get("/api/projects/current", async () => {
|
|
10
12
|
return deps.projectService.getCurrentProject();
|
|
@@ -88,7 +88,9 @@ function degradedArtifactSummary(handoffDir) {
|
|
|
88
88
|
logsDir,
|
|
89
89
|
messagesDir,
|
|
90
90
|
roleCommandPaths: Object.fromEntries(DISPATCHABLE_ROLES.map((role) => [role, `${roleCommandsDir}/${role}.md`])),
|
|
91
|
-
roleLogPaths: Object.fromEntries(ROLE_NAMES
|
|
91
|
+
roleLogPaths: Object.fromEntries(ROLE_NAMES
|
|
92
|
+
.filter((role) => role !== "codex-translator")
|
|
93
|
+
.map((role) => [role, `${logsDir}/${role}.log`])),
|
|
92
94
|
messageRoutePaths: {},
|
|
93
95
|
architecturePlanPath: `${handoffDir}/architecture-plan.md`,
|
|
94
96
|
knownIssuesPath: `${handoffDir}/known-issues.md`,
|
package/dist/backend/server.js
CHANGED
|
@@ -75,7 +75,10 @@ export async function createServer(deps, options = {}) {
|
|
|
75
75
|
projectService: deps.projectService,
|
|
76
76
|
codexTranslationService: deps.codexTranslationService
|
|
77
77
|
});
|
|
78
|
-
registerProjectRoutes(app, {
|
|
78
|
+
registerProjectRoutes(app, {
|
|
79
|
+
projectService: deps.projectService,
|
|
80
|
+
codexTranslationService: deps.codexTranslationService
|
|
81
|
+
});
|
|
79
82
|
registerHarnessRoutes(app, {
|
|
80
83
|
projectService: deps.projectService,
|
|
81
84
|
harnessService: deps.harnessService
|
|
@@ -118,6 +121,7 @@ export async function createServer(deps, options = {}) {
|
|
|
118
121
|
registerGatewayRoutes(app, { gatewayService: deps.gatewayService });
|
|
119
122
|
registerTerminalWs(app, { runtime: deps.runtime });
|
|
120
123
|
app.addHook("onReady", async () => {
|
|
124
|
+
await cleanupRecentTranslationRuntime(deps);
|
|
121
125
|
await deps.gatewayService.start();
|
|
122
126
|
});
|
|
123
127
|
app.addHook("onClose", async () => {
|
|
@@ -134,6 +138,10 @@ export async function createServer(deps, options = {}) {
|
|
|
134
138
|
}
|
|
135
139
|
return app;
|
|
136
140
|
}
|
|
141
|
+
async function cleanupRecentTranslationRuntime(deps) {
|
|
142
|
+
const repoRoots = await deps.projectService.getRecentRepositoryPaths();
|
|
143
|
+
await Promise.all(repoRoots.map((repoRoot) => deps.codexTranslationService.cleanupStartupRuntime(repoRoot)));
|
|
144
|
+
}
|
|
137
145
|
export async function startServer(options = {}) {
|
|
138
146
|
const host = options.host ?? "127.0.0.1";
|
|
139
147
|
const port = options.port ?? 4173;
|
|
@@ -42,8 +42,7 @@ export function createArtifactService(fs) {
|
|
|
42
42
|
architect: path.posix.join(logsDir, "architect.log"),
|
|
43
43
|
coder: path.posix.join(logsDir, "coder.log"),
|
|
44
44
|
reviewer: path.posix.join(logsDir, "reviewer.log"),
|
|
45
|
-
"codex-reviewer": path.posix.join(logsDir, "codex-reviewer.log")
|
|
46
|
-
"codex-translator": path.posix.join(logsDir, "codex-translator.log")
|
|
45
|
+
"codex-reviewer": path.posix.join(logsDir, "codex-reviewer.log")
|
|
47
46
|
},
|
|
48
47
|
messageRoutePaths: getDefaultMessageRoutePaths(messagesDir),
|
|
49
48
|
architecturePlanPath: path.posix.join(handoffDir, "architecture-plan.md"),
|
|
@@ -179,7 +178,15 @@ export function createArtifactService(fs) {
|
|
|
179
178
|
});
|
|
180
179
|
}
|
|
181
180
|
const paths = this.getHandoffPaths(input.repoRoot, input.handoffDir);
|
|
182
|
-
|
|
181
|
+
const roleLogPath = paths.roleLogPaths[input.role];
|
|
182
|
+
if (!roleLogPath) {
|
|
183
|
+
throw new VcmError({
|
|
184
|
+
code: "ROLE_LOG_UNAVAILABLE",
|
|
185
|
+
message: `${input.role} does not write a handoff log.`,
|
|
186
|
+
statusCode: 409
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
await fs.appendText(resolveRepoPath(input.repoRoot, roleLogPath), input.content);
|
|
183
190
|
}
|
|
184
191
|
};
|
|
185
192
|
}
|
|
@@ -7,7 +7,6 @@ const TRANSLATIONS_ROOT = ".ai/vcm/translations";
|
|
|
7
7
|
const TRANSLATIONS_RUNTIME_DIR = `${TRANSLATIONS_ROOT}/runtime`;
|
|
8
8
|
const MEMORY_DIR = `${TRANSLATIONS_ROOT}/memory`;
|
|
9
9
|
const QUEUE_PATH = `${TRANSLATIONS_RUNTIME_DIR}/queue.json`;
|
|
10
|
-
const LEGACY_QUEUE_PATH = `${TRANSLATIONS_ROOT}/queue.json`;
|
|
11
10
|
const FILE_INDEX_PATH = `${TRANSLATIONS_ROOT}/files/index.json`;
|
|
12
11
|
const FILE_COMPLETED_DIR = `${TRANSLATIONS_ROOT}/files/completed`;
|
|
13
12
|
const FILE_RUNTIME_JOBS_DIR = `${TRANSLATIONS_RUNTIME_DIR}/files/jobs`;
|
|
@@ -15,10 +14,6 @@ const BOOTSTRAP_INDEX_PATH = `${TRANSLATIONS_ROOT}/bootstrap/index.json`;
|
|
|
15
14
|
const BOOTSTRAP_RUNTIME_RUNS_DIR = `${TRANSLATIONS_RUNTIME_DIR}/bootstrap/runs`;
|
|
16
15
|
const CONVERSATION_RUNTIME_DIR = `${TRANSLATIONS_RUNTIME_DIR}/conversations`;
|
|
17
16
|
const MEMORY_UPDATE_RUNTIME_DIR = `${TRANSLATIONS_RUNTIME_DIR}/memory-updates`;
|
|
18
|
-
const TRANSLATOR_LOG_PATHS = [
|
|
19
|
-
`${TRANSLATIONS_RUNTIME_DIR}/codex-translator.log`,
|
|
20
|
-
`${TRANSLATIONS_ROOT}/codex-translator.log`
|
|
21
|
-
];
|
|
22
17
|
const DEFAULT_PROFILE = "default";
|
|
23
18
|
const DEFAULT_CHUNK_SOURCE_TOKEN_TARGET = 80000;
|
|
24
19
|
const BOOTSTRAP_DEFAULT_LIMIT = 12;
|
|
@@ -115,7 +110,6 @@ export function createCodexTranslationService(deps) {
|
|
|
115
110
|
await ensureMemoryFile(repoRoot, "style-guide.md", "# Style Guide\n");
|
|
116
111
|
await ensureMemoryFile(repoRoot, "project-context.md", "# Project Context\n");
|
|
117
112
|
await ensureMemoryFile(repoRoot, "decisions.md", "# Decisions\n");
|
|
118
|
-
await cleanupTranslatorLogs(repoRoot);
|
|
119
113
|
}
|
|
120
114
|
async function ensureMemoryFile(repoRoot, fileName, content) {
|
|
121
115
|
await deps.fs.ensureFile(resolveRepoPath(repoRoot, `${MEMORY_DIR}/${fileName}`), content);
|
|
@@ -129,19 +123,9 @@ export function createCodexTranslationService(deps) {
|
|
|
129
123
|
force: true
|
|
130
124
|
});
|
|
131
125
|
}
|
|
132
|
-
async function cleanupTranslatorLogs(repoRoot) {
|
|
133
|
-
await Promise.all(TRANSLATOR_LOG_PATHS.map((relativePath) => removeRepoPath(repoRoot, relativePath)));
|
|
134
|
-
}
|
|
135
126
|
async function loadQueue(repoRoot) {
|
|
136
127
|
const queuePath = resolveRepoPath(repoRoot, QUEUE_PATH);
|
|
137
128
|
if (!(await deps.fs.pathExists(queuePath))) {
|
|
138
|
-
const legacyQueuePath = resolveRepoPath(repoRoot, LEGACY_QUEUE_PATH);
|
|
139
|
-
if (await deps.fs.pathExists(legacyQueuePath)) {
|
|
140
|
-
const migrated = normalizeQueue(await deps.fs.readJson(legacyQueuePath));
|
|
141
|
-
await deps.fs.writeJsonAtomic(queuePath, migrated);
|
|
142
|
-
await removeRepoPath(repoRoot, LEGACY_QUEUE_PATH);
|
|
143
|
-
return migrated;
|
|
144
|
-
}
|
|
145
129
|
return {
|
|
146
130
|
version: 1,
|
|
147
131
|
updatedAt: now(),
|
|
@@ -152,7 +136,6 @@ export function createCodexTranslationService(deps) {
|
|
|
152
136
|
}
|
|
153
137
|
async function saveQueue(repoRoot, queue) {
|
|
154
138
|
await deps.fs.writeJsonAtomic(resolveRepoPath(repoRoot, QUEUE_PATH), queue);
|
|
155
|
-
await removeRepoPath(repoRoot, LEGACY_QUEUE_PATH);
|
|
156
139
|
}
|
|
157
140
|
async function loadFileIndex(repoRoot) {
|
|
158
141
|
const indexPath = resolveRepoPath(repoRoot, FILE_INDEX_PATH);
|
|
@@ -577,6 +560,7 @@ export function createCodexTranslationService(deps) {
|
|
|
577
560
|
try {
|
|
578
561
|
const request = await deps.fs.readJson(resolveRepoPath(repoRoot, requestPath));
|
|
579
562
|
return {
|
|
563
|
+
job: isFileJob(request.job) ? request.job : undefined,
|
|
580
564
|
chunks: Array.isArray(request.chunks) ? request.chunks.filter(isFileTranslationChunk) : []
|
|
581
565
|
};
|
|
582
566
|
}
|
|
@@ -584,6 +568,37 @@ export function createCodexTranslationService(deps) {
|
|
|
584
568
|
return {};
|
|
585
569
|
}
|
|
586
570
|
}
|
|
571
|
+
async function loadRuntimeFileJob(repoRoot, item) {
|
|
572
|
+
if (!isFileTranslationQueueItem(item)) {
|
|
573
|
+
return undefined;
|
|
574
|
+
}
|
|
575
|
+
const request = await loadFileTranslationRequest(repoRoot, item.requestPath);
|
|
576
|
+
if (!request.job) {
|
|
577
|
+
return undefined;
|
|
578
|
+
}
|
|
579
|
+
return {
|
|
580
|
+
...request.job,
|
|
581
|
+
status: toFileJobStatus(item.status),
|
|
582
|
+
queueItemId: item.id,
|
|
583
|
+
updatedAt: item.updatedAt
|
|
584
|
+
};
|
|
585
|
+
}
|
|
586
|
+
async function loadRuntimeFileJobs(repoRoot, queue) {
|
|
587
|
+
const sourceQueue = queue ?? await loadQueue(repoRoot);
|
|
588
|
+
const jobs = await Promise.all(sourceQueue.items
|
|
589
|
+
.filter(isFileTranslationQueueItem)
|
|
590
|
+
.filter((item) => item.status !== "completed")
|
|
591
|
+
.map((item) => loadRuntimeFileJob(repoRoot, item)));
|
|
592
|
+
return jobs
|
|
593
|
+
.filter((job) => Boolean(job))
|
|
594
|
+
.sort(compareFileJobUpdatedAtDesc);
|
|
595
|
+
}
|
|
596
|
+
async function findRuntimeFileJobById(repoRoot, jobId) {
|
|
597
|
+
const queue = await loadQueue(repoRoot);
|
|
598
|
+
const item = queue.items.find((candidate) => isFileTranslationQueueItem(candidate) &&
|
|
599
|
+
candidate.jobId === jobId);
|
|
600
|
+
return item ? loadRuntimeFileJob(repoRoot, item) : undefined;
|
|
601
|
+
}
|
|
587
602
|
async function validateMemoryBudget(repoRoot) {
|
|
588
603
|
const [usage, unexpectedEntries] = await Promise.all([
|
|
589
604
|
getMemoryUsage(repoRoot, deps.fs),
|
|
@@ -630,19 +645,29 @@ export function createCodexTranslationService(deps) {
|
|
|
630
645
|
if (item.type === "conversation") {
|
|
631
646
|
return;
|
|
632
647
|
}
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
await finalizeCompletedFileJob(repoRoot, job);
|
|
640
|
-
job.completedAt = job.updatedAt;
|
|
641
|
-
await cleanupSupersededCompletedFileJobs(repoRoot, index);
|
|
642
|
-
}
|
|
643
|
-
index.updatedAt = job.updatedAt;
|
|
644
|
-
await saveFileIndex(repoRoot, index);
|
|
648
|
+
if (!isFileTranslationQueueItem(item) || item.status !== "completed") {
|
|
649
|
+
return;
|
|
650
|
+
}
|
|
651
|
+
const runtimeJob = await loadRuntimeFileJob(repoRoot, item);
|
|
652
|
+
if (!runtimeJob) {
|
|
653
|
+
return;
|
|
645
654
|
}
|
|
655
|
+
const completedAt = now();
|
|
656
|
+
const completedJob = {
|
|
657
|
+
...runtimeJob,
|
|
658
|
+
status: "completed",
|
|
659
|
+
updatedAt: completedAt,
|
|
660
|
+
completedAt
|
|
661
|
+
};
|
|
662
|
+
await finalizeCompletedFileJob(repoRoot, completedJob);
|
|
663
|
+
const index = await loadFileIndex(repoRoot);
|
|
664
|
+
index.jobs = [
|
|
665
|
+
completedJob,
|
|
666
|
+
...index.jobs.filter((job) => job.id !== completedJob.id)
|
|
667
|
+
];
|
|
668
|
+
await cleanupSupersededCompletedFileJobs(repoRoot, index);
|
|
669
|
+
index.updatedAt = completedAt;
|
|
670
|
+
await saveFileIndex(repoRoot, index);
|
|
646
671
|
}
|
|
647
672
|
async function cleanupCompletedRuntime(repoRoot) {
|
|
648
673
|
const fileIndex = await loadFileIndex(repoRoot);
|
|
@@ -674,6 +699,48 @@ export function createCodexTranslationService(deps) {
|
|
|
674
699
|
.map((item) => cleanupRuntimeDirectoryForPath(repoRoot, item.requestPath)));
|
|
675
700
|
await pruneQueueItems(repoRoot, isPrunableCompletedQueueItem);
|
|
676
701
|
}
|
|
702
|
+
async function cleanupStartupFileIndex(repoRoot) {
|
|
703
|
+
const indexPath = resolveRepoPath(repoRoot, FILE_INDEX_PATH);
|
|
704
|
+
if (!(await deps.fs.pathExists(indexPath))) {
|
|
705
|
+
return;
|
|
706
|
+
}
|
|
707
|
+
const index = await loadFileIndex(repoRoot);
|
|
708
|
+
const seenKeys = new Set();
|
|
709
|
+
const jobs = [];
|
|
710
|
+
for (const job of index.jobs) {
|
|
711
|
+
if (job.status !== "completed" || !isCompletedFileResultPath(job.resultPath)) {
|
|
712
|
+
continue;
|
|
713
|
+
}
|
|
714
|
+
const key = fileTranslationReplacementKey(job);
|
|
715
|
+
if (seenKeys.has(key)) {
|
|
716
|
+
continue;
|
|
717
|
+
}
|
|
718
|
+
if (await deps.fs.pathExists(resolveRepoPath(repoRoot, job.resultPath))) {
|
|
719
|
+
seenKeys.add(key);
|
|
720
|
+
jobs.push(job);
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
if (jobs.length === index.jobs.length) {
|
|
724
|
+
return;
|
|
725
|
+
}
|
|
726
|
+
index.jobs = jobs;
|
|
727
|
+
index.updatedAt = now();
|
|
728
|
+
await saveFileIndex(repoRoot, index);
|
|
729
|
+
}
|
|
730
|
+
async function cleanupStartupBootstrapIndex(repoRoot) {
|
|
731
|
+
const indexPath = resolveRepoPath(repoRoot, BOOTSTRAP_INDEX_PATH);
|
|
732
|
+
if (!(await deps.fs.pathExists(indexPath))) {
|
|
733
|
+
return;
|
|
734
|
+
}
|
|
735
|
+
const index = await loadBootstrapIndex(repoRoot);
|
|
736
|
+
const runs = index.runs.filter((run) => run.status === "completed");
|
|
737
|
+
if (runs.length === index.runs.length) {
|
|
738
|
+
return;
|
|
739
|
+
}
|
|
740
|
+
index.runs = runs;
|
|
741
|
+
index.updatedAt = now();
|
|
742
|
+
await saveBootstrapIndex(repoRoot, index);
|
|
743
|
+
}
|
|
677
744
|
async function finalizeCompletedFileJob(repoRoot, job) {
|
|
678
745
|
const finalResultPath = completedFileResultPath(job.sourcePath, job.targetLanguage, job.translationProfile);
|
|
679
746
|
const absoluteCurrentResultPath = resolveRepoPath(repoRoot, job.resultPath);
|
|
@@ -750,6 +817,11 @@ export function createCodexTranslationService(deps) {
|
|
|
750
817
|
await saveQueue(repoRoot, queue);
|
|
751
818
|
}
|
|
752
819
|
return {
|
|
820
|
+
async cleanupStartupRuntime(repoRoot) {
|
|
821
|
+
await removeRepoPath(repoRoot, TRANSLATIONS_RUNTIME_DIR, true);
|
|
822
|
+
await cleanupStartupFileIndex(repoRoot);
|
|
823
|
+
await cleanupStartupBootstrapIndex(repoRoot);
|
|
824
|
+
},
|
|
753
825
|
async getState(repoRoot) {
|
|
754
826
|
await ensureLayout(repoRoot);
|
|
755
827
|
await cleanupCompletedRuntime(repoRoot);
|
|
@@ -759,9 +831,13 @@ export function createCodexTranslationService(deps) {
|
|
|
759
831
|
loadBootstrapIndex(repoRoot),
|
|
760
832
|
isMemoryInitialized(repoRoot, deps.fs)
|
|
761
833
|
]);
|
|
834
|
+
const runtimeFileJobs = await loadRuntimeFileJobs(repoRoot, queue);
|
|
762
835
|
return {
|
|
763
836
|
queue,
|
|
764
|
-
fileIndex
|
|
837
|
+
fileIndex: visibleFileTranslationIndex({
|
|
838
|
+
...fileIndex,
|
|
839
|
+
jobs: [...runtimeFileJobs, ...fileIndex.jobs]
|
|
840
|
+
}),
|
|
765
841
|
bootstrapIndex,
|
|
766
842
|
memoryInitialized
|
|
767
843
|
};
|
|
@@ -822,7 +898,15 @@ export function createCodexTranslationService(deps) {
|
|
|
822
898
|
const targetLanguage = input.targetLanguage.trim() || "zh-CN";
|
|
823
899
|
const profile = input.translationProfile?.trim() || DEFAULT_PROFILE;
|
|
824
900
|
const dedupeKey = sha256(`${sourceHash}|${targetLanguage}|${profile}`);
|
|
825
|
-
const
|
|
901
|
+
const replacementKey = fileTranslationReplacementKeyFromParts(sourcePath, targetLanguage, profile);
|
|
902
|
+
const activeExisting = (await loadRuntimeFileJobs(repoRoot)).find((job) => fileTranslationReplacementKey(job) === replacementKey &&
|
|
903
|
+
isActiveFileTranslationJobStatus(job.status));
|
|
904
|
+
if (activeExisting) {
|
|
905
|
+
if (input.taskSlug) {
|
|
906
|
+
void dispatchNext(repoRoot, input.taskSlug);
|
|
907
|
+
}
|
|
908
|
+
return activeExisting;
|
|
909
|
+
}
|
|
826
910
|
const timestamp = now();
|
|
827
911
|
const jobId = `file-${safeId(path.basename(sourcePath, path.extname(sourcePath)))}-${Date.now()}-${createId().slice(0, 8)}`;
|
|
828
912
|
const jobRoot = `${FILE_RUNTIME_JOBS_DIR}/${jobId}`;
|
|
@@ -919,9 +1003,6 @@ export function createCodexTranslationService(deps) {
|
|
|
919
1003
|
lastUpdatedAt: timestamp
|
|
920
1004
|
});
|
|
921
1005
|
await deps.fs.writeText(resolveRepoPath(repoRoot, job.reportPath), `# Translation Report\n\nStatus: queued\nJob: ${jobId}\n`);
|
|
922
|
-
index.jobs = [job, ...index.jobs];
|
|
923
|
-
index.updatedAt = timestamp;
|
|
924
|
-
await saveFileIndex(repoRoot, index);
|
|
925
1006
|
if (input.taskSlug) {
|
|
926
1007
|
void dispatchNext(repoRoot, input.taskSlug);
|
|
927
1008
|
}
|
|
@@ -1047,7 +1128,8 @@ export function createCodexTranslationService(deps) {
|
|
|
1047
1128
|
async readFileJobOutput(repoRoot, jobId) {
|
|
1048
1129
|
await ensureLayout(repoRoot);
|
|
1049
1130
|
const index = await loadFileIndex(repoRoot);
|
|
1050
|
-
const job = index.jobs.find((candidate) => candidate.id === jobId)
|
|
1131
|
+
const job = index.jobs.find((candidate) => candidate.id === jobId)
|
|
1132
|
+
?? await findRuntimeFileJobById(repoRoot, jobId);
|
|
1051
1133
|
if (!job) {
|
|
1052
1134
|
throw new VcmError({
|
|
1053
1135
|
code: "TRANSLATION_JOB_MISSING",
|
|
@@ -1607,12 +1689,60 @@ function completedFileResultPath(sourcePath, targetLanguage, translationProfile)
|
|
|
1607
1689
|
return `${FILE_COMPLETED_DIR}/${sourceBaseName}-${languagePart}-${profilePart}-${sourcePathHash}.md`;
|
|
1608
1690
|
}
|
|
1609
1691
|
function fileTranslationReplacementKey(job) {
|
|
1692
|
+
return fileTranslationReplacementKeyFromParts(job.sourcePath, job.targetLanguage, job.translationProfile);
|
|
1693
|
+
}
|
|
1694
|
+
function fileTranslationReplacementKeyFromParts(sourcePath, targetLanguage, translationProfile) {
|
|
1610
1695
|
return [
|
|
1611
|
-
normalizeRepoRelative(
|
|
1612
|
-
|
|
1613
|
-
(
|
|
1696
|
+
normalizeRepoRelative(sourcePath),
|
|
1697
|
+
targetLanguage.trim(),
|
|
1698
|
+
(translationProfile || DEFAULT_PROFILE).trim()
|
|
1614
1699
|
].join("\0");
|
|
1615
1700
|
}
|
|
1701
|
+
function isActiveFileTranslationJobStatus(status) {
|
|
1702
|
+
return status === "queued" || status === "running" || status === "validating";
|
|
1703
|
+
}
|
|
1704
|
+
function isFileTranslationQueueItem(item) {
|
|
1705
|
+
return item.type === "file" || item.type === "force-retranslate";
|
|
1706
|
+
}
|
|
1707
|
+
function toFileJobStatus(status) {
|
|
1708
|
+
if (status === "dispatching") {
|
|
1709
|
+
return "running";
|
|
1710
|
+
}
|
|
1711
|
+
return status === "completed" ||
|
|
1712
|
+
status === "queued" ||
|
|
1713
|
+
status === "running" ||
|
|
1714
|
+
status === "validating" ||
|
|
1715
|
+
status === "needs_review" ||
|
|
1716
|
+
status === "failed" ||
|
|
1717
|
+
status === "interrupted" ||
|
|
1718
|
+
status === "skipped" ||
|
|
1719
|
+
status === "cancelled"
|
|
1720
|
+
? status
|
|
1721
|
+
: "failed";
|
|
1722
|
+
}
|
|
1723
|
+
function compareFileJobUpdatedAtDesc(left, right) {
|
|
1724
|
+
return (right.updatedAt ?? "").localeCompare(left.updatedAt ?? "");
|
|
1725
|
+
}
|
|
1726
|
+
function isCompletedFileResultPath(relativePath) {
|
|
1727
|
+
const normalized = normalizeRepoRelative(relativePath);
|
|
1728
|
+
return normalized.startsWith(`${FILE_COMPLETED_DIR}/`);
|
|
1729
|
+
}
|
|
1730
|
+
function visibleFileTranslationIndex(index) {
|
|
1731
|
+
const seenKeys = new Set();
|
|
1732
|
+
const jobs = [];
|
|
1733
|
+
for (const job of index.jobs) {
|
|
1734
|
+
const key = fileTranslationReplacementKey(job);
|
|
1735
|
+
if (seenKeys.has(key)) {
|
|
1736
|
+
continue;
|
|
1737
|
+
}
|
|
1738
|
+
seenKeys.add(key);
|
|
1739
|
+
jobs.push(job);
|
|
1740
|
+
}
|
|
1741
|
+
return {
|
|
1742
|
+
...index,
|
|
1743
|
+
jobs
|
|
1744
|
+
};
|
|
1745
|
+
}
|
|
1616
1746
|
function retainedCompletedFileJobIds(index) {
|
|
1617
1747
|
const seenKeys = new Set();
|
|
1618
1748
|
const retainedIds = new Set();
|
|
@@ -1637,10 +1767,7 @@ function isPrunableCompletedQueueItem(item) {
|
|
|
1637
1767
|
}
|
|
1638
1768
|
function isTranslationRuntimeDirectory(relativePath) {
|
|
1639
1769
|
const normalized = normalizeRepoRelative(relativePath);
|
|
1640
|
-
return normalized.startsWith(`${TRANSLATIONS_RUNTIME_DIR}/`)
|
|
1641
|
-
normalized.startsWith(`${TRANSLATIONS_ROOT}/files/jobs/`) ||
|
|
1642
|
-
normalized.startsWith(`${TRANSLATIONS_ROOT}/bootstrap/runs/`) ||
|
|
1643
|
-
normalized.startsWith(`${TRANSLATIONS_ROOT}/conversations/`);
|
|
1770
|
+
return normalized.startsWith(`${TRANSLATIONS_RUNTIME_DIR}/`);
|
|
1644
1771
|
}
|
|
1645
1772
|
async function readStandaloneConversationResult(repoRoot, resultRelativePath, fs) {
|
|
1646
1773
|
const resultPath = resolveRepoPath(repoRoot, resultRelativePath);
|
|
@@ -13,11 +13,6 @@ const CODEX_CONFIG_PATH = ".ai/codex/config.toml";
|
|
|
13
13
|
const CODEX_TRANSLATOR_DIR = ".ai/codex-translator";
|
|
14
14
|
const CODEX_TRANSLATION_DIR = ".ai/vcm/translations";
|
|
15
15
|
const CODEX_TRANSLATOR_SESSION_PATH = ".ai/vcm/translations/runtime/session.json";
|
|
16
|
-
const LEGACY_CODEX_TRANSLATOR_SESSION_PATH = ".ai/vcm/translations/session.json";
|
|
17
|
-
const CODEX_TRANSLATOR_LOG_PATHS = [
|
|
18
|
-
".ai/vcm/translations/runtime/codex-translator.log",
|
|
19
|
-
".ai/vcm/translations/codex-translator.log"
|
|
20
|
-
];
|
|
21
16
|
const CODEX_TRANSLATOR_CONFIG_PATH = ".ai/codex-translator/config.toml";
|
|
22
17
|
export function createSessionService(deps) {
|
|
23
18
|
const now = deps.now ?? (() => new Date().toISOString());
|
|
@@ -42,9 +37,6 @@ export function createSessionService(deps) {
|
|
|
42
37
|
const effort = isCodexRole
|
|
43
38
|
? normalizeCodexEffort(input.effort ?? persisted?.effort)
|
|
44
39
|
: normalizeClaudeEffort(input.effort ?? persisted?.effort);
|
|
45
|
-
if (isTranslator) {
|
|
46
|
-
await cleanupCodexTranslatorLogs(deps.fs, repoRoot);
|
|
47
|
-
}
|
|
48
40
|
const claudeSessionId = launchMode === "resume"
|
|
49
41
|
? persisted?.claudeSessionId
|
|
50
42
|
: randomUUID();
|
|
@@ -412,34 +404,17 @@ async function loadPersistedRoleRecordForRole(fs, baseRepoRoot, taskRepoRoot, st
|
|
|
412
404
|
return loadPersistedRoleRecord(fs, taskRepoRoot, stateRoot, taskSlug, role);
|
|
413
405
|
}
|
|
414
406
|
async function loadPersistedCodexTranslatorSession(fs, repoRoot, taskSlug) {
|
|
415
|
-
|
|
407
|
+
const sessionPath = resolveRepoPath(repoRoot, CODEX_TRANSLATOR_SESSION_PATH);
|
|
416
408
|
if (!(await fs.pathExists(sessionPath))) {
|
|
417
|
-
|
|
418
|
-
if (!(await fs.pathExists(legacySessionPath))) {
|
|
419
|
-
return undefined;
|
|
420
|
-
}
|
|
421
|
-
sessionPath = legacySessionPath;
|
|
409
|
+
return undefined;
|
|
422
410
|
}
|
|
423
411
|
const payload = await fs.readJson(sessionPath);
|
|
424
412
|
const record = normalizePersistedRoleRecord(isProjectRoleSessionFile(payload) ? payload.record : payload);
|
|
425
413
|
if (!record) {
|
|
426
414
|
return undefined;
|
|
427
415
|
}
|
|
428
|
-
if (sessionPath.endsWith(LEGACY_CODEX_TRANSLATOR_SESSION_PATH)) {
|
|
429
|
-
await persistCodexTranslatorSession(fs, repoRoot, {
|
|
430
|
-
...record,
|
|
431
|
-
taskSlug
|
|
432
|
-
});
|
|
433
|
-
await fs.removePath?.(sessionPath, { force: true });
|
|
434
|
-
}
|
|
435
416
|
return scopeProjectRoleSession(record, taskSlug);
|
|
436
417
|
}
|
|
437
|
-
async function cleanupCodexTranslatorLogs(fs, repoRoot) {
|
|
438
|
-
if (!fs.removePath) {
|
|
439
|
-
return;
|
|
440
|
-
}
|
|
441
|
-
await Promise.all(CODEX_TRANSLATOR_LOG_PATHS.map((relativePath) => fs.removePath?.(resolveRepoPath(repoRoot, relativePath), { force: true })));
|
|
442
|
-
}
|
|
443
418
|
async function loadPersistedRoleRecord(fs, repoRoot, stateRoot, taskSlug, role) {
|
|
444
419
|
const current = await loadPersistedTaskSessionRecord(fs, repoRoot, stateRoot, taskSlug);
|
|
445
420
|
return normalizePersistedRoleRecord(current?.roles[role]?.record);
|
|
@@ -54,7 +54,9 @@ function degradedArtifactSummary(handoffDir) {
|
|
|
54
54
|
logsDir,
|
|
55
55
|
messagesDir,
|
|
56
56
|
roleCommandPaths: Object.fromEntries(DISPATCHABLE_ROLES.map((role) => [role, `${roleCommandsDir}/${role}.md`])),
|
|
57
|
-
roleLogPaths: Object.fromEntries(ROLE_NAMES
|
|
57
|
+
roleLogPaths: Object.fromEntries(ROLE_NAMES
|
|
58
|
+
.filter((role) => role !== "codex-translator")
|
|
59
|
+
.map((role) => [role, `${logsDir}/${role}.log`])),
|
|
58
60
|
messageRoutePaths: {},
|
|
59
61
|
architecturePlanPath: `${handoffDir}/architecture-plan.md`,
|
|
60
62
|
knownIssuesPath: `${handoffDir}/known-issues.md`,
|
|
@@ -79,7 +79,7 @@ Error generating stack: `+l.message+`
|
|
|
79
79
|
`))}function c(w,E,x,v){const S=x.enter("tableCell"),g=x.enter("phrasing"),_=x.containerPhrasing(w,{...v,before:y,after:y});return g(),S(),_}function h(w,E){return cw(w,{align:E,alignDelimiters:o,padding:s,stringLength:p})}function d(w,E,x){const v=w.children;let S=-1;const g=[],_=E.enter("table");for(;++S<v.length;)g[S]=u(v[S],E,x);return _(),g}function u(w,E,x){const v=w.children;let S=-1;const g=[],_=E.enter("tableRow");for(;++S<v.length;)g[S]=c(v[S],w,E,x);return _(),g}function b(w,E,x){let v=h_.inlineCode(w,E,x);return x.stack.includes("tableCell")&&(v=v.replace(/\|/g,"\\$&")),v}}function Xw(){return{exit:{taskListCheckValueChecked:Xm,taskListCheckValueUnchecked:Xm,paragraph:Zw}}}function Qw(){return{unsafe:[{atBreak:!0,character:"-",after:"[:|-]"}],handlers:{listItem:Jw}}}function Xm(n){const r=this.stack[this.stack.length-2];r.type,r.checked=n.type==="taskListCheckValueChecked"}function Zw(n){const r=this.stack[this.stack.length-2];if(r&&r.type==="listItem"&&typeof r.checked=="boolean"){const s=this.stack[this.stack.length-1];s.type;const o=s.children[0];if(o&&o.type==="text"){const p=r.children;let y=-1,f;for(;++y<p.length;){const a=p[y];if(a.type==="paragraph"){f=a;break}}f===s&&(o.value=o.value.slice(1),o.value.length===0?s.children.shift():s.position&&o.position&&typeof o.position.start.offset=="number"&&(o.position.start.column++,o.position.start.offset++,s.position.start=Object.assign({},o.position.start)))}}this.exit(n)}function Jw(n,r,s,o){const p=n.children[0],y=typeof n.checked=="boolean"&&p&&p.type==="paragraph",f="["+(n.checked?"x":" ")+"] ",a=s.createTracker(o);y&&a.move(f);let c=h_.listItem(n,r,s,{...o,...a.current()});return y&&(c=c.replace(/^(?:[*+-]|\d+\.)([\r\n]| {1,3})/,h)),c;function h(d){return d+f}}function ex(){return[LC(),JC(),iw(),qw(),Xw()]}function tx(n){return{extensions:[OC(),ew(n),rw(),Ww(n),Qw()]}}const nx={tokenize:ox,partial:!0},f_={tokenize:cx,partial:!0},d_={tokenize:ux,partial:!0},p_={tokenize:hx,partial:!0},ix={tokenize:fx,partial:!0},m_={name:"wwwAutolink",tokenize:lx,previous:__},g_={name:"protocolAutolink",tokenize:ax,previous:v_},ii={name:"emailAutolink",tokenize:sx,previous:y_},Nn={};function rx(){return{text:Nn}}let Ji=48;for(;Ji<123;)Nn[Ji]=ii,Ji++,Ji===58?Ji=65:Ji===91&&(Ji=97);Nn[43]=ii;Nn[45]=ii;Nn[46]=ii;Nn[95]=ii;Nn[72]=[ii,g_];Nn[104]=[ii,g_];Nn[87]=[ii,m_];Nn[119]=[ii,m_];function sx(n,r,s){const o=this;let p,y;return f;function f(u){return!Ou(u)||!y_.call(o,o.previous)||nh(o.events)?s(u):(n.enter("literalAutolink"),n.enter("literalAutolinkEmail"),a(u))}function a(u){return Ou(u)?(n.consume(u),a):u===64?(n.consume(u),c):s(u)}function c(u){return u===46?n.check(ix,d,h)(u):u===45||u===95||It(u)?(y=!0,n.consume(u),c):d(u)}function h(u){return n.consume(u),p=!0,c}function d(u){return y&&p&&qt(o.previous)?(n.exit("literalAutolinkEmail"),n.exit("literalAutolink"),r(u)):s(u)}}function lx(n,r,s){const o=this;return p;function p(f){return f!==87&&f!==119||!__.call(o,o.previous)||nh(o.events)?s(f):(n.enter("literalAutolink"),n.enter("literalAutolinkWww"),n.check(nx,n.attempt(f_,n.attempt(d_,y),s),s)(f))}function y(f){return n.exit("literalAutolinkWww"),n.exit("literalAutolink"),r(f)}}function ax(n,r,s){const o=this;let p="",y=!1;return f;function f(u){return(u===72||u===104)&&v_.call(o,o.previous)&&!nh(o.events)?(n.enter("literalAutolink"),n.enter("literalAutolinkHttp"),p+=String.fromCodePoint(u),n.consume(u),a):s(u)}function a(u){if(qt(u)&&p.length<5)return p+=String.fromCodePoint(u),n.consume(u),a;if(u===58){const b=p.toLowerCase();if(b==="http"||b==="https")return n.consume(u),c}return s(u)}function c(u){return u===47?(n.consume(u),y?h:(y=!0,c)):s(u)}function h(u){return u===null||Ra(u)||ot(u)||er(u)||ja(u)?s(u):n.attempt(f_,n.attempt(d_,d),s)(u)}function d(u){return n.exit("literalAutolinkHttp"),n.exit("literalAutolink"),r(u)}}function ox(n,r,s){let o=0;return p;function p(f){return(f===87||f===119)&&o<3?(o++,n.consume(f),p):f===46&&o===3?(n.consume(f),y):s(f)}function y(f){return f===null?s(f):r(f)}}function cx(n,r,s){let o,p,y;return f;function f(h){return h===46||h===95?n.check(p_,c,a)(h):h===null||ot(h)||er(h)||h!==45&&ja(h)?c(h):(y=!0,n.consume(h),f)}function a(h){return h===95?o=!0:(p=o,o=void 0),n.consume(h),f}function c(h){return p||o||!y?s(h):r(h)}}function ux(n,r){let s=0,o=0;return p;function p(f){return f===40?(s++,n.consume(f),p):f===41&&o<s?y(f):f===33||f===34||f===38||f===39||f===41||f===42||f===44||f===46||f===58||f===59||f===60||f===63||f===93||f===95||f===126?n.check(p_,r,y)(f):f===null||ot(f)||er(f)?r(f):(n.consume(f),p)}function y(f){return f===41&&o++,n.consume(f),p}}function hx(n,r,s){return o;function o(a){return a===33||a===34||a===39||a===41||a===42||a===44||a===46||a===58||a===59||a===63||a===95||a===126?(n.consume(a),o):a===38?(n.consume(a),y):a===93?(n.consume(a),p):a===60||a===null||ot(a)||er(a)?r(a):s(a)}function p(a){return a===null||a===40||a===91||ot(a)||er(a)?r(a):o(a)}function y(a){return qt(a)?f(a):s(a)}function f(a){return a===59?(n.consume(a),o):qt(a)?(n.consume(a),f):s(a)}}function fx(n,r,s){return o;function o(y){return n.consume(y),p}function p(y){return It(y)?s(y):r(y)}}function __(n){return n===null||n===40||n===42||n===95||n===91||n===93||n===126||ot(n)}function v_(n){return!qt(n)}function y_(n){return!(n===47||Ou(n))}function Ou(n){return n===43||n===45||n===46||n===95||It(n)}function nh(n){let r=n.length,s=!1;for(;r--;){const o=n[r][1];if((o.type==="labelLink"||o.type==="labelImage")&&!o._balanced){s=!0;break}if(o._gfmAutolinkLiteralWalkedInto){s=!1;break}}return n.length>0&&!s&&(n[n.length-1][1]._gfmAutolinkLiteralWalkedInto=!0),s}const dx={tokenize:bx,partial:!0};function px(){return{document:{91:{name:"gfmFootnoteDefinition",tokenize:vx,continuation:{tokenize:yx},exit:Sx}},text:{91:{name:"gfmFootnoteCall",tokenize:_x},93:{name:"gfmPotentialFootnoteCall",add:"after",tokenize:mx,resolveTo:gx}}}}function mx(n,r,s){const o=this;let p=o.events.length;const y=o.parser.gfmFootnotes||(o.parser.gfmFootnotes=[]);let f;for(;p--;){const c=o.events[p][1];if(c.type==="labelImage"){f=c;break}if(c.type==="gfmFootnoteCall"||c.type==="labelLink"||c.type==="label"||c.type==="image"||c.type==="link")break}return a;function a(c){if(!f||!f._balanced)return s(c);const h=An(o.sliceSerialize({start:f.end,end:o.now()}));return h.codePointAt(0)!==94||!y.includes(h.slice(1))?s(c):(n.enter("gfmFootnoteCallLabelMarker"),n.consume(c),n.exit("gfmFootnoteCallLabelMarker"),r(c))}}function gx(n,r){let s=n.length;for(;s--;)if(n[s][1].type==="labelImage"&&n[s][0]==="enter"){n[s][1];break}n[s+1][1].type="data",n[s+3][1].type="gfmFootnoteCallLabelMarker";const o={type:"gfmFootnoteCall",start:Object.assign({},n[s+3][1].start),end:Object.assign({},n[n.length-1][1].end)},p={type:"gfmFootnoteCallMarker",start:Object.assign({},n[s+3][1].end),end:Object.assign({},n[s+3][1].end)};p.end.column++,p.end.offset++,p.end._bufferIndex++;const y={type:"gfmFootnoteCallString",start:Object.assign({},p.end),end:Object.assign({},n[n.length-1][1].start)},f={type:"chunkString",contentType:"string",start:Object.assign({},y.start),end:Object.assign({},y.end)},a=[n[s+1],n[s+2],["enter",o,r],n[s+3],n[s+4],["enter",p,r],["exit",p,r],["enter",y,r],["enter",f,r],["exit",f,r],["exit",y,r],n[n.length-2],n[n.length-1],["exit",o,r]];return n.splice(s,n.length-s+1,...a),n}function _x(n,r,s){const o=this,p=o.parser.gfmFootnotes||(o.parser.gfmFootnotes=[]);let y=0,f;return a;function a(u){return n.enter("gfmFootnoteCall"),n.enter("gfmFootnoteCallLabelMarker"),n.consume(u),n.exit("gfmFootnoteCallLabelMarker"),c}function c(u){return u!==94?s(u):(n.enter("gfmFootnoteCallMarker"),n.consume(u),n.exit("gfmFootnoteCallMarker"),n.enter("gfmFootnoteCallString"),n.enter("chunkString").contentType="string",h)}function h(u){if(y>999||u===93&&!f||u===null||u===91||ot(u))return s(u);if(u===93){n.exit("chunkString");const b=n.exit("gfmFootnoteCallString");return p.includes(An(o.sliceSerialize(b)))?(n.enter("gfmFootnoteCallLabelMarker"),n.consume(u),n.exit("gfmFootnoteCallLabelMarker"),n.exit("gfmFootnoteCall"),r):s(u)}return ot(u)||(f=!0),y++,n.consume(u),u===92?d:h}function d(u){return u===91||u===92||u===93?(n.consume(u),y++,h):h(u)}}function vx(n,r,s){const o=this,p=o.parser.gfmFootnotes||(o.parser.gfmFootnotes=[]);let y,f=0,a;return c;function c(E){return n.enter("gfmFootnoteDefinition")._container=!0,n.enter("gfmFootnoteDefinitionLabel"),n.enter("gfmFootnoteDefinitionLabelMarker"),n.consume(E),n.exit("gfmFootnoteDefinitionLabelMarker"),h}function h(E){return E===94?(n.enter("gfmFootnoteDefinitionMarker"),n.consume(E),n.exit("gfmFootnoteDefinitionMarker"),n.enter("gfmFootnoteDefinitionLabelString"),n.enter("chunkString").contentType="string",d):s(E)}function d(E){if(f>999||E===93&&!a||E===null||E===91||ot(E))return s(E);if(E===93){n.exit("chunkString");const x=n.exit("gfmFootnoteDefinitionLabelString");return y=An(o.sliceSerialize(x)),n.enter("gfmFootnoteDefinitionLabelMarker"),n.consume(E),n.exit("gfmFootnoteDefinitionLabelMarker"),n.exit("gfmFootnoteDefinitionLabel"),b}return ot(E)||(a=!0),f++,n.consume(E),E===92?u:d}function u(E){return E===91||E===92||E===93?(n.consume(E),f++,d):d(E)}function b(E){return E===58?(n.enter("definitionMarker"),n.consume(E),n.exit("definitionMarker"),p.includes(y)||p.push(y),Ke(n,w,"gfmFootnoteDefinitionWhitespace")):s(E)}function w(E){return r(E)}}function yx(n,r,s){return n.check(ll,r,n.attempt(dx,r,s))}function Sx(n){n.exit("gfmFootnoteDefinition")}function bx(n,r,s){const o=this;return Ke(n,p,"gfmFootnoteDefinitionIndent",5);function p(y){const f=o.events[o.events.length-1];return f&&f[1].type==="gfmFootnoteDefinitionIndent"&&f[2].sliceSerialize(f[1],!0).length===4?r(y):s(y)}}function Cx(n){let s=(n||{}).singleTilde;const o={name:"strikethrough",tokenize:y,resolveAll:p};return s==null&&(s=!0),{text:{126:o},insideSpan:{null:[o]},attentionMarkers:{null:[126]}};function p(f,a){let c=-1;for(;++c<f.length;)if(f[c][0]==="enter"&&f[c][1].type==="strikethroughSequenceTemporary"&&f[c][1]._close){let h=c;for(;h--;)if(f[h][0]==="exit"&&f[h][1].type==="strikethroughSequenceTemporary"&&f[h][1]._open&&f[c][1].end.offset-f[c][1].start.offset===f[h][1].end.offset-f[h][1].start.offset){f[c][1].type="strikethroughSequence",f[h][1].type="strikethroughSequence";const d={type:"strikethrough",start:Object.assign({},f[h][1].start),end:Object.assign({},f[c][1].end)},u={type:"strikethroughText",start:Object.assign({},f[h][1].end),end:Object.assign({},f[c][1].start)},b=[["enter",d,a],["enter",f[h][1],a],["exit",f[h][1],a],["enter",u,a]],w=a.parser.constructs.insideSpan.null;w&&hn(b,b.length,0,za(w,f.slice(h+1,c),a)),hn(b,b.length,0,[["exit",u,a],["enter",f[c][1],a],["exit",f[c][1],a],["exit",d,a]]),hn(f,h-1,c-h+3,b),c=h+b.length-2;break}}for(c=-1;++c<f.length;)f[c][1].type==="strikethroughSequenceTemporary"&&(f[c][1].type="data");return f}function y(f,a,c){const h=this.previous,d=this.events;let u=0;return b;function b(E){return h===126&&d[d.length-1][1].type!=="characterEscape"?c(E):(f.enter("strikethroughSequenceTemporary"),w(E))}function w(E){const x=Xr(h);if(E===126)return u>1?c(E):(f.consume(E),u++,w);if(u<2&&!s)return c(E);const v=f.exit("strikethroughSequenceTemporary"),S=Xr(E);return v._open=!S||S===2&&!!x,v._close=!x||x===2&&!!S,a(E)}}}class wx{constructor(){this.map=[]}add(r,s,o){xx(this,r,s,o)}consume(r){if(this.map.sort(function(y,f){return y[0]-f[0]}),this.map.length===0)return;let s=this.map.length;const o=[];for(;s>0;)s-=1,o.push(r.slice(this.map[s][0]+this.map[s][1]),this.map[s][2]),r.length=this.map[s][0];o.push(r.slice()),r.length=0;let p=o.pop();for(;p;){for(const y of p)r.push(y);p=o.pop()}this.map.length=0}}function xx(n,r,s,o){let p=0;if(!(s===0&&o.length===0)){for(;p<n.map.length;){if(n.map[p][0]===r){n.map[p][1]+=s,n.map[p][2].push(...o);return}p+=1}n.map.push([r,s,o])}}function Ex(n,r){let s=!1;const o=[];for(;r<n.length;){const p=n[r];if(s){if(p[0]==="enter")p[1].type==="tableContent"&&o.push(n[r+1][1].type==="tableDelimiterMarker"?"left":"none");else if(p[1].type==="tableContent"){if(n[r-1][1].type==="tableDelimiterMarker"){const y=o.length-1;o[y]=o[y]==="left"?"center":"right"}}else if(p[1].type==="tableDelimiterRow")break}else p[0]==="enter"&&p[1].type==="tableDelimiterRow"&&(s=!0);r+=1}return o}function kx(){return{flow:{null:{name:"table",tokenize:Ax,resolveAll:Tx}}}}function Ax(n,r,s){const o=this;let p=0,y=0,f;return a;function a(N){let I=o.events.length-1;for(;I>-1;){const Y=o.events[I][1].type;if(Y==="lineEnding"||Y==="linePrefix")I--;else break}const P=I>-1?o.events[I][1].type:null,F=P==="tableHead"||P==="tableRow"?D:c;return F===D&&o.parser.lazy[o.now().line]?s(N):F(N)}function c(N){return n.enter("tableHead"),n.enter("tableRow"),h(N)}function h(N){return N===124||(f=!0,y+=1),d(N)}function d(N){return N===null?s(N):Ne(N)?y>1?(y=0,o.interrupt=!0,n.exit("tableRow"),n.enter("lineEnding"),n.consume(N),n.exit("lineEnding"),w):s(N):Ve(N)?Ke(n,d,"whitespace")(N):(y+=1,f&&(f=!1,p+=1),N===124?(n.enter("tableCellDivider"),n.consume(N),n.exit("tableCellDivider"),f=!0,d):(n.enter("data"),u(N)))}function u(N){return N===null||N===124||ot(N)?(n.exit("data"),d(N)):(n.consume(N),N===92?b:u)}function b(N){return N===92||N===124?(n.consume(N),u):u(N)}function w(N){return o.interrupt=!1,o.parser.lazy[o.now().line]?s(N):(n.enter("tableDelimiterRow"),f=!1,Ve(N)?Ke(n,E,"linePrefix",o.parser.constructs.disable.null.includes("codeIndented")?void 0:4)(N):E(N))}function E(N){return N===45||N===58?v(N):N===124?(f=!0,n.enter("tableCellDivider"),n.consume(N),n.exit("tableCellDivider"),x):M(N)}function x(N){return Ve(N)?Ke(n,v,"whitespace")(N):v(N)}function v(N){return N===58?(y+=1,f=!0,n.enter("tableDelimiterMarker"),n.consume(N),n.exit("tableDelimiterMarker"),S):N===45?(y+=1,S(N)):N===null||Ne(N)?A(N):M(N)}function S(N){return N===45?(n.enter("tableDelimiterFiller"),g(N)):M(N)}function g(N){return N===45?(n.consume(N),g):N===58?(f=!0,n.exit("tableDelimiterFiller"),n.enter("tableDelimiterMarker"),n.consume(N),n.exit("tableDelimiterMarker"),_):(n.exit("tableDelimiterFiller"),_(N))}function _(N){return Ve(N)?Ke(n,A,"whitespace")(N):A(N)}function A(N){return N===124?E(N):N===null||Ne(N)?!f||p!==y?M(N):(n.exit("tableDelimiterRow"),n.exit("tableHead"),r(N)):M(N)}function M(N){return s(N)}function D(N){return n.enter("tableRow"),T(N)}function T(N){return N===124?(n.enter("tableCellDivider"),n.consume(N),n.exit("tableCellDivider"),T):N===null||Ne(N)?(n.exit("tableRow"),r(N)):Ve(N)?Ke(n,T,"whitespace")(N):(n.enter("data"),k(N))}function k(N){return N===null||N===124||ot(N)?(n.exit("data"),T(N)):(n.consume(N),N===92?R:k)}function R(N){return N===92||N===124?(n.consume(N),k):k(N)}}function Tx(n,r){let s=-1,o=!0,p=0,y=[0,0,0,0],f=[0,0,0,0],a=!1,c=0,h,d,u;const b=new wx;for(;++s<n.length;){const w=n[s],E=w[1];w[0]==="enter"?E.type==="tableHead"?(a=!1,c!==0&&(Qm(b,r,c,h,d),d=void 0,c=0),h={type:"table",start:Object.assign({},E.start),end:Object.assign({},E.end)},b.add(s,0,[["enter",h,r]])):E.type==="tableRow"||E.type==="tableDelimiterRow"?(o=!0,u=void 0,y=[0,0,0,0],f=[0,s+1,0,0],a&&(a=!1,d={type:"tableBody",start:Object.assign({},E.start),end:Object.assign({},E.end)},b.add(s,0,[["enter",d,r]])),p=E.type==="tableDelimiterRow"?2:d?3:1):p&&(E.type==="data"||E.type==="tableDelimiterMarker"||E.type==="tableDelimiterFiller")?(o=!1,f[2]===0&&(y[1]!==0&&(f[0]=f[1],u=ka(b,r,y,p,void 0,u),y=[0,0,0,0]),f[2]=s)):E.type==="tableCellDivider"&&(o?o=!1:(y[1]!==0&&(f[0]=f[1],u=ka(b,r,y,p,void 0,u)),y=f,f=[y[1],s,0,0])):E.type==="tableHead"?(a=!0,c=s):E.type==="tableRow"||E.type==="tableDelimiterRow"?(c=s,y[1]!==0?(f[0]=f[1],u=ka(b,r,y,p,s,u)):f[1]!==0&&(u=ka(b,r,f,p,s,u)),p=0):p&&(E.type==="data"||E.type==="tableDelimiterMarker"||E.type==="tableDelimiterFiller")&&(f[3]=s)}for(c!==0&&Qm(b,r,c,h,d),b.consume(r.events),s=-1;++s<r.events.length;){const w=r.events[s];w[0]==="enter"&&w[1].type==="table"&&(w[1]._align=Ex(r.events,s))}return n}function ka(n,r,s,o,p,y){const f=o===1?"tableHeader":o===2?"tableDelimiter":"tableData",a="tableContent";s[0]!==0&&(y.end=Object.assign({},$r(r.events,s[0])),n.add(s[0],0,[["exit",y,r]]));const c=$r(r.events,s[1]);if(y={type:f,start:Object.assign({},c),end:Object.assign({},c)},n.add(s[1],0,[["enter",y,r]]),s[2]!==0){const h=$r(r.events,s[2]),d=$r(r.events,s[3]),u={type:a,start:Object.assign({},h),end:Object.assign({},d)};if(n.add(s[2],0,[["enter",u,r]]),o!==2){const b=r.events[s[2]],w=r.events[s[3]];if(b[1].end=Object.assign({},w[1].end),b[1].type="chunkText",b[1].contentType="text",s[3]>s[2]+1){const E=s[2]+1,x=s[3]-s[2]-1;n.add(E,x,[])}}n.add(s[3]+1,0,[["exit",u,r]])}return p!==void 0&&(y.end=Object.assign({},$r(r.events,p)),n.add(p,0,[["exit",y,r]]),y=void 0),y}function Qm(n,r,s,o,p){const y=[],f=$r(r.events,s);p&&(p.end=Object.assign({},f),y.push(["exit",p,r])),o.end=Object.assign({},f),y.push(["exit",o,r]),n.add(s+1,0,y)}function $r(n,r){const s=n[r],o=s[0]==="enter"?"start":"end";return s[1][o]}const Dx={name:"tasklistCheck",tokenize:Mx};function Rx(){return{text:{91:Dx}}}function Mx(n,r,s){const o=this;return p;function p(c){return o.previous!==null||!o._gfmTasklistFirstContentOfListItem?s(c):(n.enter("taskListCheck"),n.enter("taskListCheckMarker"),n.consume(c),n.exit("taskListCheckMarker"),y)}function y(c){return ot(c)?(n.enter("taskListCheckValueUnchecked"),n.consume(c),n.exit("taskListCheckValueUnchecked"),f):c===88||c===120?(n.enter("taskListCheckValueChecked"),n.consume(c),n.exit("taskListCheckValueChecked"),f):s(c)}function f(c){return c===93?(n.enter("taskListCheckMarker"),n.consume(c),n.exit("taskListCheckMarker"),n.exit("taskListCheck"),a):s(c)}function a(c){return Ne(c)?r(c):Ve(c)?n.check({tokenize:Lx},r,s)(c):s(c)}}function Lx(n,r,s){return Ke(n,o,"whitespace");function o(p){return p===null?s(p):r(p)}}function Ox(n){return Dg([rx(),px(),Cx(n),kx(),Rx()])}const Bx={};function S_(n){const r=this,s=n||Bx,o=r.data(),p=o.micromarkExtensions||(o.micromarkExtensions=[]),y=o.fromMarkdownExtensions||(o.fromMarkdownExtensions=[]),f=o.toMarkdownExtensions||(o.toMarkdownExtensions=[]);p.push(Ox(s)),y.push(ex()),f.push(tx(s))}const Nx=500,Ce={getAppPreferences(){return Me("/api/settings/preferences")},updateAppPreferences(n){return Me("/api/settings/preferences",{method:"PUT",body:JSON.stringify(n)})},getRuntimeDiagnostics(){return Me("/api/diagnostics/runtime")},getCurrentProject(){return Me("/api/projects/current")},pullCurrentProject(){return Me("/api/projects/current/pull",{method:"POST"})},getRecentRepositoryPaths(){return Me("/api/projects/recent")},connectProject(n){return Me("/api/projects/connect",{method:"POST",body:JSON.stringify(n)})},listTasks(){return Me("/api/tasks")},createTask(n){return Me("/api/tasks",{method:"POST",body:JSON.stringify(n)})},cleanupTask(n,r={}){return Me(`/api/tasks/${encodeURIComponent(n)}/cleanup`,{method:"POST",body:JSON.stringify(r)})},getHarnessStatus(){return Me("/api/projects/harness")},applyHarness(){return Me("/api/projects/harness/apply",{method:"POST"})},getHarnessBootstrapStatus(){return Me("/api/projects/harness/bootstrap")},startHarnessBootstrap(n={}){return Me("/api/projects/harness/bootstrap/start",{method:"POST",body:JSON.stringify(n)})},getTaskStatus(n){return Me(`/api/tasks/${encodeURIComponent(n)}/status`)},listSessions(n){return Me(`/api/tasks/${encodeURIComponent(n)}/sessions`)},startRoleSession(n,r,s={}){return Me(`/api/tasks/${encodeURIComponent(n)}/sessions/${r}/start`,{method:"POST",body:JSON.stringify(s)})},stopRoleSession(n,r){return Me(`/api/tasks/${encodeURIComponent(n)}/sessions/${r}/stop`,{method:"POST"})},restartRoleSession(n,r,s={}){return Me(`/api/tasks/${encodeURIComponent(n)}/sessions/${r}/restart`,{method:"POST",body:JSON.stringify(s)})},resumeRoleSession(n,r,s={}){return Me(`/api/tasks/${encodeURIComponent(n)}/sessions/${r}/resume`,{method:"POST",body:JSON.stringify(s)})},dispatchRoleCommand(n,r){return Me(`/api/tasks/${encodeURIComponent(n)}/sessions/${r}/dispatch`,{method:"POST"})},listMessages(n){return Me(`/api/tasks/${encodeURIComponent(n)}/messages`)},markAllMessagesDone(n){return Me(`/api/tasks/${encodeURIComponent(n)}/messages/mark-all-done`,{method:"POST"})},deleteMessageHistory(n){return Me(`/api/tasks/${encodeURIComponent(n)}/messages/history`,{method:"DELETE"})},getOrchestrationState(n){return Me(`/api/tasks/${encodeURIComponent(n)}/orchestration`)},updateOrchestrationState(n,r){return Me(`/api/tasks/${encodeURIComponent(n)}/orchestration`,{method:"PUT",body:JSON.stringify(r)})},getSessionRoundState(n){return Me(`/api/tasks/${encodeURIComponent(n)}/round`)},getCodexReviewState(n){return Me(`/api/tasks/${encodeURIComponent(n)}/codex-review`)},updateCodexReviewSettings(n,r){return Me(`/api/tasks/${encodeURIComponent(n)}/codex-review/settings`,{method:"PUT",body:JSON.stringify(r)})},requestCodexReviewGate(n,r){return Me(`/api/tasks/${encodeURIComponent(n)}/codex-review/${r}/request`,{method:"POST"})},retryCodexReviewGate(n,r){return Me(`/api/tasks/${encodeURIComponent(n)}/codex-review/${r}/retry`,{method:"POST"})},skipCodexReviewGate(n,r,s){return Me(`/api/tasks/${encodeURIComponent(n)}/codex-review/${r}/skip`,{method:"POST",body:JSON.stringify(s)})},overrideCodexReviewGate(n,r,s){return Me(`/api/tasks/${encodeURIComponent(n)}/codex-review/${r}/override`,{method:"POST",body:JSON.stringify(s)})},getCodexReviewReport(n,r){return Me(`/api/tasks/${encodeURIComponent(n)}/codex-review/${r}/report`)},startTranslationSession(n,r){return Me(`/api/tasks/${encodeURIComponent(n)}/sessions/${r}/translation/start`,{method:"POST"})},pollTranslationSession(n,r,s){const o=new URLSearchParams({after:String(r)});return s!==void 0&&o.set("limit",String(s)),Me(`/api/translation/sessions/${encodeURIComponent(n)}/events?${o.toString()}`)},translateUserInput(n,r,s){return Me(`/api/tasks/${encodeURIComponent(n)}/sessions/${r}/translation/input`,{method:"POST",body:JSON.stringify(s)})},sendTranslatedInput(n,r,s){return Me(`/api/tasks/${encodeURIComponent(n)}/sessions/${r}/translation/send`,{method:"POST",body:JSON.stringify(s)})},clearTranslationSession(n){return Me(`/api/translation/sessions/${encodeURIComponent(n)}/clear`,{method:"POST"})},stopTranslationSession(n){return Me(`/api/translation/sessions/${encodeURIComponent(n)}/stop`,{method:"POST"})},retryTranslation(n,r){return Me(`/api/translation/sessions/${encodeURIComponent(n)}/retry/${encodeURIComponent(r)}`,{method:"POST"})},ignoreTranslationFailures(n){return Me(`/api/translation/sessions/${encodeURIComponent(n)}/failures/ignore`,{method:"POST"})},retryTranslationFailures(n){return Me(`/api/translation/sessions/${encodeURIComponent(n)}/failures/retry`,{method:"POST"})},getCodexTranslationState(){return Me("/api/translation/codex/state")},browseCodexTranslationSourceFiles(n={}){const r=new URLSearchParams;n.path&&r.set("path",n.path),n.query&&r.set("query",n.query),n.limit!==void 0&&r.set("limit",String(n.limit));const s=r.toString()?`?${r.toString()}`:"";return Me(`/api/translation/codex/source-files${s}`)},createCodexFileTranslation(n){return Me("/api/translation/codex/files",{method:"POST",body:JSON.stringify(n)})},readCodexFileTranslation(n){return Me(`/api/translation/codex/files/${encodeURIComponent(n)}`)},createCodexBootstrap(n){return Me("/api/translation/codex/bootstrap",{method:"POST",body:JSON.stringify(n)})},createCodexMemoryUpdate(n){return Me("/api/translation/codex/memory-update",{method:"POST",body:JSON.stringify(n)})},promoteCodexTranslation(n,r){return Me(`/api/translation/codex/files/${encodeURIComponent(n)}/promote`,{method:"POST",body:JSON.stringify({targetPath:r})})},getGatewayStatus(){return Me("/api/gateway/status")},updateGatewaySettings(n){return Me("/api/gateway/settings",{method:"PUT",body:JSON.stringify(n)})},startGatewayQrLogin(){return Me("/api/gateway/qr/start",{method:"POST"})},checkGatewayQrLogin(n={}){return Me("/api/gateway/qr/check",{method:"POST",body:JSON.stringify(n)})},resetGatewayBinding(){return Me("/api/gateway/binding/reset",{method:"POST"})}};async function Me(n,r={}){var p,y,f;const s=new Headers(r.headers);r.body!==void 0&&r.body!==null&&!s.has("content-type")&&s.set("content-type","application/json");const o=await fetch(n,{...r,headers:s});if(!o.ok){const a=await o.json().catch(()=>null),c=(p=a==null?void 0:a.error)!=null&&p.hint?`${a.error.message} ${a.error.hint}`:((y=a==null?void 0:a.error)==null?void 0:y.message)??`Request failed: ${o.status}`,h=(f=a==null?void 0:a.error)==null?void 0:f.runtime,d=h?` [backend ${h.version??"unknown"} pid=${h.pid??"unknown"} cwd=${h.cwd??"unknown"}]`:"";throw new Error(`${c}${d}`)}return o.json()}const Ba=`
|
|
80
80
|
|
|
81
81
|
--- Translation ---
|
|
82
|
-
`;function jx({active:n=!0,autoSendEnabled:r,targetLanguage:s,taskSlug:o,role:p,sessionId:y}){const[f,a]=he.useState([]),[c,h]=he.useState([]),[d,u]=he.useState(""),[b,w]=he.useState(!1),[E,x]=he.useState("ready"),[v,S]=he.useState(""),[g,_]=he.useState(Date.now()),[A,M]=he.useState(!1),[D,T]=he.useState(""),[k,R]=he.useState(0),N=he.useRef(n),I=he.useRef(1),P=he.useRef(null);he.useEffect(()=>{N.current=n},[n]),he.useEffect(()=>{a([]),h([]),T(""),x("ready"),S(""),I.current=1;let j=!1,ee;const ae=()=>{j||(ee=window.setTimeout(ge,N.current?200:1e3))},ge=async()=>{if(!j)try{const K=await Ce.pollTranslationSession(y,I.current);if(j)return;W(K.events),I.current=K.nextCursor,x(K.status),N.current&&S(Qx(new Date().toISOString()))}catch(K){j||T(K instanceof Error?K.message:"Translation poll failed.")}finally{ae()}};return Ce.startTranslationSession(o,p).then(K=>{j||(x(K.status),I.current=K.nextCursor,ge())}).catch(K=>{j||T(K instanceof Error?K.message:"Translation start failed.")}),()=>{j=!0,ee!==void 0&&window.clearTimeout(ee),Ce.stopTranslationSession(y).catch(()=>{})}},[y,o,p]),he.useEffect(()=>{if(!n)return;const j=P.current;if(!j)return;const ee=window.requestAnimationFrame(()=>{j.scrollTop=j.scrollHeight});return()=>window.cancelAnimationFrame(ee)},[n,k]);const F=qx(f);he.useEffect(()=>{if(!F)return;_(Date.now());const j=window.setInterval(()=>_(Date.now()),250);return()=>window.clearInterval(j)},[F]);async function Y(j=!1){const ee=d;M(!0),T(""),w(!1);try{const ae=await Ce.translateUserInput(o,p,{text:ee,mode:j?"auto-send":"review-before-send",useContext:!1,send:j});ae.sent?(u(""),w(!1)):(u(b_(ee,ae.englishPreview)),w(!0))}catch(ae){T(ae instanceof Error?ae.message:"Translation failed.")}finally{M(!1)}}function W(j){if(j.length===0)return;for(const ae of j)ae.type==="status"?x(ae.status):ae.type==="error"?T(ae.message):ae.type==="failures"&&h(ae.failures);const ee=j.filter(ae=>ae.type==="entry");ee.length>0&&(a(ae=>{const ge=ee.reduce((q,ce)=>Wx(q,ce.entry),ae),K=Gx(ge);return K.removedIds.size>0&&h(q=>q.filter(ce=>!K.removedIds.has(ce.translationId))),K.entries}),R(ae=>ae+1))}async function G(){const j=b?Jm(d):d;if(j.trim()){M(!0),T("");try{await Ce.sendTranslatedInput(o,p,{englishText:j}),u(""),w(!1)}catch(ee){T(ee instanceof Error?ee.message:"Failed to send English input.")}finally{M(!1)}}}function $(j){j.key!=="Enter"||j.shiftKey||j.nativeEvent.isComposing||(j.preventDefault(),!A&&d.trim()&&(b?G():Y(r)))}async function Q(){a([]),h([]),I.current=1,await Ce.clearTranslationSession(y).catch(j=>T(j.message))}async function H(){M(!0),T("");try{const j=await Ce.ignoreTranslationFailures(y);h(j.failures)}catch(j){T(j instanceof Error?j.message:"Failed to ignore translation failures.")}finally{M(!1)}}async function O(){M(!0),T("");try{const j=await Ce.retryTranslationFailures(y);h(j.failures)}catch(j){T(j instanceof Error?j.message:"Failed to retry translation failures.")}finally{M(!1)}}const z=Vx(f,E,g),V=c.length;return B.jsxs("aside",{className:"translation-panel",children:[B.jsxs("header",{className:"translation-panel-header",children:[B.jsxs("div",{className:"translation-panel-titlebar",children:[B.jsx("h2",{children:"Translation"}),B.jsxs("div",{className:"translation-panel-actions",children:[V>0?B.jsxs(B.Fragment,{children:[B.jsxs("button",{type:"button",disabled:A,onClick:()=>void H(),children:["Ignore ",V]}),B.jsxs("button",{type:"button",disabled:A,onClick:()=>void O(),children:["Retry ",V]})]}):null,B.jsx("button",{type:"button",onClick:()=>void Q(),children:"Clear"})]})]}),B.jsxs("div",{className:"translation-status-row",children:[B.jsxs("p",{children:["Codex · target ",zx(s)," · ",z]}),B.jsx("p",{children:v?`poll ${v}`:"poll -"})]})]}),D?B.jsx("div",{className:"error-banner",children:D}):null,B.jsxs("div",{className:"translation-entry-list",ref:P,children:[f.length===0?B.jsx("p",{className:"muted",children:"Translated Claude Code output will appear here."}):null,f.map(j=>B.jsx(Px,{entry:j},j.id))]}),B.jsx("div",{className:"translation-composer",children:B.jsxs("div",{className:"translation-composer-row",children:[B.jsx("textarea",{value:d,onChange:j=>{u(j.target.value),(!j.target.value.trim()||b&&!Kx(j.target.value))&&w(!1)},onKeyDown:$,placeholder:"输入中文,先翻译成英文工程指令..."}),B.jsx("div",{className:"translation-composer-actions",children:B.jsx("button",{type:"button",disabled:A||!b||!Jm(d).trim(),onClick:()=>void G(),children:"Send English"})})]})})]})}function zx(n){var r;return((r=pg.find(s=>s.value===n))==null?void 0:r.label)??n}function Hx({open:n,taskSlug:r,targetLanguage:s,onClose:o}){const[p,y]=he.useState(!1),[f,a]=he.useState(""),[c,h]=he.useState(null),[d,u]=he.useState(""),[b,w]=he.useState(""),[E,x]=he.useState(""),[v,S]=he.useState(!1),[g,_]=he.useState(null),[A,M]=he.useState(""),[D,T]=he.useState(""),[k,R]=he.useState(""),[N,I]=he.useState(!1);he.useEffect(()=>{if(!n)return;let $=!1,Q;const H=async()=>{$||(await P(!0),$||(Q=window.setTimeout(H,2e3)))};return H(),()=>{$=!0,Q!==void 0&&window.clearTimeout(Q)}},[n,d]);async function P($=!1){try{const Q=await Ce.getCodexTranslationState();if(h(Q),!d&&Q.fileIndex.jobs[0])F(Q.fileIndex.jobs[0].id);else if($&&d){const H=await Ce.readCodexFileTranslation(d);w(H.output),x(H.report)}}catch(Q){a(Q instanceof Error?Q.message:"Failed to load file translations.")}}async function F($){u($),w(""),x("");try{const Q=await Ce.readCodexFileTranslation($);w(Q.output),x(Q.report)}catch(Q){a(Q instanceof Error?Q.message:"Failed to read translated file.")}}async function Y(){S(!0),await W(A,D)}async function W($="",Q=""){I(!0),a("");try{const H=await Ce.browseCodexTranslationSourceFiles({path:$,query:Q,limit:250});_(H),M(H.currentPath),T(Q)}catch(H){a(H instanceof Error?H.message:"Failed to browse source files.")}finally{I(!1)}}async function G($=k){const Q=$.trim();if(!(!Q||!r)){y(!0),a("");try{const H=await Ce.createCodexFileTranslation({taskSlug:r,sourcePath:Q,targetLanguage:s});S(!1),await P(),await F(H.id)}catch(H){a(H instanceof Error?H.message:"Failed to create file translation.")}finally{y(!1)}}}return n?B.jsxs(B.Fragment,{children:[B.jsx("div",{className:"modal-backdrop file-translation-backdrop",children:B.jsx(Ux,{busy:p,error:f,state:c,selectedJobId:d,output:b,report:E,onClose:()=>{S(!1),o()},onRefresh:()=>void P(),onSelectJob:$=>void F($),onTranslate:()=>void Y()})}),v?B.jsx(Ix,{busy:p||N,state:g,currentPath:A,query:D,selectedPath:k,onBrowse:($,Q)=>void W($,Q),onClose:()=>S(!1),onQueryChange:T,onSelectPath:R,onTranslate:()=>void G()}):null]}):null}function Ix({busy:n,state:r,currentPath:s,query:o,selectedPath:p,onBrowse:y,onClose:f,onQueryChange:a,onSelectPath:c,onTranslate:h}){const d=(r==null?void 0:r.entries)??[],u=d.filter(w=>w.type==="directory"),b=d.filter(w=>w.type==="file");return B.jsx("div",{className:"modal-backdrop translation-file-browser-backdrop",children:B.jsxs("section",{className:"translation-file-browser-modal",role:"dialog","aria-modal":"true","aria-label":"Select Source File",children:[B.jsxs("header",{children:[B.jsxs("div",{children:[B.jsx("h2",{children:"Select Source File"}),B.jsx("p",{children:s||"."})]}),B.jsx("button",{type:"button",onClick:f,children:"Close"})]}),B.jsxs("div",{className:"translation-file-browser-controls",children:[B.jsxs("div",{className:"translation-file-browser-nav",children:[B.jsx("button",{type:"button",disabled:n||!s,onClick:()=>y((r==null?void 0:r.parentPath)??"",""),children:"Up"}),B.jsx("button",{type:"button",disabled:n||!s,onClick:()=>y("",""),children:"Root"})]}),B.jsxs("form",{className:"translation-file-browser-search",onSubmit:w=>{w.preventDefault(),y(s,o)},children:[B.jsx("input",{value:o,onChange:w=>a(w.target.value),placeholder:"Search files"}),B.jsx("button",{type:"submit",disabled:n,children:"Search"}),B.jsx("button",{type:"button",disabled:n||!o,onClick:()=>y(s,""),children:"Clear"})]})]}),B.jsxs("div",{className:"translation-file-browser-layout",children:[B.jsxs("div",{className:"translation-file-browser-list",children:[n&&!r?B.jsx("p",{className:"muted",children:"Loading files..."}):null,!n&&d.length===0?B.jsx("p",{className:"muted",children:"No source files found."}):null,u.length>0?B.jsxs("div",{className:"translation-file-browser-group",children:[B.jsx("h3",{children:"Folders"}),u.map(w=>B.jsx(Zm,{entry:w,selected:p===w.path,onBrowse:y,onSelectPath:c},w.path))]}):null,b.length>0?B.jsxs("div",{className:"translation-file-browser-group",children:[B.jsx("h3",{children:"Files"}),b.map(w=>B.jsx(Zm,{entry:w,selected:p===w.path,onBrowse:y,onSelectPath:c},w.path))]}):null,r!=null&&r.truncated?B.jsx("p",{className:"translation-entry-note",children:"Result limit reached."}):null]}),B.jsxs("aside",{className:"translation-file-browser-selection",children:[B.jsxs("label",{children:[B.jsx("span",{children:"Source path"}),B.jsx("input",{value:p,onChange:w=>c(w.target.value)})]}),B.jsx("button",{type:"button",disabled:n||!p.trim(),onClick:h,children:"Translate File"})]})]})]})})}function Zm({entry:n,selected:r,onBrowse:s,onSelectPath:o}){const p=n.type==="directory";return B.jsxs("button",{className:r?"translation-file-browser-entry is-selected":"translation-file-browser-entry",type:"button",onClick:()=>p?s(n.path,""):o(n.path),onDoubleClick:()=>p?s(n.path,""):void 0,children:[B.jsx("span",{children:p?"DIR":"FILE"}),B.jsx("strong",{children:n.name}),B.jsx("small",{children:n.path})]})}function Ux({busy:n,error:r,state:s,selectedJobId:o,output:p,report:y,onClose:f,onRefresh:a,onSelectJob:c,onTranslate:h}){const d=(s==null?void 0:s.fileIndex.jobs)??[],u=d.find(b=>b.id===o);return B.jsxs("section",{className:"file-translation-modal",role:"dialog","aria-modal":"true","aria-label":"File Translation",children:[B.jsxs("header",{className:"file-translation-header",children:[B.jsxs("div",{children:[B.jsx("h2",{children:"File Translation"}),B.jsx("p",{children:"Codex · 中英互译"})]}),B.jsxs("div",{className:"file-translation-toolbar",children:[B.jsx("button",{type:"button",disabled:n,onClick:h,children:"Translate"}),B.jsx("button",{type:"button",disabled:n,onClick:a,children:"Refresh"}),B.jsx("button",{type:"button",onClick:f,children:"Close"})]})]}),r?B.jsx("div",{className:"error-banner",children:r}):null,s!=null&&s.memoryInitialized?null:B.jsx("p",{className:"translation-entry-note",children:"Translation memory is not initialized. Run Bootstrap from the sidebar before important file translations."}),B.jsxs("div",{className:"file-translation-layout",children:[B.jsxs("div",{className:"file-translation-list",children:[d.length===0?B.jsx("p",{className:"muted",children:"No translated files yet."}):null,d.map(b=>B.jsxs("button",{className:b.id===o?"file-translation-item is-active":"file-translation-item",type:"button",onClick:()=>c(b.id),children:[B.jsx("strong",{children:b.sourcePath}),B.jsxs("span",{children:[b.status," · ",b.targetLanguage]})]},b.id))]}),B.jsx("div",{className:"file-translation-preview",children:u?B.jsxs(B.Fragment,{children:[B.jsxs("header",{children:[B.jsx("strong",{children:u.sourcePath}),B.jsx("span",{children:u.status})]}),B.jsx("div",{className:"translation-markdown",children:B.jsx(Xg,{remarkPlugins:[S_],children:p||y||"Translation output is not available yet."})})]}):B.jsx("p",{className:"muted",children:"Select a translated file to preview it."})})]})]})}function Px({entry:n}){if(n.sourceKind==="conversation-boundary")return B.jsx(Fx,{entry:n});const r=Yx(n),s=n.sourceKind==="tool-output",o=n.direction==="user-input-to-english",p=["translation-entry",`is-${n.sourceKind}`,o?"is-user-input":""].filter(Boolean).join(" ");return B.jsxs("article",{className:p,children:[s?B.jsx("pre",{children:r}):B.jsx("div",{className:"translation-markdown",children:B.jsx(Xg,{remarkPlugins:[S_],children:r})}),n.warning?B.jsx("p",{className:"translation-entry-note",children:n.warning}):null,n.error?B.jsx("p",{className:"translation-entry-note is-error",children:n.error}):null]})}function Fx({entry:n}){const r=n.boundaryKind==="end"?"结束":"开始",s=n.conversationTurn??0,o=Zx(n.occurredAt??n.createdAt);return B.jsxs("div",{className:"translation-conversation-boundary","aria-label":`${r} 第 ${s} 轮 ${o}`,children:[B.jsx("span",{className:"translation-boundary-dash","aria-hidden":"true"}),B.jsx("span",{children:r}),B.jsxs("span",{children:["第 ",s," 轮"]}),B.jsx("time",{children:o}),B.jsx("span",{className:"translation-boundary-dash","aria-hidden":"true"})]})}function qx(n){const r=n.find(ih);return(r==null?void 0:r.translationStartedAt)??(r==null?void 0:r.createdAt)}function Vx(n,r,s){const o=n.find(ih);if(o)return`translating ${Xx(Math.max(0,s-$x(o)))}`;const p=n.at(-1);return(p==null?void 0:p.status)==="failed"||r==="failed"?"error":r}function ih(n){return n.status==="queued"||n.status==="translating"}function Gx(n){const r=n.length-Nx;if(r<=0)return{entries:n,removedIds:new Set};const s=new Set;for(const o of n){if(s.size>=r)break;ih(o)||s.add(o.id)}return s.size===0?{entries:n,removedIds:s}:{entries:n.filter(o=>!s.has(o.id)),removedIds:s}}function $x(n){const r=Date.parse(n.translationStartedAt??n.createdAt);return Number.isFinite(r)?r:Date.now()}function Yx(n){return n.status==="queued"||n.status==="translating"?n.sourceText:n.status==="translated"?n.direction==="user-input-to-english"?b_(n.sourceText,n.translatedText):n.translatedText:n.translatedText||n.sourceText}function b_(n,r){return`${n.trimEnd()}${Ba}${r.trimStart()}`}function Kx(n){return n.includes(Ba)}function Jm(n){const r=n.indexOf(Ba);return r===-1?n:n.slice(r+Ba.length)}function Wx(n,r){return n.findIndex(o=>o.id===r.id)===-1?[...n,r]:n.map(o=>o.id===r.id?r:o)}function Xx(n){if(n<1e3)return`${Math.max(.1,n/1e3).toFixed(1)}s`;const r=n/1e3;if(r<60)return`${r.toFixed(1)}s`;const s=Math.floor(r/60),o=Math.floor(r%60).toString().padStart(2,"0");return`${s}:${o}`}function Qx(n){const r=new Date(n);return Number.isNaN(r.getTime())?n:r.toLocaleTimeString()}function Zx(n){const r=new Date(n);return Number.isNaN(r.getTime())?n:r.toLocaleTimeString()}function Jx(n,r){return n.find(s=>s.taskSlug===r)??n[0]??null}const e2={role:"codex-reviewer",permissionMode:"default",model:"gpt-5.5",effort:"xhigh"};function t2(n,r){const s=Kr.map(o=>({role:o.name,permissionMode:n.roles[o.name].permissionMode,model:n.roles[o.name].model,effort:n.roles[o.name].effort}));return r.codexReviewerEnabled&&s.push(e2),s}const n2=["architecture-plan","validation-adequacy","final-diff"];function i2({events:n,maxEvents:r=8,showHeader:s=!0}){const o=r===null?n:n.slice(-r);return B.jsxs("section",{className:"event-log",children:[s?B.jsx("h2",{children:"Events"}):null,n.length===0?B.jsx("p",{className:"muted",children:"No terminal events yet."}):B.jsx("ol",{children:o.map((p,y)=>B.jsx("li",{children:p},`${p}-${y}`))})]})}var Su={exports:{}},eg;function r2(){return eg||(eg=1,(function(n,r){(function(s,o){n.exports=o()})(self,(()=>(()=>{var s={};return(()=>{var o=s;Object.defineProperty(o,"__esModule",{value:!0}),o.FitAddon=void 0,o.FitAddon=class{activate(p){this._terminal=p}dispose(){}fit(){const p=this.proposeDimensions();if(!p||!this._terminal||isNaN(p.cols)||isNaN(p.rows))return;const y=this._terminal._core;this._terminal.rows===p.rows&&this._terminal.cols===p.cols||(y._renderService.clear(),this._terminal.resize(p.cols,p.rows))}proposeDimensions(){if(!this._terminal||!this._terminal.element||!this._terminal.element.parentElement)return;const p=this._terminal._core,y=p._renderService.dimensions;if(y.css.cell.width===0||y.css.cell.height===0)return;const f=this._terminal.options.scrollback===0?0:p.viewport.scrollBarWidth,a=window.getComputedStyle(this._terminal.element.parentElement),c=parseInt(a.getPropertyValue("height")),h=Math.max(0,parseInt(a.getPropertyValue("width"))),d=window.getComputedStyle(this._terminal.element),u=c-(parseInt(d.getPropertyValue("padding-top"))+parseInt(d.getPropertyValue("padding-bottom"))),b=h-(parseInt(d.getPropertyValue("padding-right"))+parseInt(d.getPropertyValue("padding-left")))-f;return{cols:Math.max(2,Math.floor(b/y.css.cell.width)),rows:Math.max(1,Math.floor(u/y.css.cell.height))}}}})(),s})()))})(Su)),Su.exports}var s2=r2(),bu={exports:{}},tg;function l2(){return tg||(tg=1,(function(n,r){(function(s,o){n.exports=o()})(self,(()=>(()=>{var s={6:(f,a)=>{function c(d){try{const u=new URL(d),b=u.password&&u.username?`${u.protocol}//${u.username}:${u.password}@${u.host}`:u.username?`${u.protocol}//${u.username}@${u.host}`:`${u.protocol}//${u.host}`;return d.toLocaleLowerCase().startsWith(b.toLocaleLowerCase())}catch{return!1}}Object.defineProperty(a,"__esModule",{value:!0}),a.LinkComputer=a.WebLinkProvider=void 0,a.WebLinkProvider=class{constructor(d,u,b,w={}){this._terminal=d,this._regex=u,this._handler=b,this._options=w}provideLinks(d,u){const b=h.computeLink(d,this._regex,this._terminal,this._handler);u(this._addCallbacks(b))}_addCallbacks(d){return d.map((u=>(u.leave=this._options.leave,u.hover=(b,w)=>{if(this._options.hover){const{range:E}=u;this._options.hover(b,w,E)}},u)))}};class h{static computeLink(u,b,w,E){const x=new RegExp(b.source,(b.flags||"")+"g"),[v,S]=h._getWindowedLineStrings(u-1,w),g=v.join("");let _;const A=[];for(;_=x.exec(g);){const M=_[0];if(!c(M))continue;const[D,T]=h._mapStrIdx(w,S,0,_.index),[k,R]=h._mapStrIdx(w,D,T,M.length);if(D===-1||T===-1||k===-1||R===-1)continue;const N={start:{x:T+1,y:D+1},end:{x:R,y:k+1}};A.push({range:N,text:M,activate:E})}return A}static _getWindowedLineStrings(u,b){let w,E=u,x=u,v=0,S="";const g=[];if(w=b.buffer.active.getLine(u)){const _=w.translateToString(!0);if(w.isWrapped&&_[0]!==" "){for(v=0;(w=b.buffer.active.getLine(--E))&&v<2048&&(S=w.translateToString(!0),v+=S.length,g.push(S),w.isWrapped&&S.indexOf(" ")===-1););g.reverse()}for(g.push(_),v=0;(w=b.buffer.active.getLine(++x))&&w.isWrapped&&v<2048&&(S=w.translateToString(!0),v+=S.length,g.push(S),S.indexOf(" ")===-1););}return[g,E]}static _mapStrIdx(u,b,w,E){const x=u.buffer.active,v=x.getNullCell();let S=w;for(;E;){const g=x.getLine(b);if(!g)return[-1,-1];for(let _=S;_<g.length;++_){g.getCell(_,v);const A=v.getChars();if(v.getWidth()&&(E-=A.length||1,_===g.length-1&&A==="")){const M=x.getLine(b+1);M&&M.isWrapped&&(M.getCell(0,v),v.getWidth()===2&&(E+=1))}if(E<0)return[b,_]}b++,S=0}return[b,S]}}a.LinkComputer=h}},o={};function p(f){var a=o[f];if(a!==void 0)return a.exports;var c=o[f]={exports:{}};return s[f](c,c.exports,p),c.exports}var y={};return(()=>{var f=y;Object.defineProperty(f,"__esModule",{value:!0}),f.WebLinksAddon=void 0;const a=p(6),c=/(https?|HTTPS?):[/]{2}[^\s"'!*(){}|\\\^<>`]*[^\s"':,.!?{}|\\\^~\[\]`()<>]/;function h(d,u){const b=window.open();if(b){try{b.opener=null}catch{}b.location.href=u}else console.warn("Opening link blocked as opener could not be cleared")}f.WebLinksAddon=class{constructor(d=h,u={}){this._handler=d,this._options=u}activate(d){this._terminal=d;const u=this._options,b=u.urlRegex||c;this._linkProvider=this._terminal.registerLinkProvider(new a.WebLinkProvider(this._terminal,b,this._handler,u))}dispose(){var d;(d=this._linkProvider)==null||d.dispose()}}})(),y})()))})(bu)),bu.exports}var a2=l2(),Cu={exports:{}},ng;function o2(){return ng||(ng=1,(function(n,r){(function(s,o){n.exports=o()})(globalThis,(()=>(()=>{var s={4567:function(f,a,c){var h=this&&this.__decorate||function(g,_,A,M){var D,T=arguments.length,k=T<3?_:M===null?M=Object.getOwnPropertyDescriptor(_,A):M;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")k=Reflect.decorate(g,_,A,M);else for(var R=g.length-1;R>=0;R--)(D=g[R])&&(k=(T<3?D(k):T>3?D(_,A,k):D(_,A))||k);return T>3&&k&&Object.defineProperty(_,A,k),k},d=this&&this.__param||function(g,_){return function(A,M){_(A,M,g)}};Object.defineProperty(a,"__esModule",{value:!0}),a.AccessibilityManager=void 0;const u=c(9042),b=c(9924),w=c(844),E=c(4725),x=c(2585),v=c(3656);let S=a.AccessibilityManager=class extends w.Disposable{constructor(g,_,A,M){super(),this._terminal=g,this._coreBrowserService=A,this._renderService=M,this._rowColumns=new WeakMap,this._liveRegionLineCount=0,this._charsToConsume=[],this._charsToAnnounce="",this._accessibilityContainer=this._coreBrowserService.mainDocument.createElement("div"),this._accessibilityContainer.classList.add("xterm-accessibility"),this._rowContainer=this._coreBrowserService.mainDocument.createElement("div"),this._rowContainer.setAttribute("role","list"),this._rowContainer.classList.add("xterm-accessibility-tree"),this._rowElements=[];for(let D=0;D<this._terminal.rows;D++)this._rowElements[D]=this._createAccessibilityTreeNode(),this._rowContainer.appendChild(this._rowElements[D]);if(this._topBoundaryFocusListener=D=>this._handleBoundaryFocus(D,0),this._bottomBoundaryFocusListener=D=>this._handleBoundaryFocus(D,1),this._rowElements[0].addEventListener("focus",this._topBoundaryFocusListener),this._rowElements[this._rowElements.length-1].addEventListener("focus",this._bottomBoundaryFocusListener),this._refreshRowsDimensions(),this._accessibilityContainer.appendChild(this._rowContainer),this._liveRegion=this._coreBrowserService.mainDocument.createElement("div"),this._liveRegion.classList.add("live-region"),this._liveRegion.setAttribute("aria-live","assertive"),this._accessibilityContainer.appendChild(this._liveRegion),this._liveRegionDebouncer=this.register(new b.TimeBasedDebouncer(this._renderRows.bind(this))),!this._terminal.element)throw new Error("Cannot enable accessibility before Terminal.open");this._terminal.element.insertAdjacentElement("afterbegin",this._accessibilityContainer),this.register(this._terminal.onResize((D=>this._handleResize(D.rows)))),this.register(this._terminal.onRender((D=>this._refreshRows(D.start,D.end)))),this.register(this._terminal.onScroll((()=>this._refreshRows()))),this.register(this._terminal.onA11yChar((D=>this._handleChar(D)))),this.register(this._terminal.onLineFeed((()=>this._handleChar(`
|
|
82
|
+
`;function jx({active:n=!0,autoSendEnabled:r,targetLanguage:s,taskSlug:o,role:p,sessionId:y}){const[f,a]=he.useState([]),[c,h]=he.useState([]),[d,u]=he.useState(""),[b,w]=he.useState(!1),[E,x]=he.useState("ready"),[v,S]=he.useState(""),[g,_]=he.useState(Date.now()),[A,M]=he.useState(!1),[D,T]=he.useState(""),[k,R]=he.useState(0),N=he.useRef(n),I=he.useRef(1),P=he.useRef(null);he.useEffect(()=>{N.current=n},[n]),he.useEffect(()=>{a([]),h([]),T(""),x("ready"),S(""),I.current=1;let j=!1,ee;const ae=()=>{j||(ee=window.setTimeout(ge,N.current?200:1e3))},ge=async()=>{if(!j)try{const K=await Ce.pollTranslationSession(y,I.current);if(j)return;W(K.events),I.current=K.nextCursor,x(K.status),N.current&&S(Qx(new Date().toISOString()))}catch(K){j||T(K instanceof Error?K.message:"Translation poll failed.")}finally{ae()}};return Ce.startTranslationSession(o,p).then(K=>{j||(x(K.status),I.current=K.nextCursor,ge())}).catch(K=>{j||T(K instanceof Error?K.message:"Translation start failed.")}),()=>{j=!0,ee!==void 0&&window.clearTimeout(ee),Ce.stopTranslationSession(y).catch(()=>{})}},[y,o,p]),he.useEffect(()=>{if(!n)return;const j=P.current;if(!j)return;const ee=window.requestAnimationFrame(()=>{j.scrollTop=j.scrollHeight});return()=>window.cancelAnimationFrame(ee)},[n,k]);const F=qx(f);he.useEffect(()=>{if(!F)return;_(Date.now());const j=window.setInterval(()=>_(Date.now()),250);return()=>window.clearInterval(j)},[F]);async function Y(j=!1){const ee=d;M(!0),T(""),w(!1);try{const ae=await Ce.translateUserInput(o,p,{text:ee,mode:j?"auto-send":"review-before-send",useContext:!1,send:j});ae.sent?(u(""),w(!1)):(u(b_(ee,ae.englishPreview)),w(!0))}catch(ae){T(ae instanceof Error?ae.message:"Translation failed.")}finally{M(!1)}}function W(j){if(j.length===0)return;for(const ae of j)ae.type==="status"?x(ae.status):ae.type==="error"?T(ae.message):ae.type==="failures"&&h(ae.failures);const ee=j.filter(ae=>ae.type==="entry");ee.length>0&&(a(ae=>{const ge=ee.reduce((q,ce)=>Wx(q,ce.entry),ae),K=Gx(ge);return K.removedIds.size>0&&h(q=>q.filter(ce=>!K.removedIds.has(ce.translationId))),K.entries}),R(ae=>ae+1))}async function G(){const j=b?Jm(d):d;if(j.trim()){M(!0),T("");try{await Ce.sendTranslatedInput(o,p,{englishText:j}),u(""),w(!1)}catch(ee){T(ee instanceof Error?ee.message:"Failed to send English input.")}finally{M(!1)}}}function $(j){j.key!=="Enter"||j.shiftKey||j.nativeEvent.isComposing||(j.preventDefault(),!A&&d.trim()&&(b?G():Y(r)))}async function Q(){a([]),h([]),I.current=1,await Ce.clearTranslationSession(y).catch(j=>T(j.message))}async function H(){M(!0),T("");try{const j=await Ce.ignoreTranslationFailures(y);h(j.failures)}catch(j){T(j instanceof Error?j.message:"Failed to ignore translation failures.")}finally{M(!1)}}async function O(){M(!0),T("");try{const j=await Ce.retryTranslationFailures(y);h(j.failures)}catch(j){T(j instanceof Error?j.message:"Failed to retry translation failures.")}finally{M(!1)}}const z=Vx(f,E,g),V=c.length;return B.jsxs("aside",{className:"translation-panel",children:[B.jsxs("header",{className:"translation-panel-header",children:[B.jsxs("div",{className:"translation-panel-titlebar",children:[B.jsx("h2",{children:"Translation"}),B.jsxs("div",{className:"translation-panel-actions",children:[V>0?B.jsxs(B.Fragment,{children:[B.jsxs("button",{type:"button",disabled:A,onClick:()=>void H(),children:["Ignore ",V]}),B.jsxs("button",{type:"button",disabled:A,onClick:()=>void O(),children:["Retry ",V]})]}):null,B.jsx("button",{type:"button",onClick:()=>void Q(),children:"Clear"})]})]}),B.jsxs("div",{className:"translation-status-row",children:[B.jsxs("p",{children:["Codex · target ",zx(s)," · ",z]}),B.jsx("p",{children:v?`poll ${v}`:"poll -"})]})]}),D?B.jsx("div",{className:"error-banner",children:D}):null,B.jsxs("div",{className:"translation-entry-list",ref:P,children:[f.length===0?B.jsx("p",{className:"muted",children:"Translated Claude Code output will appear here."}):null,f.map(j=>B.jsx(Px,{entry:j},j.id))]}),B.jsx("div",{className:"translation-composer",children:B.jsxs("div",{className:"translation-composer-row",children:[B.jsx("textarea",{value:d,onChange:j=>{u(j.target.value),(!j.target.value.trim()||b&&!Kx(j.target.value))&&w(!1)},onKeyDown:$,placeholder:"输入中文,先翻译成英文工程指令..."}),B.jsx("div",{className:"translation-composer-actions",children:B.jsx("button",{type:"button",disabled:A||!b||!Jm(d).trim(),onClick:()=>void G(),children:"Send English"})})]})})]})}function zx(n){var r;return((r=pg.find(s=>s.value===n))==null?void 0:r.label)??n}function Hx({open:n,taskSlug:r,targetLanguage:s,onClose:o}){const[p,y]=he.useState(!1),[f,a]=he.useState(""),[c,h]=he.useState(null),[d,u]=he.useState(""),[b,w]=he.useState(""),[E,x]=he.useState(""),[v,S]=he.useState(!1),[g,_]=he.useState(null),[A,M]=he.useState(""),[D,T]=he.useState(""),[k,R]=he.useState(""),[N,I]=he.useState(!1);he.useEffect(()=>{if(!n)return;let $=!1,Q;const H=async()=>{$||(await P(!0),$||(Q=window.setTimeout(H,2e3)))};return H(),()=>{$=!0,Q!==void 0&&window.clearTimeout(Q)}},[n,d]);async function P($=!1){try{const Q=await Ce.getCodexTranslationState();h(Q);const H=d?Q.fileIndex.jobs.some(O=>O.id===d):!1;if((!d||!H)&&Q.fileIndex.jobs[0])F(Q.fileIndex.jobs[0].id);else if(!Q.fileIndex.jobs[0])u(""),w(""),x("");else if($&&d){const O=await Ce.readCodexFileTranslation(d);w(O.output),x(O.report)}}catch(Q){a(Q instanceof Error?Q.message:"Failed to load file translations.")}}async function F($){u($),w(""),x("");try{const Q=await Ce.readCodexFileTranslation($);w(Q.output),x(Q.report)}catch(Q){a(Q instanceof Error?Q.message:"Failed to read translated file.")}}async function Y(){S(!0),await W(A,D)}async function W($="",Q=""){I(!0),a("");try{const H=await Ce.browseCodexTranslationSourceFiles({path:$,query:Q,limit:250});_(H),M(H.currentPath),T(Q)}catch(H){a(H instanceof Error?H.message:"Failed to browse source files.")}finally{I(!1)}}async function G($=k){const Q=$.trim();if(!(!Q||!r)){y(!0),a("");try{const H=await Ce.createCodexFileTranslation({taskSlug:r,sourcePath:Q,targetLanguage:s});S(!1),await P(),await F(H.id)}catch(H){a(H instanceof Error?H.message:"Failed to create file translation.")}finally{y(!1)}}}return n?B.jsxs(B.Fragment,{children:[B.jsx("div",{className:"modal-backdrop file-translation-backdrop",children:B.jsx(Ux,{busy:p,error:f,state:c,selectedJobId:d,output:b,report:E,onClose:()=>{S(!1),o()},onRefresh:()=>void P(),onSelectJob:$=>void F($),onTranslate:()=>void Y()})}),v?B.jsx(Ix,{busy:p||N,state:g,currentPath:A,query:D,selectedPath:k,onBrowse:($,Q)=>void W($,Q),onClose:()=>S(!1),onQueryChange:T,onSelectPath:R,onTranslate:()=>void G()}):null]}):null}function Ix({busy:n,state:r,currentPath:s,query:o,selectedPath:p,onBrowse:y,onClose:f,onQueryChange:a,onSelectPath:c,onTranslate:h}){const d=(r==null?void 0:r.entries)??[],u=d.filter(w=>w.type==="directory"),b=d.filter(w=>w.type==="file");return B.jsx("div",{className:"modal-backdrop translation-file-browser-backdrop",children:B.jsxs("section",{className:"translation-file-browser-modal",role:"dialog","aria-modal":"true","aria-label":"Select Source File",children:[B.jsxs("header",{children:[B.jsxs("div",{children:[B.jsx("h2",{children:"Select Source File"}),B.jsx("p",{children:s||"."})]}),B.jsx("button",{type:"button",onClick:f,children:"Close"})]}),B.jsxs("div",{className:"translation-file-browser-controls",children:[B.jsxs("div",{className:"translation-file-browser-nav",children:[B.jsx("button",{type:"button",disabled:n||!s,onClick:()=>y((r==null?void 0:r.parentPath)??"",""),children:"Up"}),B.jsx("button",{type:"button",disabled:n||!s,onClick:()=>y("",""),children:"Root"})]}),B.jsxs("form",{className:"translation-file-browser-search",onSubmit:w=>{w.preventDefault(),y(s,o)},children:[B.jsx("input",{value:o,onChange:w=>a(w.target.value),placeholder:"Search files"}),B.jsx("button",{type:"submit",disabled:n,children:"Search"}),B.jsx("button",{type:"button",disabled:n||!o,onClick:()=>y(s,""),children:"Clear"})]})]}),B.jsxs("div",{className:"translation-file-browser-layout",children:[B.jsxs("div",{className:"translation-file-browser-list",children:[n&&!r?B.jsx("p",{className:"muted",children:"Loading files..."}):null,!n&&d.length===0?B.jsx("p",{className:"muted",children:"No source files found."}):null,u.length>0?B.jsxs("div",{className:"translation-file-browser-group",children:[B.jsx("h3",{children:"Folders"}),u.map(w=>B.jsx(Zm,{entry:w,selected:p===w.path,onBrowse:y,onSelectPath:c},w.path))]}):null,b.length>0?B.jsxs("div",{className:"translation-file-browser-group",children:[B.jsx("h3",{children:"Files"}),b.map(w=>B.jsx(Zm,{entry:w,selected:p===w.path,onBrowse:y,onSelectPath:c},w.path))]}):null,r!=null&&r.truncated?B.jsx("p",{className:"translation-entry-note",children:"Result limit reached."}):null]}),B.jsxs("aside",{className:"translation-file-browser-selection",children:[B.jsxs("label",{children:[B.jsx("span",{children:"Source path"}),B.jsx("input",{value:p,onChange:w=>c(w.target.value)})]}),B.jsx("button",{type:"button",disabled:n||!p.trim(),onClick:h,children:"Translate File"})]})]})]})})}function Zm({entry:n,selected:r,onBrowse:s,onSelectPath:o}){const p=n.type==="directory";return B.jsxs("button",{className:r?"translation-file-browser-entry is-selected":"translation-file-browser-entry",type:"button",onClick:()=>p?s(n.path,""):o(n.path),onDoubleClick:()=>p?s(n.path,""):void 0,children:[B.jsx("span",{children:p?"DIR":"FILE"}),B.jsx("strong",{children:n.name}),B.jsx("small",{children:n.path})]})}function Ux({busy:n,error:r,state:s,selectedJobId:o,output:p,report:y,onClose:f,onRefresh:a,onSelectJob:c,onTranslate:h}){const d=(s==null?void 0:s.fileIndex.jobs)??[],u=d.find(b=>b.id===o);return B.jsxs("section",{className:"file-translation-modal",role:"dialog","aria-modal":"true","aria-label":"File Translation",children:[B.jsxs("header",{className:"file-translation-header",children:[B.jsxs("div",{children:[B.jsx("h2",{children:"File Translation"}),B.jsx("p",{children:"Codex · 中英互译"})]}),B.jsxs("div",{className:"file-translation-toolbar",children:[B.jsx("button",{type:"button",disabled:n,onClick:h,children:"Translate"}),B.jsx("button",{type:"button",disabled:n,onClick:a,children:"Refresh"}),B.jsx("button",{type:"button",onClick:f,children:"Close"})]})]}),r?B.jsx("div",{className:"error-banner",children:r}):null,s!=null&&s.memoryInitialized?null:B.jsx("p",{className:"translation-entry-note",children:"Translation memory is not initialized. Run Bootstrap from the sidebar before important file translations."}),B.jsxs("div",{className:"file-translation-layout",children:[B.jsxs("div",{className:"file-translation-list",children:[d.length===0?B.jsx("p",{className:"muted",children:"No translated files yet."}):null,d.map(b=>B.jsxs("button",{className:b.id===o?"file-translation-item is-active":"file-translation-item",type:"button",onClick:()=>c(b.id),children:[B.jsx("strong",{children:b.sourcePath}),B.jsxs("span",{children:[b.status," · ",b.targetLanguage]})]},b.id))]}),B.jsx("div",{className:"file-translation-preview",children:u?B.jsxs(B.Fragment,{children:[B.jsxs("header",{children:[B.jsx("strong",{children:u.sourcePath}),B.jsx("span",{children:u.status})]}),B.jsx("div",{className:"translation-markdown",children:B.jsx(Xg,{remarkPlugins:[S_],children:p||y||"Translation output is not available yet."})})]}):B.jsx("p",{className:"muted",children:"Select a translated file to preview it."})})]})]})}function Px({entry:n}){if(n.sourceKind==="conversation-boundary")return B.jsx(Fx,{entry:n});const r=Yx(n),s=n.sourceKind==="tool-output",o=n.direction==="user-input-to-english",p=["translation-entry",`is-${n.sourceKind}`,o?"is-user-input":""].filter(Boolean).join(" ");return B.jsxs("article",{className:p,children:[s?B.jsx("pre",{children:r}):B.jsx("div",{className:"translation-markdown",children:B.jsx(Xg,{remarkPlugins:[S_],children:r})}),n.warning?B.jsx("p",{className:"translation-entry-note",children:n.warning}):null,n.error?B.jsx("p",{className:"translation-entry-note is-error",children:n.error}):null]})}function Fx({entry:n}){const r=n.boundaryKind==="end"?"结束":"开始",s=n.conversationTurn??0,o=Zx(n.occurredAt??n.createdAt);return B.jsxs("div",{className:"translation-conversation-boundary","aria-label":`${r} 第 ${s} 轮 ${o}`,children:[B.jsx("span",{className:"translation-boundary-dash","aria-hidden":"true"}),B.jsx("span",{children:r}),B.jsxs("span",{children:["第 ",s," 轮"]}),B.jsx("time",{children:o}),B.jsx("span",{className:"translation-boundary-dash","aria-hidden":"true"})]})}function qx(n){const r=n.find(ih);return(r==null?void 0:r.translationStartedAt)??(r==null?void 0:r.createdAt)}function Vx(n,r,s){const o=n.find(ih);if(o)return`translating ${Xx(Math.max(0,s-$x(o)))}`;const p=n.at(-1);return(p==null?void 0:p.status)==="failed"||r==="failed"?"error":r}function ih(n){return n.status==="queued"||n.status==="translating"}function Gx(n){const r=n.length-Nx;if(r<=0)return{entries:n,removedIds:new Set};const s=new Set;for(const o of n){if(s.size>=r)break;ih(o)||s.add(o.id)}return s.size===0?{entries:n,removedIds:s}:{entries:n.filter(o=>!s.has(o.id)),removedIds:s}}function $x(n){const r=Date.parse(n.translationStartedAt??n.createdAt);return Number.isFinite(r)?r:Date.now()}function Yx(n){return n.status==="queued"||n.status==="translating"?n.sourceText:n.status==="translated"?n.direction==="user-input-to-english"?b_(n.sourceText,n.translatedText):n.translatedText:n.translatedText||n.sourceText}function b_(n,r){return`${n.trimEnd()}${Ba}${r.trimStart()}`}function Kx(n){return n.includes(Ba)}function Jm(n){const r=n.indexOf(Ba);return r===-1?n:n.slice(r+Ba.length)}function Wx(n,r){return n.findIndex(o=>o.id===r.id)===-1?[...n,r]:n.map(o=>o.id===r.id?r:o)}function Xx(n){if(n<1e3)return`${Math.max(.1,n/1e3).toFixed(1)}s`;const r=n/1e3;if(r<60)return`${r.toFixed(1)}s`;const s=Math.floor(r/60),o=Math.floor(r%60).toString().padStart(2,"0");return`${s}:${o}`}function Qx(n){const r=new Date(n);return Number.isNaN(r.getTime())?n:r.toLocaleTimeString()}function Zx(n){const r=new Date(n);return Number.isNaN(r.getTime())?n:r.toLocaleTimeString()}function Jx(n,r){return n.find(s=>s.taskSlug===r)??n[0]??null}const e2={role:"codex-reviewer",permissionMode:"default",model:"gpt-5.5",effort:"xhigh"};function t2(n,r){const s=Kr.map(o=>({role:o.name,permissionMode:n.roles[o.name].permissionMode,model:n.roles[o.name].model,effort:n.roles[o.name].effort}));return r.codexReviewerEnabled&&s.push(e2),s}const n2=["architecture-plan","validation-adequacy","final-diff"];function i2({events:n,maxEvents:r=8,showHeader:s=!0}){const o=r===null?n:n.slice(-r);return B.jsxs("section",{className:"event-log",children:[s?B.jsx("h2",{children:"Events"}):null,n.length===0?B.jsx("p",{className:"muted",children:"No terminal events yet."}):B.jsx("ol",{children:o.map((p,y)=>B.jsx("li",{children:p},`${p}-${y}`))})]})}var Su={exports:{}},eg;function r2(){return eg||(eg=1,(function(n,r){(function(s,o){n.exports=o()})(self,(()=>(()=>{var s={};return(()=>{var o=s;Object.defineProperty(o,"__esModule",{value:!0}),o.FitAddon=void 0,o.FitAddon=class{activate(p){this._terminal=p}dispose(){}fit(){const p=this.proposeDimensions();if(!p||!this._terminal||isNaN(p.cols)||isNaN(p.rows))return;const y=this._terminal._core;this._terminal.rows===p.rows&&this._terminal.cols===p.cols||(y._renderService.clear(),this._terminal.resize(p.cols,p.rows))}proposeDimensions(){if(!this._terminal||!this._terminal.element||!this._terminal.element.parentElement)return;const p=this._terminal._core,y=p._renderService.dimensions;if(y.css.cell.width===0||y.css.cell.height===0)return;const f=this._terminal.options.scrollback===0?0:p.viewport.scrollBarWidth,a=window.getComputedStyle(this._terminal.element.parentElement),c=parseInt(a.getPropertyValue("height")),h=Math.max(0,parseInt(a.getPropertyValue("width"))),d=window.getComputedStyle(this._terminal.element),u=c-(parseInt(d.getPropertyValue("padding-top"))+parseInt(d.getPropertyValue("padding-bottom"))),b=h-(parseInt(d.getPropertyValue("padding-right"))+parseInt(d.getPropertyValue("padding-left")))-f;return{cols:Math.max(2,Math.floor(b/y.css.cell.width)),rows:Math.max(1,Math.floor(u/y.css.cell.height))}}}})(),s})()))})(Su)),Su.exports}var s2=r2(),bu={exports:{}},tg;function l2(){return tg||(tg=1,(function(n,r){(function(s,o){n.exports=o()})(self,(()=>(()=>{var s={6:(f,a)=>{function c(d){try{const u=new URL(d),b=u.password&&u.username?`${u.protocol}//${u.username}:${u.password}@${u.host}`:u.username?`${u.protocol}//${u.username}@${u.host}`:`${u.protocol}//${u.host}`;return d.toLocaleLowerCase().startsWith(b.toLocaleLowerCase())}catch{return!1}}Object.defineProperty(a,"__esModule",{value:!0}),a.LinkComputer=a.WebLinkProvider=void 0,a.WebLinkProvider=class{constructor(d,u,b,w={}){this._terminal=d,this._regex=u,this._handler=b,this._options=w}provideLinks(d,u){const b=h.computeLink(d,this._regex,this._terminal,this._handler);u(this._addCallbacks(b))}_addCallbacks(d){return d.map((u=>(u.leave=this._options.leave,u.hover=(b,w)=>{if(this._options.hover){const{range:E}=u;this._options.hover(b,w,E)}},u)))}};class h{static computeLink(u,b,w,E){const x=new RegExp(b.source,(b.flags||"")+"g"),[v,S]=h._getWindowedLineStrings(u-1,w),g=v.join("");let _;const A=[];for(;_=x.exec(g);){const M=_[0];if(!c(M))continue;const[D,T]=h._mapStrIdx(w,S,0,_.index),[k,R]=h._mapStrIdx(w,D,T,M.length);if(D===-1||T===-1||k===-1||R===-1)continue;const N={start:{x:T+1,y:D+1},end:{x:R,y:k+1}};A.push({range:N,text:M,activate:E})}return A}static _getWindowedLineStrings(u,b){let w,E=u,x=u,v=0,S="";const g=[];if(w=b.buffer.active.getLine(u)){const _=w.translateToString(!0);if(w.isWrapped&&_[0]!==" "){for(v=0;(w=b.buffer.active.getLine(--E))&&v<2048&&(S=w.translateToString(!0),v+=S.length,g.push(S),w.isWrapped&&S.indexOf(" ")===-1););g.reverse()}for(g.push(_),v=0;(w=b.buffer.active.getLine(++x))&&w.isWrapped&&v<2048&&(S=w.translateToString(!0),v+=S.length,g.push(S),S.indexOf(" ")===-1););}return[g,E]}static _mapStrIdx(u,b,w,E){const x=u.buffer.active,v=x.getNullCell();let S=w;for(;E;){const g=x.getLine(b);if(!g)return[-1,-1];for(let _=S;_<g.length;++_){g.getCell(_,v);const A=v.getChars();if(v.getWidth()&&(E-=A.length||1,_===g.length-1&&A==="")){const M=x.getLine(b+1);M&&M.isWrapped&&(M.getCell(0,v),v.getWidth()===2&&(E+=1))}if(E<0)return[b,_]}b++,S=0}return[b,S]}}a.LinkComputer=h}},o={};function p(f){var a=o[f];if(a!==void 0)return a.exports;var c=o[f]={exports:{}};return s[f](c,c.exports,p),c.exports}var y={};return(()=>{var f=y;Object.defineProperty(f,"__esModule",{value:!0}),f.WebLinksAddon=void 0;const a=p(6),c=/(https?|HTTPS?):[/]{2}[^\s"'!*(){}|\\\^<>`]*[^\s"':,.!?{}|\\\^~\[\]`()<>]/;function h(d,u){const b=window.open();if(b){try{b.opener=null}catch{}b.location.href=u}else console.warn("Opening link blocked as opener could not be cleared")}f.WebLinksAddon=class{constructor(d=h,u={}){this._handler=d,this._options=u}activate(d){this._terminal=d;const u=this._options,b=u.urlRegex||c;this._linkProvider=this._terminal.registerLinkProvider(new a.WebLinkProvider(this._terminal,b,this._handler,u))}dispose(){var d;(d=this._linkProvider)==null||d.dispose()}}})(),y})()))})(bu)),bu.exports}var a2=l2(),Cu={exports:{}},ng;function o2(){return ng||(ng=1,(function(n,r){(function(s,o){n.exports=o()})(globalThis,(()=>(()=>{var s={4567:function(f,a,c){var h=this&&this.__decorate||function(g,_,A,M){var D,T=arguments.length,k=T<3?_:M===null?M=Object.getOwnPropertyDescriptor(_,A):M;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")k=Reflect.decorate(g,_,A,M);else for(var R=g.length-1;R>=0;R--)(D=g[R])&&(k=(T<3?D(k):T>3?D(_,A,k):D(_,A))||k);return T>3&&k&&Object.defineProperty(_,A,k),k},d=this&&this.__param||function(g,_){return function(A,M){_(A,M,g)}};Object.defineProperty(a,"__esModule",{value:!0}),a.AccessibilityManager=void 0;const u=c(9042),b=c(9924),w=c(844),E=c(4725),x=c(2585),v=c(3656);let S=a.AccessibilityManager=class extends w.Disposable{constructor(g,_,A,M){super(),this._terminal=g,this._coreBrowserService=A,this._renderService=M,this._rowColumns=new WeakMap,this._liveRegionLineCount=0,this._charsToConsume=[],this._charsToAnnounce="",this._accessibilityContainer=this._coreBrowserService.mainDocument.createElement("div"),this._accessibilityContainer.classList.add("xterm-accessibility"),this._rowContainer=this._coreBrowserService.mainDocument.createElement("div"),this._rowContainer.setAttribute("role","list"),this._rowContainer.classList.add("xterm-accessibility-tree"),this._rowElements=[];for(let D=0;D<this._terminal.rows;D++)this._rowElements[D]=this._createAccessibilityTreeNode(),this._rowContainer.appendChild(this._rowElements[D]);if(this._topBoundaryFocusListener=D=>this._handleBoundaryFocus(D,0),this._bottomBoundaryFocusListener=D=>this._handleBoundaryFocus(D,1),this._rowElements[0].addEventListener("focus",this._topBoundaryFocusListener),this._rowElements[this._rowElements.length-1].addEventListener("focus",this._bottomBoundaryFocusListener),this._refreshRowsDimensions(),this._accessibilityContainer.appendChild(this._rowContainer),this._liveRegion=this._coreBrowserService.mainDocument.createElement("div"),this._liveRegion.classList.add("live-region"),this._liveRegion.setAttribute("aria-live","assertive"),this._accessibilityContainer.appendChild(this._liveRegion),this._liveRegionDebouncer=this.register(new b.TimeBasedDebouncer(this._renderRows.bind(this))),!this._terminal.element)throw new Error("Cannot enable accessibility before Terminal.open");this._terminal.element.insertAdjacentElement("afterbegin",this._accessibilityContainer),this.register(this._terminal.onResize((D=>this._handleResize(D.rows)))),this.register(this._terminal.onRender((D=>this._refreshRows(D.start,D.end)))),this.register(this._terminal.onScroll((()=>this._refreshRows()))),this.register(this._terminal.onA11yChar((D=>this._handleChar(D)))),this.register(this._terminal.onLineFeed((()=>this._handleChar(`
|
|
83
83
|
`)))),this.register(this._terminal.onA11yTab((D=>this._handleTab(D)))),this.register(this._terminal.onKey((D=>this._handleKey(D.key)))),this.register(this._terminal.onBlur((()=>this._clearLiveRegion()))),this.register(this._renderService.onDimensionsChange((()=>this._refreshRowsDimensions()))),this.register((0,v.addDisposableDomListener)(document,"selectionchange",(()=>this._handleSelectionChange()))),this.register(this._coreBrowserService.onDprChange((()=>this._refreshRowsDimensions()))),this._refreshRows(),this.register((0,w.toDisposable)((()=>{this._accessibilityContainer.remove(),this._rowElements.length=0})))}_handleTab(g){for(let _=0;_<g;_++)this._handleChar(" ")}_handleChar(g){this._liveRegionLineCount<21&&(this._charsToConsume.length>0?this._charsToConsume.shift()!==g&&(this._charsToAnnounce+=g):this._charsToAnnounce+=g,g===`
|
|
84
84
|
`&&(this._liveRegionLineCount++,this._liveRegionLineCount===21&&(this._liveRegion.textContent+=u.tooMuchOutput)))}_clearLiveRegion(){this._liveRegion.textContent="",this._liveRegionLineCount=0}_handleKey(g){this._clearLiveRegion(),new RegExp("\\p{Control}","u").test(g)||this._charsToConsume.push(g)}_refreshRows(g,_){this._liveRegionDebouncer.refresh(g,_,this._terminal.rows)}_renderRows(g,_){const A=this._terminal.buffer,M=A.lines.length.toString();for(let D=g;D<=_;D++){const T=A.lines.get(A.ydisp+D),k=[],R=(T==null?void 0:T.translateToString(!0,void 0,void 0,k))||"",N=(A.ydisp+D+1).toString(),I=this._rowElements[D];I&&(R.length===0?(I.innerText=" ",this._rowColumns.set(I,[0,1])):(I.textContent=R,this._rowColumns.set(I,k)),I.setAttribute("aria-posinset",N),I.setAttribute("aria-setsize",M))}this._announceCharacters()}_announceCharacters(){this._charsToAnnounce.length!==0&&(this._liveRegion.textContent+=this._charsToAnnounce,this._charsToAnnounce="")}_handleBoundaryFocus(g,_){const A=g.target,M=this._rowElements[_===0?1:this._rowElements.length-2];if(A.getAttribute("aria-posinset")===(_===0?"1":`${this._terminal.buffer.lines.length}`)||g.relatedTarget!==M)return;let D,T;if(_===0?(D=A,T=this._rowElements.pop(),this._rowContainer.removeChild(T)):(D=this._rowElements.shift(),T=A,this._rowContainer.removeChild(D)),D.removeEventListener("focus",this._topBoundaryFocusListener),T.removeEventListener("focus",this._bottomBoundaryFocusListener),_===0){const k=this._createAccessibilityTreeNode();this._rowElements.unshift(k),this._rowContainer.insertAdjacentElement("afterbegin",k)}else{const k=this._createAccessibilityTreeNode();this._rowElements.push(k),this._rowContainer.appendChild(k)}this._rowElements[0].addEventListener("focus",this._topBoundaryFocusListener),this._rowElements[this._rowElements.length-1].addEventListener("focus",this._bottomBoundaryFocusListener),this._terminal.scrollLines(_===0?-1:1),this._rowElements[_===0?1:this._rowElements.length-2].focus(),g.preventDefault(),g.stopImmediatePropagation()}_handleSelectionChange(){var R;if(this._rowElements.length===0)return;const g=document.getSelection();if(!g)return;if(g.isCollapsed)return void(this._rowContainer.contains(g.anchorNode)&&this._terminal.clearSelection());if(!g.anchorNode||!g.focusNode)return void console.error("anchorNode and/or focusNode are null");let _={node:g.anchorNode,offset:g.anchorOffset},A={node:g.focusNode,offset:g.focusOffset};if((_.node.compareDocumentPosition(A.node)&Node.DOCUMENT_POSITION_PRECEDING||_.node===A.node&&_.offset>A.offset)&&([_,A]=[A,_]),_.node.compareDocumentPosition(this._rowElements[0])&(Node.DOCUMENT_POSITION_CONTAINED_BY|Node.DOCUMENT_POSITION_FOLLOWING)&&(_={node:this._rowElements[0].childNodes[0],offset:0}),!this._rowContainer.contains(_.node))return;const M=this._rowElements.slice(-1)[0];if(A.node.compareDocumentPosition(M)&(Node.DOCUMENT_POSITION_CONTAINED_BY|Node.DOCUMENT_POSITION_PRECEDING)&&(A={node:M,offset:((R=M.textContent)==null?void 0:R.length)??0}),!this._rowContainer.contains(A.node))return;const D=({node:N,offset:I})=>{const P=N instanceof Text?N.parentNode:N;let F=parseInt(P==null?void 0:P.getAttribute("aria-posinset"),10)-1;if(isNaN(F))return console.warn("row is invalid. Race condition?"),null;const Y=this._rowColumns.get(P);if(!Y)return console.warn("columns is null. Race condition?"),null;let W=I<Y.length?Y[I]:Y.slice(-1)[0]+1;return W>=this._terminal.cols&&(++F,W=0),{row:F,column:W}},T=D(_),k=D(A);if(T&&k){if(T.row>k.row||T.row===k.row&&T.column>=k.column)throw new Error("invalid range");this._terminal.select(T.column,T.row,(k.row-T.row)*this._terminal.cols-T.column+k.column)}}_handleResize(g){this._rowElements[this._rowElements.length-1].removeEventListener("focus",this._bottomBoundaryFocusListener);for(let _=this._rowContainer.children.length;_<this._terminal.rows;_++)this._rowElements[_]=this._createAccessibilityTreeNode(),this._rowContainer.appendChild(this._rowElements[_]);for(;this._rowElements.length>g;)this._rowContainer.removeChild(this._rowElements.pop());this._rowElements[this._rowElements.length-1].addEventListener("focus",this._bottomBoundaryFocusListener),this._refreshRowsDimensions()}_createAccessibilityTreeNode(){const g=this._coreBrowserService.mainDocument.createElement("div");return g.setAttribute("role","listitem"),g.tabIndex=-1,this._refreshRowDimensions(g),g}_refreshRowsDimensions(){if(this._renderService.dimensions.css.cell.height){this._accessibilityContainer.style.width=`${this._renderService.dimensions.css.canvas.width}px`,this._rowElements.length!==this._terminal.rows&&this._handleResize(this._terminal.rows);for(let g=0;g<this._terminal.rows;g++)this._refreshRowDimensions(this._rowElements[g])}}_refreshRowDimensions(g){g.style.height=`${this._renderService.dimensions.css.cell.height}px`}};a.AccessibilityManager=S=h([d(1,x.IInstantiationService),d(2,E.ICoreBrowserService),d(3,E.IRenderService)],S)},3614:(f,a)=>{function c(b){return b.replace(/\r?\n/g,"\r")}function h(b,w){return w?"\x1B[200~"+b+"\x1B[201~":b}function d(b,w,E,x){b=h(b=c(b),E.decPrivateModes.bracketedPasteMode&&x.rawOptions.ignoreBracketedPasteMode!==!0),E.triggerDataEvent(b,!0),w.value=""}function u(b,w,E){const x=E.getBoundingClientRect(),v=b.clientX-x.left-10,S=b.clientY-x.top-10;w.style.width="20px",w.style.height="20px",w.style.left=`${v}px`,w.style.top=`${S}px`,w.style.zIndex="1000",w.focus()}Object.defineProperty(a,"__esModule",{value:!0}),a.rightClickHandler=a.moveTextAreaUnderMouseCursor=a.paste=a.handlePasteEvent=a.copyHandler=a.bracketTextForPaste=a.prepareTextForTerminal=void 0,a.prepareTextForTerminal=c,a.bracketTextForPaste=h,a.copyHandler=function(b,w){b.clipboardData&&b.clipboardData.setData("text/plain",w.selectionText),b.preventDefault()},a.handlePasteEvent=function(b,w,E,x){b.stopPropagation(),b.clipboardData&&d(b.clipboardData.getData("text/plain"),w,E,x)},a.paste=d,a.moveTextAreaUnderMouseCursor=u,a.rightClickHandler=function(b,w,E,x,v){u(b,w,E),v&&x.rightClickSelect(b),w.value=x.selectionText,w.select()}},7239:(f,a,c)=>{Object.defineProperty(a,"__esModule",{value:!0}),a.ColorContrastCache=void 0;const h=c(1505);a.ColorContrastCache=class{constructor(){this._color=new h.TwoKeyMap,this._css=new h.TwoKeyMap}setCss(d,u,b){this._css.set(d,u,b)}getCss(d,u){return this._css.get(d,u)}setColor(d,u,b){this._color.set(d,u,b)}getColor(d,u){return this._color.get(d,u)}clear(){this._color.clear(),this._css.clear()}}},3656:(f,a)=>{Object.defineProperty(a,"__esModule",{value:!0}),a.addDisposableDomListener=void 0,a.addDisposableDomListener=function(c,h,d,u){c.addEventListener(h,d,u);let b=!1;return{dispose:()=>{b||(b=!0,c.removeEventListener(h,d,u))}}}},3551:function(f,a,c){var h=this&&this.__decorate||function(S,g,_,A){var M,D=arguments.length,T=D<3?g:A===null?A=Object.getOwnPropertyDescriptor(g,_):A;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")T=Reflect.decorate(S,g,_,A);else for(var k=S.length-1;k>=0;k--)(M=S[k])&&(T=(D<3?M(T):D>3?M(g,_,T):M(g,_))||T);return D>3&&T&&Object.defineProperty(g,_,T),T},d=this&&this.__param||function(S,g){return function(_,A){g(_,A,S)}};Object.defineProperty(a,"__esModule",{value:!0}),a.Linkifier=void 0;const u=c(3656),b=c(8460),w=c(844),E=c(2585),x=c(4725);let v=a.Linkifier=class extends w.Disposable{get currentLink(){return this._currentLink}constructor(S,g,_,A,M){super(),this._element=S,this._mouseService=g,this._renderService=_,this._bufferService=A,this._linkProviderService=M,this._linkCacheDisposables=[],this._isMouseOut=!0,this._wasResized=!1,this._activeLine=-1,this._onShowLinkUnderline=this.register(new b.EventEmitter),this.onShowLinkUnderline=this._onShowLinkUnderline.event,this._onHideLinkUnderline=this.register(new b.EventEmitter),this.onHideLinkUnderline=this._onHideLinkUnderline.event,this.register((0,w.getDisposeArrayDisposable)(this._linkCacheDisposables)),this.register((0,w.toDisposable)((()=>{var D;this._lastMouseEvent=void 0,(D=this._activeProviderReplies)==null||D.clear()}))),this.register(this._bufferService.onResize((()=>{this._clearCurrentLink(),this._wasResized=!0}))),this.register((0,u.addDisposableDomListener)(this._element,"mouseleave",(()=>{this._isMouseOut=!0,this._clearCurrentLink()}))),this.register((0,u.addDisposableDomListener)(this._element,"mousemove",this._handleMouseMove.bind(this))),this.register((0,u.addDisposableDomListener)(this._element,"mousedown",this._handleMouseDown.bind(this))),this.register((0,u.addDisposableDomListener)(this._element,"mouseup",this._handleMouseUp.bind(this)))}_handleMouseMove(S){this._lastMouseEvent=S;const g=this._positionFromMouseEvent(S,this._element,this._mouseService);if(!g)return;this._isMouseOut=!1;const _=S.composedPath();for(let A=0;A<_.length;A++){const M=_[A];if(M.classList.contains("xterm"))break;if(M.classList.contains("xterm-hover"))return}this._lastBufferCell&&g.x===this._lastBufferCell.x&&g.y===this._lastBufferCell.y||(this._handleHover(g),this._lastBufferCell=g)}_handleHover(S){if(this._activeLine!==S.y||this._wasResized)return this._clearCurrentLink(),this._askForLink(S,!1),void(this._wasResized=!1);this._currentLink&&this._linkAtPosition(this._currentLink.link,S)||(this._clearCurrentLink(),this._askForLink(S,!0))}_askForLink(S,g){var A,M;this._activeProviderReplies&&g||((A=this._activeProviderReplies)==null||A.forEach((D=>{D==null||D.forEach((T=>{T.link.dispose&&T.link.dispose()}))})),this._activeProviderReplies=new Map,this._activeLine=S.y);let _=!1;for(const[D,T]of this._linkProviderService.linkProviders.entries())g?(M=this._activeProviderReplies)!=null&&M.get(D)&&(_=this._checkLinkProviderResult(D,S,_)):T.provideLinks(S.y,(k=>{var N,I;if(this._isMouseOut)return;const R=k==null?void 0:k.map((P=>({link:P})));(N=this._activeProviderReplies)==null||N.set(D,R),_=this._checkLinkProviderResult(D,S,_),((I=this._activeProviderReplies)==null?void 0:I.size)===this._linkProviderService.linkProviders.length&&this._removeIntersectingLinks(S.y,this._activeProviderReplies)}))}_removeIntersectingLinks(S,g){const _=new Set;for(let A=0;A<g.size;A++){const M=g.get(A);if(M)for(let D=0;D<M.length;D++){const T=M[D],k=T.link.range.start.y<S?0:T.link.range.start.x,R=T.link.range.end.y>S?this._bufferService.cols:T.link.range.end.x;for(let N=k;N<=R;N++){if(_.has(N)){M.splice(D--,1);break}_.add(N)}}}}_checkLinkProviderResult(S,g,_){var D;if(!this._activeProviderReplies)return _;const A=this._activeProviderReplies.get(S);let M=!1;for(let T=0;T<S;T++)this._activeProviderReplies.has(T)&&!this._activeProviderReplies.get(T)||(M=!0);if(!M&&A){const T=A.find((k=>this._linkAtPosition(k.link,g)));T&&(_=!0,this._handleNewLink(T))}if(this._activeProviderReplies.size===this._linkProviderService.linkProviders.length&&!_)for(let T=0;T<this._activeProviderReplies.size;T++){const k=(D=this._activeProviderReplies.get(T))==null?void 0:D.find((R=>this._linkAtPosition(R.link,g)));if(k){_=!0,this._handleNewLink(k);break}}return _}_handleMouseDown(){this._mouseDownLink=this._currentLink}_handleMouseUp(S){if(!this._currentLink)return;const g=this._positionFromMouseEvent(S,this._element,this._mouseService);g&&this._mouseDownLink===this._currentLink&&this._linkAtPosition(this._currentLink.link,g)&&this._currentLink.link.activate(S,this._currentLink.link.text)}_clearCurrentLink(S,g){this._currentLink&&this._lastMouseEvent&&(!S||!g||this._currentLink.link.range.start.y>=S&&this._currentLink.link.range.end.y<=g)&&(this._linkLeave(this._element,this._currentLink.link,this._lastMouseEvent),this._currentLink=void 0,(0,w.disposeArray)(this._linkCacheDisposables))}_handleNewLink(S){if(!this._lastMouseEvent)return;const g=this._positionFromMouseEvent(this._lastMouseEvent,this._element,this._mouseService);g&&this._linkAtPosition(S.link,g)&&(this._currentLink=S,this._currentLink.state={decorations:{underline:S.link.decorations===void 0||S.link.decorations.underline,pointerCursor:S.link.decorations===void 0||S.link.decorations.pointerCursor},isHovered:!0},this._linkHover(this._element,S.link,this._lastMouseEvent),S.link.decorations={},Object.defineProperties(S.link.decorations,{pointerCursor:{get:()=>{var _,A;return(A=(_=this._currentLink)==null?void 0:_.state)==null?void 0:A.decorations.pointerCursor},set:_=>{var A;(A=this._currentLink)!=null&&A.state&&this._currentLink.state.decorations.pointerCursor!==_&&(this._currentLink.state.decorations.pointerCursor=_,this._currentLink.state.isHovered&&this._element.classList.toggle("xterm-cursor-pointer",_))}},underline:{get:()=>{var _,A;return(A=(_=this._currentLink)==null?void 0:_.state)==null?void 0:A.decorations.underline},set:_=>{var A,M,D;(A=this._currentLink)!=null&&A.state&&((D=(M=this._currentLink)==null?void 0:M.state)==null?void 0:D.decorations.underline)!==_&&(this._currentLink.state.decorations.underline=_,this._currentLink.state.isHovered&&this._fireUnderlineEvent(S.link,_))}}}),this._linkCacheDisposables.push(this._renderService.onRenderedViewportChange((_=>{if(!this._currentLink)return;const A=_.start===0?0:_.start+1+this._bufferService.buffer.ydisp,M=this._bufferService.buffer.ydisp+1+_.end;if(this._currentLink.link.range.start.y>=A&&this._currentLink.link.range.end.y<=M&&(this._clearCurrentLink(A,M),this._lastMouseEvent)){const D=this._positionFromMouseEvent(this._lastMouseEvent,this._element,this._mouseService);D&&this._askForLink(D,!1)}}))))}_linkHover(S,g,_){var A;(A=this._currentLink)!=null&&A.state&&(this._currentLink.state.isHovered=!0,this._currentLink.state.decorations.underline&&this._fireUnderlineEvent(g,!0),this._currentLink.state.decorations.pointerCursor&&S.classList.add("xterm-cursor-pointer")),g.hover&&g.hover(_,g.text)}_fireUnderlineEvent(S,g){const _=S.range,A=this._bufferService.buffer.ydisp,M=this._createLinkUnderlineEvent(_.start.x-1,_.start.y-A-1,_.end.x,_.end.y-A-1,void 0);(g?this._onShowLinkUnderline:this._onHideLinkUnderline).fire(M)}_linkLeave(S,g,_){var A;(A=this._currentLink)!=null&&A.state&&(this._currentLink.state.isHovered=!1,this._currentLink.state.decorations.underline&&this._fireUnderlineEvent(g,!1),this._currentLink.state.decorations.pointerCursor&&S.classList.remove("xterm-cursor-pointer")),g.leave&&g.leave(_,g.text)}_linkAtPosition(S,g){const _=S.range.start.y*this._bufferService.cols+S.range.start.x,A=S.range.end.y*this._bufferService.cols+S.range.end.x,M=g.y*this._bufferService.cols+g.x;return _<=M&&M<=A}_positionFromMouseEvent(S,g,_){const A=_.getCoords(S,g,this._bufferService.cols,this._bufferService.rows);if(A)return{x:A[0],y:A[1]+this._bufferService.buffer.ydisp}}_createLinkUnderlineEvent(S,g,_,A,M){return{x1:S,y1:g,x2:_,y2:A,cols:this._bufferService.cols,fg:M}}};a.Linkifier=v=h([d(1,x.IMouseService),d(2,x.IRenderService),d(3,E.IBufferService),d(4,x.ILinkProviderService)],v)},9042:(f,a)=>{Object.defineProperty(a,"__esModule",{value:!0}),a.tooMuchOutput=a.promptLabel=void 0,a.promptLabel="Terminal input",a.tooMuchOutput="Too much output to announce, navigate to rows manually to read"},3730:function(f,a,c){var h=this&&this.__decorate||function(x,v,S,g){var _,A=arguments.length,M=A<3?v:g===null?g=Object.getOwnPropertyDescriptor(v,S):g;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")M=Reflect.decorate(x,v,S,g);else for(var D=x.length-1;D>=0;D--)(_=x[D])&&(M=(A<3?_(M):A>3?_(v,S,M):_(v,S))||M);return A>3&&M&&Object.defineProperty(v,S,M),M},d=this&&this.__param||function(x,v){return function(S,g){v(S,g,x)}};Object.defineProperty(a,"__esModule",{value:!0}),a.OscLinkProvider=void 0;const u=c(511),b=c(2585);let w=a.OscLinkProvider=class{constructor(x,v,S){this._bufferService=x,this._optionsService=v,this._oscLinkService=S}provideLinks(x,v){var R;const S=this._bufferService.buffer.lines.get(x-1);if(!S)return void v(void 0);const g=[],_=this._optionsService.rawOptions.linkHandler,A=new u.CellData,M=S.getTrimmedLength();let D=-1,T=-1,k=!1;for(let N=0;N<M;N++)if(T!==-1||S.hasContent(N)){if(S.loadCell(N,A),A.hasExtendedAttrs()&&A.extended.urlId){if(T===-1){T=N,D=A.extended.urlId;continue}k=A.extended.urlId!==D}else T!==-1&&(k=!0);if(k||T!==-1&&N===M-1){const I=(R=this._oscLinkService.getLinkData(D))==null?void 0:R.uri;if(I){const P={start:{x:T+1,y:x},end:{x:N+(k||N!==M-1?0:1),y:x}};let F=!1;if(!(_!=null&&_.allowNonHttpProtocols))try{const Y=new URL(I);["http:","https:"].includes(Y.protocol)||(F=!0)}catch{F=!0}F||g.push({text:I,range:P,activate:(Y,W)=>_?_.activate(Y,W,P):E(0,W),hover:(Y,W)=>{var G;return(G=_==null?void 0:_.hover)==null?void 0:G.call(_,Y,W,P)},leave:(Y,W)=>{var G;return(G=_==null?void 0:_.leave)==null?void 0:G.call(_,Y,W,P)}})}k=!1,A.hasExtendedAttrs()&&A.extended.urlId?(T=N,D=A.extended.urlId):(T=-1,D=-1)}}v(g)}};function E(x,v){if(confirm(`Do you want to navigate to ${v}?
|
|
85
85
|
|
package/dist-frontend/index.html
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<title>VibeCodingMaster</title>
|
|
7
|
-
<script type="module" crossorigin src="/assets/index-
|
|
7
|
+
<script type="module" crossorigin src="/assets/index-CEB6Bssn.js"></script>
|
|
8
8
|
<link rel="stylesheet" crossorigin href="/assets/index-Dmefx9m7.css">
|
|
9
9
|
</head>
|
|
10
10
|
<body>
|
|
@@ -36,7 +36,7 @@ conversation translation. It should:
|
|
|
36
36
|
`<baseRepoRoot>/.ai/vcm/translations/`
|
|
37
37
|
- write only the exact output paths assigned by VCM
|
|
38
38
|
- record file metadata so unchanged files are not translated repeatedly
|
|
39
|
-
- support
|
|
39
|
+
- support retry or retranslation after interruption
|
|
40
40
|
- produce a translation report with required light QA checks
|
|
41
41
|
- translate short conversation items sent by VCM and write the translated text to
|
|
42
42
|
VCM-assigned temporary result files
|
|
@@ -69,7 +69,7 @@ Codex session translation improves this because:
|
|
|
69
69
|
- the session can inspect the whole repository and the whole source document
|
|
70
70
|
- Codex can keep a long conversation state and use its normal context
|
|
71
71
|
compaction behavior
|
|
72
|
-
- durable memory files can preserve decisions across session compaction,
|
|
72
|
+
- durable memory files can preserve decisions across session compaction, VCM
|
|
73
73
|
restarts, and future translation jobs
|
|
74
74
|
- translation output can be written to files instead of returned through one
|
|
75
75
|
very large API response
|
|
@@ -92,9 +92,9 @@ model. Their lifecycles are still different:
|
|
|
92
92
|
|
|
93
93
|
| Translation type | Purpose | Root | Lifecycle | Cleanup |
|
|
94
94
|
| --- | --- | --- | --- | --- |
|
|
95
|
-
| Translation bootstrap | First-run project understanding and memory initialization | `<baseRepoRoot>/.ai/vcm/translations/bootstrap/` plus temporary runtime files | Long-term index and memory, temporary run files | Runtime files are deleted after completion |
|
|
96
|
-
| File translation | Project documents, whitepapers, specs, long-form artifacts | `<baseRepoRoot>/.ai/vcm/translations/files/completed/` | Long-term project-local state | Completed outputs survive; request/progress/report files are deleted after completion |
|
|
97
|
-
| Conversation translation | Role console output, user prompt translation, gateway replies | `<baseRepoRoot>/.ai/vcm/translations/runtime/conversations/<taskSlug>/...` | Task-scoped runtime cache | Deleted after the translated result is consumed |
|
|
95
|
+
| Translation bootstrap | First-run project understanding and memory initialization | `<baseRepoRoot>/.ai/vcm/translations/bootstrap/` plus temporary runtime files | Long-term index and memory, temporary run files | Runtime files are deleted on VCM startup and after completion |
|
|
96
|
+
| File translation | Project documents, whitepapers, specs, long-form artifacts | `<baseRepoRoot>/.ai/vcm/translations/files/completed/` | Long-term project-local state | Completed outputs survive; request/progress/report/chunk files are deleted on VCM startup and after completion |
|
|
97
|
+
| Conversation translation | Role console output, user prompt translation, gateway replies | `<baseRepoRoot>/.ai/vcm/translations/runtime/conversations/<taskSlug>/...` | Task-scoped runtime cache | Deleted on VCM startup or after the translated result is consumed |
|
|
98
98
|
| Translation memory | Shared terminology and style rules | `<baseRepoRoot>/.ai/vcm/translations/memory/` | Long-term project-local state | Survives task cleanup and worktree deletion |
|
|
99
99
|
|
|
100
100
|
Recommended layout:
|
|
@@ -138,9 +138,10 @@ Recommended layout:
|
|
|
138
138
|
report.md
|
|
139
139
|
```
|
|
140
140
|
|
|
141
|
-
Files under `runtime/` are working state.
|
|
142
|
-
|
|
143
|
-
|
|
141
|
+
Files under `runtime/` are temporary working state. VCM deletes the entire
|
|
142
|
+
`translations/runtime/` tree on startup for recent or connected projects.
|
|
143
|
+
Completed file translations are moved into `files/completed/`; the matching
|
|
144
|
+
runtime job directory is also deleted after validation.
|
|
144
145
|
|
|
145
146
|
The root is intentionally under `<baseRepoRoot>`, not `<taskRepoRoot>`. In
|
|
146
147
|
worktree-backed tasks, `<taskRepoRoot>` points at
|
|
@@ -148,9 +149,10 @@ worktree-backed tasks, `<taskRepoRoot>` points at
|
|
|
148
149
|
closed. Translation state must not be split between the base repo and task
|
|
149
150
|
worktrees.
|
|
150
151
|
|
|
151
|
-
Conversation translation entries are temporary. VCM
|
|
152
|
-
|
|
153
|
-
|
|
152
|
+
Conversation translation entries are temporary. VCM removes matching runtime
|
|
153
|
+
conversation files after their result JSON has been consumed and removes all
|
|
154
|
+
runtime conversation files on startup. Startup cleanup must not remove
|
|
155
|
+
`translations/files/completed/` or `translations/memory/`.
|
|
154
156
|
|
|
155
157
|
All translation state is local VCM state and is normally ignored by git through
|
|
156
158
|
`.ai/vcm/`. If the user wants a translated file committed to the project, VCM
|
|
@@ -312,13 +314,16 @@ User enables translation
|
|
|
312
314
|
```
|
|
313
315
|
|
|
314
316
|
Bootstrap should be rerunnable. A rerun creates a new bootstrap id and preserves
|
|
315
|
-
|
|
316
|
-
memory
|
|
317
|
+
durable memory files and completed-run index history; runtime reports are
|
|
318
|
+
temporary. Codex may append new memory entries, but user corrections in memory
|
|
319
|
+
files override automatic bootstrap entries.
|
|
317
320
|
|
|
318
321
|
## 7. File Index And Replacement
|
|
319
322
|
|
|
320
|
-
`index.json`
|
|
321
|
-
|
|
323
|
+
`index.json` is the durable completed-translation index. It records only file
|
|
324
|
+
translations that passed validation and were moved into `files/completed/`.
|
|
325
|
+
Queued, running, failed, interrupted, and `needs_review` jobs stay under
|
|
326
|
+
`runtime/` and must not be written to this index.
|
|
322
327
|
|
|
323
328
|
Suggested schema shape:
|
|
324
329
|
|
|
@@ -362,18 +367,19 @@ Replacement rules:
|
|
|
362
367
|
- Selecting `Translate` always creates a new file translation job for the
|
|
363
368
|
chosen source file and target language.
|
|
364
369
|
- If a completed translation already exists for the same `sourcePath`,
|
|
365
|
-
`targetLanguage`, and `translationProfile`, VCM keeps
|
|
366
|
-
job completes successfully.
|
|
367
|
-
|
|
368
|
-
|
|
370
|
+
`targetLanguage`, and `translationProfile`, VCM keeps the old completed file
|
|
371
|
+
and index entry on disk until the new job completes successfully. During the
|
|
372
|
+
run, the UI may show the latest runtime job by merging `runtime/queue.json`
|
|
373
|
+
with `files/index.json`, but the durable index itself is unchanged.
|
|
374
|
+
- After the new job passes validation, VCM writes the completed output for that
|
|
375
|
+
same file/language/profile, then replaces the superseded entry in
|
|
369
376
|
`files/index.json`.
|
|
370
377
|
- If the new job fails, is interrupted, or needs review, the previous completed
|
|
371
378
|
output remains intact.
|
|
372
379
|
- If the same file is selected from a task worktree, VCM should normalize the
|
|
373
380
|
source path back to the base repo path when possible; the long-term job still
|
|
374
381
|
belongs to `<baseRepoRoot>/.ai/vcm/translations/files/completed/`.
|
|
375
|
-
- Failed or interrupted jobs can be
|
|
376
|
-
section state.
|
|
382
|
+
- Failed or interrupted jobs can be retried by creating a new translation job.
|
|
377
383
|
|
|
378
384
|
## 8. Codex Translator Role
|
|
379
385
|
|
|
@@ -396,26 +402,27 @@ management pattern:
|
|
|
396
402
|
- start/resume/restart/stop terminal controls
|
|
397
403
|
- model and effort selectors
|
|
398
404
|
- hook-based running/idle state
|
|
399
|
-
-
|
|
400
|
-
- long-lived terminal session for follow-up discussion
|
|
405
|
+
- runtime Codex session id for the current VCM process
|
|
406
|
+
- long-lived terminal session for follow-up discussion until VCM is restarted
|
|
401
407
|
|
|
402
|
-
VCM
|
|
408
|
+
VCM stores the active translator session runtime record at:
|
|
403
409
|
|
|
404
410
|
```text
|
|
405
411
|
<baseRepoRoot>/.ai/vcm/translations/runtime/session.json
|
|
406
412
|
```
|
|
407
413
|
|
|
408
|
-
This record is project-level state, not task-level state. It
|
|
409
|
-
session id, selected model, selected effort, terminal cwd,
|
|
410
|
-
activity state
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
+
This record is project-level runtime state, not task-level durable state. It
|
|
415
|
+
stores the Codex session id, selected model, selected effort, terminal cwd, and
|
|
416
|
+
hook activity state for the current VCM process. VCM deletes
|
|
417
|
+
`translations/runtime/` on startup, so this record must not be used for restart
|
|
418
|
+
recovery. The embedded terminal `Restart` control must stop the current runtime
|
|
419
|
+
process, create a fresh Codex session id, overwrite this record, and keep old
|
|
420
|
+
translation outputs intact.
|
|
414
421
|
|
|
415
|
-
When a Codex hook has captured the real Codex `session_id`, `Resume`
|
|
416
|
-
`codex resume <session_id>`
|
|
417
|
-
|
|
418
|
-
|
|
422
|
+
When a Codex hook has captured the real Codex `session_id`, `Resume` may run
|
|
423
|
+
`codex resume <session_id>` during the same VCM runtime. After VCM restarts,
|
|
424
|
+
the user should start a fresh translator session and rely on durable memory
|
|
425
|
+
files plus completed translations.
|
|
419
426
|
|
|
420
427
|
Session identity is fixed by base repository. If VCM later supports multiple
|
|
421
428
|
parallel target-language translator sessions, split this file into a
|
|
@@ -600,7 +607,7 @@ All translation work enters the same VCM-managed queue:
|
|
|
600
607
|
- conversation translation requests
|
|
601
608
|
- bootstrap runs
|
|
602
609
|
- retry requests
|
|
603
|
-
-
|
|
610
|
+
- retranslation requests
|
|
604
611
|
|
|
605
612
|
Queue rules:
|
|
606
613
|
|
|
@@ -645,7 +652,7 @@ Suggested queue item shape:
|
|
|
645
652
|
"items": [
|
|
646
653
|
{
|
|
647
654
|
"id": "queue-item-001",
|
|
648
|
-
"type": "bootstrap | file | conversation | retry |
|
|
655
|
+
"type": "bootstrap | file | conversation | retry | force-retranslate",
|
|
649
656
|
"status": "running",
|
|
650
657
|
"targetLanguage": "zh-CN",
|
|
651
658
|
"jobId": "whitepaper-v0-8-zh-20260614-001",
|
|
@@ -733,8 +740,8 @@ Completion rule:
|
|
|
733
740
|
structure, corrupted code blocks, invalid result metadata, or unresolved risky
|
|
734
741
|
choices, mark the job `needs_review`.
|
|
735
742
|
- If required output files are missing or unreadable, mark the job `failed`.
|
|
736
|
-
- `needs_review` jobs remain visible in the file list
|
|
737
|
-
retried
|
|
743
|
+
- `needs_review` jobs remain visible in the file list during the current VCM
|
|
744
|
+
runtime and can be retried or manually resolved.
|
|
738
745
|
|
|
739
746
|
## 14. Conversation Translation Workflow
|
|
740
747
|
|
|
@@ -936,10 +943,13 @@ on one giant prompt or one giant assistant response to translate the entire file
|
|
|
936
943
|
|
|
937
944
|
Resume behavior:
|
|
938
945
|
|
|
939
|
-
- If Codex session is still available
|
|
940
|
-
|
|
941
|
-
- If the
|
|
942
|
-
|
|
946
|
+
- If Codex session is still available in the current VCM process, continue in
|
|
947
|
+
the same session.
|
|
948
|
+
- If the terminal was stopped during the same VCM process, resume the Codex
|
|
949
|
+
session id when possible.
|
|
950
|
+
- After VCM restarts, do not resume runtime jobs or partial runtime outputs.
|
|
951
|
+
Start a fresh Codex Translator session and requeue the translation from the
|
|
952
|
+
durable source file or conversation source.
|
|
943
953
|
- Never replace a completed output until the new job has passed validation.
|
|
944
954
|
|
|
945
955
|
Cancellation and interruption behavior:
|
|
@@ -948,10 +958,11 @@ Cancellation and interruption behavior:
|
|
|
948
958
|
leave its request files for debugging.
|
|
949
959
|
- If the user stops Codex Translator, closes VCM, or the hook flow does not
|
|
950
960
|
return, mark the active item `interrupted` on the next state reconciliation.
|
|
951
|
-
- On VCM
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
961
|
+
- On VCM startup, delete `translations/runtime/` entirely. Do not resume
|
|
962
|
+
queued, dispatching, running, validating, failed, or interrupted runtime
|
|
963
|
+
jobs from a previous process.
|
|
964
|
+
- Startup cleanup also removes file-index entries that do not point at a
|
|
965
|
+
validated completed output under `translations/files/completed/`.
|
|
955
966
|
- Interrupted conversation translation requests should normally be retried from
|
|
956
967
|
the original request file because they are short and temporary.
|
|
957
968
|
- Manual resolve can mark an item completed only after the expected result file
|
|
@@ -974,13 +985,16 @@ Recommended UI:
|
|
|
974
985
|
- right pane: selected translated file content preview
|
|
975
986
|
- The view has a `Translate` action. Clicking it opens a file picker or path
|
|
976
987
|
selector and creates a file translation job for the chosen file.
|
|
977
|
-
- Selecting
|
|
978
|
-
output in the right pane. Runtime reports are only retained while a
|
|
979
|
-
queued, running, failed, or interrupted.
|
|
988
|
+
- Selecting a completed item in the left pane loads the completed translated
|
|
989
|
+
Markdown output in the right pane. Runtime reports are only retained while a
|
|
990
|
+
job is queued, running, failed, or interrupted.
|
|
980
991
|
- Existing translated files come from
|
|
981
|
-
`<baseRepoRoot>/.ai/vcm/translations/files/index.json
|
|
982
|
-
|
|
983
|
-
|
|
992
|
+
`<baseRepoRoot>/.ai/vcm/translations/files/index.json`; active and queued
|
|
993
|
+
jobs are derived from `runtime/queue.json` and their runtime `request.json`
|
|
994
|
+
files.
|
|
995
|
+
- The merged list should show at most one row for each
|
|
996
|
+
`sourcePath + targetLanguage + translationProfile`; runtime rows win over
|
|
997
|
+
completed rows while a retranslation is in progress.
|
|
984
998
|
|
|
985
999
|
Controls in the file translation view:
|
|
986
1000
|
|
|
@@ -1059,11 +1073,12 @@ New backend pieces:
|
|
|
1059
1073
|
- validate file and conversation result files
|
|
1060
1074
|
- record promote metadata when users export translations into the repo tree
|
|
1061
1075
|
- translation queue service
|
|
1062
|
-
- enqueue bootstrap, file, conversation, retry, and
|
|
1076
|
+
- enqueue bootstrap, file, conversation, retry, and retranslation tasks
|
|
1063
1077
|
- persist `runtime/queue.json`
|
|
1064
1078
|
- persist queue item status
|
|
1065
1079
|
- ensure only one active Codex Translator task at a time
|
|
1066
|
-
-
|
|
1080
|
+
- delete startup runtime state instead of restoring interrupted state after
|
|
1081
|
+
VCM restart
|
|
1067
1082
|
- advance the queue only after hook completion and result-file validation
|
|
1068
1083
|
- start/resume Codex Translator
|
|
1069
1084
|
- send job prompt
|
|
@@ -1081,7 +1096,7 @@ New backend pieces:
|
|
|
1081
1096
|
- create job
|
|
1082
1097
|
- get job status
|
|
1083
1098
|
- read result/report
|
|
1084
|
-
-
|
|
1099
|
+
- retry/force retranslate
|
|
1085
1100
|
- cancel/skip/manual resolve queue items
|
|
1086
1101
|
- promote completed translations into explicit user-selected repo paths
|
|
1087
1102
|
- get conversation translation request status when needed for debugging
|
|
@@ -1143,6 +1158,8 @@ durable under `translations/files/completed/`.
|
|
|
1143
1158
|
- Add the unified `.ai/vcm/translations/` directory contract, including
|
|
1144
1159
|
`runtime/queue.json`, `memory/`, `bootstrap/`, `files/completed/`, and
|
|
1145
1160
|
`runtime/conversations/`.
|
|
1161
|
+
- Define `runtime/` as startup-cleaned temporary state; only memory, completed
|
|
1162
|
+
files, and durable indexes survive VCM restart.
|
|
1146
1163
|
- Define index, request, progress, report, queue, and conversation result
|
|
1147
1164
|
schemas.
|
|
1148
1165
|
- Define memory file format, bootstrap candidate discovery, scan budgets, and
|
|
@@ -1158,10 +1175,10 @@ durable under `translations/files/completed/`.
|
|
|
1158
1175
|
|
|
1159
1176
|
- Implement bootstrap state, candidate discovery, and bootstrap run creation.
|
|
1160
1177
|
- Implement source hash and de-duplication.
|
|
1161
|
-
- Implement job create/list/read/
|
|
1178
|
+
- Implement job create/list/read/retranslate.
|
|
1162
1179
|
- Implement the shared translation queue and persist `runtime/queue.json`.
|
|
1163
1180
|
- Implement result-file validation for file and conversation translation.
|
|
1164
|
-
- Implement
|
|
1181
|
+
- Implement startup runtime cleanup and durable-index pruning on VCM restart.
|
|
1165
1182
|
- Persist completed file outputs under
|
|
1166
1183
|
`<baseRepoRoot>/.ai/vcm/translations/files/completed/`.
|
|
1167
1184
|
- Persist active queue, file/bootstrap request files, and conversation
|
|
@@ -1174,8 +1191,8 @@ durable under `translations/files/completed/`.
|
|
|
1174
1191
|
### Phase 3: Codex Session Integration
|
|
1175
1192
|
|
|
1176
1193
|
- Add `codex-translator` role/session support.
|
|
1177
|
-
-
|
|
1178
|
-
sessions by translation profile.
|
|
1194
|
+
- Keep session identity as current-process runtime state by `<baseRepoRoot> +
|
|
1195
|
+
targetLanguage`; do not split sessions by translation profile.
|
|
1179
1196
|
- Reuse Codex embedded terminal startup with model/effort selectors.
|
|
1180
1197
|
- Add hook endpoints and running/idle tracking.
|
|
1181
1198
|
- Send translation job prompts into the long-lived Codex session.
|
|
@@ -1191,7 +1208,8 @@ durable under `translations/files/completed/`.
|
|
|
1191
1208
|
- Add a file-translation button to the existing translation panel.
|
|
1192
1209
|
- Add the file translation modal.
|
|
1193
1210
|
- Add first-use bootstrap recommendation and bootstrap controls.
|
|
1194
|
-
- Add the translated-file left pane backed by
|
|
1211
|
+
- Add the translated-file left pane backed by completed entries from
|
|
1212
|
+
`files/index.json` plus active runtime file jobs from the queue.
|
|
1195
1213
|
- Add the translated-content right pane backed by completed output files.
|
|
1196
1214
|
- Show selected job status; show runtime report details only while a job is not
|
|
1197
1215
|
completed.
|
|
@@ -1219,11 +1237,11 @@ durable under `translations/files/completed/`.
|
|
|
1219
1237
|
conversation or file translation.
|
|
1220
1238
|
- Add bootstrap tests for candidate discovery, memory writes, queue ordering,
|
|
1221
1239
|
and rerun behavior.
|
|
1222
|
-
- Add queue status-machine tests, including
|
|
1240
|
+
- Add queue status-machine tests, including startup runtime cleanup.
|
|
1223
1241
|
- Add conversation result text validation tests.
|
|
1224
1242
|
- Add memory priority tests proving user entries override automatic entries.
|
|
1225
1243
|
- Add promote tests proving source files are not overwritten by default.
|
|
1226
|
-
- Add
|
|
1244
|
+
- Add retry/retranslation tests after failed or interrupted work.
|
|
1227
1245
|
- Test with `docs/whitepaper-v0.8.md` scale files.
|
|
1228
1246
|
|
|
1229
1247
|
## 21. Resolved Decisions
|