viveworker 0.1.10 → 0.1.11
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/package.json +1 -1
- package/scripts/viveworker-bridge.mjs +352 -108
- package/web/i18n.js +23 -17
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "viveworker",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.11",
|
|
4
4
|
"description": "Local device companion for Codex Desktop approvals, plan checks, questions, and notifications on your LAN.",
|
|
5
5
|
"author": "Yuta Hoshino <hoshino.lireneo@gmail.com>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -328,6 +328,17 @@ function fileEventDetailCopy(locale, fileEventType) {
|
|
|
328
328
|
}
|
|
329
329
|
}
|
|
330
330
|
|
|
331
|
+
function diffThreadDetailCopy(locale, sourceMode, count) {
|
|
332
|
+
switch (cleanText(sourceMode || "")) {
|
|
333
|
+
case "git_current":
|
|
334
|
+
return t(locale, "detail.diffThread.copy.current", { count });
|
|
335
|
+
case "non_git_latest":
|
|
336
|
+
return t(locale, "detail.diffThread.copy.latest", { count });
|
|
337
|
+
default:
|
|
338
|
+
return t(locale, "detail.diffThread.copy", { count });
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
331
342
|
function inferTimelineOutcome(kind, summary = "", messageText = "") {
|
|
332
343
|
const normalizedKind = cleanText(kind || "");
|
|
333
344
|
if (!normalizedKind) {
|
|
@@ -1764,6 +1775,205 @@ function resolveCurrentChangeOwner(change, candidates) {
|
|
|
1764
1775
|
return null;
|
|
1765
1776
|
}
|
|
1766
1777
|
|
|
1778
|
+
function normalizeCodeFallbackFileRef({ fileRef, cwd = "" }) {
|
|
1779
|
+
const normalizedFileRef = cleanTimelineFileRef(fileRef);
|
|
1780
|
+
if (!normalizedFileRef) {
|
|
1781
|
+
return "";
|
|
1782
|
+
}
|
|
1783
|
+
if (path.isAbsolute(normalizedFileRef)) {
|
|
1784
|
+
return resolvePath(normalizedFileRef);
|
|
1785
|
+
}
|
|
1786
|
+
const normalizedCwd = resolvePath(cleanText(cwd || ""));
|
|
1787
|
+
if (!normalizedCwd) {
|
|
1788
|
+
return normalizedFileRef;
|
|
1789
|
+
}
|
|
1790
|
+
return resolvePath(path.resolve(normalizedCwd, normalizedFileRef));
|
|
1791
|
+
}
|
|
1792
|
+
|
|
1793
|
+
function buildNonGitCodeChangeEntries(item) {
|
|
1794
|
+
const changeType = normalizeTimelineFileEventType(item?.fileEventType || "");
|
|
1795
|
+
if (!["write", "create", "delete", "rename"].includes(changeType)) {
|
|
1796
|
+
return [];
|
|
1797
|
+
}
|
|
1798
|
+
|
|
1799
|
+
const normalizedCwd = cleanText(item?.cwd || "");
|
|
1800
|
+
const normalizedFileRefs = normalizeTimelineFileRefs(item?.fileRefs ?? []).map((fileRef) =>
|
|
1801
|
+
normalizeCodeFallbackFileRef({ fileRef, cwd: normalizedCwd })
|
|
1802
|
+
);
|
|
1803
|
+
const normalizedPreviousFileRefs = normalizeTimelineFileRefs(item?.previousFileRefs ?? []).map((fileRef) =>
|
|
1804
|
+
normalizeCodeFallbackFileRef({ fileRef, cwd: normalizedCwd })
|
|
1805
|
+
);
|
|
1806
|
+
const sections = splitUnifiedDiffTextByFile(item?.diffText ?? "");
|
|
1807
|
+
const rawChanges = [];
|
|
1808
|
+
|
|
1809
|
+
if (changeType === "rename") {
|
|
1810
|
+
const pairCount = Math.max(normalizedFileRefs.length, normalizedPreviousFileRefs.length);
|
|
1811
|
+
for (let index = 0; index < pairCount; index += 1) {
|
|
1812
|
+
const newFileRef = cleanTimelineFileRef(normalizedFileRefs[index] || "");
|
|
1813
|
+
const oldFileRef = cleanTimelineFileRef(normalizedPreviousFileRefs[index] || "");
|
|
1814
|
+
if (!newFileRef && !oldFileRef) {
|
|
1815
|
+
continue;
|
|
1816
|
+
}
|
|
1817
|
+
rawChanges.push({
|
|
1818
|
+
changeType,
|
|
1819
|
+
fileRef: newFileRef || oldFileRef,
|
|
1820
|
+
oldFileRef,
|
|
1821
|
+
newFileRef: newFileRef || oldFileRef,
|
|
1822
|
+
});
|
|
1823
|
+
}
|
|
1824
|
+
} else {
|
|
1825
|
+
const targetRefs =
|
|
1826
|
+
normalizedFileRefs.length > 0
|
|
1827
|
+
? normalizedFileRefs
|
|
1828
|
+
: changeType === "delete"
|
|
1829
|
+
? normalizedPreviousFileRefs
|
|
1830
|
+
: [];
|
|
1831
|
+
for (const fileRef of targetRefs) {
|
|
1832
|
+
const normalizedFileRef = cleanTimelineFileRef(fileRef || "");
|
|
1833
|
+
if (!normalizedFileRef) {
|
|
1834
|
+
continue;
|
|
1835
|
+
}
|
|
1836
|
+
rawChanges.push({
|
|
1837
|
+
changeType,
|
|
1838
|
+
fileRef: normalizedFileRef,
|
|
1839
|
+
oldFileRef: changeType === "delete" ? normalizedFileRef : "",
|
|
1840
|
+
newFileRef: changeType === "delete" ? "" : normalizedFileRef,
|
|
1841
|
+
});
|
|
1842
|
+
}
|
|
1843
|
+
}
|
|
1844
|
+
|
|
1845
|
+
const allowWholeItemDiff = sections.length === 0 && rawChanges.length <= 1;
|
|
1846
|
+
const baseDiffSource = normalizeTimelineDiffSource(item?.diffSource ?? "");
|
|
1847
|
+
const baseAddedLines = Math.max(0, Number(item?.diffAddedLines) || 0);
|
|
1848
|
+
const baseRemovedLines = Math.max(0, Number(item?.diffRemovedLines) || 0);
|
|
1849
|
+
const threadId = cleanText(item?.threadId || "");
|
|
1850
|
+
const threadLabel = cleanText(item?.threadLabel || "");
|
|
1851
|
+
const createdAtMs = Number(item?.createdAtMs) || 0;
|
|
1852
|
+
|
|
1853
|
+
return rawChanges.map((change) => {
|
|
1854
|
+
const section = findMatchingCurrentDiffSection(sections, change);
|
|
1855
|
+
const diffText = normalizeTimelineDiffText(section?.diffText || (allowWholeItemDiff ? item?.diffText ?? "" : ""));
|
|
1856
|
+
const counts = diffText
|
|
1857
|
+
? diffLineCounts(diffText)
|
|
1858
|
+
: {
|
|
1859
|
+
addedLines: allowWholeItemDiff ? baseAddedLines : 0,
|
|
1860
|
+
removedLines: allowWholeItemDiff ? baseRemovedLines : 0,
|
|
1861
|
+
};
|
|
1862
|
+
return {
|
|
1863
|
+
threadId,
|
|
1864
|
+
threadLabel,
|
|
1865
|
+
createdAtMs,
|
|
1866
|
+
changeType,
|
|
1867
|
+
fileRef: cleanTimelineFileRef(change.fileRef || change.newFileRef || change.oldFileRef || ""),
|
|
1868
|
+
oldFileRef: cleanTimelineFileRef(change.oldFileRef || ""),
|
|
1869
|
+
newFileRef: cleanTimelineFileRef(change.newFileRef || change.fileRef || ""),
|
|
1870
|
+
diffText,
|
|
1871
|
+
diffAvailable: item?.diffAvailable === true || Boolean(diffText),
|
|
1872
|
+
diffSource: baseDiffSource,
|
|
1873
|
+
diffAddedLines: counts.addedLines,
|
|
1874
|
+
diffRemovedLines: counts.removedLines,
|
|
1875
|
+
};
|
|
1876
|
+
});
|
|
1877
|
+
}
|
|
1878
|
+
|
|
1879
|
+
function nonGitCodeChangeIdentity(change) {
|
|
1880
|
+
const anchorFileRef = cleanTimelineFileRef(change?.newFileRef || change?.fileRef || change?.oldFileRef || "");
|
|
1881
|
+
return anchorFileRef ? `file:${anchorFileRef}` : "";
|
|
1882
|
+
}
|
|
1883
|
+
|
|
1884
|
+
function mergeDiffThreadSourceMode(currentMode, nextMode) {
|
|
1885
|
+
const normalizedCurrentMode = cleanText(currentMode || "");
|
|
1886
|
+
const normalizedNextMode = cleanText(nextMode || "");
|
|
1887
|
+
if (!normalizedCurrentMode) {
|
|
1888
|
+
return normalizedNextMode;
|
|
1889
|
+
}
|
|
1890
|
+
if (!normalizedNextMode || normalizedCurrentMode === normalizedNextMode) {
|
|
1891
|
+
return normalizedCurrentMode;
|
|
1892
|
+
}
|
|
1893
|
+
return "mixed";
|
|
1894
|
+
}
|
|
1895
|
+
|
|
1896
|
+
function ensureDiffThreadGroup(groupsByThread, { threadId = "", threadLabel = "", fallbackKey = "", sourceMode = "" }) {
|
|
1897
|
+
const normalizedThreadId = cleanText(threadId || "");
|
|
1898
|
+
const normalizedThreadLabel = cleanText(threadLabel || "");
|
|
1899
|
+
const normalizedFallbackKey = cleanText(fallbackKey || "");
|
|
1900
|
+
const threadKey = normalizedThreadId || `unknown:${normalizedThreadLabel || normalizedFallbackKey || "thread"}`;
|
|
1901
|
+
let threadGroup = groupsByThread.get(threadKey);
|
|
1902
|
+
if (!threadGroup) {
|
|
1903
|
+
threadGroup = {
|
|
1904
|
+
kind: "diff_thread",
|
|
1905
|
+
token: diffThreadToken(normalizedThreadId, normalizedThreadLabel),
|
|
1906
|
+
threadId: normalizedThreadId,
|
|
1907
|
+
threadLabel: normalizedThreadLabel,
|
|
1908
|
+
sourceMode: cleanText(sourceMode || ""),
|
|
1909
|
+
filesByRef: new Map(),
|
|
1910
|
+
};
|
|
1911
|
+
groupsByThread.set(threadKey, threadGroup);
|
|
1912
|
+
return threadGroup;
|
|
1913
|
+
}
|
|
1914
|
+
|
|
1915
|
+
if (!threadGroup.threadLabel && normalizedThreadLabel) {
|
|
1916
|
+
threadGroup.threadLabel = normalizedThreadLabel;
|
|
1917
|
+
}
|
|
1918
|
+
threadGroup.sourceMode = mergeDiffThreadSourceMode(threadGroup.sourceMode, sourceMode);
|
|
1919
|
+
return threadGroup;
|
|
1920
|
+
}
|
|
1921
|
+
|
|
1922
|
+
function addChangeToDiffThreadGroup({ groupsByThread, threadId, threadLabel, fallbackKey = "", sourceMode = "", change, createdAtMs }) {
|
|
1923
|
+
const normalizedChangeType = normalizeTimelineFileEventType(change?.changeType || "");
|
|
1924
|
+
const normalizedFileRef = cleanTimelineFileRef(change?.fileRef || change?.newFileRef || change?.oldFileRef || "");
|
|
1925
|
+
const normalizedOldFileRef = cleanTimelineFileRef(change?.oldFileRef || "");
|
|
1926
|
+
const normalizedNewFileRef = cleanTimelineFileRef(change?.newFileRef || normalizedFileRef);
|
|
1927
|
+
if (!normalizedChangeType || !(normalizedFileRef || normalizedOldFileRef || normalizedNewFileRef)) {
|
|
1928
|
+
return;
|
|
1929
|
+
}
|
|
1930
|
+
|
|
1931
|
+
const group = ensureDiffThreadGroup(groupsByThread, {
|
|
1932
|
+
threadId,
|
|
1933
|
+
threadLabel,
|
|
1934
|
+
fallbackKey: normalizedFileRef || normalizedNewFileRef || normalizedOldFileRef || fallbackKey,
|
|
1935
|
+
sourceMode,
|
|
1936
|
+
});
|
|
1937
|
+
|
|
1938
|
+
const fileGroupKey = `file:${normalizedNewFileRef || normalizedFileRef || normalizedOldFileRef}`;
|
|
1939
|
+
if (!fileGroupKey) {
|
|
1940
|
+
return;
|
|
1941
|
+
}
|
|
1942
|
+
|
|
1943
|
+
const latestChangedAtMs = Number(createdAtMs) || 0;
|
|
1944
|
+
const fileGroup = {
|
|
1945
|
+
fileRef: normalizedFileRef || normalizedNewFileRef || normalizedOldFileRef,
|
|
1946
|
+
oldFileRef: normalizedOldFileRef,
|
|
1947
|
+
newFileRef: normalizedNewFileRef || normalizedFileRef,
|
|
1948
|
+
fileLabel:
|
|
1949
|
+
path.basename(
|
|
1950
|
+
normalizedChangeType === "delete"
|
|
1951
|
+
? normalizedOldFileRef || normalizedFileRef
|
|
1952
|
+
: normalizedNewFileRef || normalizedFileRef || normalizedOldFileRef
|
|
1953
|
+
) ||
|
|
1954
|
+
normalizedNewFileRef ||
|
|
1955
|
+
normalizedOldFileRef ||
|
|
1956
|
+
normalizedFileRef,
|
|
1957
|
+
changeType: normalizedChangeType,
|
|
1958
|
+
fileEventTypes: [normalizedChangeType],
|
|
1959
|
+
addedLines: Math.max(0, Number(change?.diffAddedLines) || 0),
|
|
1960
|
+
removedLines: Math.max(0, Number(change?.diffRemovedLines) || 0),
|
|
1961
|
+
latestChangedAtMs,
|
|
1962
|
+
sections: [
|
|
1963
|
+
{
|
|
1964
|
+
createdAtMs: latestChangedAtMs,
|
|
1965
|
+
diffText: normalizeTimelineDiffText(change?.diffText ?? ""),
|
|
1966
|
+
diffAvailable: change?.diffAvailable === true || Boolean(change?.diffText),
|
|
1967
|
+
diffSource: normalizeTimelineDiffSource(change?.diffSource ?? ""),
|
|
1968
|
+
addedLines: Math.max(0, Number(change?.diffAddedLines) || 0),
|
|
1969
|
+
removedLines: Math.max(0, Number(change?.diffRemovedLines) || 0),
|
|
1970
|
+
fileEventType: normalizedChangeType,
|
|
1971
|
+
},
|
|
1972
|
+
],
|
|
1973
|
+
};
|
|
1974
|
+
group.filesByRef.set(fileGroupKey, fileGroup);
|
|
1975
|
+
}
|
|
1976
|
+
|
|
1767
1977
|
function handleSignal() {
|
|
1768
1978
|
runtime.stopping = true;
|
|
1769
1979
|
}
|
|
@@ -6772,6 +6982,90 @@ function getNativeThreadLabel({ runtime, conversationId, cwd }) {
|
|
|
6772
6982
|
return shortId(normalizedConversationId) || "Codex task";
|
|
6773
6983
|
}
|
|
6774
6984
|
|
|
6985
|
+
function threadStateArchiveStatus(threadState) {
|
|
6986
|
+
if (!isPlainObject(threadState)) {
|
|
6987
|
+
return "";
|
|
6988
|
+
}
|
|
6989
|
+
|
|
6990
|
+
const booleanCandidates = [
|
|
6991
|
+
threadState.archived,
|
|
6992
|
+
threadState.isArchived,
|
|
6993
|
+
threadState.hidden,
|
|
6994
|
+
threadState.isHidden,
|
|
6995
|
+
threadState.deleted,
|
|
6996
|
+
threadState.isDeleted,
|
|
6997
|
+
threadState.closed,
|
|
6998
|
+
threadState.isClosed,
|
|
6999
|
+
threadState.thread?.archived,
|
|
7000
|
+
threadState.thread?.isArchived,
|
|
7001
|
+
threadState.thread?.hidden,
|
|
7002
|
+
threadState.thread?.isHidden,
|
|
7003
|
+
threadState.thread?.deleted,
|
|
7004
|
+
threadState.thread?.isDeleted,
|
|
7005
|
+
threadState.metadata?.archived,
|
|
7006
|
+
threadState.metadata?.isArchived,
|
|
7007
|
+
threadState.metadata?.hidden,
|
|
7008
|
+
threadState.metadata?.isHidden,
|
|
7009
|
+
threadState.metadata?.deleted,
|
|
7010
|
+
threadState.metadata?.isDeleted,
|
|
7011
|
+
];
|
|
7012
|
+
if (booleanCandidates.some((value) => value === true)) {
|
|
7013
|
+
return "archived";
|
|
7014
|
+
}
|
|
7015
|
+
|
|
7016
|
+
const statusCandidates = [
|
|
7017
|
+
threadState.status,
|
|
7018
|
+
threadState.state,
|
|
7019
|
+
threadState.visibility,
|
|
7020
|
+
threadState.lifecycle,
|
|
7021
|
+
threadState.thread?.status,
|
|
7022
|
+
threadState.thread?.state,
|
|
7023
|
+
threadState.thread?.visibility,
|
|
7024
|
+
threadState.metadata?.status,
|
|
7025
|
+
threadState.metadata?.state,
|
|
7026
|
+
threadState.metadata?.visibility,
|
|
7027
|
+
]
|
|
7028
|
+
.map((value) => cleanText(value || "").toLowerCase())
|
|
7029
|
+
.filter(Boolean);
|
|
7030
|
+
|
|
7031
|
+
for (const status of statusCandidates) {
|
|
7032
|
+
if (["archived", "hidden", "deleted", "closed"].includes(status)) {
|
|
7033
|
+
return status;
|
|
7034
|
+
}
|
|
7035
|
+
}
|
|
7036
|
+
|
|
7037
|
+
return "";
|
|
7038
|
+
}
|
|
7039
|
+
|
|
7040
|
+
function shouldExcludeCodeThread(runtime, threadId) {
|
|
7041
|
+
const normalizedThreadId = cleanText(threadId || "");
|
|
7042
|
+
if (!normalizedThreadId) {
|
|
7043
|
+
return false;
|
|
7044
|
+
}
|
|
7045
|
+
|
|
7046
|
+
const threadState = runtime.threadStates.get(normalizedThreadId) ?? null;
|
|
7047
|
+
if (threadStateArchiveStatus(threadState)) {
|
|
7048
|
+
return true;
|
|
7049
|
+
}
|
|
7050
|
+
|
|
7051
|
+
const currentSessionHasThread = Array.isArray(runtime.knownFiles)
|
|
7052
|
+
? runtime.knownFiles.some((filePath) => extractThreadIdFromRolloutPath(filePath) === normalizedThreadId)
|
|
7053
|
+
: false;
|
|
7054
|
+
if (currentSessionHasThread) {
|
|
7055
|
+
return false;
|
|
7056
|
+
}
|
|
7057
|
+
|
|
7058
|
+
if (threadState) {
|
|
7059
|
+
return false;
|
|
7060
|
+
}
|
|
7061
|
+
|
|
7062
|
+
if (runtime.sessionIndex instanceof Map && runtime.sessionIndex.size > 0) {
|
|
7063
|
+
return runtime.sessionIndex.has(normalizedThreadId);
|
|
7064
|
+
}
|
|
7065
|
+
|
|
7066
|
+
return false;
|
|
7067
|
+
}
|
|
7068
|
+
|
|
6775
7069
|
async function findRolloutThreadCwd(runtime, conversationId) {
|
|
6776
7070
|
const normalizedConversationId = cleanText(conversationId || "");
|
|
6777
7071
|
if (!normalizedConversationId) {
|
|
@@ -8447,6 +8741,7 @@ async function buildDiffInboxItems(runtime, state, config, locale) {
|
|
|
8447
8741
|
token: group.token,
|
|
8448
8742
|
threadId: group.threadId,
|
|
8449
8743
|
threadLabel: group.threadLabel || "",
|
|
8744
|
+
sourceMode: cleanText(group.sourceMode || ""),
|
|
8450
8745
|
title: cleanText(group.threadLabel || "") || kindTitle(locale, "diff_thread"),
|
|
8451
8746
|
summary: t(locale, "diff.threadSummary", { count: group.changedFileCount }),
|
|
8452
8747
|
changedFileCount: group.changedFileCount,
|
|
@@ -8487,10 +8782,12 @@ async function buildDiffThreadGroups(runtime, state, config) {
|
|
|
8487
8782
|
.slice()
|
|
8488
8783
|
.sort((left, right) => Number(right.createdAtMs ?? 0) - Number(left.createdAtMs ?? 0));
|
|
8489
8784
|
const candidatesByRepoRoot = new Map();
|
|
8785
|
+
const nonGitRelevantItems = [];
|
|
8490
8786
|
|
|
8491
8787
|
for (const item of relevantItems) {
|
|
8492
8788
|
const repoRoot = await resolveCodeEventRepoRoot(item, repoRootCache);
|
|
8493
8789
|
if (!repoRoot) {
|
|
8790
|
+
nonGitRelevantItems.push(item);
|
|
8494
8791
|
continue;
|
|
8495
8792
|
}
|
|
8496
8793
|
const candidates = expandCodeEventOwnershipCandidates(item, repoRoot);
|
|
@@ -8512,112 +8809,42 @@ async function buildDiffThreadGroups(runtime, state, config) {
|
|
|
8512
8809
|
continue;
|
|
8513
8810
|
}
|
|
8514
8811
|
|
|
8515
|
-
|
|
8516
|
-
|
|
8517
|
-
|
|
8518
|
-
|
|
8519
|
-
|
|
8520
|
-
|
|
8521
|
-
|
|
8522
|
-
|
|
8523
|
-
|
|
8524
|
-
|
|
8525
|
-
|
|
8526
|
-
latestChangedAtMs: 0,
|
|
8527
|
-
latestChangedAtMsForSummary: 0,
|
|
8528
|
-
latestChangeType: "",
|
|
8529
|
-
latestChangeFileRefs: [],
|
|
8530
|
-
diffAddedLines: 0,
|
|
8531
|
-
diffRemovedLines: 0,
|
|
8532
|
-
filesByRef: new Map(),
|
|
8533
|
-
};
|
|
8534
|
-
groupsByThread.set(threadKey, threadGroup);
|
|
8535
|
-
} else if (!threadGroup.threadLabel && threadLabel) {
|
|
8536
|
-
threadGroup.threadLabel = threadLabel;
|
|
8537
|
-
}
|
|
8812
|
+
addChangeToDiffThreadGroup({
|
|
8813
|
+
groupsByThread,
|
|
8814
|
+
threadId: cleanText(owner.threadId || ""),
|
|
8815
|
+
threadLabel: cleanText(owner.threadLabel || ""),
|
|
8816
|
+
fallbackKey: cleanText(change.fileRef || change.newFileRef || change.oldFileRef || ""),
|
|
8817
|
+
sourceMode: "git_current",
|
|
8818
|
+
change,
|
|
8819
|
+
createdAtMs: Number(owner.createdAtMs) || 0,
|
|
8820
|
+
});
|
|
8821
|
+
}
|
|
8822
|
+
}
|
|
8538
8823
|
|
|
8539
|
-
|
|
8540
|
-
|
|
8541
|
-
|
|
8542
|
-
|
|
8543
|
-
|
|
8824
|
+
const latestNonGitChangesByIdentity = new Map();
|
|
8825
|
+
for (const item of nonGitRelevantItems) {
|
|
8826
|
+
const changes = buildNonGitCodeChangeEntries(item);
|
|
8827
|
+
for (const change of changes) {
|
|
8828
|
+
const identity = nonGitCodeChangeIdentity(change);
|
|
8829
|
+
if (!identity || latestNonGitChangesByIdentity.has(identity)) {
|
|
8544
8830
|
continue;
|
|
8545
8831
|
}
|
|
8546
|
-
|
|
8547
|
-
const latestOwnerChangeAtMs = Number(owner.createdAtMs) || 0;
|
|
8548
|
-
const normalizedFileRef = cleanTimelineFileRef(change.fileRef || change.newFileRef || change.oldFileRef || "");
|
|
8549
|
-
const normalizedOldFileRef = cleanTimelineFileRef(change.oldFileRef || "");
|
|
8550
|
-
const normalizedNewFileRef = cleanTimelineFileRef(change.newFileRef || normalizedFileRef);
|
|
8551
|
-
let fileGroup = threadGroup.filesByRef.get(fileGroupKey);
|
|
8552
|
-
if (!fileGroup) {
|
|
8553
|
-
fileGroup = {
|
|
8554
|
-
fileRef: normalizedFileRef,
|
|
8555
|
-
oldFileRef: normalizedOldFileRef,
|
|
8556
|
-
newFileRef: normalizedNewFileRef,
|
|
8557
|
-
fileLabel:
|
|
8558
|
-
path.basename(
|
|
8559
|
-
normalizeTimelineFileEventType(change.changeType) === "delete"
|
|
8560
|
-
? normalizedOldFileRef || normalizedFileRef
|
|
8561
|
-
: normalizedNewFileRef || normalizedFileRef
|
|
8562
|
-
) ||
|
|
8563
|
-
normalizedNewFileRef ||
|
|
8564
|
-
normalizedOldFileRef ||
|
|
8565
|
-
normalizedFileRef,
|
|
8566
|
-
changeType: normalizeTimelineFileEventType(change.changeType),
|
|
8567
|
-
fileEventTypes: new Set(),
|
|
8568
|
-
addedLines: 0,
|
|
8569
|
-
removedLines: 0,
|
|
8570
|
-
latestChangedAtMs: latestOwnerChangeAtMs,
|
|
8571
|
-
sections: [],
|
|
8572
|
-
};
|
|
8573
|
-
threadGroup.filesByRef.set(fileGroupKey, fileGroup);
|
|
8574
|
-
}
|
|
8575
|
-
|
|
8576
|
-
const changeType = normalizeTimelineFileEventType(change.changeType);
|
|
8577
|
-
if (changeType) {
|
|
8578
|
-
fileGroup.fileEventTypes.add(changeType);
|
|
8579
|
-
}
|
|
8580
|
-
fileGroup.changeType = changeType || fileGroup.changeType;
|
|
8581
|
-
fileGroup.addedLines = Math.max(0, Number(change.diffAddedLines) || 0);
|
|
8582
|
-
fileGroup.removedLines = Math.max(0, Number(change.diffRemovedLines) || 0);
|
|
8583
|
-
fileGroup.latestChangedAtMs = latestOwnerChangeAtMs;
|
|
8584
|
-
fileGroup.fileRef = normalizedFileRef;
|
|
8585
|
-
fileGroup.oldFileRef = normalizedOldFileRef;
|
|
8586
|
-
fileGroup.newFileRef = normalizedNewFileRef;
|
|
8587
|
-
fileGroup.sections = [
|
|
8588
|
-
{
|
|
8589
|
-
createdAtMs: latestOwnerChangeAtMs,
|
|
8590
|
-
diffText: normalizeTimelineDiffText(change.diffText ?? ""),
|
|
8591
|
-
diffAvailable: change.diffAvailable === true || Boolean(change.diffText),
|
|
8592
|
-
diffSource: normalizeTimelineDiffSource(change.diffSource ?? ""),
|
|
8593
|
-
addedLines: Math.max(0, Number(change.diffAddedLines) || 0),
|
|
8594
|
-
removedLines: Math.max(0, Number(change.diffRemovedLines) || 0),
|
|
8595
|
-
fileEventType: changeType,
|
|
8596
|
-
},
|
|
8597
|
-
];
|
|
8598
|
-
|
|
8599
|
-
threadGroup.latestChangedAtMs = Math.max(threadGroup.latestChangedAtMs, latestOwnerChangeAtMs);
|
|
8600
|
-
threadGroup.diffAddedLines += Math.max(0, Number(change.diffAddedLines) || 0);
|
|
8601
|
-
threadGroup.diffRemovedLines += Math.max(0, Number(change.diffRemovedLines) || 0);
|
|
8602
|
-
|
|
8603
|
-
if (latestOwnerChangeAtMs > threadGroup.latestChangedAtMsForSummary) {
|
|
8604
|
-
threadGroup.latestChangedAtMsForSummary = latestOwnerChangeAtMs;
|
|
8605
|
-
threadGroup.latestChangeType = changeType || "";
|
|
8606
|
-
threadGroup.latestChangeFileRefs = [normalizedFileRef || normalizedNewFileRef || normalizedOldFileRef];
|
|
8607
|
-
} else if (latestOwnerChangeAtMs === (threadGroup.latestChangedAtMsForSummary || 0)) {
|
|
8608
|
-
if (changeType && threadGroup.latestChangeType && threadGroup.latestChangeType !== changeType) {
|
|
8609
|
-
threadGroup.latestChangeType = "";
|
|
8610
|
-
} else if (!threadGroup.latestChangeType && changeType && threadGroup.latestChangeFileRefs.length === 0) {
|
|
8611
|
-
threadGroup.latestChangeType = changeType;
|
|
8612
|
-
}
|
|
8613
|
-
const latestFileRef = normalizedFileRef || normalizedNewFileRef || normalizedOldFileRef;
|
|
8614
|
-
if (latestFileRef && !threadGroup.latestChangeFileRefs.includes(latestFileRef)) {
|
|
8615
|
-
threadGroup.latestChangeFileRefs.push(latestFileRef);
|
|
8616
|
-
}
|
|
8617
|
-
}
|
|
8832
|
+
latestNonGitChangesByIdentity.set(identity, change);
|
|
8618
8833
|
}
|
|
8619
8834
|
}
|
|
8620
8835
|
|
|
8836
|
+
for (const change of latestNonGitChangesByIdentity.values()) {
|
|
8837
|
+
addChangeToDiffThreadGroup({
|
|
8838
|
+
groupsByThread,
|
|
8839
|
+
threadId: cleanText(change.threadId || ""),
|
|
8840
|
+
threadLabel: cleanText(change.threadLabel || ""),
|
|
8841
|
+
fallbackKey: cleanText(change.fileRef || change.newFileRef || change.oldFileRef || ""),
|
|
8842
|
+
sourceMode: "non_git_latest",
|
|
8843
|
+
change,
|
|
8844
|
+
createdAtMs: Number(change.createdAtMs) || 0,
|
|
8845
|
+
});
|
|
8846
|
+
}
|
|
8847
|
+
|
|
8621
8848
|
return [...groupsByThread.values()]
|
|
8622
8849
|
.map((group) => {
|
|
8623
8850
|
const files = [...group.filesByRef.values()]
|
|
@@ -8627,7 +8854,9 @@ async function buildDiffThreadGroups(runtime, state, config) {
|
|
|
8627
8854
|
newFileRef: fileGroup.newFileRef,
|
|
8628
8855
|
fileLabel: fileGroup.fileLabel,
|
|
8629
8856
|
changeType: normalizeTimelineFileEventType(fileGroup.changeType),
|
|
8630
|
-
fileEventTypes:
|
|
8857
|
+
fileEventTypes: Array.isArray(fileGroup.fileEventTypes)
|
|
8858
|
+
? fileGroup.fileEventTypes
|
|
8859
|
+
: [...fileGroup.fileEventTypes.values()],
|
|
8631
8860
|
addedLines: fileGroup.addedLines,
|
|
8632
8861
|
removedLines: fileGroup.removedLines,
|
|
8633
8862
|
latestChangedAtMs: fileGroup.latestChangedAtMs,
|
|
@@ -8635,20 +8864,33 @@ async function buildDiffThreadGroups(runtime, state, config) {
|
|
|
8635
8864
|
}))
|
|
8636
8865
|
.sort((left, right) => Number(right.latestChangedAtMs ?? 0) - Number(left.latestChangedAtMs ?? 0));
|
|
8637
8866
|
|
|
8867
|
+
const latestChangedAtMs = Math.max(0, ...files.map((fileGroup) => Number(fileGroup.latestChangedAtMs) || 0));
|
|
8868
|
+
const latestFiles = files.filter((fileGroup) => Number(fileGroup.latestChangedAtMs || 0) === latestChangedAtMs);
|
|
8869
|
+
const latestChangeTypes = [...new Set(latestFiles.map((fileGroup) => normalizeTimelineFileEventType(fileGroup.changeType)).filter(Boolean))];
|
|
8870
|
+
const latestChangeFileRefs = normalizeTimelineFileRefs(
|
|
8871
|
+
latestFiles
|
|
8872
|
+
.map((fileGroup) => cleanTimelineFileRef(fileGroup.fileRef || fileGroup.newFileRef || fileGroup.oldFileRef || ""))
|
|
8873
|
+
.filter(Boolean)
|
|
8874
|
+
);
|
|
8875
|
+
const diffAddedLines = files.reduce((sum, fileGroup) => sum + Math.max(0, Number(fileGroup.addedLines) || 0), 0);
|
|
8876
|
+
const diffRemovedLines = files.reduce((sum, fileGroup) => sum + Math.max(0, Number(fileGroup.removedLines) || 0), 0);
|
|
8877
|
+
|
|
8638
8878
|
return {
|
|
8639
8879
|
kind: "diff_thread",
|
|
8640
8880
|
token: group.token,
|
|
8641
8881
|
threadId: group.threadId,
|
|
8642
8882
|
threadLabel: group.threadLabel,
|
|
8883
|
+
sourceMode: cleanText(group.sourceMode || ""),
|
|
8643
8884
|
changedFileCount: files.length,
|
|
8644
|
-
latestChangedAtMs
|
|
8645
|
-
latestChangeType:
|
|
8646
|
-
latestChangeFileRefs
|
|
8647
|
-
diffAddedLines
|
|
8648
|
-
diffRemovedLines
|
|
8885
|
+
latestChangedAtMs,
|
|
8886
|
+
latestChangeType: latestChangeTypes.length === 1 ? latestChangeTypes[0] : "",
|
|
8887
|
+
latestChangeFileRefs,
|
|
8888
|
+
diffAddedLines,
|
|
8889
|
+
diffRemovedLines,
|
|
8649
8890
|
files,
|
|
8650
8891
|
};
|
|
8651
8892
|
})
|
|
8893
|
+
.filter((group) => !shouldExcludeCodeThread(runtime, group.threadId))
|
|
8652
8894
|
.filter((group) => group.changedFileCount > 0)
|
|
8653
8895
|
.sort((left, right) => Number(right.latestChangedAtMs ?? 0) - Number(left.latestChangedAtMs ?? 0));
|
|
8654
8896
|
}
|
|
@@ -9165,18 +9407,20 @@ function buildTimelineFileEventDetail(entry, locale) {
|
|
|
9165
9407
|
}
|
|
9166
9408
|
|
|
9167
9409
|
function buildDiffThreadDetail(group, locale) {
|
|
9410
|
+
const changedFileCount = Math.max(0, Number(group.changedFileCount) || 0);
|
|
9168
9411
|
return {
|
|
9169
9412
|
kind: "diff_thread",
|
|
9170
9413
|
token: group.token,
|
|
9171
9414
|
threadId: cleanText(group.threadId || ""),
|
|
9172
9415
|
title: cleanText(group.threadLabel || "") || kindTitle(locale, "diff_thread"),
|
|
9173
9416
|
threadLabel: group.threadLabel || "",
|
|
9417
|
+
sourceMode: cleanText(group.sourceMode || ""),
|
|
9174
9418
|
createdAtMs: Number(group.latestChangedAtMs) || 0,
|
|
9175
|
-
changedFileCount
|
|
9419
|
+
changedFileCount,
|
|
9176
9420
|
diffAddedLines: Math.max(0, Number(group.diffAddedLines) || 0),
|
|
9177
9421
|
diffRemovedLines: Math.max(0, Number(group.diffRemovedLines) || 0),
|
|
9178
9422
|
messageHtml: renderMessageHtml(
|
|
9179
|
-
|
|
9423
|
+
diffThreadDetailCopy(locale, group.sourceMode, changedFileCount),
|
|
9180
9424
|
`<p>${escapeHtml(t(locale, "detail.detailUnavailable"))}</p>`
|
|
9181
9425
|
),
|
|
9182
9426
|
files: Array.isArray(group.files)
|
package/web/i18n.js
CHANGED
|
@@ -65,12 +65,12 @@ const translations = {
|
|
|
65
65
|
"tab.timeline.description": "Conversation updates and operational events across recent threads.",
|
|
66
66
|
"tab.diff.title": "Diff",
|
|
67
67
|
"tab.diff.label": "Diff",
|
|
68
|
-
"tab.diff.eyebrow": "
|
|
69
|
-
"tab.diff.description": "Review
|
|
68
|
+
"tab.diff.eyebrow": "Code changes",
|
|
69
|
+
"tab.diff.description": "Review file changes from Codex in a mobile-friendly diff view.",
|
|
70
70
|
"tab.code.title": "Code",
|
|
71
71
|
"tab.code.label": "Code",
|
|
72
|
-
"tab.code.eyebrow": "
|
|
73
|
-
"tab.code.description": "Review
|
|
72
|
+
"tab.code.eyebrow": "Code changes",
|
|
73
|
+
"tab.code.description": "Review file changes from Codex in a mobile-friendly diff view on your device.",
|
|
74
74
|
"tab.completed.title": "Completed",
|
|
75
75
|
"tab.completed.label": "Completed",
|
|
76
76
|
"tab.completed.eyebrow": "History",
|
|
@@ -112,7 +112,7 @@ const translations = {
|
|
|
112
112
|
"empty.pending":
|
|
113
113
|
"Nothing needs attention right now. New approvals, plans, and choices will appear here first.",
|
|
114
114
|
"empty.timeline": "No timeline activity is available yet. New conversation updates will show up here.",
|
|
115
|
-
"empty.diff": "No
|
|
115
|
+
"empty.diff": "No file changes are available right now.",
|
|
116
116
|
"empty.completed": "Completed history is empty for now.",
|
|
117
117
|
"empty.default": "Nothing to show right now.",
|
|
118
118
|
"detail.selectTitle": "Choose something from the list",
|
|
@@ -127,7 +127,11 @@ const translations = {
|
|
|
127
127
|
"detail.diffTitle": "Diff",
|
|
128
128
|
"detail.diffUnavailable": "Diff is not available for this change. Showing touched files only.",
|
|
129
129
|
"detail.diffThread.copy": ({ count }) =>
|
|
130
|
+
`This thread has ${count} ${count === 1 ? "changed file" : "changed files"}. Review each file below.`,
|
|
131
|
+
"detail.diffThread.copy.current": ({ count }) =>
|
|
130
132
|
`This thread currently has ${count} ${count === 1 ? "unstaged changed file" : "unstaged changed files"}. Review each file below.`,
|
|
133
|
+
"detail.diffThread.copy.latest": ({ count }) =>
|
|
134
|
+
`This thread has ${count} ${count === 1 ? "latest observed file change" : "latest observed file changes"}. Review each file below.`,
|
|
131
135
|
"detail.fileEvent.read": "Codex checked these files in this step.",
|
|
132
136
|
"detail.fileEvent.write": "Codex updated these files in this step.",
|
|
133
137
|
"detail.fileEvent.create": "Codex created these files in this step.",
|
|
@@ -182,14 +186,14 @@ const translations = {
|
|
|
182
186
|
"summary.plan": "Check the proposed plan before Codex starts implementing it.",
|
|
183
187
|
"summary.choice": "Pick the option Codex needs to continue.",
|
|
184
188
|
"summary.fileEvent": "Review the files Codex checked or updated in this step.",
|
|
185
|
-
"summary.diffThread": "Review the
|
|
189
|
+
"summary.diffThread": "Review the file changes for this thread.",
|
|
186
190
|
"summary.default": "Open the item to review its details.",
|
|
187
191
|
"intent.approval": "Approve or reject this request.",
|
|
188
192
|
"intent.plan": "Review this plan before Codex continues.",
|
|
189
193
|
"intent.choice": "Choose an answer so Codex can continue.",
|
|
190
194
|
"intent.completed": "Finished. Open to review the result.",
|
|
191
195
|
"intent.fileEvent": "Review the files involved in this step.",
|
|
192
|
-
"intent.diffThread": "Review the
|
|
196
|
+
"intent.diffThread": "Review the file changes for this thread.",
|
|
193
197
|
"intent.userMessage": "Open this message again.",
|
|
194
198
|
"intent.assistantCommentary": "Read the latest working update.",
|
|
195
199
|
"intent.assistantFinal": "Read Codex's final reply for this turn.",
|
|
@@ -224,7 +228,7 @@ const translations = {
|
|
|
224
228
|
"fileEvent.timeline.rename": ({ count }) => `Renamed ${count} ${count === 1 ? "file" : "files"}`,
|
|
225
229
|
"diff.threadSummary": ({ count }) => `Changed ${count} ${count === 1 ? "file" : "files"}`,
|
|
226
230
|
"diff.latestChange": "Latest change",
|
|
227
|
-
"diff.latestChangeFallback": "
|
|
231
|
+
"diff.latestChangeFallback": "File changes are available in this thread.",
|
|
228
232
|
"settings.intro": "Check pairing, language, install status, and Web Push health for this device.",
|
|
229
233
|
"settings.section.overview": "Quick setup",
|
|
230
234
|
"settings.section.notifications": "Notifications",
|
|
@@ -588,12 +592,12 @@ const translations = {
|
|
|
588
592
|
"tab.timeline.description": "最近のスレッドにまたがる会話の更新と操作イベントです。",
|
|
589
593
|
"tab.diff.title": "差分",
|
|
590
594
|
"tab.diff.label": "差分",
|
|
591
|
-
"tab.diff.eyebrow": "
|
|
592
|
-
"tab.diff.description": "Codex
|
|
595
|
+
"tab.diff.eyebrow": "コード変更",
|
|
596
|
+
"tab.diff.description": "Codex のファイル変更を端末で確認します。",
|
|
593
597
|
"tab.code.title": "コード",
|
|
594
598
|
"tab.code.label": "コード",
|
|
595
|
-
"tab.code.eyebrow": "
|
|
596
|
-
"tab.code.description": "Codex
|
|
599
|
+
"tab.code.eyebrow": "コード変更",
|
|
600
|
+
"tab.code.description": "Codex のファイル変更を端末で確認します。",
|
|
597
601
|
"tab.completed.title": "完了",
|
|
598
602
|
"tab.completed.label": "完了",
|
|
599
603
|
"tab.completed.eyebrow": "履歴",
|
|
@@ -634,7 +638,7 @@ const translations = {
|
|
|
634
638
|
"shell.subtitle.detail": "いまの流れを途切れさせずに、項目を確認して操作できます。",
|
|
635
639
|
"empty.pending": "いま対応が必要な項目はありません。新しい承認、プラン、選択がここに表示されます。",
|
|
636
640
|
"empty.timeline": "まだタイムライン項目はありません。新しい会話の更新がここに表示されます。",
|
|
637
|
-
"empty.diff": "
|
|
641
|
+
"empty.diff": "いま確認できるファイル変更はありません。",
|
|
638
642
|
"empty.completed": "完了履歴はまだありません。",
|
|
639
643
|
"empty.default": "いま表示できる項目はありません。",
|
|
640
644
|
"detail.selectTitle": "一覧から項目を選んでください",
|
|
@@ -648,7 +652,9 @@ const translations = {
|
|
|
648
652
|
"detail.filesTitle": "関連ファイル",
|
|
649
653
|
"detail.diffTitle": "差分",
|
|
650
654
|
"detail.diffUnavailable": "この変更の差分はまだ利用できません。対象ファイルのみ表示します。",
|
|
651
|
-
"detail.diffThread.copy": ({ count }) =>
|
|
655
|
+
"detail.diffThread.copy": ({ count }) => `このスレッドで変更があるファイルは ${count}件です。下でファイルごとに確認できます。`,
|
|
656
|
+
"detail.diffThread.copy.current": ({ count }) => `このスレッドで現在未ステージの変更があるファイルは ${count}件です。下でファイルごとに確認できます。`,
|
|
657
|
+
"detail.diffThread.copy.latest": ({ count }) => `このスレッドで最後に観測した変更があるファイルは ${count}件です。下でファイルごとに確認できます。`,
|
|
652
658
|
"detail.fileEvent.read": "このステップで確認したファイルです。",
|
|
653
659
|
"detail.fileEvent.write": "このステップで更新したファイルです。",
|
|
654
660
|
"detail.fileEvent.create": "このステップで作成したファイルです。",
|
|
@@ -703,14 +709,14 @@ const translations = {
|
|
|
703
709
|
"summary.plan": "Codex が実装を始める前に、提案されたプランを確認します。",
|
|
704
710
|
"summary.choice": "Codex が先へ進むために必要な選択肢を選びます。",
|
|
705
711
|
"summary.fileEvent": "このステップで触れたファイルを確認します。",
|
|
706
|
-
"summary.diffThread": "
|
|
712
|
+
"summary.diffThread": "このスレッドのファイル変更を確認します。",
|
|
707
713
|
"summary.default": "項目を開いて詳細を確認します。",
|
|
708
714
|
"intent.approval": "このリクエストを承認するか拒否します。",
|
|
709
715
|
"intent.plan": "Codex が続行する前にこのプランを確認します。",
|
|
710
716
|
"intent.choice": "Codex が続行できるように回答を選びます。",
|
|
711
717
|
"intent.completed": "完了済みです。結果を確認できます。",
|
|
712
718
|
"intent.fileEvent": "このステップで触れたファイルを確認します。",
|
|
713
|
-
"intent.diffThread": "
|
|
719
|
+
"intent.diffThread": "このスレッドのファイル変更を確認します。",
|
|
714
720
|
"intent.userMessage": "このメッセージを開き直します。",
|
|
715
721
|
"intent.assistantCommentary": "最新の途中経過を確認します。",
|
|
716
722
|
"intent.assistantFinal": "このターンの Codex の最終回答を確認します。",
|
|
@@ -745,7 +751,7 @@ const translations = {
|
|
|
745
751
|
"fileEvent.timeline.rename": ({ count }) => `ファイル名を変更 ${count}件`,
|
|
746
752
|
"diff.threadSummary": ({ count }) => `変更ファイル ${count}件`,
|
|
747
753
|
"diff.latestChange": "最終変更",
|
|
748
|
-
"diff.latestChangeFallback": "
|
|
754
|
+
"diff.latestChangeFallback": "このスレッドにファイル変更があります。",
|
|
749
755
|
"settings.intro": "この端末のペアリング、言語、インストール状況、Web Push の状態を確認できます。",
|
|
750
756
|
"settings.section.overview": "クイック確認",
|
|
751
757
|
"settings.section.notifications": "通知",
|