@eddyskywalker/dsh-chatgpt-subscription 0.27.0 → 0.27.2
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/CHANGELOG.md +13 -0
- package/lib/client.js +119 -6
- package/lib/client.js.map +1 -1
- package/lib/index.js +2 -2
- package/lib/types/client/progress-updates/markdown-lite.d.ts +30 -4
- package/lib/types/client/progress-updates/markdown-lite.d.ts.map +1 -1
- package/lib/types/client/progress-updates/progress-row.d.ts.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.27.2 - 2026-10-18
|
|
6
|
+
- **[进展更新] 正文补上 GFM 表格,对话流与侧栏面板改用同一个渲染器**
|
|
7
|
+
- **现象**:模型在进展正文里写 GFM 表格(`| 题 | 难度 |` + `| --- | --- |`)时,面板把整块表格**原样**显示成一堆竖线;同时对话流里的主形态(`progress-row.tsx`)正文是纯文本 `<p>{message}</p>`,连 `**粗体**` 都不解析——同一份进展在侧栏渲染过、在对话流里是原文,两处观感对不上。
|
|
8
|
+
- **改法一(`markdown-lite.tsx`)**:补 GFM 表格块。识别用**两行前瞻**(本行含 `|` 且下一行是分隔行 `| :--- | ---: |`):孤立的竖线不会被误判成表格;支持 `:---` / `:---:` / `---:` 三种对齐、单元格内 `\|` 转义、数据行短于表头时补空格子。渲染成真实 `<table>/<thead>/<tbody>/<th>/<td>`,对齐落在 `text-align` 上,窄屏外包一层 `overflow-x:auto`。仍然**零依赖**、不经 `dangerouslySetInnerHTML`。
|
|
9
|
+
- **改法二(`progress-row.tsx`)**:正文改用同一个 `MarkdownLite`,并去掉外层 `white-space: pre-wrap`(换行该由块级元素决定,而不是靠保留原文换行)。两处观感自此一致。
|
|
10
|
+
- **改法三(提示词与工具描述)**:`prompt.ts` 的正文写法与 `tool.ts` 的 `message` 参数描述都补了一句「有几行数据要对照时用 GFM 管道符表格」,让模型知道表格现在真的会被渲染出来。
|
|
11
|
+
- **仍然不做**:图片、链接、原始 HTML、脚注、围栏代码块——要么需要安全过滤,要么不属于「进展汇报」这个场景。
|
|
12
|
+
- **验证**:`npm run typecheck` 0 错误;全量 **246 passed | 1 skipped(247 文件)、3988 passed | 7 skipped、0 failed**;`npm run build` 通过,`lib/client.js` 里已含 `md-table`/`md-th`/`md-td` 标记。新增 3 条回归(面板表格 / 孤立竖线不误判 / 对话流也渲染),并做变异验证:把表格识别分支关掉,其中两条立刻变红(2 failed),恢复后 31 passed。
|
|
13
|
+
|
|
14
|
+
## 0.27.1 - 2026-10-18
|
|
15
|
+
- **仅版本号变更**:`package.json` 由 0.27.0 提到 0.27.1,源码零改动(`git diff v0.27.0 v0.27.1` 只有一行版本号)。
|
|
16
|
+
- **补记原因**:0.27.1 当天已发布到 npm(2026-10-18T04:31:48Z),但发版时漏打了 git tag、也没在 CHANGELOG 留记录,导致版本线在 git 侧断了一格。事后**只在本机补了 `v0.27.1` 标签**(指向 `f75bc78`),**未推送**——推上去会让 CI 去发布一个已存在的版本而失败。
|
|
17
|
+
|
|
5
18
|
## 0.27.0 - 2026-10-18
|
|
6
19
|
- **【进展更新】agent 在多步任务中主动汇报,对话流里一行一条,右侧栏可回看**
|
|
7
20
|
- **是什么**:新增 in-tree 子模块 `src/host/progress-updates/` + `src/client/progress-updates/`,复刻 Kimi Code 的「进展更新」。agent 通过一个**不结束回合**的工具 `progress_update(title?, message)` 主动汇报,对话流里渲染成一行(状态点 + 标题 + 状态词,正文点开看),右侧栏有一个总览面板。
|
package/lib/client.js
CHANGED
|
@@ -15158,6 +15158,45 @@ window.__ModuleLoader__.load({
|
|
|
15158
15158
|
if (last < text.length) nodes.push(text.slice(last));
|
|
15159
15159
|
return nodes;
|
|
15160
15160
|
}
|
|
15161
|
+
/** GFM 分隔行:至少一个 `-` 的单元格,形如 `| --- | :--: | ---: |`。 */
|
|
15162
|
+
const TABLE_SEPARATOR = /^\|?\s*:?-+:?\s*(\|\s*:?-+:?\s*)*\|?$/;
|
|
15163
|
+
/**
|
|
15164
|
+
* 一行表格 → 单元格数组。
|
|
15165
|
+
*
|
|
15166
|
+
* 先按未转义的 `|` 切,再剥掉首尾因为 `| a | b |` 这种写法留下的空单元;
|
|
15167
|
+
* `\|` 是单元格里的字面量竖线,切之前先换成占位符,切完再换回来。
|
|
15168
|
+
* @param line - 表格的一行原文。
|
|
15169
|
+
* @returns 去掉两侧空白的单元格。
|
|
15170
|
+
*/
|
|
15171
|
+
function splitRow(line) {
|
|
15172
|
+
const PH = "\0";
|
|
15173
|
+
const cells = line.replaceAll("\\|", PH).split("|").map((cell) => cell.replaceAll(PH, "|").trim());
|
|
15174
|
+
if (cells.length > 0 && cells[0] === "") cells.shift();
|
|
15175
|
+
if (cells.length > 0 && cells[cells.length - 1] === "") cells.pop();
|
|
15176
|
+
return cells;
|
|
15177
|
+
}
|
|
15178
|
+
/**
|
|
15179
|
+
* 分隔行的每个单元格 → 对齐方式。
|
|
15180
|
+
* @param line - 分隔行原文。
|
|
15181
|
+
* @returns 与列一一对应的对齐方式;缺省 left。
|
|
15182
|
+
*/
|
|
15183
|
+
function alignmentsOf(line) {
|
|
15184
|
+
return splitRow(line).map((cell) => {
|
|
15185
|
+
const left = cell.startsWith(":");
|
|
15186
|
+
const right = cell.endsWith(":");
|
|
15187
|
+
if (left && right) return "center";
|
|
15188
|
+
if (right) return "right";
|
|
15189
|
+
return "left";
|
|
15190
|
+
});
|
|
15191
|
+
}
|
|
15192
|
+
/**
|
|
15193
|
+
* 判断某一行是不是表格的分隔行(表格识别的前瞻条件之一)。
|
|
15194
|
+
* @param line - 待判定的行(已 trim)。
|
|
15195
|
+
* @returns 是分隔行则为 true。
|
|
15196
|
+
*/
|
|
15197
|
+
function isSeparator(line) {
|
|
15198
|
+
return line.includes("-") && TABLE_SEPARATOR.test(line);
|
|
15199
|
+
}
|
|
15161
15200
|
/**
|
|
15162
15201
|
* 把正文切成块。
|
|
15163
15202
|
* @param source - Markdown 原文。
|
|
@@ -15176,13 +15215,42 @@ window.__ModuleLoader__.load({
|
|
|
15176
15215
|
}
|
|
15177
15216
|
};
|
|
15178
15217
|
const lastBlock = () => blocks[blocks.length - 1];
|
|
15179
|
-
|
|
15180
|
-
|
|
15218
|
+
const rows = source.replaceAll("\r\n", "\n").split("\n");
|
|
15219
|
+
for (let index = 0; index < rows.length; index += 1) {
|
|
15220
|
+
const line = rows[index].trimEnd();
|
|
15181
15221
|
const trimmed = line.trim();
|
|
15182
15222
|
if (trimmed === "") {
|
|
15183
15223
|
flushParagraph();
|
|
15184
15224
|
continue;
|
|
15185
15225
|
}
|
|
15226
|
+
/**
|
|
15227
|
+
* 表格必须**在当前行前瞻两行**才认:本行是表头、下一行是分隔行、两侧管道符
|
|
15228
|
+
* 数目对得上。只凭「这行有 |」不行——普通正文里一个竖线不该把后文变成表格。
|
|
15229
|
+
*/
|
|
15230
|
+
const next = index + 1 < rows.length ? rows[index + 1].trim() : "";
|
|
15231
|
+
if (trimmed.includes("|") && isSeparator(next)) {
|
|
15232
|
+
const header = splitRow(trimmed);
|
|
15233
|
+
const aligns = alignmentsOf(next);
|
|
15234
|
+
if (header.length > 0) {
|
|
15235
|
+
flushParagraph();
|
|
15236
|
+
const body = [];
|
|
15237
|
+
index += 2;
|
|
15238
|
+
while (index < rows.length) {
|
|
15239
|
+
const rowLine = rows[index].trim();
|
|
15240
|
+
if (rowLine === "" || !rowLine.includes("|")) break;
|
|
15241
|
+
body.push(splitRow(rowLine));
|
|
15242
|
+
index += 1;
|
|
15243
|
+
}
|
|
15244
|
+
index -= 1;
|
|
15245
|
+
blocks.push({
|
|
15246
|
+
kind: "table",
|
|
15247
|
+
header,
|
|
15248
|
+
aligns,
|
|
15249
|
+
rows: body
|
|
15250
|
+
});
|
|
15251
|
+
continue;
|
|
15252
|
+
}
|
|
15253
|
+
}
|
|
15186
15254
|
const heading = /^(#{1,3})\s+(.*)$/.exec(trimmed);
|
|
15187
15255
|
if (heading !== null) {
|
|
15188
15256
|
flushParagraph();
|
|
@@ -15237,6 +15305,45 @@ window.__ModuleLoader__.load({
|
|
|
15237
15305
|
},
|
|
15238
15306
|
children: renderInline(block.text, key)
|
|
15239
15307
|
}, key);
|
|
15308
|
+
if (block.kind === "table") {
|
|
15309
|
+
/** 单元格:行内标记照常解析,对齐落到 style 上(表格里没有 class 可挂)。 */
|
|
15310
|
+
const cellStyle = (column) => ({
|
|
15311
|
+
textAlign: block.aligns[column] ?? "left",
|
|
15312
|
+
padding: "3px 8px",
|
|
15313
|
+
verticalAlign: "top"
|
|
15314
|
+
});
|
|
15315
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
15316
|
+
"data-dsh-part": "md-table-wrap",
|
|
15317
|
+
style: {
|
|
15318
|
+
overflowX: "auto",
|
|
15319
|
+
margin: "6px 0"
|
|
15320
|
+
},
|
|
15321
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("table", {
|
|
15322
|
+
"data-dsh-part": "md-table",
|
|
15323
|
+
style: {
|
|
15324
|
+
borderCollapse: "collapse",
|
|
15325
|
+
fontSize: "12px",
|
|
15326
|
+
lineHeight: "1.5"
|
|
15327
|
+
},
|
|
15328
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("thead", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("tr", { children: block.header.map((cell, column) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", {
|
|
15329
|
+
"data-dsh-part": "md-th",
|
|
15330
|
+
style: {
|
|
15331
|
+
...cellStyle(column),
|
|
15332
|
+
borderBottom: "1px solid var(--dsw-alias-border-l2, rgb(0 0 0 / 15%))",
|
|
15333
|
+
fontWeight: 600
|
|
15334
|
+
},
|
|
15335
|
+
children: renderInline(cell, key + "-h" + String(column))
|
|
15336
|
+
}, key + "-h" + String(column))) }) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("tbody", { children: block.rows.map((row, rowIndex) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("tr", { children: block.header.map((_, column) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
|
|
15337
|
+
"data-dsh-part": "md-td",
|
|
15338
|
+
style: {
|
|
15339
|
+
...cellStyle(column),
|
|
15340
|
+
borderBottom: "1px solid var(--dsw-alias-border-l3, rgb(0 0 0 / 7%))"
|
|
15341
|
+
},
|
|
15342
|
+
children: renderInline(row[column] ?? "", key + "-r" + String(rowIndex) + "-" + String(column))
|
|
15343
|
+
}, key + "-r" + String(rowIndex) + "-" + String(column))) }, key + "-r" + String(rowIndex))) })]
|
|
15344
|
+
})
|
|
15345
|
+
}, key);
|
|
15346
|
+
}
|
|
15240
15347
|
if (block.kind === "ul" || block.kind === "ol") {
|
|
15241
15348
|
const items = block.items.map((item, itemIndex) => {
|
|
15242
15349
|
const itemKey = key + "-" + String(itemIndex);
|
|
@@ -15766,9 +15873,15 @@ window.__ModuleLoader__.load({
|
|
|
15766
15873
|
lineHeight: "1.5",
|
|
15767
15874
|
color: "var(--dsw-alias-label-tertiary, #8a9099)"
|
|
15768
15875
|
};
|
|
15769
|
-
/**
|
|
15876
|
+
/**
|
|
15877
|
+
* 正文样式:只管外边距、字号与颜色。
|
|
15878
|
+
*
|
|
15879
|
+
* **不再**在这里写 `whiteSpace: 'pre-wrap'`:正文交给 {@link MarkdownLite} 渲染,
|
|
15880
|
+
* 换行该不该保留由它产出的块级元素决定。早先这里是纯文本 `<p>{message}</p>`,
|
|
15881
|
+
* 于是列表符号、`**粗体**` 和管道符表格全部原样上屏 —— 同一份进展在侧栏面板里
|
|
15882
|
+
* 是渲染过的、在对话流里是原文,两处观感对不上。
|
|
15883
|
+
*/
|
|
15770
15884
|
const messageStyle = {
|
|
15771
|
-
whiteSpace: "pre-wrap",
|
|
15772
15885
|
overflowWrap: "anywhere",
|
|
15773
15886
|
margin: "0",
|
|
15774
15887
|
fontSize: "12px",
|
|
@@ -15868,10 +15981,10 @@ window.__ModuleLoader__.load({
|
|
|
15868
15981
|
children: translate(STATE_KEYS[state])
|
|
15869
15982
|
})
|
|
15870
15983
|
]
|
|
15871
|
-
}), expanded && message !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("
|
|
15984
|
+
}), expanded && message !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
15872
15985
|
"data-dsh-part": "progress-row-message",
|
|
15873
15986
|
style: messageStyle,
|
|
15874
|
-
children: message
|
|
15987
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MarkdownLite, { text: message })
|
|
15875
15988
|
})]
|
|
15876
15989
|
});
|
|
15877
15990
|
}
|