@very_aq/codex-cli-web 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +228 -0
- package/README.zh-CN.md +228 -0
- package/package.json +38 -0
- package/server/dist/admin/userAdminRoutes.d.ts +7 -0
- package/server/dist/admin/userAdminRoutes.js +91 -0
- package/server/dist/admin/userAdminRoutes.js.map +1 -0
- package/server/dist/app.d.ts +22 -0
- package/server/dist/app.js +993 -0
- package/server/dist/app.js.map +1 -0
- package/server/dist/auth/adminInit.d.ts +41 -0
- package/server/dist/auth/adminInit.js +126 -0
- package/server/dist/auth/adminInit.js.map +1 -0
- package/server/dist/auth/bootstrapAdmin.d.ts +6 -0
- package/server/dist/auth/bootstrapAdmin.js +11 -0
- package/server/dist/auth/bootstrapAdmin.js.map +1 -0
- package/server/dist/auth/httpAuth.d.ts +16 -0
- package/server/dist/auth/httpAuth.js +31 -0
- package/server/dist/auth/httpAuth.js.map +1 -0
- package/server/dist/auth/password.d.ts +2 -0
- package/server/dist/auth/password.js +68 -0
- package/server/dist/auth/password.js.map +1 -0
- package/server/dist/auth/requireAdmin.d.ts +2 -0
- package/server/dist/auth/requireAdmin.js +14 -0
- package/server/dist/auth/requireAdmin.js.map +1 -0
- package/server/dist/auth/roles.d.ts +3 -0
- package/server/dist/auth/roles.js +13 -0
- package/server/dist/auth/roles.js.map +1 -0
- package/server/dist/auth/session.d.ts +24 -0
- package/server/dist/auth/session.js +127 -0
- package/server/dist/auth/session.js.map +1 -0
- package/server/dist/auth/sqlite/authDb.d.ts +18 -0
- package/server/dist/auth/sqlite/authDb.js +26 -0
- package/server/dist/auth/sqlite/authDb.js.map +1 -0
- package/server/dist/auth/sqlite/legacyImport.d.ts +22 -0
- package/server/dist/auth/sqlite/legacyImport.js +208 -0
- package/server/dist/auth/sqlite/legacyImport.js.map +1 -0
- package/server/dist/auth/sqlite/schema.d.ts +11 -0
- package/server/dist/auth/sqlite/schema.js +47 -0
- package/server/dist/auth/sqlite/schema.js.map +1 -0
- package/server/dist/auth/sqlite/sqliteUserStore.d.ts +12 -0
- package/server/dist/auth/sqlite/sqliteUserStore.js +194 -0
- package/server/dist/auth/sqlite/sqliteUserStore.js.map +1 -0
- package/server/dist/auth/userStore.d.ts +19 -0
- package/server/dist/auth/userStore.js +26 -0
- package/server/dist/auth/userStore.js.map +1 -0
- package/server/dist/auth/userTypes.d.ts +13 -0
- package/server/dist/auth/userTypes.js +3 -0
- package/server/dist/auth/userTypes.js.map +1 -0
- package/server/dist/chat/attachmentPathRedaction.d.ts +5 -0
- package/server/dist/chat/attachmentPathRedaction.js +67 -0
- package/server/dist/chat/attachmentPathRedaction.js.map +1 -0
- package/server/dist/chat/chatItemEnricher.d.ts +5 -0
- package/server/dist/chat/chatItemEnricher.js +40 -0
- package/server/dist/chat/chatItemEnricher.js.map +1 -0
- package/server/dist/chat/codexEventProjector.d.ts +33 -0
- package/server/dist/chat/codexEventProjector.js +482 -0
- package/server/dist/chat/codexEventProjector.js.map +1 -0
- package/server/dist/chat/contextUsageProjector.d.ts +10 -0
- package/server/dist/chat/contextUsageProjector.js +472 -0
- package/server/dist/chat/contextUsageProjector.js.map +1 -0
- package/server/dist/chat/fileChangeExtractor.d.ts +5 -0
- package/server/dist/chat/fileChangeExtractor.js +121 -0
- package/server/dist/chat/fileChangeExtractor.js.map +1 -0
- package/server/dist/chat/markdown/markdownAst.d.ts +5 -0
- package/server/dist/chat/markdown/markdownAst.js +154 -0
- package/server/dist/chat/markdown/markdownAst.js.map +1 -0
- package/server/dist/chat/systemToolCallSummary.d.ts +10 -0
- package/server/dist/chat/systemToolCallSummary.js +112 -0
- package/server/dist/chat/systemToolCallSummary.js.map +1 -0
- package/server/dist/chat/terminal/terminalPlainText.d.ts +14 -0
- package/server/dist/chat/terminal/terminalPlainText.js +139 -0
- package/server/dist/chat/terminal/terminalPlainText.js.map +1 -0
- package/server/dist/chat/textMetrics.d.ts +9 -0
- package/server/dist/chat/textMetrics.js +24 -0
- package/server/dist/chat/textMetrics.js.map +1 -0
- package/server/dist/chat/threadTurnsProjector.d.ts +12 -0
- package/server/dist/chat/threadTurnsProjector.js +292 -0
- package/server/dist/chat/threadTurnsProjector.js.map +1 -0
- package/server/dist/chat/todoPlanProjector.d.ts +8 -0
- package/server/dist/chat/todoPlanProjector.js +94 -0
- package/server/dist/chat/todoPlanProjector.js.map +1 -0
- package/server/dist/chat/todoPlanTypes.d.ts +21 -0
- package/server/dist/chat/todoPlanTypes.js +3 -0
- package/server/dist/chat/todoPlanTypes.js.map +1 -0
- package/server/dist/chat/types.d.ts +138 -0
- package/server/dist/chat/types.js +3 -0
- package/server/dist/chat/types.js.map +1 -0
- package/server/dist/cli/configArg.d.ts +21 -0
- package/server/dist/cli/configArg.js +70 -0
- package/server/dist/cli/configArg.js.map +1 -0
- package/server/dist/codex/appServerProcess.d.ts +24 -0
- package/server/dist/codex/appServerProcess.js +56 -0
- package/server/dist/codex/appServerProcess.js.map +1 -0
- package/server/dist/codex/cliArgs.d.ts +17 -0
- package/server/dist/codex/cliArgs.js +34 -0
- package/server/dist/codex/cliArgs.js.map +1 -0
- package/server/dist/codex/codexAppServer.d.ts +103 -0
- package/server/dist/codex/codexAppServer.js +206 -0
- package/server/dist/codex/codexAppServer.js.map +1 -0
- package/server/dist/codex/jsonl.d.ts +4 -0
- package/server/dist/codex/jsonl.js +23 -0
- package/server/dist/codex/jsonl.js.map +1 -0
- package/server/dist/codex/jsonrpc.d.ts +43 -0
- package/server/dist/codex/jsonrpc.js +96 -0
- package/server/dist/codex/jsonrpc.js.map +1 -0
- package/server/dist/config/serverConfig.d.ts +150 -0
- package/server/dist/config/serverConfig.js +64 -0
- package/server/dist/config/serverConfig.js.map +1 -0
- package/server/dist/env.d.ts +101 -0
- package/server/dist/env.js +523 -0
- package/server/dist/env.js.map +1 -0
- package/server/dist/history/http/historyRoutes.d.ts +18 -0
- package/server/dist/history/http/historyRoutes.js +67 -0
- package/server/dist/history/http/historyRoutes.js.map +1 -0
- package/server/dist/history/index.d.ts +24 -0
- package/server/dist/history/index.js +30 -0
- package/server/dist/history/index.js.map +1 -0
- package/server/dist/history/ingest/historyIngestService.d.ts +15 -0
- package/server/dist/history/ingest/historyIngestService.js +42 -0
- package/server/dist/history/ingest/historyIngestService.js.map +1 -0
- package/server/dist/history/projector/extractIds.d.ts +36 -0
- package/server/dist/history/projector/extractIds.js +111 -0
- package/server/dist/history/projector/extractIds.js.map +1 -0
- package/server/dist/history/projector/projectCodexEvent.d.ts +27 -0
- package/server/dist/history/projector/projectCodexEvent.js +845 -0
- package/server/dist/history/projector/projectCodexEvent.js.map +1 -0
- package/server/dist/history/query/historyQueryService.d.ts +34 -0
- package/server/dist/history/query/historyQueryService.js +170 -0
- package/server/dist/history/query/historyQueryService.js.map +1 -0
- package/server/dist/history/sqlite/schema.d.ts +11 -0
- package/server/dist/history/sqlite/schema.js +34 -0
- package/server/dist/history/sqlite/schema.js.map +1 -0
- package/server/dist/history/sqlite/sqliteHistoryStore.d.ts +69 -0
- package/server/dist/history/sqlite/sqliteHistoryStore.js +206 -0
- package/server/dist/history/sqlite/sqliteHistoryStore.js.map +1 -0
- package/server/dist/history/types.d.ts +29 -0
- package/server/dist/history/types.js +3 -0
- package/server/dist/history/types.js.map +1 -0
- package/server/dist/index.d.ts +1 -0
- package/server/dist/index.js +166 -0
- package/server/dist/index.js.map +1 -0
- package/server/dist/security/executionPolicy.d.ts +33 -0
- package/server/dist/security/executionPolicy.js +72 -0
- package/server/dist/security/executionPolicy.js.map +1 -0
- package/server/dist/security/origin.d.ts +11 -0
- package/server/dist/security/origin.js +40 -0
- package/server/dist/security/origin.js.map +1 -0
- package/server/dist/settings/sqliteUserSettingsStore.d.ts +12 -0
- package/server/dist/settings/sqliteUserSettingsStore.js +62 -0
- package/server/dist/settings/sqliteUserSettingsStore.js.map +1 -0
- package/server/dist/settings/userSettingsRoutes.d.ts +8 -0
- package/server/dist/settings/userSettingsRoutes.js +55 -0
- package/server/dist/settings/userSettingsRoutes.js.map +1 -0
- package/server/dist/settings/userSettingsStore.d.ts +19 -0
- package/server/dist/settings/userSettingsStore.js +26 -0
- package/server/dist/settings/userSettingsStore.js.map +1 -0
- package/server/dist/settings/userSettingsTypes.d.ts +70 -0
- package/server/dist/settings/userSettingsTypes.js +196 -0
- package/server/dist/settings/userSettingsTypes.js.map +1 -0
- package/server/dist/status/codexTaskTracker.d.ts +21 -0
- package/server/dist/status/codexTaskTracker.js +123 -0
- package/server/dist/status/codexTaskTracker.js.map +1 -0
- package/server/dist/status/threadContextUsage.d.ts +19 -0
- package/server/dist/status/threadContextUsage.js +229 -0
- package/server/dist/status/threadContextUsage.js.map +1 -0
- package/server/dist/threadList/threadListServerCache.d.ts +10 -0
- package/server/dist/threadList/threadListServerCache.js +42 -0
- package/server/dist/threadList/threadListServerCache.js.map +1 -0
- package/server/dist/tools/cwdSuggest.d.ts +11 -0
- package/server/dist/tools/cwdSuggest.js +128 -0
- package/server/dist/tools/cwdSuggest.js.map +1 -0
- package/server/dist/workspace/accessControl.d.ts +16 -0
- package/server/dist/workspace/accessControl.js +82 -0
- package/server/dist/workspace/accessControl.js.map +1 -0
- package/server/dist/workspace/sqliteUserWorkspaceStore.d.ts +12 -0
- package/server/dist/workspace/sqliteUserWorkspaceStore.js +82 -0
- package/server/dist/workspace/sqliteUserWorkspaceStore.js.map +1 -0
- package/server/dist/workspace/threadAccess.d.ts +19 -0
- package/server/dist/workspace/threadAccess.js +22 -0
- package/server/dist/workspace/threadAccess.js.map +1 -0
- package/server/dist/workspace/threadListVisibility.d.ts +25 -0
- package/server/dist/workspace/threadListVisibility.js +104 -0
- package/server/dist/workspace/threadListVisibility.js.map +1 -0
- package/server/dist/workspace/userWorkspaceRoutes.d.ts +7 -0
- package/server/dist/workspace/userWorkspaceRoutes.js +124 -0
- package/server/dist/workspace/userWorkspaceRoutes.js.map +1 -0
- package/server/dist/workspace/userWorkspaceStore.d.ts +12 -0
- package/server/dist/workspace/userWorkspaceStore.js +23 -0
- package/server/dist/workspace/userWorkspaceStore.js.map +1 -0
- package/server/dist/ws/socketIoBridge.d.ts +32 -0
- package/server/dist/ws/socketIoBridge.js +194 -0
- package/server/dist/ws/socketIoBridge.js.map +1 -0
- package/server/dist/ws/types.d.ts +113 -0
- package/server/dist/ws/types.js +3 -0
- package/server/dist/ws/types.js.map +1 -0
- package/server/dist/ws/wsHub.d.ts +119 -0
- package/server/dist/ws/wsHub.js +1259 -0
- package/server/dist/ws/wsHub.js.map +1 -0
- package/web/dist/assets/index-CY6cnwQz.js +174 -0
- package/web/dist/assets/index-DI7kJHr2.css +32 -0
- package/web/dist/favicon-mask.svg +9 -0
- package/web/dist/favicon.svg +26 -0
- package/web/dist/index.html +75 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.redactAttachmentPathsForDisplay = redactAttachmentPathsForDisplay;
|
|
4
|
+
const ATTACHMENT_PREFIX_REGEX = /^(\\s*\\[attachment\\]\\s+)(.+)$/i;
|
|
5
|
+
/**
|
|
6
|
+
* 从附件路径中提取文件名(basename)。
|
|
7
|
+
*/
|
|
8
|
+
function extractAttachmentFilename(rawAttachmentPath) {
|
|
9
|
+
// Trim 并移除尾部分隔符,兼容 `/` 与 `\\`。
|
|
10
|
+
const normalizedAttachmentPath = rawAttachmentPath.trim().replace(/[\\\\/]+$/g, "");
|
|
11
|
+
if (!normalizedAttachmentPath)
|
|
12
|
+
return "";
|
|
13
|
+
const pathParts = normalizedAttachmentPath.split(/[\\\\/]/).filter(Boolean);
|
|
14
|
+
if (!pathParts.length)
|
|
15
|
+
return "";
|
|
16
|
+
return pathParts[pathParts.length - 1] ?? "";
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* 将附件路径转换为安全展示名(仅文件名)。
|
|
20
|
+
*/
|
|
21
|
+
function extractAttachmentDisplayName(rawAttachmentPath) {
|
|
22
|
+
const attachmentFilename = extractAttachmentFilename(rawAttachmentPath);
|
|
23
|
+
if (!attachmentFilename)
|
|
24
|
+
return "attachment";
|
|
25
|
+
return attachmentFilename;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* 解析一行 `[attachment] ...`,提取展示所需元数据。
|
|
29
|
+
*/
|
|
30
|
+
function parseAttachmentLineForDisplay(line) {
|
|
31
|
+
const matchedAttachmentLine = line.match(ATTACHMENT_PREFIX_REGEX);
|
|
32
|
+
if (!matchedAttachmentLine)
|
|
33
|
+
return null;
|
|
34
|
+
// 保留原始前缀,便于未来格式化扩展。
|
|
35
|
+
const linePrefix = matchedAttachmentLine[1] ?? "[attachment] ";
|
|
36
|
+
const rawAttachmentPath = String(matchedAttachmentLine[2] ?? "").trim();
|
|
37
|
+
if (!rawAttachmentPath)
|
|
38
|
+
return null;
|
|
39
|
+
const attachmentFilename = extractAttachmentFilename(rawAttachmentPath);
|
|
40
|
+
if (!attachmentFilename)
|
|
41
|
+
return null;
|
|
42
|
+
const attachmentDisplayName = extractAttachmentDisplayName(rawAttachmentPath);
|
|
43
|
+
return {
|
|
44
|
+
prefix: linePrefix,
|
|
45
|
+
rawPath: rawAttachmentPath,
|
|
46
|
+
filename: attachmentFilename,
|
|
47
|
+
displayName: attachmentDisplayName,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* 将 `[attachment] <path>` 行脱敏为 `[attachment] <filename>`。
|
|
52
|
+
* 注意:仅用于 UI 展示,不能影响真正发送给 codex 的原始文本。
|
|
53
|
+
*/
|
|
54
|
+
function redactAttachmentPathsForDisplay(text) {
|
|
55
|
+
if (!text.trim())
|
|
56
|
+
return text;
|
|
57
|
+
return text
|
|
58
|
+
.split("\n")
|
|
59
|
+
.map((line) => {
|
|
60
|
+
const parsedAttachmentLine = parseAttachmentLineForDisplay(line);
|
|
61
|
+
if (!parsedAttachmentLine)
|
|
62
|
+
return line;
|
|
63
|
+
return `${parsedAttachmentLine.prefix}${parsedAttachmentLine.displayName}`;
|
|
64
|
+
})
|
|
65
|
+
.join("\n");
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=attachmentPathRedaction.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attachmentPathRedaction.js","sourceRoot":"","sources":["../../src/chat/attachmentPathRedaction.ts"],"names":[],"mappings":";;AA4DA,0EAWC;AAvED,MAAM,uBAAuB,GAAG,mCAAmC,CAAC;AAEpE;;GAEG;AACH,SAAS,yBAAyB,CAAC,iBAAyB;IAC1D,+BAA+B;IAC/B,MAAM,wBAAwB,GAAG,iBAAiB,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;IACpF,IAAI,CAAC,wBAAwB;QAAE,OAAO,EAAE,CAAC;IAEzC,MAAM,SAAS,GAAG,wBAAwB,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC5E,IAAI,CAAC,SAAS,CAAC,MAAM;QAAE,OAAO,EAAE,CAAC;IAEjC,OAAO,SAAS,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;AAC/C,CAAC;AAED;;GAEG;AACH,SAAS,4BAA4B,CAAC,iBAAyB;IAC7D,MAAM,kBAAkB,GAAG,yBAAyB,CAAC,iBAAiB,CAAC,CAAC;IACxE,IAAI,CAAC,kBAAkB;QAAE,OAAO,YAAY,CAAC;IAC7C,OAAO,kBAAkB,CAAC;AAC5B,CAAC;AASD;;GAEG;AACH,SAAS,6BAA6B,CAAC,IAAY;IACjD,MAAM,qBAAqB,GAAG,IAAI,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC;IAClE,IAAI,CAAC,qBAAqB;QAAE,OAAO,IAAI,CAAC;IAExC,oBAAoB;IACpB,MAAM,UAAU,GAAG,qBAAqB,CAAC,CAAC,CAAC,IAAI,eAAe,CAAC;IAC/D,MAAM,iBAAiB,GAAG,MAAM,CAAC,qBAAqB,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACxE,IAAI,CAAC,iBAAiB;QAAE,OAAO,IAAI,CAAC;IAEpC,MAAM,kBAAkB,GAAG,yBAAyB,CAAC,iBAAiB,CAAC,CAAC;IACxE,IAAI,CAAC,kBAAkB;QAAE,OAAO,IAAI,CAAC;IAErC,MAAM,qBAAqB,GAAG,4BAA4B,CAAC,iBAAiB,CAAC,CAAC;IAC9E,OAAO;QACL,MAAM,EAAE,UAAU;QAClB,OAAO,EAAE,iBAAiB;QAC1B,QAAQ,EAAE,kBAAkB;QAC5B,WAAW,EAAE,qBAAqB;KACnC,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,SAAgB,+BAA+B,CAAC,IAAY;IAC1D,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;QAAE,OAAO,IAAI,CAAC;IAE9B,OAAO,IAAI;SACR,KAAK,CAAC,IAAI,CAAC;SACX,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QACZ,MAAM,oBAAoB,GAAG,6BAA6B,CAAC,IAAI,CAAC,CAAC;QACjE,IAAI,CAAC,oBAAoB;YAAE,OAAO,IAAI,CAAC;QACvC,OAAO,GAAG,oBAAoB,CAAC,MAAM,GAAG,oBAAoB,CAAC,WAAW,EAAE,CAAC;IAC7E,CAAC,CAAC;SACD,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.enrichChatItemForUi = enrichChatItemForUi;
|
|
4
|
+
const markdownAst_1 = require("./markdown/markdownAst");
|
|
5
|
+
const systemToolCallSummary_1 = require("./systemToolCallSummary");
|
|
6
|
+
const textMetrics_1 = require("./textMetrics");
|
|
7
|
+
const terminalPlainText_1 = require("./terminal/terminalPlainText");
|
|
8
|
+
/**
|
|
9
|
+
* 为 ChatItem 追加“后端解析后的渲染字段”,让前端只负责渲染。
|
|
10
|
+
*/
|
|
11
|
+
function enrichChatItemForUi(item) {
|
|
12
|
+
const isTerminal = item.render === "terminal";
|
|
13
|
+
const isDiff = item.render === "diff";
|
|
14
|
+
const next = { ...item };
|
|
15
|
+
// streaming 缺省视为“已完成”(历史/turns 快照常省略该字段)。
|
|
16
|
+
const isStreaming = next.streaming === true;
|
|
17
|
+
if (isTerminal && !next.plainText && !isStreaming) {
|
|
18
|
+
next.plainText = (0, terminalPlainText_1.normalizeTerminalText)(next.text);
|
|
19
|
+
}
|
|
20
|
+
if (!next.metrics) {
|
|
21
|
+
const metricsSource = isDiff ? "" : next.plainText ?? next.text;
|
|
22
|
+
next.metrics = (0, textMetrics_1.getTextMetrics)(metricsSource);
|
|
23
|
+
}
|
|
24
|
+
const isTextRender = !isTerminal && !isDiff && next.render !== "approval";
|
|
25
|
+
const role = next.role;
|
|
26
|
+
const canHaveMarkdown = isTextRender && (role === "assistant" || role === "reasoning" || role === "system");
|
|
27
|
+
if (canHaveMarkdown && !isStreaming) {
|
|
28
|
+
if (role === "system") {
|
|
29
|
+
const parsedSummary = (0, systemToolCallSummary_1.parseSystemToolCallSummary)(next.text);
|
|
30
|
+
next.systemToolCallSummary = parsedSummary;
|
|
31
|
+
next.markdownAst = parsedSummary ? null : (0, markdownAst_1.buildMarkdownAst)(next.text);
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
next.markdownAst = (0, markdownAst_1.buildMarkdownAst)(next.text);
|
|
35
|
+
next.systemToolCallSummary = null;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return next;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=chatItemEnricher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chatItemEnricher.js","sourceRoot":"","sources":["../../src/chat/chatItemEnricher.ts"],"names":[],"mappings":";;AASA,kDAiCC;AA1CD,wDAA0D;AAC1D,mEAAqE;AACrE,+CAA+C;AAC/C,oEAAqE;AAGrE;;GAEG;AACH,SAAgB,mBAAmB,CAAC,IAAc;IAChD,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,KAAK,UAAU,CAAC;IAC9C,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,KAAK,MAAM,CAAC;IAEtC,MAAM,IAAI,GAAa,EAAE,GAAG,IAAI,EAAE,CAAC;IACnC,0CAA0C;IAC1C,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,KAAK,IAAI,CAAC;IAE5C,IAAI,UAAU,IAAI,CAAC,IAAI,CAAC,SAAS,IAAI,CAAC,WAAW,EAAE,CAAC;QAClD,IAAI,CAAC,SAAS,GAAG,IAAA,yCAAqB,EAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACpD,CAAC;IAED,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;QAClB,MAAM,aAAa,GAAG,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,IAAI,CAAC;QAChE,IAAI,CAAC,OAAO,GAAG,IAAA,4BAAc,EAAC,aAAa,CAAC,CAAC;IAC/C,CAAC;IAED,MAAM,YAAY,GAAG,CAAC,UAAU,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,KAAK,UAAU,CAAC;IAC1E,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;IACvB,MAAM,eAAe,GAAG,YAAY,IAAI,CAAC,IAAI,KAAK,WAAW,IAAI,IAAI,KAAK,WAAW,IAAI,IAAI,KAAK,QAAQ,CAAC,CAAC;IAE5G,IAAI,eAAe,IAAI,CAAC,WAAW,EAAE,CAAC;QACpC,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;YACtB,MAAM,aAAa,GAAG,IAAA,kDAA0B,EAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC5D,IAAI,CAAC,qBAAqB,GAAG,aAAa,CAAC;YAC3C,IAAI,CAAC,WAAW,GAAG,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAA,8BAAgB,EAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxE,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,WAAW,GAAG,IAAA,8BAAgB,EAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC/C,IAAI,CAAC,qBAAqB,GAAG,IAAI,CAAC;QACpC,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { ChatOp } from "./types";
|
|
2
|
+
import type { TodoPlanUpdate } from "./todoPlanTypes";
|
|
3
|
+
/**
|
|
4
|
+
* 后端“聊天投影器”:
|
|
5
|
+
* - 接收 Codex notification(method/params);
|
|
6
|
+
* - 产出 UI 可直接消费的 ChatOp(前端只需合并与渲染);
|
|
7
|
+
* - 并可选解析 TODO/上下文使用率等轻量附属状态。
|
|
8
|
+
*
|
|
9
|
+
* 说明:该投影器只支持 app-server v2 的 item/turn 生命周期事件;
|
|
10
|
+
* 不再兼容 legacy `codex/event/*`(按你的要求移除旧版本兼容)。
|
|
11
|
+
*/
|
|
12
|
+
export declare class ChatProjector {
|
|
13
|
+
/**
|
|
14
|
+
* 递增计数器:用于生成 best-effort 的 fallback id。
|
|
15
|
+
*/
|
|
16
|
+
private fallbackSeq;
|
|
17
|
+
/**
|
|
18
|
+
* 投影单条 Codex notification。
|
|
19
|
+
*/
|
|
20
|
+
projectNotification(input: {
|
|
21
|
+
threadId: string | null;
|
|
22
|
+
payload: unknown;
|
|
23
|
+
nowMs: number;
|
|
24
|
+
}): {
|
|
25
|
+
ops: ChatOp[];
|
|
26
|
+
todoUpdate: TodoPlanUpdate | null;
|
|
27
|
+
usagePercent: number | null;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* 生成 best-effort fallback id:用于 itemId 缺失等非理想输入。
|
|
31
|
+
*/
|
|
32
|
+
private resolveFallbackId;
|
|
33
|
+
}
|
|
@@ -0,0 +1,482 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ChatProjector = void 0;
|
|
4
|
+
const attachmentPathRedaction_1 = require("./attachmentPathRedaction");
|
|
5
|
+
const chatItemEnricher_1 = require("./chatItemEnricher");
|
|
6
|
+
const fileChangeExtractor_1 = require("./fileChangeExtractor");
|
|
7
|
+
const contextUsageProjector_1 = require("./contextUsageProjector");
|
|
8
|
+
const todoPlanProjector_1 = require("./todoPlanProjector");
|
|
9
|
+
/**
|
|
10
|
+
* 后端“聊天投影器”:
|
|
11
|
+
* - 接收 Codex notification(method/params);
|
|
12
|
+
* - 产出 UI 可直接消费的 ChatOp(前端只需合并与渲染);
|
|
13
|
+
* - 并可选解析 TODO/上下文使用率等轻量附属状态。
|
|
14
|
+
*
|
|
15
|
+
* 说明:该投影器只支持 app-server v2 的 item/turn 生命周期事件;
|
|
16
|
+
* 不再兼容 legacy `codex/event/*`(按你的要求移除旧版本兼容)。
|
|
17
|
+
*/
|
|
18
|
+
class ChatProjector {
|
|
19
|
+
/**
|
|
20
|
+
* 递增计数器:用于生成 best-effort 的 fallback id。
|
|
21
|
+
*/
|
|
22
|
+
fallbackSeq = 0;
|
|
23
|
+
/**
|
|
24
|
+
* 投影单条 Codex notification。
|
|
25
|
+
*/
|
|
26
|
+
projectNotification(input) {
|
|
27
|
+
const normalizedThreadId = typeof input.threadId === "string" ? input.threadId.trim() : "";
|
|
28
|
+
if (!normalizedThreadId) {
|
|
29
|
+
return {
|
|
30
|
+
ops: [],
|
|
31
|
+
todoUpdate: null,
|
|
32
|
+
usagePercent: null,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
const nowMs = Number.isFinite(input.nowMs) ? Math.max(0, Math.floor(input.nowMs)) : Date.now();
|
|
36
|
+
const payload = input.payload;
|
|
37
|
+
const method = typeof payload?.method === "string" ? payload.method : "";
|
|
38
|
+
const params = payload?.params;
|
|
39
|
+
const todoUpdate = (0, todoPlanProjector_1.extractTodoPlanUpdateFromCodexPayload)(input.payload);
|
|
40
|
+
const usagePercent = (0, contextUsageProjector_1.extractContextUsagePercentFromPayload)(input.payload);
|
|
41
|
+
const ops = projectCodexEventToChatOps({
|
|
42
|
+
method,
|
|
43
|
+
params,
|
|
44
|
+
nowMs,
|
|
45
|
+
resolveFallbackId: (prefix) => this.resolveFallbackId(prefix),
|
|
46
|
+
});
|
|
47
|
+
return {
|
|
48
|
+
ops,
|
|
49
|
+
todoUpdate,
|
|
50
|
+
usagePercent,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* 生成 best-effort fallback id:用于 itemId 缺失等非理想输入。
|
|
55
|
+
*/
|
|
56
|
+
resolveFallbackId(prefix) {
|
|
57
|
+
this.fallbackSeq += 1;
|
|
58
|
+
const normalizedPrefix = String(prefix ?? "").trim().replace(/[^a-zA-Z0-9._:-]/g, "_");
|
|
59
|
+
return `${normalizedPrefix || "x"}-${Date.now()}-${this.fallbackSeq}`;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
exports.ChatProjector = ChatProjector;
|
|
63
|
+
/**
|
|
64
|
+
* 将完整文件变更收敛为“摘要模式”:
|
|
65
|
+
* - 保留 path/kind 供 UI 展示文件列表;
|
|
66
|
+
* - 清空 diff 正文,避免在聊天实时流里下发大体积 patch。
|
|
67
|
+
*/
|
|
68
|
+
function toDiffSummaryChanges(changes) {
|
|
69
|
+
return changes.map((change) => ({
|
|
70
|
+
path: change.path,
|
|
71
|
+
kind: change.kind,
|
|
72
|
+
diff: "",
|
|
73
|
+
}));
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* 将单条 codex 通知投影为 ChatOps(增量操作)。
|
|
77
|
+
*/
|
|
78
|
+
function projectCodexEventToChatOps(input) {
|
|
79
|
+
const ops = [];
|
|
80
|
+
const method = String(input.method ?? "");
|
|
81
|
+
const params = input.params;
|
|
82
|
+
const nowMs = input.nowMs;
|
|
83
|
+
/**
|
|
84
|
+
* v2 item 生命周期事件:唯一实时来源。
|
|
85
|
+
*/
|
|
86
|
+
if (method === "item/started") {
|
|
87
|
+
const item = params?.item;
|
|
88
|
+
const itemId = typeof item?.id === "string" ? item.id : "";
|
|
89
|
+
const itemType = typeof item?.type === "string" ? item.type : "";
|
|
90
|
+
const turnId = String(params?.turnId ?? "").trim();
|
|
91
|
+
const safeTurnId = turnId || `t-${nowMs}`;
|
|
92
|
+
if (itemType === "userMessage") {
|
|
93
|
+
const parts = Array.isArray(item?.content) ? item.content : [];
|
|
94
|
+
const message = parts
|
|
95
|
+
.map((p) => (typeof p?.text === "string" ? p.text : ""))
|
|
96
|
+
.filter(Boolean)
|
|
97
|
+
.join("")
|
|
98
|
+
.trim();
|
|
99
|
+
if (!message)
|
|
100
|
+
return ops;
|
|
101
|
+
const displayMessage = (0, attachmentPathRedaction_1.redactAttachmentPathsForDisplay)(message);
|
|
102
|
+
const safeItemId = itemId || input.resolveFallbackId("um");
|
|
103
|
+
ops.push({
|
|
104
|
+
op: "upsert",
|
|
105
|
+
item: (0, chatItemEnricher_1.enrichChatItemForUi)({
|
|
106
|
+
id: `v2:um-${safeTurnId}:${safeItemId}`,
|
|
107
|
+
ts: nowMs,
|
|
108
|
+
role: "user",
|
|
109
|
+
text: displayMessage,
|
|
110
|
+
deliveryStatus: "sent",
|
|
111
|
+
}),
|
|
112
|
+
});
|
|
113
|
+
return ops;
|
|
114
|
+
}
|
|
115
|
+
if (itemType === "commandExecution") {
|
|
116
|
+
const command = String(item?.command ?? "").trim();
|
|
117
|
+
if (!command)
|
|
118
|
+
return ops;
|
|
119
|
+
const header = formatCommandTranscript(stripBashLcAndEscape(command));
|
|
120
|
+
const safeItemId = itemId || input.resolveFallbackId("cmd");
|
|
121
|
+
ops.push({
|
|
122
|
+
op: "upsert",
|
|
123
|
+
item: (0, chatItemEnricher_1.enrichChatItemForUi)({
|
|
124
|
+
id: `v2:cmd-${safeTurnId}:${safeItemId}`,
|
|
125
|
+
ts: nowMs,
|
|
126
|
+
role: "system",
|
|
127
|
+
text: header,
|
|
128
|
+
streaming: true,
|
|
129
|
+
render: "terminal",
|
|
130
|
+
}),
|
|
131
|
+
});
|
|
132
|
+
return ops;
|
|
133
|
+
}
|
|
134
|
+
{
|
|
135
|
+
// 容错:部分 app-server 会使用不同的 item.type 命名。
|
|
136
|
+
const normalizedType = itemType.trim().toLowerCase();
|
|
137
|
+
const changes = (0, fileChangeExtractor_1.extractFileChangesFromAny)(item);
|
|
138
|
+
const looksLikeFileChange = normalizedType === "filechange" ||
|
|
139
|
+
normalizedType === "file_change" ||
|
|
140
|
+
normalizedType.includes("file") ||
|
|
141
|
+
normalizedType.includes("patch");
|
|
142
|
+
if (looksLikeFileChange && changes.length) {
|
|
143
|
+
const safeItemId = itemId || input.resolveFallbackId("fc");
|
|
144
|
+
const title = "文件变更";
|
|
145
|
+
const summaryChanges = toDiffSummaryChanges(changes);
|
|
146
|
+
ops.push({
|
|
147
|
+
op: "upsert",
|
|
148
|
+
item: (0, chatItemEnricher_1.enrichChatItemForUi)({
|
|
149
|
+
id: `v2:fc-${safeTurnId}:${safeItemId}`,
|
|
150
|
+
ts: nowMs,
|
|
151
|
+
role: "system",
|
|
152
|
+
text: title,
|
|
153
|
+
streaming: true,
|
|
154
|
+
render: "diff",
|
|
155
|
+
diff: { title, changes: summaryChanges },
|
|
156
|
+
}),
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
return ops;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
if (method === "item/agentMessage/delta") {
|
|
163
|
+
const itemId = String(params?.itemId ?? "").trim();
|
|
164
|
+
const turnId = String(params?.turnId ?? "").trim();
|
|
165
|
+
const safeTurnId = turnId || `t-${nowMs}`;
|
|
166
|
+
const delta = String(params?.delta ?? "");
|
|
167
|
+
if (!itemId || !delta)
|
|
168
|
+
return ops;
|
|
169
|
+
ops.push({ op: "text_delta", id: `v2:am-${safeTurnId}:${itemId}`, ts: nowMs, role: "assistant", delta });
|
|
170
|
+
return ops;
|
|
171
|
+
}
|
|
172
|
+
if (method === "item/plan/delta") {
|
|
173
|
+
const itemId = String(params?.itemId ?? "").trim();
|
|
174
|
+
const turnId = String(params?.turnId ?? "").trim();
|
|
175
|
+
const safeTurnId = turnId || `t-${nowMs}`;
|
|
176
|
+
const delta = String(params?.delta ?? "");
|
|
177
|
+
if (!itemId || !delta)
|
|
178
|
+
return ops;
|
|
179
|
+
ops.push({ op: "text_delta", id: `v2:plan-${safeTurnId}:${itemId}`, ts: nowMs, role: "assistant", delta });
|
|
180
|
+
return ops;
|
|
181
|
+
}
|
|
182
|
+
if (method === "item/reasoning/summaryTextDelta") {
|
|
183
|
+
const itemId = String(params?.itemId ?? "").trim();
|
|
184
|
+
const turnId = String(params?.turnId ?? "").trim();
|
|
185
|
+
const safeTurnId = turnId || `t-${nowMs}`;
|
|
186
|
+
const summaryIndex = Number(params?.summaryIndex ?? 0);
|
|
187
|
+
const delta = String(params?.delta ?? "");
|
|
188
|
+
if (!itemId || !delta)
|
|
189
|
+
return ops;
|
|
190
|
+
ops.push({
|
|
191
|
+
op: "text_delta",
|
|
192
|
+
id: `v2:rs-${safeTurnId}:${itemId}:${Number.isFinite(summaryIndex) ? summaryIndex : 0}`,
|
|
193
|
+
ts: nowMs,
|
|
194
|
+
role: "reasoning",
|
|
195
|
+
delta,
|
|
196
|
+
});
|
|
197
|
+
return ops;
|
|
198
|
+
}
|
|
199
|
+
if (method === "item/reasoning/textDelta") {
|
|
200
|
+
// reasoning 完整内容不用于 UI 渲染(仅展示 summary)。
|
|
201
|
+
return ops;
|
|
202
|
+
}
|
|
203
|
+
if (method === "item/commandExecution/outputDelta") {
|
|
204
|
+
const itemId = String(params?.itemId ?? "").trim();
|
|
205
|
+
const turnId = String(params?.turnId ?? "").trim();
|
|
206
|
+
const safeTurnId = turnId || `t-${nowMs}`;
|
|
207
|
+
const delta = String(params?.delta ?? "");
|
|
208
|
+
if (!itemId || !delta)
|
|
209
|
+
return ops;
|
|
210
|
+
ops.push({
|
|
211
|
+
op: "text_delta",
|
|
212
|
+
id: `v2:cmd-${safeTurnId}:${itemId}`,
|
|
213
|
+
ts: nowMs,
|
|
214
|
+
role: "system",
|
|
215
|
+
delta,
|
|
216
|
+
render: "terminal",
|
|
217
|
+
});
|
|
218
|
+
return ops;
|
|
219
|
+
}
|
|
220
|
+
if (method === "item/fileChange/outputDelta") {
|
|
221
|
+
// 文件变更正文改为按需加载;聊天实时流不再下发 patch/output 增量。
|
|
222
|
+
return ops;
|
|
223
|
+
}
|
|
224
|
+
// Some builds may use slightly different naming for fileChange streaming payloads; best-effort attach.
|
|
225
|
+
if (method.startsWith("item/") && method.toLowerCase().includes("filechange") && method.toLowerCase().endsWith("delta")) {
|
|
226
|
+
// 同上:统一屏蔽 fileChange delta 的实时下发。
|
|
227
|
+
return ops;
|
|
228
|
+
}
|
|
229
|
+
if (method === "item/completed") {
|
|
230
|
+
const item = params?.item;
|
|
231
|
+
const itemId = typeof item?.id === "string" ? item.id : "";
|
|
232
|
+
const itemType = typeof item?.type === "string" ? item.type : "";
|
|
233
|
+
const turnId = String(params?.turnId ?? "").trim();
|
|
234
|
+
const safeTurnId = turnId || `t-${nowMs}`;
|
|
235
|
+
if (itemType === "agentMessage") {
|
|
236
|
+
const text = String(item?.text ?? "");
|
|
237
|
+
const safeItemId = itemId || input.resolveFallbackId("am");
|
|
238
|
+
ops.push({
|
|
239
|
+
op: "upsert",
|
|
240
|
+
preserveTs: true,
|
|
241
|
+
item: (0, chatItemEnricher_1.enrichChatItemForUi)({
|
|
242
|
+
id: `v2:am-${safeTurnId}:${safeItemId}`,
|
|
243
|
+
ts: nowMs,
|
|
244
|
+
role: "assistant",
|
|
245
|
+
text,
|
|
246
|
+
streaming: false,
|
|
247
|
+
}),
|
|
248
|
+
});
|
|
249
|
+
return ops;
|
|
250
|
+
}
|
|
251
|
+
if (itemType === "plan") {
|
|
252
|
+
const safeItemId = itemId || input.resolveFallbackId("plan");
|
|
253
|
+
const id = `v2:plan-${safeTurnId}:${safeItemId}`;
|
|
254
|
+
const text = String(item?.text ?? "");
|
|
255
|
+
if (text.trim()) {
|
|
256
|
+
ops.push({
|
|
257
|
+
op: "upsert",
|
|
258
|
+
preserveTs: true,
|
|
259
|
+
item: (0, chatItemEnricher_1.enrichChatItemForUi)({ id, ts: nowMs, role: "assistant", text, streaming: false }),
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
else {
|
|
263
|
+
ops.push({ op: "finalize", id, ts: nowMs, patch: { text, markdownAst: null, systemToolCallSummary: null } });
|
|
264
|
+
}
|
|
265
|
+
return ops;
|
|
266
|
+
}
|
|
267
|
+
if (itemType === "reasoning") {
|
|
268
|
+
const summary = Array.isArray(item?.summary) ? item.summary.map(String).filter(Boolean) : [];
|
|
269
|
+
if (!summary.length)
|
|
270
|
+
return ops;
|
|
271
|
+
const safeItemId = itemId || input.resolveFallbackId("rs");
|
|
272
|
+
const base = `v2:rs-${safeTurnId}:${safeItemId}:`;
|
|
273
|
+
// 确保每条 summary 都存在(部分 server 只发 completed payload)。
|
|
274
|
+
for (let i = 0; i < summary.length; i += 1) {
|
|
275
|
+
const text = String(summary[i] ?? "").trim();
|
|
276
|
+
if (!text)
|
|
277
|
+
continue;
|
|
278
|
+
const id = `${base}${i}`;
|
|
279
|
+
ops.push({
|
|
280
|
+
op: "upsert",
|
|
281
|
+
preserveTs: true,
|
|
282
|
+
item: (0, chatItemEnricher_1.enrichChatItemForUi)({ id, ts: nowMs, role: "reasoning", text, streaming: false }),
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
// 标记所有同前缀 in-flight delta 为 done,便于 UI 自动折叠。
|
|
286
|
+
ops.push({ op: "mark_streaming_done_by_prefix", ts: nowMs, prefix: base });
|
|
287
|
+
return ops;
|
|
288
|
+
}
|
|
289
|
+
if (itemType === "commandExecution") {
|
|
290
|
+
const safeItemId = itemId || input.resolveFallbackId("cmd-final");
|
|
291
|
+
const id = `v2:cmd-${safeTurnId}:${safeItemId}`;
|
|
292
|
+
const command = String(item?.command ?? "").trim();
|
|
293
|
+
const header = formatCommandTranscript(stripBashLcAndEscape(command));
|
|
294
|
+
const output = String(item?.aggregatedOutput ?? "");
|
|
295
|
+
const status = String(item?.status ?? "").trim();
|
|
296
|
+
const exitCode = typeof item?.exitCode === "number" ? item.exitCode : null;
|
|
297
|
+
const durationMs = typeof item?.durationMs === "number" ? item.durationMs : null;
|
|
298
|
+
const nextTextParts = [header];
|
|
299
|
+
if (output) {
|
|
300
|
+
nextTextParts.push(output);
|
|
301
|
+
if (!output.endsWith("\n"))
|
|
302
|
+
nextTextParts.push("\n");
|
|
303
|
+
}
|
|
304
|
+
const statusLineParts = [];
|
|
305
|
+
if (exitCode !== null)
|
|
306
|
+
statusLineParts.push(exitCode === 0 ? "✓" : `✗ (code: ${exitCode})`);
|
|
307
|
+
else if (status)
|
|
308
|
+
statusLineParts.push(status);
|
|
309
|
+
if (durationMs !== null)
|
|
310
|
+
statusLineParts.push(fmtDurationMs(durationMs));
|
|
311
|
+
if (statusLineParts.length) {
|
|
312
|
+
const lead = statusLineParts[0] ?? "";
|
|
313
|
+
const tail = statusLineParts.slice(1).join(" • ");
|
|
314
|
+
nextTextParts.push(`${tail ? `${lead} • ${tail}` : lead}\n`);
|
|
315
|
+
}
|
|
316
|
+
const text = nextTextParts.join("");
|
|
317
|
+
ops.push({
|
|
318
|
+
op: "upsert",
|
|
319
|
+
preserveTs: true,
|
|
320
|
+
item: (0, chatItemEnricher_1.enrichChatItemForUi)({ id, ts: nowMs, role: "system", text, streaming: false, render: "terminal" }),
|
|
321
|
+
});
|
|
322
|
+
return ops;
|
|
323
|
+
}
|
|
324
|
+
{
|
|
325
|
+
const safeItemId = itemId || input.resolveFallbackId("fc-final");
|
|
326
|
+
const id = `v2:fc-${safeTurnId}:${safeItemId}`;
|
|
327
|
+
const normalizedType = itemType.trim().toLowerCase();
|
|
328
|
+
const changes = (0, fileChangeExtractor_1.extractFileChangesFromAny)(item);
|
|
329
|
+
const looksLikeFileChange = normalizedType === "filechange" ||
|
|
330
|
+
normalizedType === "file_change" ||
|
|
331
|
+
normalizedType.includes("file") ||
|
|
332
|
+
normalizedType.includes("patch");
|
|
333
|
+
if (!looksLikeFileChange)
|
|
334
|
+
return ops;
|
|
335
|
+
if (!changes.length) {
|
|
336
|
+
ops.push({ op: "finalize", id, ts: nowMs, patch: { render: "diff" } });
|
|
337
|
+
return ops;
|
|
338
|
+
}
|
|
339
|
+
const title = "文件变更";
|
|
340
|
+
const summaryChanges = toDiffSummaryChanges(changes);
|
|
341
|
+
const diff = { title, changes: summaryChanges };
|
|
342
|
+
ops.push({
|
|
343
|
+
op: "upsert",
|
|
344
|
+
preserveTs: true,
|
|
345
|
+
item: (0, chatItemEnricher_1.enrichChatItemForUi)({ id, ts: nowMs, role: "system", text: title, streaming: false, render: "diff", diff }),
|
|
346
|
+
});
|
|
347
|
+
return ops;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
if (method === "turn/diff/updated" || method === "turn/diff/created") {
|
|
351
|
+
const turnId = String(params?.turnId ?? "").trim();
|
|
352
|
+
const safeTurnId = turnId || `t-${nowMs}`;
|
|
353
|
+
const diff = params?.diff;
|
|
354
|
+
const changes = (0, fileChangeExtractor_1.extractFileChangesFromAny)(diff ?? params);
|
|
355
|
+
if (!turnId || !changes.length)
|
|
356
|
+
return ops;
|
|
357
|
+
const id = `v2:turn-diff:${safeTurnId}`;
|
|
358
|
+
const title = "本回合总变更";
|
|
359
|
+
const summaryChanges = toDiffSummaryChanges(changes);
|
|
360
|
+
ops.push({
|
|
361
|
+
op: "upsert",
|
|
362
|
+
item: (0, chatItemEnricher_1.enrichChatItemForUi)({
|
|
363
|
+
id,
|
|
364
|
+
ts: nowMs,
|
|
365
|
+
role: "system",
|
|
366
|
+
text: title,
|
|
367
|
+
streaming: false,
|
|
368
|
+
render: "diff",
|
|
369
|
+
diff: { title, changes: summaryChanges },
|
|
370
|
+
}),
|
|
371
|
+
});
|
|
372
|
+
return ops;
|
|
373
|
+
}
|
|
374
|
+
// Generic fallback: if we see a changes list in params, surface it.
|
|
375
|
+
{
|
|
376
|
+
const changes = (0, fileChangeExtractor_1.extractFileChangesFromAny)(params);
|
|
377
|
+
if (changes.length) {
|
|
378
|
+
const turnId = String(params?.turnId ?? params?.turn_id ?? "").trim();
|
|
379
|
+
const itemId = String(params?.itemId ?? params?.item_id ?? "").trim();
|
|
380
|
+
const id = `fc:${method}:${turnId || "t"}:${itemId || "i"}:${nowMs}`;
|
|
381
|
+
const title = "文件变更";
|
|
382
|
+
const summaryChanges = toDiffSummaryChanges(changes);
|
|
383
|
+
ops.push({
|
|
384
|
+
op: "upsert",
|
|
385
|
+
item: (0, chatItemEnricher_1.enrichChatItemForUi)({
|
|
386
|
+
id,
|
|
387
|
+
ts: nowMs,
|
|
388
|
+
role: "system",
|
|
389
|
+
text: title,
|
|
390
|
+
streaming: false,
|
|
391
|
+
render: "diff",
|
|
392
|
+
diff: { title, changes: summaryChanges },
|
|
393
|
+
}),
|
|
394
|
+
});
|
|
395
|
+
return ops;
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
// Mark any in-flight output as done when a turn finishes (avoid a "stuck cursor" on errors).
|
|
399
|
+
if (method === "turn/completed" || method === "turn/failed" || method === "turn/cancelled" || method === "turn/interrupted") {
|
|
400
|
+
ops.push({ op: "mark_all_streaming_done", ts: nowMs });
|
|
401
|
+
return ops;
|
|
402
|
+
}
|
|
403
|
+
return ops;
|
|
404
|
+
}
|
|
405
|
+
function stripOuterQuotesAndUnescape(input) {
|
|
406
|
+
if (input.length < 2)
|
|
407
|
+
return null;
|
|
408
|
+
const quote = input[0];
|
|
409
|
+
if (quote !== "'" && quote !== '"')
|
|
410
|
+
return null;
|
|
411
|
+
if (!input.endsWith(quote))
|
|
412
|
+
return null;
|
|
413
|
+
const inner = input.slice(1, -1);
|
|
414
|
+
if (!inner)
|
|
415
|
+
return "";
|
|
416
|
+
let out = "";
|
|
417
|
+
for (let i = 0; i < inner.length; i += 1) {
|
|
418
|
+
const ch = inner[i];
|
|
419
|
+
if (ch !== "\\\\") {
|
|
420
|
+
out += ch;
|
|
421
|
+
continue;
|
|
422
|
+
}
|
|
423
|
+
const next = inner[i + 1];
|
|
424
|
+
if (next === undefined)
|
|
425
|
+
break;
|
|
426
|
+
i += 1;
|
|
427
|
+
if (next === "n")
|
|
428
|
+
out += "\\n";
|
|
429
|
+
else if (next === "t")
|
|
430
|
+
out += "\\t";
|
|
431
|
+
else if (next === "r")
|
|
432
|
+
out += "\\r";
|
|
433
|
+
else if (next === "\\\\")
|
|
434
|
+
out += "\\\\";
|
|
435
|
+
else if (next === '"' && quote === '"')
|
|
436
|
+
out += '"';
|
|
437
|
+
else if (next === "'" && quote === "'")
|
|
438
|
+
out += "'";
|
|
439
|
+
else
|
|
440
|
+
out += next;
|
|
441
|
+
}
|
|
442
|
+
return out;
|
|
443
|
+
}
|
|
444
|
+
function stripBashLcAndEscape(command) {
|
|
445
|
+
const prefix = "bash -lc ";
|
|
446
|
+
if (!command.startsWith(prefix))
|
|
447
|
+
return command;
|
|
448
|
+
const rest = command.slice(prefix.length);
|
|
449
|
+
return stripOuterQuotesAndUnescape(rest) ?? rest;
|
|
450
|
+
}
|
|
451
|
+
function formatCommandTranscript(script) {
|
|
452
|
+
const lines = script.replace(/\\r\\n/g, "\\n").split("\\n");
|
|
453
|
+
if (!lines.length)
|
|
454
|
+
return "$\\n";
|
|
455
|
+
const out = [];
|
|
456
|
+
out.push(`$ ${lines[0] ?? ""}`);
|
|
457
|
+
for (let i = 1; i < lines.length; i += 1)
|
|
458
|
+
out.push(` ${lines[i] ?? ""}`);
|
|
459
|
+
return `${out.join("\\n")}\\n`;
|
|
460
|
+
}
|
|
461
|
+
function fmtDurationMs(durationMs) {
|
|
462
|
+
const totalMs = Math.max(0, Math.trunc(durationMs));
|
|
463
|
+
const secs = Math.floor(totalMs / 1000);
|
|
464
|
+
const millis = totalMs % 1000;
|
|
465
|
+
if (secs >= 60) {
|
|
466
|
+
const minutes = Math.floor(secs / 60);
|
|
467
|
+
const seconds = secs % 60;
|
|
468
|
+
return `${minutes}m${seconds}s`;
|
|
469
|
+
}
|
|
470
|
+
if (secs > 0) {
|
|
471
|
+
if (millis >= 100) {
|
|
472
|
+
if (secs < 10)
|
|
473
|
+
return `${secs}.${Math.floor(millis / 100)}s`;
|
|
474
|
+
return `${secs}s`;
|
|
475
|
+
}
|
|
476
|
+
return `${secs}.${String(millis).padStart(3, "0")}s`;
|
|
477
|
+
}
|
|
478
|
+
if (millis >= 100)
|
|
479
|
+
return `${millis}ms`;
|
|
480
|
+
return `0.${String(millis).padStart(3, "0")}ms`;
|
|
481
|
+
}
|
|
482
|
+
//# sourceMappingURL=codexEventProjector.js.map
|