dsh-pre-duediligence 0.1.22 → 0.1.23
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 +6 -0
- package/README.md +6 -6
- package/docs/COMPATIBILITY.md +10 -0
- package/docs/DSH-UX-001-ADOPTION.md +11 -0
- package/docs/MARKETPLACE.md +3 -3
- package/docs/RELEASE-0.1.23.md +22 -0
- package/docs/SEARCH-CONVERSION.md +2 -2
- package/docs/TASK-SCOPE-HISTORY-CONTRACT.md +24 -0
- package/install.sh +1 -1
- package/lib/client.js +23 -14
- package/lib/index.js +17 -9
- package/lib/index.js.map +2 -2
- package/lib/types/hosted-task-api.d.ts +9 -2
- package/lib/types/hosted-task-sync.d.ts +8 -0
- package/package.json +1 -1
- package/skills/qcc-previsit-onepager/SKILL.md +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
# 更新日志
|
|
2
2
|
## [Unreleased]
|
|
3
3
|
|
|
4
|
+
## [0.1.23] - 2026-09-13
|
|
5
|
+
|
|
6
|
+
- Host 存储兼容缺少 Workspace / Session 来源元数据的旧记录:记录继续进入 Profile 历史,但绝不匹配或重绑为当前 Session 任务。
|
|
7
|
+
- 历史卡片对缺失来源明确显示“未记录(旧记录)”;客户端以 `HostedTaskListScope` 判别联合固化当前任务与 Profile 历史边界。
|
|
8
|
+
- 新增可复用 TaskScope/History 契约及 Session A/B/legacy fixtures,并将跨 Session 历史来源纳入四种隔离 Chrome 布局回归。
|
|
9
|
+
|
|
4
10
|
## [0.1.22] - 2026-09-13
|
|
5
11
|
|
|
6
12
|
- “任务历史”改为汇总当前 DSH Profile 内所有访前尽调 Session 的 Host 持久记录,重新打开插件或进入新会话后仍可查看既有任务。
|
package/README.md
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
# dsh-pre-duediligence
|
|
2
2
|
|
|
3
|
-
0.1.
|
|
3
|
+
0.1.23 补齐旧 Host 记录兼容:缺少 Workspace / Session 来源元数据的记录继续进入 Profile 历史,并明确显示“未记录(旧记录)”,但绝不匹配或重绑为当前 Session 任务;显式 TaskScope 契约固化当前任务隔离与跨 Session 历史汇总边界。已发布版本与验证边界见 [发布说明](docs/RELEASE-0.1.23.md)、[作用域契约](docs/TASK-SCOPE-HISTORY-CONTRACT.md)、[采用记录](docs/DSH-UX-001-ADOPTION.md)和[兼容矩阵](docs/COMPATIBILITY.md)。
|
|
4
4
|
|
|
5
5
|
## 安装与三分钟上手
|
|
6
6
|
|
|
7
7
|
访前尽调智能体:面向拜访前调查,提供企业尽调、客户尽调、客户背景调查、工商核验与风险信息整理;使用企查查 MCP,提供固定路由连续调用、主体确认、动态进度和可下载报告。
|
|
8
8
|
|
|
9
9
|
```sh
|
|
10
|
-
dsh plugin --profile web add dsh-pre-duediligence@0.1.
|
|
10
|
+
dsh plugin --profile web add dsh-pre-duediligence@0.1.23
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
请先满足下文的 DSH 与连接器要求;Better Sidebar 仅在需要可视化工作台时选装。安装后完整停止并重启对应 Profile。
|
|
@@ -23,7 +23,7 @@ dsh plugin --profile web add dsh-pre-duediligence@0.1.22
|
|
|
23
23
|
相关智能体:[数据清洗补全](https://github.com/duhu2000/dsh-data-cleaning-agent) · [AI填表](https://github.com/duhu2000/dsh-form-fill-agent) · [访前尽调](https://github.com/duhu2000/dsh-pre-duediligence) · [招投标](https://github.com/duhu2000/dsh-tender-workbench)
|
|
24
24
|
|
|
25
25
|
|
|
26
|
-
版本:**0.1.
|
|
26
|
+
版本:**0.1.23**。本版保持 DSH-UX-001 v1.5.2 的 Workspace / Session 隔离、工作台初始关闭和核验完成门;当前任务、阶段进度、报告回写及下载仍绑定当前 Session,任务历史则从 Host 持久库汇总当前 Profile 的全部访前 Session。每条历史记录显示来源 Workspace / Session;旧记录缺少来源时明确显示“未记录(旧记录)”,只进入 Profile 历史且不会被当前 Session 认领。完整消息与证据仍保留在来源原生会话。本轮自动化使用合成 Host 记录,不声明生产账号全链路验收通过。详见 [更新日志](CHANGELOG.md)、[作用域契约](docs/TASK-SCOPE-HISTORY-CONTRACT.md)、[采用记录](docs/DSH-UX-001-ADOPTION.md)、[兼容与验收矩阵](docs/COMPATIBILITY.md)和[市场投稿登记](docs/MARKETPLACE.md)。
|
|
27
27
|
|
|
28
28
|
面向 DeepSeek Harness 的 Session 级访前尽调智能体。业务人员从左侧菜单进入,在会话级工作台定义一次拜访;Agent 调用企查查五类 MCP,使用机会与风险双引擎完成经营状态识别、假设与反证、风险核验,最终交付可追溯的访前尽调报告。
|
|
29
29
|
|
|
@@ -92,7 +92,7 @@ bash <(curl -fsSL https://raw.githubusercontent.com/duhu2000/dsh-pre-duediligenc
|
|
|
92
92
|
安装脚本默认向 DSH Web profile 安装两个基础 Bundle:
|
|
93
93
|
|
|
94
94
|
1. `dsh-mcp-connector@0.2.32`:提供通用 MCP 连接器与市场,通过“企查查·企业工商”完成 OAuth,并动态挂载企业、风险、知产、经营、历史和董监高 MCP。
|
|
95
|
-
2. `dsh-pre-duediligence@0.1.
|
|
95
|
+
2. `dsh-pre-duediligence@0.1.23`:提供左侧智能体入口、原生会话首页、提示词生成器、Host 执行门和 Skill。
|
|
96
96
|
|
|
97
97
|
默认不会安装 Better Sidebar。需要 Session 级可视化工作台时显式开启:
|
|
98
98
|
|
|
@@ -120,7 +120,7 @@ dsh web
|
|
|
120
120
|
|
|
121
121
|
~~~bash
|
|
122
122
|
dsh plugin --profile web add dsh-mcp-connector@0.2.32
|
|
123
|
-
dsh plugin --profile web add dsh-pre-duediligence@0.1.
|
|
123
|
+
dsh plugin --profile web add dsh-pre-duediligence@0.1.23 --allow-build=node-pty,dsh-pre-duediligence
|
|
124
124
|
dsh web
|
|
125
125
|
~~~
|
|
126
126
|
|
|
@@ -136,7 +136,7 @@ dsh web
|
|
|
136
136
|
dsh plugin --profile web list --depth 0
|
|
137
137
|
~~~
|
|
138
138
|
|
|
139
|
-
应始终看到所选基线的 Connector 和 `dsh-pre-duediligence@0.1.
|
|
139
|
+
应始终看到所选基线的 Connector 和 `dsh-pre-duediligence@0.1.23`;仅在显式启用或原本已安装时看到 Sidebar。重启 DSH 并连接“企查查·企业工商”后,在左侧菜单点击“访前尽调”进入初始原生会话。无 Sidebar 时可继续生成提示词、回填/发送草稿并在会话中阅读报告;五项流程按钮会提示安装可选工作台。安装 Sidebar 时,右侧工作台仍默认关闭,点击业务按钮后才打开对应视图;其右侧“+”菜单不会列出该入口,普通会话保持 DSH 原样。
|
|
140
140
|
|
|
141
141
|
### 无 Sidebar 功能边界
|
|
142
142
|
|
package/docs/COMPATIBILITY.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# 访前尽调兼容与验收记录
|
|
2
2
|
|
|
3
|
+
## 0.1.23:旧记录来源与显式 TaskScope(2026-09-13)
|
|
4
|
+
|
|
5
|
+
| 实测问题 | 修复契约 | 验证边界 |
|
|
6
|
+
| --- | --- | --- |
|
|
7
|
+
| 旧 Host 记录缺少 Workspace / Session 时被丢弃 | 兼容读取并以空来源哨兵持久化,继续进入 Profile 历史 | 旧记录不进入任何当前 Session 列表,也不被猜测或重绑 |
|
|
8
|
+
| 历史卡片来源空白,无法判断归属 | 缺失项明确显示“来源:Workspace 未记录(旧记录) · Session 未记录(旧记录)”,使用中性样式 | 无法恢复从未持久化的真实来源,完整会话仍需回到原生会话查阅 |
|
|
9
|
+
| 可选 `sessionId` 参数让当前任务与历史查询边界含糊 | 客户端改用 `HostedTaskListScope` 判别联合;Session A/B/legacy fixtures 固化可见性 | 单任务读取、报告回写和下载继续由 Host 强制校验当前 `sessionId` |
|
|
10
|
+
|
|
11
|
+
本地 Node 24.19.0 发布门禁通过严格类型检查、23 个测试文件 / 165 项测试、Host/Client 构建,以及浅色/深色 × 桌面/窄屏 4 个隔离 Chrome 场景。自动化覆盖当前 Session A、跨 Session B 与缺少来源的 legacy 记录,并检查长来源文本和旧记录标识不造成横向溢出。生产 DSH Profile 与真实企查查 Provider 未在本轮自动化中调用,仍以安装后的用户验收为准。
|
|
12
|
+
|
|
3
13
|
## 0.1.22:跨 Session 历史汇总(2026-09-13)
|
|
4
14
|
|
|
5
15
|
| 实测问题 | 修复契约 | 验证边界 |
|
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# DSH-UX-001 采纳与验收记录
|
|
2
2
|
|
|
3
|
+
## 0.1.23:旧记录兼容与 TaskScope 契约
|
|
4
|
+
|
|
5
|
+
日期:2026-09-13。
|
|
6
|
+
|
|
7
|
+
| 交互要求 | 当前实现 |
|
|
8
|
+
| --- | --- |
|
|
9
|
+
| 历史升级不能丢弃旧 Host 记录 | 缺少 Workspace / Session 的合法旧记录继续进入 Profile 历史,并规范化为空来源哨兵 |
|
|
10
|
+
| 来源缺失不得猜测或重绑 | 卡片明确显示“未记录(旧记录)”;旧记录不匹配任何当前 Session,也不能由当前页下载或回写 |
|
|
11
|
+
| 当前任务与历史查询边界应可复用 | `HostedTaskListScope` 显式区分 `current` 和 `profile-history`;独立 TaskScope 文档覆盖 Session A/B/legacy fixtures |
|
|
12
|
+
| 长来源信息不能破坏布局 | 浅色/深色 × 桌面/窄屏四种隔离 Chrome 场景检查跨 Session 长路径与旧记录标识 |
|
|
13
|
+
|
|
3
14
|
## 0.1.22:跨 Session 历史汇总
|
|
4
15
|
|
|
5
16
|
日期:2026-09-13。
|
package/docs/MARKETPLACE.md
CHANGED
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
| 项目 | 已核验值 |
|
|
8
8
|
| --- | --- |
|
|
9
9
|
| 仓库 | `https://github.com/duhu2000/dsh-pre-duediligence`,公开、未归档 |
|
|
10
|
-
| npm | `dsh-pre-duediligence@0.1.
|
|
11
|
-
| Release | `https://github.com/duhu2000/dsh-pre-duediligence/releases/tag/v0.1.
|
|
10
|
+
| npm | `dsh-pre-duediligence@0.1.23`,发布后核验 `latest=0.1.23` |
|
|
11
|
+
| Release | `https://github.com/duhu2000/dsh-pre-duediligence/releases/tag/v0.1.23` |
|
|
12
12
|
| 许可证 | MIT |
|
|
13
13
|
| Topic | `dsh-plugin` |
|
|
14
14
|
| Manifest | `package.json` 的 `dsh.bundle.patch` 指向 `./cordis.patch.yml` |
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
- 企查查数据采用 BYO QCC:用户需要自行安装并配置兼容的 MCP Connector,使用自己的企查查账号、产品权限和可用额度完成 OAuth;本插件不附带账号、数据权限或查询额度。
|
|
29
29
|
- 多候选时需要用户确认唯一法律实体;用户发送任务即表示同意固定路由内连续执行,不再二次询问,也不受插件调用次数硬上限阻断。
|
|
30
30
|
- 零记录、无权限、额度不足和调用失败是不同状态;未执行或失败的维度不得写成“零风险”。
|
|
31
|
-
- 0.1.
|
|
31
|
+
- 0.1.23 已补齐缺少来源元数据的旧 Host 记录兼容,以显式 TaskScope 保持当前任务严格按 Session 隔离,并完成 Session A/B/legacy 契约、构建和隔离 UI 回归;生产账号端到端复测仍以用户验收为准,市场描述不把待验项写成已通过。
|
|
32
32
|
|
|
33
33
|
## 安装、卸载与截图证据
|
|
34
34
|
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# v0.1.23 发布说明
|
|
2
|
+
|
|
3
|
+
本版补齐 v0.1.22 跨 Session 历史汇总中的旧记录兼容边界。
|
|
4
|
+
|
|
5
|
+
## 修复
|
|
6
|
+
|
|
7
|
+
- 合法旧 Host 记录即使缺少 Workspace / Session 来源元数据,也会继续出现在当前 DSH Profile 的任务历史中。
|
|
8
|
+
- 历史卡片明确显示“未记录(旧记录)”,不再空白,也不会把未知来源伪装成当前 Workspace 或 Session。
|
|
9
|
+
- 客户端以 `HostedTaskListScope` 判别联合显式区分当前 Session 列表与 Profile 历史列表。
|
|
10
|
+
- 当前任务认领、单任务读取、报告回写和下载继续严格校验 Session;旧记录只可浏览,不会被当前 Session 重绑。
|
|
11
|
+
|
|
12
|
+
## 验证
|
|
13
|
+
|
|
14
|
+
- Session A/B/legacy fixtures 覆盖当前任务隔离、跨 Session 历史汇总和旧记录展示。
|
|
15
|
+
- 浅色/深色 × 桌面/窄屏四种隔离 Chrome 场景覆盖长来源文本、旧记录标识与横向溢出。
|
|
16
|
+
- 严格类型检查、单元/集成测试、Host/Client 构建与 npm 包清单门禁均纳入发布流程。
|
|
17
|
+
|
|
18
|
+
本轮验证使用合成 Host 记录,没有读取或修改生产 DSH Profile,也没有调用真实企查查 Provider;生产账号端到端结果仍以安装后的用户验收为准。
|
|
19
|
+
|
|
20
|
+
```sh
|
|
21
|
+
dsh plugin --profile web add dsh-pre-duediligence@0.1.23
|
|
22
|
+
```
|
|
@@ -12,14 +12,14 @@ npm keywords 已在包清单内更新。GitHub description 建议使用上述英
|
|
|
12
12
|
|
|
13
13
|
验收:使用实时完整目录和原版搜索函数对比登记描述更新前后;记录语言、命中位置、结果数与版本。独立目录缺失条目必须标为未上线,不能把模拟添加的结果当作上线结果。
|
|
14
14
|
|
|
15
|
-
发布清单:0.1.
|
|
15
|
+
发布清单:0.1.23 已获得发布授权;完成仓库 check、README 与包清单差异审核后,以新的不可变 tag 和 npm 版本发布,不覆盖旧版本或移动旧 tag。仅登记 YAML 更新仍无需重复发布 npm。
|
|
16
16
|
|
|
17
17
|
## 安装与三分钟上手
|
|
18
18
|
|
|
19
19
|
访前尽调智能体:面向拜访前调查,提供企业尽调、客户尽调、客户背景调查、工商核验与风险信息整理;使用企查查 MCP,提供固定路由连续调用、主体确认、动态进度和可下载报告。
|
|
20
20
|
|
|
21
21
|
```sh
|
|
22
|
-
dsh plugin --profile web add dsh-pre-duediligence@0.1.
|
|
22
|
+
dsh plugin --profile web add dsh-pre-duediligence@0.1.23
|
|
23
23
|
```
|
|
24
24
|
|
|
25
25
|
请先满足下文的 DSH 与连接器要求;Better Sidebar 只在需要可视化工作台时选装。安装后完整停止并重启对应 Profile。
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# TaskScope 与任务历史契约
|
|
2
|
+
|
|
3
|
+
本契约供访前尽调及其它 DSH 业务智能体复用。它区分“当前工作真相”和“历史浏览索引”,避免跨 Session 串单。
|
|
4
|
+
|
|
5
|
+
## 作用域
|
|
6
|
+
|
|
7
|
+
| 能力 | TaskScope | 请求 | 允许行为 |
|
|
8
|
+
| --- | --- | --- | --- |
|
|
9
|
+
| 当前任务发现与进度 | 当前 Session | `GET /previsit/api/tasks?sessionId=A` | 只能认领 Session A 的任务 |
|
|
10
|
+
| 当前任务正文与报告回写 | 当前 Session | `GET/PUT /previsit/api/tasks/:id...?sessionId=A` | Host 必须校验记录归属 A |
|
|
11
|
+
| 当前任务报告下载 | 当前 Session | `GET /previsit/api/tasks/:id/report?sessionId=A` | 不允许从 A 下载 B 的制品 |
|
|
12
|
+
| 任务历史列表 | 当前 DSH Profile | `GET /previsit/api/tasks` | 可汇总 A、B 等访前 Session 的 Host 持久记录 |
|
|
13
|
+
|
|
14
|
+
历史列表不是第二套浏览器数据库,也不是重新认领入口。完整对话与证据引用继续归属于来源 DSH 原生会话。
|
|
15
|
+
|
|
16
|
+
## A/B/legacy fixtures
|
|
17
|
+
|
|
18
|
+
| 记录 | origin Workspace / Session | 当前 A 视图 | Profile 历史 | 展示规则 |
|
|
19
|
+
| --- | --- | --- | --- | --- |
|
|
20
|
+
| Task A | `/workspace-a` / `session-a` | 可认领 | 可见 | 显示真实来源 |
|
|
21
|
+
| Task B | `/workspace-b` / `session-b` | 不可认领 | 可见 | 显示真实来源 |
|
|
22
|
+
| Legacy | 缺失 / 缺失 | 不可认领 | 可见 | 显示“未记录(旧记录)”,不得猜测为 A |
|
|
23
|
+
|
|
24
|
+
实现以 `HostedTaskListScope` 的 `current` / `profile-history` 判别联合为客户端契约;Host 对单任务、报告回写和下载继续强制校验 `sessionId`。旧记录缺失来源时使用空字符串兼容哨兵,只用于 Profile 历史,不参与任一当前 Session 匹配。
|
package/install.sh
CHANGED
|
@@ -5,7 +5,7 @@ set -euo pipefail
|
|
|
5
5
|
readonly PROFILE_NAME="${DSH_PROFILE:-web}"
|
|
6
6
|
readonly BASELINE="${DSH_PREVISIT_BASELINE:-stable}"
|
|
7
7
|
readonly WORKBENCH_MODE="${DSH_PREVISIT_WORKBENCH:-off}"
|
|
8
|
-
readonly PREVISIT_SPEC="${DSH_PRE_DUEDILIGENCE_SPEC:-dsh-pre-duediligence@0.1.
|
|
8
|
+
readonly PREVISIT_SPEC="${DSH_PRE_DUEDILIGENCE_SPEC:-dsh-pre-duediligence@0.1.23}"
|
|
9
9
|
readonly LEGACY_PREVISIT_NAME="qcc-previsit-dsh"
|
|
10
10
|
readonly LEGACY_QCC_OAUTH_NAME="qcc-dsh-mcp-oauth"
|
|
11
11
|
|
package/lib/client.js
CHANGED
|
@@ -1406,6 +1406,9 @@ function PrevisitHome({ sessionId, useSession, openWorkbench: openWorkbench2 })
|
|
|
1406
1406
|
}
|
|
1407
1407
|
|
|
1408
1408
|
// src/hosted-task-api.ts
|
|
1409
|
+
function hostedTaskListUrl(scope) {
|
|
1410
|
+
return scope.kind === "current" ? `/previsit/api/tasks?sessionId=${encodeURIComponent(scope.sessionId)}` : "/previsit/api/tasks";
|
|
1411
|
+
}
|
|
1409
1412
|
async function fetchHostedTask(taskId, sessionId) {
|
|
1410
1413
|
const response = await fetch(`/previsit/api/tasks/${encodeURIComponent(taskId)}?sessionId=${encodeURIComponent(sessionId)}`, { headers: { accept: "application/json" } });
|
|
1411
1414
|
if (response.status === 404) return null;
|
|
@@ -1413,15 +1416,24 @@ async function fetchHostedTask(taskId, sessionId) {
|
|
|
1413
1416
|
if (!response.ok || payload.ok === false || payload.task === void 0) throw new Error(payload.message ?? `\u4EFB\u52A1\u72B6\u6001\u8BFB\u53D6\u5931\u8D25\uFF08HTTP ${response.status}\uFF09`);
|
|
1414
1417
|
return payload.task;
|
|
1415
1418
|
}
|
|
1416
|
-
async function fetchHostedTasks(
|
|
1417
|
-
const
|
|
1418
|
-
const response = await fetch(`/previsit/api/tasks${scope}`, { headers: { accept: "application/json" } });
|
|
1419
|
+
async function fetchHostedTasks(scope) {
|
|
1420
|
+
const response = await fetch(hostedTaskListUrl(scope), { headers: { accept: "application/json" } });
|
|
1419
1421
|
const payload = await response.json();
|
|
1420
1422
|
if (!response.ok || payload.ok === false || !Array.isArray(payload.tasks)) throw new Error(payload.message ?? `\u4EFB\u52A1\u5386\u53F2\u8BFB\u53D6\u5931\u8D25\uFF08HTTP ${response.status}\uFF09`);
|
|
1421
1423
|
return payload.tasks;
|
|
1422
1424
|
}
|
|
1423
1425
|
|
|
1424
1426
|
// src/hosted-task-sync.ts
|
|
1427
|
+
function hostedTaskOrigin(task) {
|
|
1428
|
+
const workspace = task.workspace.trim() || "\u672A\u8BB0\u5F55\uFF08\u65E7\u8BB0\u5F55\uFF09";
|
|
1429
|
+
const sessionId = task.sessionId.trim() || "\u672A\u8BB0\u5F55\uFF08\u65E7\u8BB0\u5F55\uFF09";
|
|
1430
|
+
return {
|
|
1431
|
+
workspace,
|
|
1432
|
+
sessionId,
|
|
1433
|
+
label: `\u6765\u6E90\uFF1AWorkspace ${workspace} \xB7 Session ${sessionId}`,
|
|
1434
|
+
complete: task.workspace.trim() !== "" && task.sessionId.trim() !== ""
|
|
1435
|
+
};
|
|
1436
|
+
}
|
|
1425
1437
|
var HOSTED_TERMINAL = /* @__PURE__ */ new Set(["completed", "partial", "failed"]);
|
|
1426
1438
|
var VERIFY_RUN = /risk|dishonest|enforcement|terminated|freeze|exception|penalty|tax|judicial|executive/;
|
|
1427
1439
|
var COMPLETE_RUN = /* @__PURE__ */ new Set(["done", "no-data", "skipped"]);
|
|
@@ -1877,15 +1889,16 @@ html[data-theme="dark"] .qccPrevisitHeroLogo,html.dark .qccPrevisitHeroLogo{colo
|
|
|
1877
1889
|
.qccPwStageIcon{display:grid;place-items:center;width:30px;height:30px;border:1px solid var(--qcc-border);border-radius:7px;background:var(--qcc-surface);flex:0 0 30px}.qccPwStage[data-selected="true"] .qccPwStageIcon,.qccPwStage[data-progress="active"] .qccPwStageIcon{border-color:var(--qcc-brand);background:var(--qcc-selected);color:var(--qcc-action)}.qccPwStage[data-progress="done"] .qccPwStageIcon{border-color:var(--qcc-success);background:var(--qcc-success-bg);color:var(--qcc-success)}.qccPwStage[data-progress="review"] .qccPwStageIcon{border-color:var(--qcc-border);background:var(--qcc-table-head);color:var(--qcc-secondary)}.qccPwStage[data-progress="failed"] .qccPwStageIcon{border-color:var(--qcc-danger);background:var(--qcc-danger-bg);color:var(--qcc-danger)}.qccPwStage[data-progress="done"]:not([data-selected="true"]){color:var(--qcc-success)}.qccPwStage[data-progress="review"]:not([data-selected="true"]){color:var(--qcc-secondary)}.qccPwStage[data-progress="failed"]:not([data-selected="true"]){color:var(--qcc-danger)}
|
|
1878
1890
|
.qccPwIcon{width:17px;height:17px;fill:none;stroke:currentColor;stroke-width:1.65;stroke-linecap:round;stroke-linejoin:round}
|
|
1879
1891
|
.qccPwStageCopy{display:block;min-width:0;max-width:100%}.qccPwStageCopy strong{display:block;overflow:hidden;font-size:12px;line-height:1.35;text-overflow:ellipsis;white-space:nowrap}
|
|
1880
|
-
.qccPwBody{min-height:0;padding:16px;overflow:auto;flex:1}.qccPwPanel{display:grid;gap:13px;max-width:960px;margin:0 auto}
|
|
1892
|
+
.qccPwBody{min-height:0;padding:16px;overflow:auto;flex:1}.qccPwPanel{display:grid;width:100%;min-width:0;gap:13px;max-width:960px;margin:0 auto}
|
|
1881
1893
|
.qccPwPageHeading{display:flex;align-items:flex-start;justify-content:space-between;gap:14px}.qccPwPageHeading h2{margin:1px 0 0;font-size:19px}.qccPwPageHeading p:not(.qccPwEyebrow){margin:4px 0 0;color:var(--qcc-secondary);font-size:12px;line-height:1.5}.qccPwEyebrow{margin:0;color:var(--qcc-action);font-size:10px;font-weight:750;letter-spacing:.12em}.qccPwTaskId{padding:5px 8px;border:1px solid var(--qcc-border);border-radius:7px;background:var(--qcc-surface);color:var(--qcc-secondary);font:11px ui-monospace,SFMono-Regular,Menlo,monospace}
|
|
1882
|
-
.qccPwCard{padding:15px;border:1px solid var(--qcc-border);border-radius:12px;background:var(--qcc-surface)}.qccPwCardHeader{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;margin-bottom:12px}.qccPwCardHeader h3{margin:0;font-size:14px}.qccPwCardHeader p{margin:4px 0 0;color:var(--qcc-secondary);font-size:11px;line-height:1.5}.qccPwModeGroup{display:flex;justify-content:flex-end;flex-wrap:wrap;gap:5px}.qccPwMode{padding:3px 7px;border-radius:999px;background:var(--qcc-selected);color:var(--qcc-action);font-size:10px;white-space:nowrap}.qccPwMode[data-tone="neutral"]{background:var(--qcc-table-head);color:var(--qcc-secondary)}.qccPwMode[data-tone="success"]{background:var(--qcc-success-bg);color:var(--qcc-success)}.qccPwMode[data-tone="review"]{background:var(--qcc-review-bg);color:var(--qcc-review)}.qccPwMode[data-tone="error"]{background:var(--qcc-danger-bg);color:var(--qcc-danger)}
|
|
1894
|
+
.qccPwCard{min-width:0;padding:15px;border:1px solid var(--qcc-border);border-radius:12px;background:var(--qcc-surface)}.qccPwCardHeader{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;margin-bottom:12px}.qccPwCardHeader>div{min-width:0;flex:1 1 0}.qccPwCardHeader h3{margin:0;font-size:14px}.qccPwCardHeader p{margin:4px 0 0;color:var(--qcc-secondary);font-size:11px;line-height:1.5}.qccPwModeGroup{display:flex;justify-content:flex-end;flex-wrap:wrap;gap:5px}.qccPwMode{padding:3px 7px;border-radius:999px;background:var(--qcc-selected);color:var(--qcc-action);font-size:10px;white-space:nowrap}.qccPwMode[data-tone="neutral"]{background:var(--qcc-table-head);color:var(--qcc-secondary)}.qccPwMode[data-tone="success"]{background:var(--qcc-success-bg);color:var(--qcc-success)}.qccPwMode[data-tone="review"]{background:var(--qcc-review-bg);color:var(--qcc-review)}.qccPwMode[data-tone="error"]{background:var(--qcc-danger-bg);color:var(--qcc-danger)}
|
|
1883
1895
|
.qccPwFeedback{display:flex;align-items:flex-start;gap:10px;padding:12px 13px;border:1px solid var(--qcc-border);border-radius:10px;background:var(--qcc-table-head)}.qccPwFeedback[data-tone="success"]{border-color:var(--qcc-success);background:var(--qcc-success-bg)}.qccPwFeedback[data-tone="error"]{border-color:var(--qcc-danger);background:var(--qcc-danger-bg)}.qccPwFeedbackIcon{color:var(--qcc-action);flex:none}.qccPwFeedback[data-tone="success"] .qccPwFeedbackIcon{color:var(--qcc-success)}.qccPwFeedback[data-tone="error"] .qccPwFeedbackIcon{color:var(--qcc-danger)}.qccPwFeedback strong{font-size:13px}.qccPwFeedback p{margin:3px 0 0;color:var(--qcc-secondary);font-size:11px;line-height:1.55}
|
|
1884
1896
|
.qccPwLiveProgress{display:grid;grid-template-columns:auto minmax(0,1fr);align-items:start;gap:10px;padding:13px;border:1px solid var(--qcc-brand);border-radius:10px;background:var(--qcc-selected)}.qccPwLivePulse{width:9px;height:9px;margin-top:4px;border-radius:50%;background:var(--qcc-brand);box-shadow:0 0 0 0 color-mix(in srgb,var(--qcc-brand) 45%,transparent);animation:qccPwPulse 1.6s ease-out infinite}.qccPwLiveCopy{min-width:0}.qccPwLiveCopy strong{display:block;color:var(--qcc-action);font-size:13px}.qccPwLiveCopy p{margin:4px 0 0;color:var(--qcc-secondary);font-size:11px;line-height:1.55}.qccPwLiveMetrics{grid-column:2;display:flex;flex-wrap:wrap;gap:5px}.qccPwLiveMetrics span{padding:3px 7px;border:1px solid var(--qcc-border);border-radius:999px;background:var(--qcc-surface);color:var(--qcc-secondary);font-size:9px}.qccPwLiveMetrics span[data-tone="success"]{border-color:var(--qcc-success);background:var(--qcc-success-bg);color:var(--qcc-success)}.qccPwLiveMetrics span[data-tone="error"]{border-color:var(--qcc-danger);background:var(--qcc-danger-bg);color:var(--qcc-danger)}@keyframes qccPwPulse{70%{box-shadow:0 0 0 7px transparent}100%{box-shadow:0 0 0 0 transparent}}
|
|
1885
1897
|
.qccPwSteps{display:grid;grid-template-columns:repeat(4,1fr);gap:8px;margin:0;padding:0;list-style:none}.qccPwStep{display:flex;align-items:flex-start;gap:8px;padding:10px;border:1px solid var(--qcc-border);border-radius:9px;background:var(--qcc-surface)}.qccPwStepDot{display:grid;place-items:center;width:23px;height:23px;border-radius:50%;background:var(--qcc-page);color:var(--qcc-secondary);font-size:10px;flex:none}.qccPwStep[data-state="done"]{border-color:var(--qcc-success)}.qccPwStep[data-state="done"] .qccPwStepDot{background:var(--qcc-success-bg);color:var(--qcc-success)}.qccPwStep[data-state="active"]{border-color:var(--qcc-brand)}.qccPwStep[data-state="active"] .qccPwStepDot{background:var(--qcc-selected);color:var(--qcc-action)}.qccPwStep[data-state="review"]{border-color:var(--qcc-review)}.qccPwStep[data-state="review"] .qccPwStepDot{background:var(--qcc-review-bg);color:var(--qcc-review)}.qccPwStep[data-state="failed"]{border-color:var(--qcc-danger)}.qccPwStep[data-state="failed"] .qccPwStepDot{background:var(--qcc-danger-bg);color:var(--qcc-danger)}.qccPwStepCopy{display:grid;gap:3px}.qccPwStepCopy b{font-size:11px}.qccPwStepCopy small{color:var(--qcc-secondary);font-size:9px}
|
|
1886
1898
|
.qccPwDims{display:flex;flex-wrap:wrap;gap:7px}.qccPwDim{padding:5px 8px;border:1px solid var(--qcc-border);border-radius:7px;color:var(--qcc-secondary);font-size:11px}.qccPwDim[data-status="done"],.qccPwDim[data-status="no-data"],.qccPwDim[data-status="skipped"]{border-color:var(--qcc-success);background:var(--qcc-success-bg);color:var(--qcc-success)}.qccPwDim[data-status="running"]{border-color:var(--qcc-brand);background:var(--qcc-selected);color:var(--qcc-action)}.qccPwDim[data-status="unknown"],.qccPwDim[data-status="no-permission"],.qccPwDim[data-status="not-executed"]{border-color:var(--qcc-review);background:var(--qcc-review-bg);color:var(--qcc-review)}.qccPwDim[data-status="failed"]{border-color:var(--qcc-danger);background:var(--qcc-danger-bg);color:var(--qcc-danger)}.qccPwDim[data-status="not-executed"]{border-style:dashed}
|
|
1887
1899
|
.qccPwEmpty,.qccPwNote{margin:0;color:var(--qcc-secondary);font-size:12px;line-height:1.65}.qccPwNote{padding:10px 12px;border-left:3px solid var(--qcc-brand);background:var(--qcc-selected)}
|
|
1888
|
-
.qccPwHistorySource{max-width:
|
|
1900
|
+
.qccPwHistorySource{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
1901
|
+
.qccPwHistorySource[data-complete="false"]{font-style:italic}
|
|
1889
1902
|
.qccPwStateStrip{display:grid;grid-template-columns:repeat(4,1fr);gap:6px}.qccPwState{display:grid;gap:3px;padding:7px;border:1px solid var(--qcc-border);border-radius:7px;background:var(--qcc-surface);color:var(--qcc-secondary);text-align:center}.qccPwState b{font-size:10px;font-weight:600}.qccPwState small{font-size:8px;color:var(--qcc-secondary)}.qccPwState[data-state="pending"]{border-style:dashed}.qccPwState[data-state="selected"]{border-color:var(--qcc-brand);background:var(--qcc-selected);color:var(--qcc-action)}.qccPwState[data-state="selected"] b{font-weight:700}.qccPwState[data-state="selected"] small{color:var(--qcc-action)}.qccPwState[data-state="excluded"]{background:var(--qcc-page)}.qccPwState[data-state="undetermined"]{border-color:var(--qcc-review);background:var(--qcc-review-bg);color:var(--qcc-review)}.qccPwState[data-state="undetermined"] small{color:var(--qcc-review)}
|
|
1890
1903
|
.qccPwHypos{display:grid;gap:8px;margin:0;padding:0;list-style:none}.qccPwHypos li{display:grid;grid-template-columns:auto auto 1fr;align-items:start;gap:8px;padding:9px;border-radius:8px;background:var(--qcc-page);font-size:11px;line-height:1.55}.qccPwPri{padding:2px 5px;border-radius:5px;background:var(--qcc-table-head);color:var(--qcc-secondary)}.qccPwPri[data-p="P0"]{background:var(--qcc-danger-bg);color:var(--qcc-danger)}.qccPwPri[data-p="P1"]{background:var(--qcc-review-bg);color:var(--qcc-review)}
|
|
1891
1904
|
.qccPwRiskTiles{display:grid;grid-template-columns:repeat(3,1fr);gap:8px}.qccPwRiskTile{padding:11px;border:1px solid var(--qcc-border);border-radius:9px;background:var(--qcc-page)}.qccPwRiskTileTop{display:flex;justify-content:space-between;gap:8px}.qccPwRiskTileTop b,.qccPwRiskTileTop strong{font-size:12px}.qccPwRiskTile p{margin:6px 0 0;color:var(--qcc-secondary);font-size:10px;line-height:1.5}.qccPwRiskTile[data-clear="true"]{border-color:var(--qcc-success);background:var(--qcc-success-bg)}.qccPwRiskTile[data-clear="true"] .qccPwRiskTileTop{color:var(--qcc-success)}.qccPwRiskTile[data-level="红线"]:not([data-empty="true"]){border-color:var(--qcc-danger);background:var(--qcc-danger-bg)}.qccPwRiskTile[data-level="关注"]:not([data-empty="true"]){border-color:var(--qcc-review);background:var(--qcc-review-bg)}.qccPwRiskTile[data-level="信息"]:not([data-empty="true"]){border-color:var(--qcc-brand);background:var(--qcc-selected)}.qccPwRiskBoundary{grid-column:1/-1;margin:0;color:var(--qcc-secondary);font-size:10px;line-height:1.5}
|
|
@@ -2522,6 +2535,7 @@ function HistoryPanel(props) {
|
|
|
2522
2535
|
] }) }),
|
|
2523
2536
|
props.hosted.length > 0 ? props.hosted.map((item) => {
|
|
2524
2537
|
const status = hostedStatus(item);
|
|
2538
|
+
const origin = hostedTaskOrigin(item);
|
|
2525
2539
|
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "qccPwCard", children: [
|
|
2526
2540
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "qccPwCardHeader", children: [
|
|
2527
2541
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { children: [
|
|
@@ -2531,12 +2545,7 @@ function HistoryPanel(props) {
|
|
|
2531
2545
|
" \xB7 ",
|
|
2532
2546
|
new Date(item.createdAt).toLocaleString("zh-CN")
|
|
2533
2547
|
] }),
|
|
2534
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.
|
|
2535
|
-
"\u6765\u6E90\uFF1A",
|
|
2536
|
-
item.workspace,
|
|
2537
|
-
" \xB7 ",
|
|
2538
|
-
item.sessionId
|
|
2539
|
-
] })
|
|
2548
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "qccPwHistorySource", "data-complete": origin.complete, title: origin.label, children: origin.label })
|
|
2540
2549
|
] }),
|
|
2541
2550
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "qccPwStatus", "data-status": status, children: STATUS_LABELS[status] })
|
|
2542
2551
|
] }),
|
|
@@ -2593,7 +2602,7 @@ function PrevisitWorkbenchTab(props) {
|
|
|
2593
2602
|
const refresh = async () => {
|
|
2594
2603
|
try {
|
|
2595
2604
|
const current = props.shared.get(sessionId);
|
|
2596
|
-
const records = await fetchHostedTasks(sessionId);
|
|
2605
|
+
const records = await fetchHostedTasks({ kind: "current", sessionId });
|
|
2597
2606
|
const summary = selectHostedTask(records, current.task, current.dismissedTaskIds);
|
|
2598
2607
|
const record = summary?.reportReady === true ? await fetchHostedTask(summary.id, sessionId) ?? summary : summary;
|
|
2599
2608
|
if (disposed) return;
|
|
@@ -2630,7 +2639,7 @@ function PrevisitWorkbenchTab(props) {
|
|
|
2630
2639
|
let timer;
|
|
2631
2640
|
const refresh = async () => {
|
|
2632
2641
|
try {
|
|
2633
|
-
const records = await fetchHostedTasks();
|
|
2642
|
+
const records = await fetchHostedTasks({ kind: "profile-history" });
|
|
2634
2643
|
if (disposed) return;
|
|
2635
2644
|
setHostedHistory(records);
|
|
2636
2645
|
setHostError(void 0);
|
package/lib/index.js
CHANGED
|
@@ -265,10 +265,16 @@ var DOMAIN_SPEC = {
|
|
|
265
265
|
};
|
|
266
266
|
var VALID_REQUEST_ID = /^PV-\d{8}-[A-Z0-9-]{4,40}$/;
|
|
267
267
|
var nowIso = () => (/* @__PURE__ */ new Date()).toISOString();
|
|
268
|
-
function
|
|
269
|
-
if (value === null || typeof value !== "object") return
|
|
268
|
+
function parseStoredRecord(value) {
|
|
269
|
+
if (value === null || typeof value !== "object") return void 0;
|
|
270
270
|
const record = value;
|
|
271
|
-
|
|
271
|
+
const valid = typeof record.id === "string" && record.schemaVersion === 1 && (record.sessionId === void 0 || typeof record.sessionId === "string") && (record.workspace === void 0 || typeof record.workspace === "string") && typeof record.query === "string" && typeof record.limit === "number" && typeof record.used === "number" && Array.isArray(record.runs) && PREVISIT_TASK_STATES.includes(record.state);
|
|
272
|
+
if (!valid) return void 0;
|
|
273
|
+
return normalizeTerminalRecord({
|
|
274
|
+
...record,
|
|
275
|
+
sessionId: typeof record.sessionId === "string" ? record.sessionId : "",
|
|
276
|
+
workspace: typeof record.workspace === "string" ? record.workspace : ""
|
|
277
|
+
});
|
|
272
278
|
}
|
|
273
279
|
function normalizeTerminalRecord(record) {
|
|
274
280
|
const unlimited = record.limit === 0 ? record : { ...record, limit: 0 };
|
|
@@ -321,7 +327,10 @@ var PrevisitWorkflowStore = class {
|
|
|
321
327
|
if (this.attachPromise !== void 0) return this.attachPromise;
|
|
322
328
|
this.attachPromise = storageDomain.open(DOMAIN_SPEC).then(async (access) => {
|
|
323
329
|
this.table = access.table("tasks");
|
|
324
|
-
for (const [id, value] of this.table.entries())
|
|
330
|
+
for (const [id, value] of this.table.entries()) {
|
|
331
|
+
const record = parseStoredRecord(value);
|
|
332
|
+
if (record !== void 0) this.records.set(id, record);
|
|
333
|
+
}
|
|
325
334
|
for (const [id, record] of this.records) await this.table.put(id, record);
|
|
326
335
|
logger.info?.("[dsh-pre-duediligence] persistent task state ready");
|
|
327
336
|
}).catch((error) => {
|
|
@@ -348,10 +357,9 @@ var PrevisitWorkflowStore = class {
|
|
|
348
357
|
}
|
|
349
358
|
if (this.table === void 0) return void 0;
|
|
350
359
|
const value = await this.table.get(id);
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
else this.records.set(id, normalized);
|
|
360
|
+
const normalized = parseStoredRecord(value);
|
|
361
|
+
if (normalized === void 0) return void 0;
|
|
362
|
+
await this.put(normalized);
|
|
355
363
|
return normalized;
|
|
356
364
|
}
|
|
357
365
|
async put(record) {
|
|
@@ -980,7 +988,7 @@ function loadBundledSkill() {
|
|
|
980
988
|
},
|
|
981
989
|
metadata: {
|
|
982
990
|
author: "QCC",
|
|
983
|
-
version: "0.1.
|
|
991
|
+
version: "0.1.23",
|
|
984
992
|
industry: "enterprise-services",
|
|
985
993
|
mcpServers: ["qcc-company", "qcc-risk", "qcc-ipr", "qcc-operation", "qcc-executive"]
|
|
986
994
|
}
|
package/lib/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/index.ts", "../src/skill-file.ts", "../src/previsit-session.ts", "../src/report-export.ts", "../src/previsit-workflow.ts", "../src/previsit-web.ts", "../src/previsit-tools.ts", "../src/tool-outcome.ts"],
|
|
4
|
-
"sourcesContent": ["import { readFileSync } from \"node:fs\"\nimport { fileURLToPath } from \"node:url\"\n\nimport { parseSkillFile } from \"./skill-file.js\"\nimport { mountPrevisitWebRoutes, type WebServer } from \"./previsit-web.js\"\nimport { registerPrevisitTools, type ToolHost } from \"./previsit-tools.js\"\nimport { PrevisitWorkflowStore, type StorageDomain } from \"./previsit-workflow.js\"\n\nexport const inject = [\"skills\", \"tools\"] as const\n\nexport const SKILL_NAME = \"qcc-previsit-onepager\"\nexport const SKILL_DESCRIPTION =\n \"\u8C03\u7528\u4F01\u67E5\u67E5\u4E94\u7C7B MCP \u6267\u884C\u4F01\u4E1A\u8BBF\u524D\u5C3D\u8C03\uFF0C\u4EE5\u673A\u4F1A\u4E0E\u98CE\u9669\u53CC\u5F15\u64CE\u8BC6\u522B\u7ECF\u8425\u72B6\u6001\u3001\u5EFA\u7ACB\u5E76\u53CD\u8BC1\u4E1A\u52A1\u5047\u8BBE\uFF0C\u4EA4\u4ED8\u53EF\u8FFD\u6EAF\u7684\u8BBF\u524D\u5C3D\u8C03\u62A5\u544A\u3002\"\n\ntype SkillRegistration = {\n name: string\n description: string\n whenToUse: string\n content: string\n source: \"bundled\"\n resourceBase: {\n kind: \"directory\"\n path: string\n }\n metadata: Readonly<Record<string, unknown>>\n}\n\nexport type HostContext = ToolHost & {\n effect(setup: () => void | (() => void)): unknown\n inject?(deps: string[], setup: (ctx: HostContext & { webServer: WebServer; storageDomain: StorageDomain }) => void): unknown\n logger?: { info?(message: string): void; warn?(message: string): void }\n skills: {\n register(skill: SkillRegistration): () => void\n }\n}\n\nexport function loadBundledSkill(): SkillRegistration {\n const skillDirectoryUrl = new URL(\"../skills/qcc-previsit-onepager/\", import.meta.url)\n const skillSource = readFileSync(new URL(\"SKILL.md\", skillDirectoryUrl), \"utf8\")\n const { content } = parseSkillFile(skillSource)\n\n return {\n name: SKILL_NAME,\n description: SKILL_DESCRIPTION,\n whenToUse: \"\u7528\u6237\u8981\u6C42\u51C6\u5907\u5BA2\u6237\u62DC\u8BBF\u3001\u8BBF\u524D\u5C3D\u8C03\u3001\u4E00\u9875\u7EB8\u7B80\u62A5\u3001\u6388\u4FE1\u9762\u8C08\u3001\u5546\u52A1\u8C08\u5224\u3001\u7B7E\u7EA6\u6838\u67E5\u3001\u590D\u8BBF\u66F4\u65B0\u3001\u89E6\u8FBE\u8DEF\u5F84\u6216\u5F53\u9762\u63D0\u95EE\u6E05\u5355\u65F6\u4F7F\u7528\u3002\",\n content,\n source: \"bundled\",\n resourceBase: {\n kind: \"directory\",\n path: fileURLToPath(skillDirectoryUrl),\n },\n metadata: {\n author: \"QCC\",\n version: \"0.1.22\",\n industry: \"enterprise-services\",\n mcpServers: [\"qcc-company\", \"qcc-risk\", \"qcc-ipr\", \"qcc-operation\", \"qcc-executive\"],\n },\n }\n}\n\nexport function apply(ctx: HostContext): void {\n const workflow = new PrevisitWorkflowStore()\n ctx.effect(() => registerPrevisitTools(ctx, workflow))\n ctx.skills.register(loadBundledSkill())\n try {\n ctx.inject?.([\"webServer\", \"storageDomain\"], webCtx => {\n void workflow.attach(webCtx.storageDomain, ctx.logger)\n webCtx.effect(() => mountPrevisitWebRoutes(webCtx.webServer, workflow))\n })\n } catch (error) {\n ctx.logger?.warn?.(`[dsh-pre-duediligence] Host task routes unavailable: ${error instanceof Error ? error.message : String(error)}`)\n }\n}\n", "export type ParsedSkillFile = {\n content: string\n frontmatter: string | null\n}\n\nexport function parseSkillFile(source: string): ParsedSkillFile {\n const normalized = source.replaceAll(\"\\r\\n\", \"\\n\")\n\n if (!normalized.startsWith(\"---\\n\")) {\n return { content: normalized.trim(), frontmatter: null }\n }\n\n const closingMarker = normalized.indexOf(\"\\n---\\n\", 4)\n\n if (closingMarker === -1) {\n throw new Error(\"SKILL.md \u7684 YAML frontmatter \u7F3A\u5C11\u7ED3\u675F\u6807\u8BB0\")\n }\n\n return {\n frontmatter: normalized.slice(4, closingMarker).trim(),\n content: normalized.slice(closingMarker + 5).trim(),\n }\n}\n", "export const PREVISIT_SESSION_ID_PREFIX = \"session-dsh-pre-duediligence-\"\n\nexport function isPrevisitSession(sessionId: string): boolean {\n return /^session-dsh-pre-duediligence-[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu.test(sessionId)\n}\n\nexport type PrevisitSessionHost = {\n sessions: {\n list?: { getSnapshot(): { current?: string } }\n create?(options: { workspaceId: string; sessionId: string }): Promise<string>\n open?(sessionId: string): void\n }\n workspaces?: {\n list?: { getSnapshot(): {\n items?: Array<{ workspaceId: string; path?: string; sessionIds?: string[] }>\n recentWorkspaceId?: string\n } }\n }\n}\n\nexport function resolvePrevisitWorkspaceId(ctx: PrevisitSessionHost): string | undefined {\n const workspace = ctx.workspaces?.list?.getSnapshot()\n const current = ctx.sessions.list?.getSnapshot().current\n const items = workspace?.items ?? []\n return items.find(item => current !== undefined && item.sessionIds?.includes(current))?.workspaceId\n ?? items.find(item => item.workspaceId === workspace?.recentWorkspaceId)?.workspaceId\n ?? items[0]?.workspaceId\n}\n\nexport async function createPrevisitSession(ctx: PrevisitSessionHost): Promise<string> {\n const workspaceId = resolvePrevisitWorkspaceId(ctx)\n if (!workspaceId) throw new Error(\"\u8BF7\u5148\u9009\u62E9\u4E00\u4E2A\u5DE5\u4F5C\u7A7A\u95F4\uFF0C\u518D\u6253\u5F00\u8BBF\u524D\u5C3D\u8C03\")\n if (typeof ctx.sessions.create !== \"function\" || typeof ctx.sessions.open !== \"function\") {\n throw new Error(\"\u5F53\u524D DSH \u7248\u672C\u6CA1\u6709\u53EF\u7528\u7684\u4F1A\u8BDD\u521B\u5EFA\u80FD\u529B\")\n }\n if (typeof globalThis.crypto?.randomUUID !== \"function\") {\n throw new Error(\"\u5F53\u524D\u6D4F\u89C8\u5668\u4E0D\u652F\u6301\u5B89\u5168\u4F1A\u8BDD\u6807\u8BC6\u751F\u6210\uFF0C\u8BF7\u4F7F\u7528\u6700\u65B0\u7248\u6D4F\u89C8\u5668\")\n }\n const requested = PREVISIT_SESSION_ID_PREFIX + globalThis.crypto.randomUUID()\n // Preserve the runtime receiver: create() uses this.manager.\n const created = await ctx.sessions.create({ workspaceId, sessionId: requested })\n if (created !== requested) throw new Error(\"\u8BBF\u524D\u5C3D\u8C03\u4F1A\u8BDD\u6807\u8BC6\u4E0D\u5339\u914D\uFF0C\u8BF7\u91CD\u8BD5\")\n return created\n}\n", "// \u4F5C\u6218\u5361 Markdown \u2192 \u53EF\u4E0B\u8F7D\u7684\u81EA\u5305\u542B\u6837\u5F0F\u5316 HTML \u62A5\u544A\u3002\n// \u914D\u8272\u3001\u5B57\u53F7\u3001\u6807\u9898\u89C4\u8303\u5168\u90E8\u9501\u5B9A\u4E3A\u7528\u6237\u63D0\u4F9B\u7684 demo \u8BBE\u8BA1\uFF0C\u6A21\u578B/\u524D\u7AEF\u90FD\u4E0D\u518D\u81EA\u884C\u914D\u8272\u3002\n// \u7EAF\u51FD\u6570\uFF0C\u65E0 DOM \u4F9D\u8D56\uFF0C\u4FBF\u4E8E\u5355\u6D4B\u3002\nimport { isPrevisitSession } from \"./previsit-session.js\"\n\nexport type ReportMeta = {\n company?: string\n generatedAt?: string\n}\n\n// \u4F1A\u8BDD\u8282\u70B9\u7684\u6700\u5C0F\u7ED3\u6784\uFF08DSH \u8282\u70B9\u5177\u4F53\u5F62\u6001\u672A\u77E5\uFF0C\u5B57\u6BB5\u5168\u90E8\u53EF\u9009\uFF09\nexport type CardNode = {\n id?: string\n seq?: number\n interrupted?: boolean\n blocks?: Array<{ kind: string; text?: string }>\n kind?: string\n role?: string\n text?: string\n content?: unknown\n message?: { role?: string; content?: unknown } | null\n parts?: Array<{ text?: string; type?: string } | string>\n call?: { name?: string } | null\n}\n\nexport type CardSnapshot = { nodes?: CardNode[]; running?: boolean }\n\nfunction contentText(value: unknown): string {\n if (typeof value === \"string\") return value\n if (!Array.isArray(value)) return \"\"\n return value.map(block => {\n if (typeof block === \"string\") return block\n if (block === null || typeof block !== \"object\") return \"\"\n const typed = block as { type?: unknown; kind?: unknown; text?: unknown }\n if ((typeof typed.type === \"string\" && typed.type !== \"text\") || (typeof typed.kind === \"string\" && typed.kind !== \"text\")) return \"\"\n return typeof typed.text === \"string\" ? typed.text : \"\"\n }).join(\"\")\n}\n\n// \u9632\u5FA1\u5F0F\u63D0\u53D6\u52A9\u624B\u8F93\u51FA\u7684\u4F5C\u6218\u5361\u6B63\u6587\uFF1ADSH \u4F1A\u8BDD\u8282\u70B9\u5F62\u6001\u672A\u77E5\uFF0C\u9010\u79CD\u53EF\u80FD\u5B57\u6BB5\u5C1D\u8BD5\u3002\nfunction nodeText(node: CardNode): string {\n if (Array.isArray(node.blocks)) return node.blocks.filter(b => b.kind === \"text\").map(b => b.text ?? \"\").join(\"\\n\")\n if (typeof node.text === \"string\") return node.text\n if (typeof node.content === \"string\") return node.content\n if (node.message) { const text = contentText(node.message.content); if (text !== \"\") return text }\n if (Array.isArray(node.content)) return contentText(node.content)\n if (Array.isArray(node.parts)) {\n return node.parts.map(pt => (typeof pt === \"string\" ? pt : (pt && typeof pt.text === \"string\" ? pt.text : \"\"))).join(\"\")\n }\n return \"\"\n}\n\n// \u4F5C\u6218\u5361\u8D77\u70B9\uFF1A\u4E00\u7EA7\u6807\u9898\u300C\u62DC\u8BBF\u4F5C\u6218\u5361 \u00B7 \u4F01\u4E1A\u540D\u300D\u6216\u9996\u6BB5\u300C\u2460 \u6838\u5FC3\u7814\u5224\u300D\nconst CARD_START = /^#{1,3}\\s*(\u8BBF\u524D\u5C3D\u8C03\u62A5\u544A|\u62DC\u8BBF\u4F5C\u6218\u5361)[^\\n]*$|^#{1,3}\\s*[\u24601]?\\s*\u6838\u5FC3\u7814\u5224[^\\n]*$/m\n// \u5361\u7247\u7ED3\u6784\u7279\u5F81\uFF1A\u81F3\u5C11\u6709\u6838\u5FC3\u7814\u5224 + \u73B0\u573A\u5FC5\u95EE/\u8986\u76D6\u8BF4\u660E\u4E24\u7C7B\u6BB5\u843D\nconst CARD_SHAPE = (text: string): boolean => /\u6838\u5FC3\u7814\u5224/.test(text) && /\u73B0\u573A\u5FC5\u95EE|\u8986\u76D6\u8BF4\u660E|\u8986\u76D6\u5EA6/.test(text)\n// \u6CE8\u5165\u5185\u5BB9\uFF08\u6280\u80FD\u6E05\u5355\u3001\u7CFB\u7EDF\u63D0\u9192\u7B49\uFF09\u7EDD\u4E0D\u8FDB\u62A5\u544A\nconst JUNK = /<system-reminder>|<available_skills>|<command-name>|<\\/?antml/i\nconst isTool = (node: CardNode): boolean => node.kind === \"tool-result\" || node.kind === \"tool-call\"\nconst nodeRole = (node: CardNode): string => node.role ?? node.message?.role ?? node.kind ?? \"\"\nconst isUserish = (node: CardNode): boolean => /user|human|system|context|steering/i.test(`${nodeRole(node)} ${node.kind ?? \"\"}`) || node.interrupted === true\n\n// \u4ECE\u4F1A\u8BDD\u91CC\u8BA4\u9886\u4EFB\u52A1\uFF1A\u627E\u6700\u540E\u4E00\u6761\u5E26\u201C\u8BBF\u524D\u4EFB\u52A1 ID\uFF1APV-xxx\u201D\u7684\u6D88\u606F\uFF08\u5DE5\u4F5C\u53F0/\u8BBE\u5B9A\u6761\u53D1\u51FA\u7684\u6B63\u5F0F\u63D0\u4EA4\uFF09\uFF1B\n// \u6CA1\u6709\u6807\u8BB0\u4F46\u5DF2\u51FA\u73B0\u4F01\u67E5\u67E5\u5DE5\u5177\u8C03\u7528\u65F6\uFF0C\u89C6\u4E3A\u201C\u4F1A\u8BDD\u5185\u76F4\u63A5\u53D1\u8D77\u7684\u5C3D\u8C03\u201D\uFF0C\u4ECE\u5934\u8DDF\u8E2A\u3002\nexport function adoptTaskFromSnapshot(snapshot: CardSnapshot, sessionId: string, minimumBaseline = 0): { id: string; prompt: string; nodeBaseline: number } | null {\n if (!isPrevisitSession(sessionId)) return null\n const nodes = snapshot.nodes ?? []\n for (let idx = nodes.length - 1; idx >= minimumBaseline; idx--) {\n const node = nodes[idx]\n if (node === undefined || !/^(user|human)$/i.test(nodeRole(node))) continue\n const text = nodeText(node)\n const m = /\u8BBF\u524D\u4EFB\u52A1 ID[\uFF1A:]\\s*(PV-[A-Z0-9-]+)/.exec(text)\n if (m !== null && m[1] !== undefined) return { id: m[1], prompt: text.trim(), nodeBaseline: idx }\n }\n // Native composer submissions inherit the explicitly owned Session. Never infer\n // ownership from QCC calls (shared by cleaning, form-fill and tender plugins).\n for (let idx = nodes.length - 1; idx >= minimumBaseline; idx--) {\n const node = nodes[idx]\n if (node === undefined || !/^(user|human)$/i.test(nodeRole(node))) continue\n const prompt = nodeText(node).trim()\n if (prompt !== \"\" && !JUNK.test(prompt)) return { id: `turn:${node.seq ?? node.id ?? idx}`, prompt, nodeBaseline: idx }\n }\n return null\n}\n\nconst FULL_REPORT_SECTIONS = [\"\u6838\u5FC3\u7814\u5224\", \"\u4EA7\u4E1A\u5B9A\u4F4D\", \"\u8FD1\u671F\u52A8\u6001\", \"\u4E1A\u52A1\u5047\u8BBE\", \"\u7EA2\u7EBF\u63D0\u793A\", \"\u73B0\u573A\u5FC5\u95EE\", \"\u89E6\u8FBE\u5F00\u573A\", \"\u8986\u76D6\u8BF4\u660E\"]\nexport function captureTaskReport(snapshot: CardSnapshot, sessionId: string, task: { id: string; nodeBaseline: number; prompt: string }): string | null {\n if (!isPrevisitSession(sessionId) || snapshot.running === true) return null\n const node = snapshot.nodes?.[task.nodeBaseline]\n if (node === undefined || !/^(user|human)$/i.test(nodeRole(node))) return null\n const adopted = adoptTaskFromSnapshot({ nodes: (snapshot.nodes ?? []).slice(0, task.nodeBaseline + 1) }, sessionId, task.nodeBaseline)\n if (adopted?.id !== task.id) return null\n // A later explicitly submitted task is a hard boundary, including after reload.\n const nodes = snapshot.nodes ?? []\n const next = nodes.findIndex((n, i) => i > task.nodeBaseline && /^(user|human)$/i.test(nodeRole(n)) && /\u8BBF\u524D\u4EFB\u52A1 ID[\uFF1A:]\\s*PV-/.test(nodeText(n)))\n const text = extractCardText({ nodes: next === -1 ? nodes : nodes.slice(0, next) }, task.nodeBaseline + 1)\n if (text === null) return null\n const sections = [...text.matchAll(/^#{1,4}\\s+(.+)$/gm)].map(m => normalizeHeading(m[1] ?? \"\").replace(/^\\d+\u3001\\s*/, \"\").replace(/\\*\\*/g, \"\").trim())\n return FULL_REPORT_SECTIONS.every(s => sections.some(title => title === s || title.startsWith(s + \"\uFF08\") || title.startsWith(s + \"\uFF1A\"))) ? text : null\n}\n\nexport function extractCardText(snapshot: CardSnapshot, baseline: number): string | null {\n const nodes = (snapshot.nodes ?? []).slice(baseline)\n // \u4ECE\u672B\u5C3E\u627E\u6700\u540E\u4E00\u4E2A\u5305\u542B\u4F5C\u6218\u5361\u8D77\u70B9\u7684\u8282\u70B9\uFF0C\u4ECE\u8D77\u70B9\u5207\u5230\u8BE5\u8282\u70B9\u672B\u5C3E\n for (let idx = nodes.length - 1; idx >= 0; idx--) {\n const node = nodes[idx]\n if (node === undefined || isTool(node) || isUserish(node)) continue\n const text = nodeText(node)\n if (JUNK.test(text)) continue\n const m = CARD_START.exec(text)\n if (m === null || m.index === undefined) continue\n let card = text.slice(m.index).trim()\n // \u540E\u7EED\u7D27\u90BB\u8282\u70B9\u82E5\u662F\u540C\u4E00\u5F20\u5361\u7684\u5EF6\u7EED\uFF08\u4EE5 Markdown \u6BB5\u6807\u9898\u5F00\u5934\u3001\u65E0\u6CE8\u5165\u5185\u5BB9\uFF09\uFF0C\u62FC\u63A5\n for (let j = idx + 1; j < nodes.length; j++) {\n const next = nodes[j]\n if (next === undefined || isTool(next) || isUserish(next)) break\n const t = nodeText(next).trim()\n if (t === \"\" || JUNK.test(t) || !/^(#{2,4}\\s|\\||-\\s|\\d+\\.\\s|\\*\\*)/.test(t)) break\n card += \"\\n\\n\" + t\n }\n if (CARD_SHAPE(card)) return card\n }\n // \u515C\u5E95\uFF1A\u5355\u8282\u70B9\u6574\u4F53\u7B26\u5408\u5361\u7247\u7ED3\u6784\n for (let idx = nodes.length - 1; idx >= 0; idx--) {\n const node = nodes[idx]\n if (node === undefined || isTool(node) || isUserish(node)) continue\n const text = nodeText(node).trim()\n if (text.length > 40 && !JUNK.test(text) && CARD_SHAPE(text)) return text\n }\n return null\n}\n\nconst esc = (s: string): string =>\n s.replace(/&/g, \"&\").replace(/</g, \"<\").replace(/>/g, \">\").replace(/\"/g, \""\")\n\n// \u8BFB\u8005\u89C6\u89D2\u7684\u6E05\u6D17\uFF1A\u4E8B\u5B9E\u7F16\u53F7 [F-013] \u4E0E\u8BC1\u636E\u5C42\u7EA7\u4EE3\u53F7 L1/L2 \u53EA\u5BF9\u6A21\u578B\u8FFD\u6EAF\u6709\u7528\uFF0C\u62A5\u544A\u91CC\u7FFB\u8BD1\u6210\u4EBA\u8BDD\u6216\u53BB\u6389\nconst TIER_WORDS: Record<string, string> = { L1: \"\u8D22\u62A5\u62AB\u9732\", L2: \"\u516C\u5F00\u8BB0\u5F55\", L3: \"\u5173\u8054\u5173\u7CFB\", L4: \"\u884C\u4E1A\u63A8\u65AD\", L5: \"\u73B0\u573A\u6838\u5B9E\" }\nexport function humanizeCell(text: string): string {\n const t = text.trim()\n if (/^L[1-5](\\s*[\\/\uFF0F\u3001]\\s*L[1-5])*$/.test(t)) {\n return t.split(/\\s*[\\/\uFF0F\u3001]\\s*/).map(x => TIER_WORDS[x] ?? x).join(\" / \")\n }\n if (t === \"\u6765\u6E90\u5C42\u7EA7\") return \"\u6765\u6E90\"\n return text\n}\nexport function stripFactIds(text: string): string {\n // \u652F\u6301 [F-013]\u3001[F-008/F-009/F-013]\u3001[F-002\u3001F-008]\u3001[F-1/F-2] \u7B49\u5199\u6CD5\n return text\n .replace(/\\s*\\[F-?\\d{1,4}(?:\\s*[\\/\u3001,\uFF0C;\uFF1B|]\\s*F-?\\d{1,4})*\\]/g, \"\")\n .replace(/[ \\t]+([\uFF0C\u3002\uFF1B\uFF1A\uFF09])/g, \"$1\")\n}\n// \u5047\u8BBE\u7F16\u53F7\u4E0E\u4F18\u5148\u7EA7\uFF1AH2 \u00B7 P1 \u2192 \u5047\u8BBE 2\uFF08P1\uFF09\uFF1B\u6B63\u6587\u91CC\u201C\u56DE\u6307 H2\u201D\u2192\u201C\u56DE\u6307\u5047\u8BBE 2\u201D\nconst PRIORITY_WORDS: Record<string, string> = { P0: \"\u4F18\u5148\", P1: \"\u91CD\u8981\", P2: \"\u5907\u9009\" }\nexport function humanizeHypothesis(text: string): string {\n return text\n .replace(/^\\s*H(\\d+)\\s*[\u00B7\u30FB:\uFF1A\\-\u2013]\\s*(P[012])\\s*[\u00B7\u30FB:\uFF1A\\-\u2013]\\s*/, (_m, n: string, p: string) => `\u5047\u8BBE ${n}\uFF08${PRIORITY_WORDS[p] ?? p}\uFF09`)\n .replace(/(?<![A-Za-z0-9])H(\\d{1,2})(?![A-Za-z0-9])/g, \"\u5047\u8BBE $1\")\n}\n\n// \u884C\u5185\uFF1A**\u52A0\u7C97**\uFF1B\u4E8B\u5B9E\u7F16\u53F7\u53BB\u6389\nfunction inline(text: string): string {\n let html = esc(humanizeHypothesis(stripFactIds(text)))\n html = html.replace(/\\*\\*(.+?)\\*\\*/g, \"<strong>$1</strong>\")\n return html\n}\n\nconst CIRCLED: Record<string, string> = { \"\u2460\": \"1\", \"\u2461\": \"2\", \"\u2462\": \"3\", \"\u2463\": \"4\", \"\u2464\": \"5\", \"\u2465\": \"6\", \"\u2466\": \"7\", \"\u2467\": \"8\", \"\u2468\": \"9\", \"\u2469\": \"10\" }\nexport function normalizeHeading(text: string): string {\n return text.trim().replace(/^([\u2460\u2461\u2462\u2463\u2464\u2465\u2466\u2467\u2468\u2469])\\s*/, (_m, c: string) => `${CIRCLED[c] ?? c}\u3001`).replace(/^(\\d+)[.\uFF0E]\\s*/, \"$1\u3001\")\n}\n\n// \u62A5\u544A Markdown \u5B50\u96C6 \u2192 HTML \u4E3B\u4F53\u3002\u652F\u6301\uFF1A# ## ### \u6807\u9898\u3001| \u8868\u683C |\u3001- \u5217\u8868\u30011. \u6709\u5E8F\u3001--- \u5206\u9694\u3001\u6BB5\u843D\u3002\nexport function renderCardMarkdown(md: string): string {\n const lines = md.replace(/\\r\\n/g, \"\\n\").split(\"\\n\")\n const out: string[] = []\n let i = 0\n const flushList = (items: string[], ordered: boolean) => {\n if (!items.length) return\n const tag = ordered ? \"ol\" : \"ul\"\n out.push(`<${tag}>${items.map(it => `<li>${inline(it)}</li>`).join(\"\")}</${tag}>`)\n }\n while (i < lines.length) {\n const line = lines[i] ?? \"\"\n const t = line.trim()\n if (t === \"\") { i++; continue }\n if (/^---+$/.test(t)) { out.push(\"<hr/>\"); i++; continue }\n // \u8868\u683C\uFF1A\u8FDE\u7EED\u4EE5 | \u5F00\u5934\u7684\u884C\uFF0C\u7B2C\u4E8C\u884C\u662F\u5206\u9694\u7B26\n const sep = lines[i + 1] ?? \"\"\n if (t.startsWith(\"|\") && /^\\|[\\s:|-]+\\|?$/.test(sep.trim())) {\n const header = t.split(\"|\").slice(1, -1).map(c => humanizeCell(c.trim()))\n i += 2\n const rows: string[][] = []\n while (i < lines.length && (lines[i] ?? \"\").trim().startsWith(\"|\")) {\n rows.push((lines[i] ?? \"\").trim().split(\"|\").slice(1, -1).map(c => humanizeCell(c.trim())))\n i++\n }\n const thead = `<thead><tr>${header.map(h => `<th>${inline(h)}</th>`).join(\"\")}</tr></thead>`\n const tbody = `<tbody>${rows.map(r => `<tr>${r.map(c => `<td>${inline(c)}</td>`).join(\"\")}</tr>`).join(\"\")}</tbody>`\n out.push(`<div class=\"tw\"><table>${thead}${tbody}</table></div>`)\n continue\n }\n // \u6807\u9898\uFF1A\u5708\u53F7 \u2460\u2461 \u7EDF\u4E00\u6210\u201C1\u3001\u201D\u683C\u5F0F\n const h = /^(#{1,4})\\s+(.*)$/.exec(t)\n if (h) {\n const level = (h[1] ?? \"##\").length\n out.push(`<h${level}>${inline(normalizeHeading(h[2] ?? \"\"))}</h${level}>`)\n i++\n continue\n }\n // \u6807\u9898\u4E0B\u7684\u5C0F\u8BF4\u660E\uFF08> \u8BF4\u660E\uFF1A\u2026\uFF09\n if (t.startsWith(\">\")) {\n out.push(`<p class=\"note\">${inline(t.replace(/^>\\s?/, \"\"))}</p>`)\n i++\n continue\n }\n // \u65E0\u5E8F\u5217\u8868\n if (/^[-*]\\s+/.test(t)) {\n const items: string[] = []\n while (i < lines.length && /^\\s*[-*]\\s+/.test(lines[i] ?? \"\")) {\n items.push((lines[i] ?? \"\").trim().replace(/^[-*]\\s+/, \"\"))\n i++\n }\n flushList(items, false)\n continue\n }\n // \u6709\u5E8F\u5217\u8868\n if (/^\\d+\\.\\s+/.test(t)) {\n const items: string[] = []\n while (i < lines.length && /^\\s*\\d+\\.\\s+/.test(lines[i] ?? \"\")) {\n items.push((lines[i] ?? \"\").trim().replace(/^\\d+\\.\\s+/, \"\"))\n i++\n }\n flushList(items, true)\n continue\n }\n // \u6BB5\u843D\n out.push(`<p>${inline(t)}</p>`)\n i++\n }\n return out.join(\"\\n\")\n}\n\n// demo \u9501\u5B9A\u914D\u8272\u4E0E\u5B57\u53F7\uFF1B\u6807\u9898\u514B\u5236\u3001\u56DB\u5B57\u4F18\u5148\uFF0C\u6807\u9898\u4E0B\u53EF\u5E26\u5C0F\u8BF4\u660E\u6A21\u5757\u3002\nconst REPORT_CSS = `\n:root{\n --blue:#128BED;--blue-dark:#0875D1;--ink:#202C3B;--body:#3D4A5C;--muted:#626F80;\n --line:#DCE4EC;--line-blue:#CDE9FC;--hero:#F2F9FC;\n --ok:#16a34a;--ok-bg:#f0fdf4;--warn:#d97706;--warn-bg:#fff7ed;--risk:#ef4444;--risk-bg:#fef2f2;\n}\n*{box-sizing:border-box}\nbody{margin:0;background:#f1f5f9;color:var(--body);\n font:15px/1.75 -apple-system,BlinkMacSystemFont,\"PingFang SC\",\"Microsoft YaHei\",\"Noto Sans SC\",sans-serif;\n -webkit-font-smoothing:antialiased}\n.sheet{max-width:860px;margin:24px auto;background:#fff;border:1px solid var(--line);border-radius:12px;overflow:hidden;\n box-shadow:0 1px 2px rgba(15,23,42,.04),0 12px 32px -20px rgba(15,23,42,.25)}\n.hero{background:var(--hero);border-bottom:1px solid var(--line-blue);padding:22px 26px 20px}\n.hero .eyebrow{font-size:11px;font-weight:800;letter-spacing:.12em;color:var(--blue);margin:0 0 6px}\n.hero h1{margin:0;color:var(--ink);font-size:22px;font-weight:900;line-height:1.4}\n.hero .meta{margin:8px 0 0;color:var(--muted);font-size:12.5px;line-height:1.7}\n.body{padding:8px 26px 26px}\n/* \u5927\u6807\u9898\uFF1A\u84DD\u8272 + \u6807\u9898\u4E0B\u77ED\u6A2A\u7EBF\uFF1B\u5C0F\u6807\u9898\uFF1A\u6D45\u7070\u5E95 + \u5DE6\u4FA7\u84DD\u7AD6\u7EBF */\n.body h2{position:relative;margin:26px 0 12px;padding:0 0 8px;color:var(--blue-dark);font-size:16px;font-weight:800;letter-spacing:.01em}\n.body h2::after{content:\"\";position:absolute;left:0;bottom:0;width:32px;height:3px;border-radius:2px;background:var(--blue)}\n.body h2:first-of-type{margin-top:10px}\n.body h3{margin:16px 0 8px;padding:6px 10px;border-left:3px solid var(--blue);border-radius:0 4px 4px 0;background:#f5f7fa;color:var(--ink);font-size:13.5px;font-weight:800}\n.body h4{margin:12px 0 4px;color:var(--ink);font-size:13px;font-weight:700}\n.body h1{display:none}\n.note{margin:-4px 0 10px;color:var(--muted);font-size:12px;line-height:1.7}\nblockquote{margin:-4px 0 10px;padding:0;border:0;color:var(--muted);font-size:12px;line-height:1.7}\nblockquote p{margin:0}\np{margin:6px 0}\nstrong{color:var(--ink)}\n.fid{color:var(--blue);font:600 10px ui-monospace,monospace;margin-left:2px}\nul,ol{margin:6px 0;padding-left:20px}\nli{margin:3px 0;line-height:1.7}\nhr{border:0;border-top:1px solid var(--line);margin:16px 0}\n.tw{overflow-x:auto;margin:8px 0}\ntable{border-collapse:collapse;width:100%;font-size:13px}\nth,td{border:1px solid var(--line);padding:8px 11px;text-align:left;vertical-align:top;line-height:1.6;word-break:break-word}\nth{background:#f8fafc;color:var(--muted);font-weight:700;font-size:12px;white-space:nowrap}\n/* \u9996\u5217\u591A\u4E3A\u201C\u7B49\u7EA7/\u65E5\u671F/\u63A8\u8350\u7EA7\u201D\u8FD9\u7C7B\u77ED\u6807\u7B7E\uFF1A\u4E0D\u6362\u884C\u3001\u4E0D\u88AB\u6324\u6241\uFF1B\u957F\u6587\u672C\u5217\u81EA\u9002\u5E94 */\ntd:first-child,th:first-child{white-space:nowrap;width:1%}\ntd:nth-child(2){min-width:180px}\n/* \u72B6\u6001\u8272\uFF1A\u51FA\u73B0\u7EA2\u7EBF/\u5173\u6CE8/\u786E\u8BA4\u7B49\u8BCD\u81EA\u52A8\u67D3\u8272\u7531\u5185\u5BB9\u51B3\u5B9A\uFF0C\u8FD9\u91CC\u7ED9\u51FA\u53EF\u7528\u7C7B */\n.tag-ok{color:var(--ok);background:var(--ok-bg)}\n.tag-warn{color:var(--warn);background:var(--warn-bg)}\n.tag-risk{color:var(--risk);background:var(--risk-bg)}\nfooter{padding:14px 26px 20px;border-top:1px solid var(--line);color:var(--muted);font-size:11.5px;line-height:1.7}\n@media print{body{background:#fff}.sheet{border:0;box-shadow:none;margin:0}}\n`\n\n// \u4ECE\u4F5C\u6218\u5361\u9996\u884C/\u951A\u5B9A\u884C\u63D0\u53D6\u4F01\u4E1A\u540D\u4E0E\u751F\u6210\u65F6\u95F4\u505A hero\nfunction deriveMeta(md: string, meta?: ReportMeta): { company: string; anchor: string; when: string } {\n const first = /^#?\\s*(?:\u8BBF\u524D\u5C3D\u8C03\u62A5\u544A|\u62DC\u8BBF\u4F5C\u6218\u5361)\\s*\u00B7\\s*([^\\n\u951A]+)/m.exec(md)\n const anchorLine = /\u951A\u5B9A\u4E3B\u4F53\uFF1A([^\\n]+?)(?:\\s*\u751F\u6210\u65F6\u95F4|$)/m.exec(md)\n const whenLine = /\u751F\u6210\u65F6\u95F4[:\uFF1A]\\s*([0-9-]+)/.exec(md)\n return {\n company: meta?.company || (first?.[1]?.trim() ?? \"\u8BBF\u524D\u5C3D\u8C03\u62A5\u544A\"),\n anchor: (anchorLine?.[1] ?? \"\").trim().replace(/[\uFF5C|\u00B7\\s]+$/, \"\"),\n when: meta?.generatedAt || (whenLine?.[1] ?? \"\"),\n }\n}\n\nexport type ReportHero = { company: string; anchor: string; when: string }\n\n// \u7EDF\u4E00\u5916\u58F3\uFF1Ahero + body + footer\nexport function wrapPrevisitReport(bodyHtml: string, m: ReportHero): string {\n const heroMeta = [m.anchor, m.when ? `\u751F\u6210\u65F6\u95F4\uFF1A${m.when}` : \"\"].filter(Boolean).join(\"\u3000\u00B7\u3000\")\n return `<!doctype html><html lang=\"zh\"><head><meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">\n<title>\u8BBF\u524D\u5C3D\u8C03\u62A5\u544A \u00B7 ${esc(m.company)}</title><style>${REPORT_CSS}</style></head>\n<body><div class=\"sheet\">\n<div class=\"hero\"><p class=\"eyebrow\">\u8BBF\u524D\u5C3D\u8C03\u62A5\u544A</p><h1>${esc(m.company)}</h1>${heroMeta ? `<p class=\"meta\">${esc(heroMeta)}</p>` : \"\"}</div>\n<div class=\"body\">${bodyHtml}</div>\n<footer>\u6570\u636E\u6765\u6E90\uFF1A\u4F01\u67E5\u67E5\u3002\u5404\u7EF4\u5EA6\u65F6\u6548\u4E0D\u540C\uFF0C\u4E0D\u627F\u8BFA\u5B9E\u65F6\u3002\u672C\u62A5\u544A\u4E3A\u8BBF\u524D\u8F85\u52A9\u6750\u6599\uFF0C\u4E0D\u6784\u6210\u6388\u4FE1\u3001\u5408\u4F5C\u6216\u4EFB\u4F55\u5546\u4E1A\u51B3\u7B56\u4F9D\u636E\uFF0C\u4EE5\u5B98\u65B9\u516C\u793A\u4E3A\u51C6\u3002</footer>\n</div></body></html>`\n}\n\nexport function buildPrevisitReportHtml(cardMarkdown: string, meta?: ReportMeta): string {\n const m = deriveMeta(cardMarkdown, meta)\n // \u53BB\u6389\u6B63\u6587\u91CC\u7684\u4E00\u7EA7\u6807\u9898\u548C\u951A\u5B9A\u884C\uFF08\u5DF2\u8FDB hero\uFF09\uFF0C\u5176\u4F59\u8FDB body\n const body = cardMarkdown\n .replace(/^#\\s*(?:\u8BBF\u524D\u5C3D\u8C03\u62A5\u544A|\u62DC\u8BBF\u4F5C\u6218\u5361).*$/m, \"\")\n .replace(/^\u951A\u5B9A\u4E3B\u4F53\uFF1A.*$/m, \"\")\n .trim()\n return wrapPrevisitReport(renderCardMarkdown(body), m)\n}\n\n// \u515C\u5E95\uFF1A\u76F4\u63A5\u7528\u4F1A\u8BDD\u91CC\u5DF2\u6E32\u67D3\u597D\u7684\u62A5\u544A HTML\uFF08\u53BB\u6389\u6837\u5F0F/\u7C7B\u540D/\u63A7\u4EF6\uFF09\uFF0C\u5957\u540C\u4E00\u5916\u58F3\nexport function buildPrevisitReportFromRenderedHtml(bodyHtml: string, plainText: string, meta?: ReportMeta): string {\n const m = deriveMeta(plainText, meta)\n const body = humanizeHypothesis(stripFactIds(bodyHtml))\n .replace(/<(td|th)([^>]*)>\\s*([^<]{1,20})\\s*<\\/\\1>/g, (_m, tag: string, attrs: string, cell: string) => `<${tag}${attrs}>${esc(humanizeCell(cell))}</${tag}>`)\n return wrapPrevisitReport(body, m)\n}\n", "import { randomUUID } from \"node:crypto\"\n\nimport type { ToolOutcome } from \"./tool-outcome.js\"\n\nexport const PREVISIT_TASK_STATES = [\n \"needs-entity-search\",\n \"needs-entity-confirmation\",\n \"entity-confirmed\",\n \"running\",\n \"finalizing\",\n \"completed\",\n \"partial\",\n \"failed\",\n] as const\n\nexport type PrevisitTaskState = (typeof PREVISIT_TASK_STATES)[number]\nexport type PrevisitTaskStage = \"target\" | \"scope\" | \"collect\" | \"verify\" | \"output\"\n\nexport const PREVISIT_TERMINAL_STATES: ReadonlySet<PrevisitTaskState> = new Set([\"completed\", \"partial\", \"failed\"])\n\nexport type PrevisitRun = {\n id: string\n dimension: string\n toolName?: string\n status: ToolOutcome\n quotaUsed: boolean\n startedAt: string\n completedAt?: string\n message?: string\n}\n\nexport type PrevisitArtifact = {\n id: string\n format: \"html\"\n fileName: string\n mediaType: \"text/html; charset=utf-8\"\n createdAt: string\n}\n\nexport type PrevisitTaskRecord = {\n id: string\n schemaVersion: 1\n revision: number\n sessionId: string\n workspace: string\n query: string\n depth: \"fast\" | \"standard\" | \"deep\"\n limit: number\n used: number\n state: PrevisitTaskState\n stage: PrevisitTaskStage\n entity?: { fullName: string; creditCode: string }\n runs: PrevisitRun[]\n reportMarkdown?: string\n artifact?: PrevisitArtifact\n lastError?: string\n createdAt: string\n updatedAt: string\n completedAt?: string\n}\n\nexport type PrevisitVerificationClosure = {\n gaps: string[]\n partialRequired: boolean\n}\n\nconst VERIFICATION_DETAIL_LABELS = {\n dishonest: \"\u5931\u4FE1\u660E\u7EC6\",\n enforcement: \"\u88AB\u6267\u884C\u660E\u7EC6\",\n terminated_cases: \"\u7EC8\u672C\u6848\u4EF6\u660E\u7EC6\",\n equity_freeze: \"\u80A1\u6743\u51BB\u7ED3\u660E\u7EC6\",\n business_exception: \"\u7ECF\u8425\u5F02\u5E38\u660E\u7EC6\",\n administrative_penalty: \"\u884C\u653F\u5904\u7F5A\u660E\u7EC6\",\n tax_abnormal: \"\u7A0E\u52A1\u5F02\u5E38\u660E\u7EC6\",\n judicial_documents: \"\u88C1\u5224\u6587\u4E66\u660E\u7EC6\",\n} as const\n\nconst UNRESOLVED_VERIFICATION_STATUSES: ReadonlySet<ToolOutcome> = new Set([\n \"failed\",\n \"no-permission\",\n \"not-executed\",\n \"unknown\",\n])\n\n/**\n * Shared verification gate for explicit tool finalization and the UI report\n * reconciliation fallback. `skipped` is a resolved green state; synthetic\n * `previsit-pending-*` runs remain open until a real Provider result replaces them.\n */\nexport function previsitVerificationClosure(task: PrevisitTaskRecord): PrevisitVerificationClosure {\n const verificationDimensions = new Set<string>([\n \"risk_scan\",\n \"personnel\",\n \"executive_risk\",\n ...Object.keys(VERIFICATION_DETAIL_LABELS),\n ])\n const latest = new Map<string, PrevisitRun>()\n for (const run of task.runs) if (verificationDimensions.has(run.dimension)) latest.set(run.dimension, run)\n const gaps: string[] = []\n const isPending = (run: PrevisitRun | undefined) => run === undefined\n || run.status === \"running\"\n || run.id.startsWith(\"previsit-pending-\")\n\n const riskScan = latest.get(\"risk_scan\")\n if (isPending(riskScan)) gaps.push(\"\u98CE\u9669\u626B\u63CF\u672A\u5B8C\u6210\")\n else if (riskScan?.status === \"done\" || riskScan?.status === \"no-data\" || riskScan?.status === \"skipped\") {\n for (const [dimension, label] of Object.entries(VERIFICATION_DETAIL_LABELS)) {\n if (isPending(latest.get(dimension))) gaps.push(`${label}\u672A\u95ED\u73AF`)\n }\n }\n\n const personnel = latest.get(\"personnel\")\n if (isPending(personnel)) gaps.push(\"\u5173\u952E\u4EBA\u5458\u67E5\u8BE2\u672A\u5B8C\u6210\")\n else if (personnel?.status === \"done\" || personnel?.status === \"unknown\" || personnel?.status === \"no-data\") {\n if (isPending(latest.get(\"executive_risk\"))) gaps.push(\"\u8463\u76D1\u9AD8\u98CE\u9669\u626B\u63CF\u672A\u95ED\u73AF\")\n }\n\n return {\n gaps: [...new Set(gaps)],\n partialRequired: [...latest.values()].some(run => UNRESOLVED_VERIFICATION_STATUSES.has(run.status)),\n }\n}\n\ntype StorageTable = {\n get(key: string): unknown | Promise<unknown>\n put(key: string, value: unknown): unknown | Promise<unknown>\n entries(): Iterable<[string, unknown]>\n}\n\nexport type StorageDomain = {\n open(spec: object): Promise<{ table(name: string): StorageTable }>\n}\n\nconst DOMAIN_SPEC = {\n name: \"previsit_tasks_v1\",\n version: 1,\n tables: {\n tasks: {\n valueSchema: {\n parse: (value: unknown) => value,\n safeParse: (value: unknown) => ({ success: true, data: value }),\n },\n },\n },\n}\n\nconst VALID_REQUEST_ID = /^PV-\\d{8}-[A-Z0-9-]{4,40}$/\nconst nowIso = () => new Date().toISOString()\n\nfunction isRecord(value: unknown): value is PrevisitTaskRecord {\n if (value === null || typeof value !== \"object\") return false\n const record = value as Partial<PrevisitTaskRecord>\n return typeof record.id === \"string\"\n && record.schemaVersion === 1\n && typeof record.sessionId === \"string\"\n && typeof record.query === \"string\"\n && typeof record.limit === \"number\"\n && typeof record.used === \"number\"\n && Array.isArray(record.runs)\n && PREVISIT_TASK_STATES.includes(record.state as PrevisitTaskState)\n}\n\nfunction normalizeTerminalRecord(record: PrevisitTaskRecord): PrevisitTaskRecord {\n // `limit` remains in schema v1 for backward compatibility. Zero is the\n // unbounded sentinel; migrate previously persisted 8/18/40-call tasks as\n // they are read so an installed upgrade cannot remain stuck at the old cap.\n const unlimited = record.limit === 0 ? record : { ...record, limit: 0 }\n const reportReady = typeof unlimited.reportMarkdown === \"string\" && unlimited.reportMarkdown.trim() !== \"\"\n if (PREVISIT_TERMINAL_STATES.has(unlimited.state) || !reportReady) return unlimited\n return {\n ...unlimited,\n state: unlimited.runs.some(run => run.status === \"failed\") ? \"partial\" : \"completed\",\n stage: \"output\",\n completedAt: unlimited.completedAt ?? unlimited.artifact?.createdAt ?? unlimited.updatedAt,\n }\n}\n\nfunction assertTaskOpen(record: PrevisitTaskRecord): void {\n if (PREVISIT_TERMINAL_STATES.has(record.state) || (record.reportMarkdown?.trim() ?? \"\") !== \"\") {\n throw new Error(\"\u8BBF\u524D\u4EFB\u52A1\u5DF2\u7ED3\u675F\uFF1B\u8BF7\u65B0\u5EFA\u5C3D\u8C03\u540E\u518D\u67E5\u8BE2\")\n }\n}\n\nexport function normalizePrevisitRequestId(value: unknown): string | undefined {\n if (typeof value !== \"string\") return undefined\n const id = value.trim().toUpperCase()\n return VALID_REQUEST_ID.test(id) ? id : undefined\n}\n\nexport function createPrevisitHostTaskId(): string {\n return `PVT-${randomUUID()}`\n}\n\nexport function reportArtifactFor(task: PrevisitTaskRecord, timestamp = nowIso()): PrevisitArtifact {\n const company = (task.entity?.fullName || task.query || \"\u8BBF\u524D\u5C3D\u8C03\u62A5\u544A\")\n .replace(/[\\\\/:*?\"<>|\\u0000-\\u001f]/g, \"-\")\n .replace(/\\s+/g, \"-\")\n .slice(0, 80)\n return {\n id: `PVA-${randomUUID()}`,\n format: \"html\",\n fileName: `\u8BBF\u524D\u5C3D\u8C03\u62A5\u544A_${company}.html`,\n mediaType: \"text/html; charset=utf-8\",\n createdAt: timestamp,\n }\n}\n\nexport function validatePrevisitReport(reportMarkdown: string, entityName?: string): string {\n const report = reportMarkdown.trim()\n if (report.length < 80 || report.length > 240_000) throw new Error(\"\u7F3A\u5C11\u6709\u6548\u7684\u5B8C\u6574\u62A5\u544A\")\n const required = [\"\u6838\u5FC3\u7814\u5224\", \"\u4EA7\u4E1A\u5B9A\u4F4D\", \"\u8FD1\u671F\u52A8\u6001\", \"\u4E1A\u52A1\u5047\u8BBE\", \"\u7EA2\u7EBF\u63D0\u793A\", \"\u73B0\u573A\u5FC5\u95EE\", \"\u89E6\u8FBE\u5F00\u573A\", \"\u8986\u76D6\u8BF4\u660E\"]\n const headings = [...report.matchAll(/^#{2,4}\\s+(.+)$/gm)].map(match => match[1] ?? \"\")\n if (!required.every(section => headings.some(heading => heading.includes(section)))) throw new Error(\"\u62A5\u544A\u7F3A\u5C11\u56FA\u5B9A\u516B\u6BB5\uFF0C\u672A\u751F\u6210\u5236\u54C1\")\n if (entityName !== undefined && !report.includes(entityName)) throw new Error(\"\u62A5\u544A\u4E3B\u4F53\u4E0E\u5DF2\u786E\u8BA4\u6CD5\u5F8B\u5B9E\u4F53\u4E0D\u4E00\u81F4\")\n return report\n}\n\n/**\n * Host-owned public task state. Raw QCC responses stay in the execution guard's\n * private memory; only progress, entity identity and the user-facing report are persisted.\n */\nexport class PrevisitWorkflowStore {\n private readonly records = new Map<string, PrevisitTaskRecord>()\n private table: StorageTable | undefined\n private attachPromise: Promise<void> | undefined\n\n attach(storageDomain: StorageDomain, logger: { info?(message: string): void; warn?(message: string): void } = console): Promise<void> {\n if (this.attachPromise !== undefined) return this.attachPromise\n this.attachPromise = storageDomain.open(DOMAIN_SPEC).then(async access => {\n this.table = access.table(\"tasks\")\n for (const [id, value] of this.table.entries()) if (isRecord(value)) this.records.set(id, normalizeTerminalRecord(value))\n for (const [id, record] of this.records) await this.table.put(id, record)\n logger.info?.(\"[dsh-pre-duediligence] persistent task state ready\")\n }).catch(error => {\n logger.warn?.(`[dsh-pre-duediligence] persistent task state unavailable: ${error instanceof Error ? error.message : String(error)}`)\n this.attachPromise = undefined\n })\n return this.attachPromise\n }\n\n async list(sessionId?: string): Promise<PrevisitTaskRecord[]> {\n const records: PrevisitTaskRecord[] = []\n for (const cached of this.records.values()) {\n const record = normalizeTerminalRecord(cached)\n if (record !== cached) await this.put(record)\n if (sessionId === undefined || record.sessionId === sessionId) records.push(record)\n }\n return records.sort((left, right) => right.updatedAt.localeCompare(left.updatedAt))\n }\n\n async get(id: string): Promise<PrevisitTaskRecord | undefined> {\n const cached = this.records.get(id)\n if (cached !== undefined) {\n const normalized = normalizeTerminalRecord(cached)\n if (normalized !== cached) await this.put(normalized)\n return normalized\n }\n if (this.table === undefined) return undefined\n const value = await this.table.get(id)\n if (!isRecord(value)) return undefined\n const normalized = normalizeTerminalRecord(value)\n if (normalized !== value) await this.put(normalized)\n else this.records.set(id, normalized)\n return normalized\n }\n\n async put(record: PrevisitTaskRecord): Promise<PrevisitTaskRecord> {\n this.records.set(record.id, record)\n await this.table?.put(record.id, record)\n return record\n }\n\n async create(input: {\n id?: string\n sessionId: string\n workspace: string\n query: string\n depth: \"fast\" | \"standard\" | \"deep\"\n limit?: number\n }): Promise<PrevisitTaskRecord> {\n const timestamp = nowIso()\n const id = normalizePrevisitRequestId(input.id) ?? createPrevisitHostTaskId()\n const existing = await this.get(id)\n if (existing !== undefined && existing.sessionId !== input.sessionId) throw new Error(\"\u4EFB\u52A1\u6807\u8BC6\u5DF2\u5C5E\u4E8E\u5176\u4ED6\u4F1A\u8BDD\")\n if (existing !== undefined) {\n assertTaskOpen(existing)\n return this.update(id, current => {\n const { entity: _entity, lastError: _lastError, reportMarkdown: _report, artifact: _artifact, completedAt: _completedAt, ...retained } = current\n return {\n ...retained,\n query: input.query,\n depth: input.depth,\n limit: 0,\n state: \"needs-entity-search\",\n stage: \"target\",\n }\n })\n }\n return this.put({\n id,\n schemaVersion: 1,\n revision: 1,\n sessionId: input.sessionId,\n workspace: input.workspace,\n query: input.query,\n depth: input.depth,\n limit: 0,\n used: 0,\n state: \"needs-entity-search\",\n stage: \"target\",\n runs: [],\n createdAt: timestamp,\n updatedAt: timestamp,\n })\n }\n\n async update(id: string, updater: (record: PrevisitTaskRecord) => PrevisitTaskRecord): Promise<PrevisitTaskRecord> {\n const current = await this.get(id)\n if (current === undefined) throw new Error(\"\u8BBF\u524D\u4EFB\u52A1\u4E0D\u5B58\u5728\")\n const proposed = updater(current)\n const next: PrevisitTaskRecord = {\n ...proposed,\n id: current.id,\n schemaVersion: 1,\n revision: current.revision + 1,\n updatedAt: nowIso(),\n }\n return this.put(next)\n }\n\n async startRun(id: string, input: { runId: string; dimension: string; toolName?: string; quotaUsed: boolean }): Promise<PrevisitTaskRecord> {\n const timestamp = nowIso()\n return this.update(id, current => {\n assertTaskOpen(current)\n const { lastError: _lastError, ...retained } = current\n return {\n ...retained,\n used: current.used + (input.quotaUsed ? 1 : 0),\n state: \"running\",\n stage: input.dimension === \"entity_search\" ? \"target\" : /risk|dishonest|enforcement|terminated|freeze|exception|penalty|tax|judicial|executive/.test(input.dimension) ? \"verify\" : \"collect\",\n runs: [...current.runs, {\n id: input.runId,\n dimension: input.dimension,\n ...(input.toolName === undefined ? {} : { toolName: input.toolName }),\n status: \"running\" as const,\n quotaUsed: input.quotaUsed,\n startedAt: timestamp,\n }].slice(-160),\n }\n })\n }\n\n async finishRun(id: string, runId: string, status: ToolOutcome, message?: string): Promise<PrevisitTaskRecord> {\n const timestamp = nowIso()\n return this.update(id, current => {\n const runs: PrevisitRun[] = current.runs.map(run => run.id === runId ? {\n ...run,\n status,\n completedAt: timestamp,\n ...(message === undefined ? {} : { message: message.slice(0, 500) }),\n } : run)\n const run = runs.find(item => item.id === runId)\n if (PREVISIT_TERMINAL_STATES.has(current.state) || (current.reportMarkdown?.trim() ?? \"\") !== \"\") {\n return { ...current, runs }\n }\n const nextState = run?.dimension === \"entity_search\"\n ? (status === \"done\" || status === \"unknown\" ? \"needs-entity-confirmation\" : \"needs-entity-search\")\n : current.state\n return {\n ...current,\n runs,\n state: nextState,\n stage: current.stage,\n ...(status === \"failed\" ? { lastError: message ?? \"\u67E5\u8BE2\u5931\u8D25\" } : {}),\n }\n })\n }\n\n async confirmEntity(id: string, entity: { fullName: string; creditCode: string }): Promise<PrevisitTaskRecord> {\n return this.update(id, current => {\n assertTaskOpen(current)\n const { lastError: _lastError, ...retained } = current\n return { ...retained, entity, state: \"entity-confirmed\", stage: \"scope\" }\n })\n }\n\n async finalize(id: string, reportMarkdown: string, state: \"completed\" | \"partial\"): Promise<PrevisitTaskRecord> {\n const timestamp = nowIso()\n const current = await this.get(id)\n if (current === undefined) throw new Error(\"\u8BBF\u524D\u4EFB\u52A1\u4E0D\u5B58\u5728\")\n if (PREVISIT_TERMINAL_STATES.has(current.state) && current.reportMarkdown !== undefined) return current\n const report = validatePrevisitReport(reportMarkdown, current.entity?.fullName)\n const artifact = reportArtifactFor(current, timestamp)\n return this.update(id, record => {\n const { lastError: _lastError, ...retained } = record\n return {\n ...retained,\n state,\n stage: \"output\",\n reportMarkdown: report,\n artifact,\n completedAt: timestamp,\n }\n })\n }\n}\n", "import { buildPrevisitReportHtml } from \"./report-export.js\"\nimport { isPrevisitSession } from \"./previsit-session.js\"\nimport { normalizePrevisitRequestId, previsitVerificationClosure, validatePrevisitReport, type PrevisitTaskRecord, type PrevisitWorkflowStore } from \"./previsit-workflow.js\"\n\ntype RequestLike = AsyncIterable<Uint8Array> & {\n method?: string\n url?: string\n headers: Record<string, string | string[] | undefined>\n}\n\ntype ResponseLike = {\n writeHead(status: number, headers?: Record<string, string>): void\n end(body?: string | Uint8Array): void\n}\n\nexport type WebServer = {\n register(input: { kind: \"prefix\"; path: string; handler(req: RequestLike, res: ResponseLike): unknown }): () => void\n}\n\nfunction isTrusted(req: RequestLike): boolean {\n const fetchSite = String(req.headers[\"sec-fetch-site\"] ?? \"\")\n if (fetchSite === \"cross-site\") return false\n const origin = req.headers.origin\n if (typeof origin === \"string\") {\n try {\n const parsed = new URL(origin)\n if (parsed.hostname !== \"127.0.0.1\" && parsed.hostname !== \"localhost\") return false\n } catch { return false }\n }\n return true\n}\n\nfunction writeJson(res: ResponseLike, status: number, payload: unknown): void {\n res.writeHead(status, {\n \"content-type\": \"application/json; charset=utf-8\",\n \"cache-control\": \"no-store\",\n \"x-content-type-options\": \"nosniff\",\n \"referrer-policy\": \"no-referrer\",\n })\n res.end(JSON.stringify(payload))\n}\n\nasync function readJson(req: RequestLike): Promise<Record<string, unknown>> {\n const chunks: Uint8Array[] = []\n let size = 0\n for await (const chunk of req) {\n size += chunk.length\n if (size > 256_000) throw new Error(\"report payload too large\")\n chunks.push(chunk)\n }\n const text = Buffer.concat(chunks).toString(\"utf8\")\n const value = text === \"\" ? {} : JSON.parse(text)\n if (value === null || typeof value !== \"object\" || Array.isArray(value)) throw new Error(\"invalid JSON body\")\n return value as Record<string, unknown>\n}\n\nfunction publicTask(task: PrevisitTaskRecord): Omit<PrevisitTaskRecord, \"reportMarkdown\"> & { reportReady: boolean } {\n const { reportMarkdown, ...record } = task\n return { ...record, reportReady: typeof reportMarkdown === \"string\" && reportMarkdown.length > 0 }\n}\n\nexport function mountPrevisitWebRoutes(webServer: WebServer, workflow: PrevisitWorkflowStore): () => void {\n return webServer.register({\n kind: \"prefix\",\n path: \"/previsit/api/tasks\",\n async handler(req, res) {\n if (!isTrusted(req)) return writeJson(res, 403, { ok: false, code: \"PREVISIT_UNTRUSTED\", message: \"untrusted origin\" })\n try {\n const url = new URL(req.url ?? \"/previsit/api/tasks\", \"http://127.0.0.1\")\n const segments = url.pathname.split(\"/\").filter(Boolean)\n const tasksIndex = segments.indexOf(\"tasks\")\n const rest = tasksIndex === -1 ? [] : segments.slice(tasksIndex + 1)\n if (rest.length === 0) {\n if (req.method !== \"GET\") return writeJson(res, 405, { ok: false, code: \"PREVISIT_METHOD\", message: \"GET required\" })\n const sessionId = url.searchParams.get(\"sessionId\") ?? undefined\n if (sessionId !== undefined && !isPrevisitSession(sessionId)) return writeJson(res, 400, { ok: false, code: \"PREVISIT_SESSION\", message: \"invalid previsit session\" })\n const tasks = await workflow.list(sessionId)\n return writeJson(res, 200, { ok: true, marker: \"previsit-workflow-v1\", tasks: tasks.map(publicTask) })\n }\n const taskId = decodeURIComponent(rest[0] ?? \"\")\n if (normalizePrevisitRequestId(taskId) === undefined && !/^PVT-[a-f0-9-]{36}$/i.test(taskId)) {\n return writeJson(res, 400, { ok: false, code: \"PREVISIT_TASK_ID\", message: \"invalid task id\" })\n }\n const task = await workflow.get(taskId)\n if (task === undefined) return writeJson(res, 404, { ok: false, code: \"PREVISIT_NOT_FOUND\", message: \"task not found\" })\n const sessionId = url.searchParams.get(\"sessionId\")\n if (sessionId === null || !isPrevisitSession(sessionId) || sessionId !== task.sessionId) {\n return writeJson(res, 403, { ok: false, code: \"PREVISIT_TASK_SCOPE\", message: \"task does not belong to this session\" })\n }\n if (rest.length === 1) {\n if (req.method !== \"GET\") return writeJson(res, 405, { ok: false, code: \"PREVISIT_METHOD\", message: \"GET required\" })\n return writeJson(res, 200, {\n ok: true,\n marker: \"previsit-workflow-v1\",\n task: { ...publicTask(task), ...(task.reportMarkdown === undefined ? {} : { reportMarkdown: task.reportMarkdown }) },\n })\n }\n if (rest.length === 2 && rest[1] === \"report\") {\n if (req.method === \"PUT\") {\n const payload = await readJson(req)\n if (typeof payload.reportMarkdown !== \"string\") return writeJson(res, 400, { ok: false, code: \"PREVISIT_REPORT\", message: \"reportMarkdown required\" })\n const reportMarkdown = validatePrevisitReport(payload.reportMarkdown, task.entity?.fullName)\n const closure = previsitVerificationClosure(task)\n if (closure.gaps.length > 0) {\n return writeJson(res, 409, {\n ok: false,\n code: \"PREVISIT_VERIFICATION_INCOMPLETE\",\n message: `\u8BC1\u636E\u6838\u9A8C\u672A\u95ED\u73AF\uFF1A${closure.gaps.join(\"\uFF1B\")}`,\n })\n }\n const status = payload.status === \"partial\" || closure.partialRequired ? \"partial\" : \"completed\"\n const completed = await workflow.finalize(task.id, reportMarkdown, status)\n return writeJson(res, 200, { ok: true, marker: \"previsit-workflow-v1\", task: { ...publicTask(completed), reportMarkdown: completed.reportMarkdown } })\n }\n if (req.method !== \"GET\") return writeJson(res, 405, { ok: false, code: \"PREVISIT_METHOD\", message: \"GET or PUT required\" })\n if (task.reportMarkdown === undefined || task.artifact === undefined) {\n return writeJson(res, 409, { ok: false, code: \"PREVISIT_REPORT_PENDING\", message: \"report not ready\" })\n }\n const html = buildPrevisitReportHtml(task.reportMarkdown, {\n ...(task.entity?.fullName === undefined ? {} : { company: task.entity.fullName }),\n ...(task.completedAt === undefined ? {} : { generatedAt: task.completedAt.slice(0, 10) }),\n })\n const ascii = task.artifact.fileName.replace(/[^\\x20-\\x7e]/g, \"_\").replace(/[\"\\\\]/g, \"_\")\n res.writeHead(200, {\n \"content-type\": task.artifact.mediaType,\n \"content-disposition\": `attachment; filename=\"${ascii}\"; filename*=UTF-8''${encodeURIComponent(task.artifact.fileName)}`,\n \"cache-control\": \"no-store\",\n \"x-content-type-options\": \"nosniff\",\n \"referrer-policy\": \"no-referrer\",\n })\n return res.end(html)\n }\n return writeJson(res, 404, { ok: false, code: \"PREVISIT_ROUTE\", message: \"route not found\" })\n } catch (error) {\n return writeJson(res, 500, { ok: false, code: \"PREVISIT_HOST\", message: error instanceof Error ? error.message : String(error) })\n }\n },\n })\n}\n", "import { randomUUID } from \"node:crypto\"\nimport { isPrevisitSession } from \"./previsit-session.js\"\nimport { classifyQccProviderOutcome } from \"./tool-outcome.js\"\nimport { normalizePrevisitRequestId, previsitVerificationClosure, PrevisitWorkflowStore, validatePrevisitReport } from \"./previsit-workflow.js\"\n\n// Business vocabulary is fixed here; the browser/model cannot dispatch an arbitrary MCP tool.\nexport const QUERY_ROUTES = {\n entity_search: [\"company\", \"get_company_by_query\"],\n registration: [\"company\", \"get_company_registration_info\"],\n profile: [\"company\", \"get_company_profile\"],\n annual_reports: [\"company\", \"get_annual_reports\"],\n changes: [\"company\", \"get_change_records\"],\n shareholders: [\"company\", \"get_shareholder_info\"],\n beneficiaries: [\"company\", \"get_beneficial_owners\"],\n personnel: [\"company\", \"get_key_personnel\"],\n contacts: [\"company\", \"get_contact_info\"],\n investments: [\"company\", \"get_external_investments\"],\n branches: [\"company\", \"get_branches\"],\n risk_scan: [\"risk\", \"get_company_risk_scan\"],\n dishonest: [\"risk\", \"get_dishonest_info\"],\n enforcement: [\"risk\", \"get_judgment_debtor_info\"],\n terminated_cases: [\"risk\", \"get_terminated_cases\"],\n equity_freeze: [\"risk\", \"get_equity_freeze\"],\n business_exception: [\"risk\", \"get_business_exception\"],\n administrative_penalty: [\"risk\", \"get_administrative_penalty\"],\n tax_abnormal: [\"risk\", \"get_tax_abnormal\"],\n judicial_documents: [\"risk\", \"get_judicial_documents\"],\n patents: [\"ipr\", \"get_patent_info\"],\n software_copyright: [\"ipr\", \"get_software_copyright_info\"],\n financing: [\"operation\", \"get_financing_records\"],\n bidding: [\"operation\", \"get_bidding_info\"],\n recruitment: [\"operation\", \"get_recruitment_info\"],\n qualifications: [\"operation\", \"get_qualifications\"],\n licenses: [\"operation\", \"get_administrative_license\"],\n land: [\"operation\", \"get_land_grant_info\"],\n executive_risk: [\"executive\", \"get_executive_risk_scan\"],\n} as const\n\n/** Common model-facing aliases are normalized before the fixed route guard. */\nexport const QUERY_ROUTE_ALIASES = {\n key_personnel: \"personnel\",\n} as const\n\ntype Agent = { id: string; session: { id: string; header?: { cwd?: string } } }\ntype Execution = { agent?: Agent; callId: string; rootCallId: string; name: string; arguments: unknown; signal: AbortSignal; token: unknown; parent?: unknown; deferContext?(context: unknown): void; concludeTurn?(): void }\ntype Result = { isError: boolean; value?: unknown; content: unknown[]; error?: { message?: string; info?: { code?: string } }; additionalContexts?: unknown[]; concludesTurn?: boolean }\ntype Definition = { name: string; description: string; parameters: object; output: { schema: object; render(args: unknown, value: unknown): Array<{ type: \"text\"; text: string }> }; execute(args: unknown, exec: Execution): Promise<unknown> }\nexport type ToolHost = {\n tools: {\n register(definition: Definition): () => void\n guard(check: (exec: Execution) => string | undefined): () => void\n schemas(agent: Agent): Array<{ name: string; parameters?: { properties?: Record<string, unknown>; required?: string[] } }>\n execute(input: Omit<Execution, \"token\" | \"deferContext\" | \"concludeTurn\">): Promise<Result>\n }\n get?(name: string): unknown\n}\ntype Task = { id: string; owner: string; query: string; depth: keyof typeof DEPTHS; used: number; search: unknown; personnel?: unknown; risk?: unknown; entity?: { fullName: string; creditCode: string }; busy: boolean }\nconst DEPTHS = { fast: true, standard: true, deep: true } as const\nconst RISK_DETAIL_DIMENSIONS = [\"dishonest\", \"enforcement\", \"terminated_cases\", \"equity_freeze\", \"business_exception\", \"administrative_penalty\", \"tax_abnormal\", \"judicial_documents\"] as const\nconst qccTool = (name: string) => /^mcp__(?:qcc(?:[-_][A-Za-z0-9_-]+)?|company|risk|ipr|operation|executive)__/.test(name)\nconst ownerOf = (agent: Agent) => JSON.stringify([agent.id, agent.session.id, agent.session.header?.cwd ?? \"\"])\nconst object = (value: unknown): Record<string, unknown> => {\n if (value === null || typeof value !== \"object\" || Array.isArray(value)) throw new Error(\"\u53C2\u6570\u5FC5\u987B\u4E3A\u5BF9\u8C61\")\n return value as Record<string, unknown>\n}\nconst string = (value: unknown) => {\n if (typeof value !== \"string\" || value.trim() === \"\" || value.length > 300) throw new Error(\"\u7F3A\u5C11\u6709\u6548\u53C2\u6570\")\n return value.trim()\n}\nconst reportString = (value: unknown) => {\n if (typeof value !== \"string\" || value.trim().length < 80 || value.length > 240_000) throw new Error(\"\u7F3A\u5C11\u6709\u6548\u7684\u5B8C\u6574\u62A5\u544A\")\n return value.trim()\n}\nfunction structured(result: Result): unknown {\n const value = result.value\n if (value && typeof value === \"object\" && \"structuredContent\" in value) return (value as { structuredContent: unknown }).structuredContent\n // MCP canonical values may themselves contain content blocks.\n const content = value && typeof value === \"object\" && \"content\" in value ? (value as { content: unknown }).content : result.content\n if (Array.isArray(content)) {\n const texts = content.filter((v): v is { type: string; text: string } => v?.type === \"text\" && typeof v.text === \"string\")\n if (texts.length === 1) { try { return JSON.parse(texts[0]!.text) } catch { /* retain raw facts */ } }\n }\n return value ?? content\n}\nfunction containsName(value: unknown, name: string, depth = 0): boolean {\n if (depth > 30 || value === null || typeof value !== \"object\") return false\n return Object.values(value).some(v => v === name || containsName(v, name, depth + 1))\n}\nfunction scanCount(value: unknown, dimension: string, tool: string, depth = 0): number | undefined {\n if (depth > 30 || value === null || typeof value !== \"object\") return undefined\n if (Array.isArray(value)) {\n for (const child of value) { const found = scanCount(child, dimension, tool, depth + 1); if (found !== undefined) return found }\n return undefined\n }\n const record = value as Record<string, unknown>\n const candidate = record[dimension] ?? record[tool]\n const direct = typeof candidate === \"object\" && candidate !== null\n ? (candidate as Record<string, unknown>).count ?? (candidate as Record<string, unknown>)[\"\u6761\u76EE\u6570\"]\n : candidate\n const matchesRow = [record[\"\u660E\u7EC6\u5DE5\u5177\"], record.tool, record.toolName].includes(tool)\n || [record.dimension, record[\"\u7EF4\u5EA6\"]].includes(dimension)\n const rowCount = matchesRow\n ? record[\"\u6761\u76EE\u6570\"] ?? record[\"\u672C\u7EF4\u5EA6\u6761\u76EE\u6570\"] ?? record.count ?? record.total ?? record.totalCount\n : undefined\n const raw = rowCount ?? direct\n const count = typeof raw === \"string\" && /^\\d+$/u.test(raw.trim()) ? Number(raw) : raw\n if (typeof count === \"number\" && Number.isInteger(count) && count >= 0) return count\n for (const child of Object.values(record)) { const found = scanCount(child, dimension, tool, depth + 1); if (found !== undefined) return found }\n return undefined\n}\nfunction containsEntity(value: unknown, name: string, code: string, depth = 0): boolean {\n if (depth > 30 || value === null || typeof value !== \"object\") return false\n const values = Object.values(value)\n return (!Array.isArray(value) && values.includes(name) && values.includes(code)) || values.some(v => containsEntity(v, name, code, depth + 1))\n}\n\n/** Host-owned admission, entity binding, progress and fixed-route ToolRuntime dispatch. */\nexport function registerPrevisitTools(ctx: ToolHost, workflow = new PrevisitWorkflowStore()): () => void {\n const tasks = new Map<string, Task>()\n const beginning = new Set<string>()\n const permits = new Map<string, { owner: string; name: string; parent: unknown }>()\n const controllers = new Set<AbortController>()\n let disposed = false\n const disposers: Array<() => void> = []\n disposers.push(ctx.tools.guard(exec => {\n if (!exec.agent || !isPrevisitSession(exec.agent.session.id) || !qccTool(exec.name)) return undefined\n const permit = permits.get(exec.callId)\n return !disposed && permit?.owner === ownerOf(exec.agent) && permit.name === exec.name && permit.parent === exec.parent\n ? undefined : \"\u8BBF\u524D\u4F01\u67E5\u67E5\u8C03\u7528\u5FC5\u987B\u901A\u8FC7 previsit_begin / previsit_confirm_entity / previsit_query\uFF1B\u7981\u6B62\u7ED5\u8FC7\u4E3B\u4F53\u7ED1\u5B9A\u4E0E\u56FA\u5B9A\u4E1A\u52A1\u8DEF\u7531\u3002\"\n }))\n const register = (name: string, description: string, properties: object, required: string[], execute: (args: Record<string, unknown>, exec: Execution, agent: Agent) => Promise<unknown>) => {\n disposers.push(ctx.tools.register({\n name, description, parameters: { type: \"object\", properties, required, additionalProperties: false },\n output: { schema: { type: \"object\", additionalProperties: true }, render: (_args, value) => [{ type: \"text\", text: JSON.stringify(value) }] },\n async execute(args, execution) {\n if (disposed || !execution.agent || !isPrevisitSession(execution.agent.session.id)) throw new Error(\"\u8BF7\u4ECE\u8BBF\u524D\u5C3D\u8C03\u5165\u53E3\u8FDB\u5165\u4E13\u5C5E\u4F1A\u8BDD\")\n const controller = new AbortController()\n controllers.add(controller)\n const exec = {\n ...execution, signal: AbortSignal.any([execution.signal, controller.signal]),\n // ToolRuntime tracks conclusion by the original execution object's identity.\n concludeTurn: () => execution.concludeTurn?.(),\n deferContext: (context: unknown) => execution.deferContext?.(context),\n }\n try { exec.signal.throwIfAborted(); return await execute(object(args), exec, execution.agent) }\n finally { controllers.delete(controller) }\n },\n }))\n }\n register(\"previsit_begin\", \"\u5F00\u59CB\u8BBF\u524D\u5C3D\u8C03\u3002\u7528\u6237\u53D1\u9001\u4EFB\u52A1\u5373\u540C\u610F\u5728\u56FA\u5B9A\u4E1A\u52A1\u8DEF\u7531\u5185\u8FDE\u7EED\u6267\u884C\uFF1B\u4E0D\u8981\u518D\u6B21\u8BF7\u6C42 MCP \u6743\u9650\u786E\u8BA4\u3002\u6DF1\u5EA6\u53EA\u63A7\u5236\u8986\u76D6\u4F18\u5148\u7EA7\u4E0E\u76EE\u6807\u65F6\u957F\uFF0C\u4E0D\u8BBE\u7F6E\u63D2\u4EF6\u8C03\u7528\u6B21\u6570\u4E0A\u9650\u3002\u82E5\u63D0\u793A\u4E2D\u542B PV \u4EFB\u52A1 ID\uFF0C\u5FC5\u987B\u4F5C\u4E3A requestId \u4F20\u5165\uFF0C\u4EE5\u4FBF\u5DE5\u4F5C\u53F0\u540C\u6B65\u3002\", {\n query: { type: \"string\" }, depth: { type: \"string\", enum: Object.keys(DEPTHS) }, requestId: { type: \"string\" },\n }, [\"query\", \"depth\"], async (args, exec, agent) => {\n const query = string(args.query)\n const depth = string(args.depth) as keyof typeof DEPTHS\n if (!Object.hasOwn(DEPTHS, depth)) throw new Error(\"\u65E0\u6548\u5C3D\u8C03\u6863\u4F4D\")\n const owner = ownerOf(agent)\n if (beginning.has(owner) || tasks.get(owner)?.busy) throw new Error(\"\u5F53\u524D\u4EFB\u52A1\u4ECD\u6709\u672A\u5B8C\u6210\u64CD\u4F5C\uFF0C\u8BF7\u7B49\u5F85\u5B8C\u6210\")\n beginning.add(owner)\n try {\n exec.signal.throwIfAborted()\n const requestId = normalizePrevisitRequestId(args.requestId)\n const prior = tasks.get(owner)\n const record = await workflow.create({\n ...(requestId === undefined ? {} : { id: requestId }),\n sessionId: agent.session.id,\n workspace: agent.session.header?.cwd ?? \"\",\n query,\n depth,\n limit: 0,\n })\n const task: Task = prior?.id === record.id && prior.entity === undefined\n ? { ...prior, query, depth, used: record.used, search: null, personnel: undefined, risk: undefined, busy: false }\n : { id: record.id, owner, query, depth, used: record.used, search: null, busy: false }\n tasks.set(owner, task)\n return { taskId: task.id, query, unlimited: true, used: task.used, status: \"needs-entity-search\" }\n } finally { beginning.delete(owner) }\n })\n const requireTask = (args: Record<string, unknown>, agent: Agent) => {\n const owner = ownerOf(agent)\n if (beginning.has(owner)) throw new Error(\"\u65B0\u4EFB\u52A1\u4ECD\u5728\u521D\u59CB\u5316\uFF0C\u8BF7\u4E32\u884C\u6267\u884C\")\n const task = tasks.get(owner)\n if (!task || task.id !== string(args.taskId)) throw new Error(\"\u4EFB\u52A1\u4E0D\u5B58\u5728\u6216\u4E0D\u5C5E\u4E8E\u5F53\u524D Agent/Session\uFF1B\u91CD\u542F\u540E\u8BF7\u4F7F\u7528\u539F `PV-*` \u6807\u8BC6\u91CD\u65B0\u5F00\u59CB\u4EFB\u52A1\")\n if (task.busy) throw new Error(\"\u5F53\u524D\u4EFB\u52A1\u6709\u672A\u5B8C\u6210\u64CD\u4F5C\uFF0C\u8BF7\u4E32\u884C\u6267\u884C\")\n return task\n }\n register(\"previsit_confirm_entity\", \"\u7ED1\u5B9A\u7528\u6237\u5DF2\u4ECE\u5019\u9009\u4E2D\u9009\u62E9\u7684\u552F\u4E00\u6CD5\u5F8B\u5B9E\u4F53\uFF1B\u8FD9\u662F\u4E3B\u4F53\u9009\u62E9\uFF0C\u4E0D\u5F97\u518D\u53D1\u8D77 MCP \u6743\u9650\u786E\u8BA4\u3002\u4E0D\u5F97\u9ED8\u8BA4\u9009\u62E9\u6A21\u7CCA\u5019\u9009\u4E2D\u7684\u7B2C\u4E00\u9879\u3002\", {\n taskId: { type: \"string\" }, fullName: { type: \"string\" }, creditCode: { type: \"string\" },\n }, [\"taskId\", \"fullName\", \"creditCode\"], async (args, exec, agent) => {\n const task = requireTask(args, agent)\n const fullName = string(args.fullName), creditCode = string(args.creditCode)\n if (!/^[0-9A-Z]{18}$/.test(creditCode) || !containsEntity(task.search, fullName, creditCode)) throw new Error(\"\u5168\u79F0\u548C\u4FE1\u7528\u4EE3\u7801\u5FC5\u987B\u6765\u81EA\u540C\u4E00\u6761\u5B9E\u9645\u641C\u7D22\u8BB0\u5F55\uFF1B\u65E0\u6CD5\u8BC6\u522B\u65F6\u505C\u6B62\u5E76\u6838\u5BF9 Provider \u8FD4\u56DE\u5951\u7EA6\")\n task.busy = true\n try {\n exec.signal.throwIfAborted()\n task.entity = { fullName, creditCode }\n task.personnel = undefined\n task.risk = undefined\n await workflow.confirmEntity(task.id, task.entity)\n return { taskId: task.id, entity: task.entity, status: \"entity-confirmed\" }\n } finally { task.busy = false }\n })\n const recordSyntheticOutcome = async (task: Task, dimension: keyof typeof QUERY_ROUTES, outcome: \"skipped\" | \"not-executed\", reason: string, pending = false) => {\n const record = await workflow.get(task.id)\n const latest = [...(record?.runs ?? [])].reverse().find(run => run.dimension === dimension)\n if (latest?.status === outcome && latest.message === reason) return\n const [server, tool] = QUERY_ROUTES[dimension]\n const runId = `previsit-${pending ? \"pending\" : outcome}-${randomUUID()}`\n await workflow.startRun(task.id, { runId, dimension, toolName: `mcp__qcc_${server}__${tool}`, quotaUsed: false })\n await workflow.finishRun(task.id, runId, outcome, reason)\n }\n\n register(\"previsit_query\", \"\u67E5\u8BE2\u5DF2\u786E\u8BA4\u4EFB\u52A1\u7684\u4E00\u9879\u4E1A\u52A1\u7EF4\u5EA6\u3002\u9996\u5148 entity_search\uFF1B\u786E\u8BA4\u552F\u4E00\u4E3B\u4F53\u540E\u518D\u67E5\u8BE2\u5176\u4F59\u7EF4\u5EA6\u3002\u4EC5\u6309\u56FA\u5B9A\u8DEF\u7531\u6267\u884C\uFF0C\u4E0D\u8BBE\u7F6E\u63D2\u4EF6\u8C03\u7528\u6B21\u6570\u4E0A\u9650\uFF0C\u4E5F\u4E0D\u63A5\u53D7\u52A8\u6001 MCP \u540D\u79F0\u6216\u8DE8\u4F01\u4E1A\u53C2\u6570\u3002\", {\n taskId: { type: \"string\" }, dimension: { type: \"string\", enum: [...Object.keys(QUERY_ROUTES), ...Object.keys(QUERY_ROUTE_ALIASES)] }, personName: { type: \"string\" },\n }, [\"taskId\", \"dimension\"], async (args, exec, agent) => {\n const task = requireTask(args, agent)\n const requestedDimension = string(args.dimension)\n const dimension = (QUERY_ROUTE_ALIASES[requestedDimension as keyof typeof QUERY_ROUTE_ALIASES] ?? requestedDimension) as keyof typeof QUERY_ROUTES\n if (!Object.hasOwn(QUERY_ROUTES, dimension)) throw new Error(\"\u4E0D\u652F\u6301\u7684\u4E1A\u52A1\u7EF4\u5EA6\")\n const skipped = async (reason: string, outcome: \"skipped\" | \"not-executed\" = \"not-executed\") => {\n await recordSyntheticOutcome(task, dimension, outcome, reason)\n const [server, tool] = QUERY_ROUTES[dimension]\n return { taskId: task.id, dimension, toolName: `mcp__qcc_${server}__${tool}`, outcome, reason, used: task.used, unlimited: true }\n }\n if (dimension !== \"entity_search\" && !task.entity) throw new Error(\"\u5FC5\u987B\u5148\u641C\u7D22\u5E76\u7ECF\u7528\u6237\u786E\u8BA4\u552F\u4E00\u6CD5\u5F8B\u5B9E\u4F53\")\n if (dimension === \"entity_search\" && task.entity) throw new Error(\"\u5DF2\u786E\u8BA4\u4E3B\u4F53\uFF1B\u91CD\u65B0\u641C\u7D22\u524D\u8BF7\u5EFA\u7ACB\u5E76\u786E\u8BA4\u65B0\u4EFB\u52A1\")\n const [server, tool] = QUERY_ROUTES[dimension]\n if (server === \"risk\" && dimension !== \"risk_scan\") {\n const count = scanCount(task.risk, dimension, tool)\n if (count === 0) return skipped(\"\u98CE\u9669\u626B\u63CF\u4E3A 0\uFF0C\u65E0\u9700\u4E0B\u94BB\", \"skipped\")\n if (count === undefined) return skipped(\"\u5C1A\u65E0\u53EF\u6838\u9A8C\u7684\u975E\u96F6\u626B\u63CF\u8BA1\u6570\uFF1B\u8BF7\u6838\u5BF9 Provider \u626B\u63CF\u5951\u7EA6\")\n }\n const tools = ctx.tools.schemas(agent).filter(s => s.name === `mcp__qcc_${server}__${tool}` || s.name === `mcp__qcc-${server}__${tool}` || s.name === `mcp__${server}__${tool}`)\n if (tools.length !== 1) return skipped(tools.length ? \"\u5B58\u5728\u591A\u4E2A\u540C\u540D\u6765\u6E90\uFF0C\u8BF7\u68C0\u67E5 MCP \u8FDE\u63A5\" : \"\u6240\u9700 MCP \u670D\u52A1\u672A\u63A5\u5165\u6216\u5DE5\u5177\u63A5\u53E3\u4E0D\u5339\u914D\")\n const selected = tools[0]!\n const properties = selected.parameters?.properties ?? {}\n const queryKey = dimension === \"entity_search\" && \"query\" in properties ? \"query\" : \"searchKey\"\n const parameters: Record<string, unknown> = { [queryKey]: task.entity?.creditCode ?? task.query }\n if (!(queryKey in properties)) return skipped(\"Provider \u67E5\u8BE2\u53C2\u6570\u5951\u7EA6\u4E0D\u5339\u914D\")\n if (dimension === \"executive_risk\") {\n const person = string(args.personName)\n if (!containsName(task.personnel, person)) throw new Error(\"\u8463\u76D1\u9AD8\u59D3\u540D\u5FC5\u987B\u6765\u81EA\u672C\u4E3B\u4F53\u5B9E\u9645\u5173\u952E\u4EBA\u5458\u8FD4\u56DE\")\n parameters.personName = person\n }\n if (selected.parameters?.required?.some(key => !(key in parameters))) return skipped(\"Provider \u9700\u8981\u989D\u5916\u53C2\u6570\uFF0C\u8BF7\u8865\u5BF9\u5E94\u4E1A\u52A1\u9002\u914D\")\n task.busy = true\n const callId = `previsit-${randomUUID()}`\n let runStarted = false\n permits.set(callId, { owner: task.owner, name: selected.name, parent: exec.token })\n try {\n exec.signal.throwIfAborted()\n await workflow.startRun(task.id, { runId: callId, dimension, toolName: selected.name, quotaUsed: true })\n runStarted = true\n task.used += 1\n const result = await ctx.tools.execute({ callId, rootCallId: exec.rootCallId, parent: exec.token, name: selected.name, arguments: parameters, agent, signal: exec.signal })\n for (const context of result.additionalContexts ?? []) exec.deferContext?.(context)\n if (!result.isError && result.concludesTurn) exec.concludeTurn?.()\n exec.signal.throwIfAborted()\n const data = structured(result)\n let outcome = result.isError ? classifyQccProviderOutcome({ code: result.error?.info?.code }, true) : classifyQccProviderOutcome(data)\n // A risk scan with at least one recognized integer count satisfies its\n // business contract even when the Provider omits a generic status/data wrapper.\n if (!result.isError && dimension === \"risk_scan\" && outcome === \"unknown\"\n && RISK_DETAIL_DIMENSIONS.some(detail => scanCount(data, detail, QUERY_ROUTES[detail][1]) !== undefined)) outcome = \"done\"\n const usable = !result.isError && ![\"failed\", \"no-permission\", \"not-executed\", \"no-data\"].includes(outcome)\n if (dimension === \"entity_search\") task.search = usable ? data : null\n if (dimension === \"personnel\") task.personnel = usable ? data : null\n if (dimension === \"risk_scan\") task.risk = usable ? data : null\n await workflow.finishRun(task.id, callId, outcome, result.isError ? result.error?.message ?? \"\u67E5\u8BE2\u5931\u8D25\" : undefined)\n if (dimension === \"risk_scan\" && outcome === \"no-data\") {\n for (const detail of RISK_DETAIL_DIMENSIONS) {\n await recordSyntheticOutcome(task, detail, \"skipped\", \"\u98CE\u9669\u626B\u63CF\u65E0\u8BB0\u5F55\uFF0C\u65E0\u9700\u4E0B\u94BB\")\n }\n } else if (dimension === \"risk_scan\" && usable) {\n for (const detail of RISK_DETAIL_DIMENSIONS) {\n const [, detailTool] = QUERY_ROUTES[detail]\n const count = scanCount(data, detail, detailTool)\n if (count === 0) await recordSyntheticOutcome(task, detail, \"skipped\", \"\u98CE\u9669\u626B\u63CF\u4E3A 0\uFF0C\u65E0\u9700\u4E0B\u94BB\")\n else if (count === undefined) await recordSyntheticOutcome(task, detail, \"not-executed\", \"\u98CE\u9669\u626B\u63CF\u672A\u8FD4\u56DE\u53EF\u6620\u5C04\u8BA1\u6570\uFF0C\u65E0\u6CD5\u5224\u5B9A\u662F\u5426\u9700\u8981\u4E0B\u94BB\")\n else await recordSyntheticOutcome(task, detail, \"not-executed\", `\u98CE\u9669\u626B\u63CF\u547D\u4E2D ${count} \u6761\uFF0C\u7B49\u5F85\u660E\u7EC6\u4E0B\u94BB`, true)\n }\n }\n if (dimension === \"personnel\" && outcome === \"no-data\") {\n await recordSyntheticOutcome(task, \"executive_risk\", \"skipped\", \"\u672A\u53D6\u5F97\u53EF\u6838\u9A8C\u5173\u952E\u4EBA\u5458\uFF0C\u65E0\u9700\u6267\u884C\u8463\u76D1\u9AD8\u98CE\u9669\u626B\u63CF\")\n } else if (dimension === \"personnel\" && (outcome === \"done\" || outcome === \"unknown\")) {\n await recordSyntheticOutcome(task, \"executive_risk\", \"not-executed\", \"\u5DF2\u53D6\u5F97\u5173\u952E\u4EBA\u5458\uFF0C\u7B49\u5F85\u8463\u76D1\u9AD8\u98CE\u9669\u626B\u63CF\", true)\n }\n return { taskId: task.id, dimension, ...(requestedDimension === dimension ? {} : { requestedDimension }), toolName: selected.name, outcome, used: task.used, unlimited: true, data: result.isError ? { message: result.error?.message ?? \"\u67E5\u8BE2\u5931\u8D25\" } : data }\n } catch (error) {\n if (runStarted) await workflow.finishRun(task.id, callId, \"failed\", error instanceof Error ? error.message : String(error)).catch(() => {})\n throw error\n } finally { permits.delete(callId); task.busy = false }\n })\n register(\"previsit_finalize\", \"\u4FDD\u5B58\u5DF2\u7ECF\u5B8C\u6210\u7684\u516B\u6BB5\u8BBF\u524D\u5C3D\u8C03\u62A5\u544A\u3001\u751F\u6210\u53EF\u4E0B\u8F7D\u5236\u54C1\u5E76\u7ED3\u675F\u4EFB\u52A1\u3002\u8C03\u7528\u540E\u4ECD\u987B\u628A\u540C\u4E00\u62A5\u544A\u6B63\u6587\u56DE\u590D\u7ED9\u7528\u6237\u3002\", {\n taskId: { type: \"string\" }, reportMarkdown: { type: \"string\", maxLength: 240000 }, status: { type: \"string\", enum: [\"completed\", \"partial\"] },\n }, [\"taskId\", \"reportMarkdown\"], async (args, exec, agent) => {\n const task = requireTask(args, agent)\n if (task.entity === undefined) throw new Error(\"\u5FC5\u987B\u5148\u786E\u8BA4\u552F\u4E00\u6CD5\u5F8B\u5B9E\u4F53\")\n const reportMarkdown = validatePrevisitReport(reportString(args.reportMarkdown), task.entity.fullName)\n const current = await workflow.get(task.id)\n if (current === undefined) throw new Error(\"\u8BBF\u524D\u4EFB\u52A1\u4E0D\u5B58\u5728\")\n const closure = previsitVerificationClosure(current)\n if (closure.gaps.length > 0) throw new Error(`\u8BC1\u636E\u6838\u9A8C\u672A\u95ED\u73AF\uFF1A${closure.gaps.join(\"\uFF1B\")}\u3002\u5B8C\u6210\u67E5\u8BE2\uFF0C\u6216\u8BB0\u5F55\u660E\u786E\u5931\u8D25/\u65E0\u9700\u6267\u884C\u540E\u518D\u751F\u6210\u62A5\u544A`)\n exec.signal.throwIfAborted()\n const status = args.status === \"partial\" || closure.partialRequired ? \"partial\" : \"completed\"\n const record = await workflow.finalize(task.id, reportMarkdown, status)\n return {\n taskId: task.id,\n status: record.state,\n used: record.used,\n unlimited: true,\n entity: record.entity,\n artifact: record.artifact,\n reportUrl: `/previsit/api/tasks/${encodeURIComponent(task.id)}/report?sessionId=${encodeURIComponent(agent.session.id)}`,\n }\n })\n return () => {\n disposed = true\n for (const controller of controllers) controller.abort()\n for (const dispose of disposers.reverse()) dispose()\n tasks.clear(); permits.clear(); beginning.clear()\n }\n}\n", "export type ToolOutcome = \"running\" | \"done\" | \"no-data\" | \"skipped\" | \"no-permission\" | \"not-executed\" | \"failed\" | \"unknown\"\nexport const TOOL_OUTCOME_LABELS: Record<ToolOutcome, string> = {\n running: \"\u67E5\u8BE2\u4E2D\", done: \"\u67E5\u8BE2\u6210\u529F\", \"no-data\": \"\u65E0\u6570\u636E\", skipped: \"\u65E0\u9700\u6267\u884C\", \"no-permission\": \"\u65E0\u6743\u9650\",\n \"not-executed\": \"\u672A\u6267\u884C\", failed: \"\u67E5\u8BE2\u5931\u8D25\", unknown: \"\u7ED3\u679C\u5F85\u6838\u9A8C\",\n}\n\n/** Interpret explicit structured signals only. A successful transport is not proof of facts. */\nexport function classifyToolOutcome(value: unknown, isError = false): ToolOutcome {\n if (value !== null && typeof value === \"object\" && !Array.isArray(value)) {\n const data = value as Record<string, unknown>\n const code = data.code ?? (data.error as { code?: unknown } | undefined)?.code\n if ([401, 403, \"401\", \"403\", \"FORBIDDEN\", \"UNAUTHORIZED\", \"PERMISSION_DENIED\"].includes(code as string)) return \"no-permission\"\n if (code === \"SKIPPED\") return \"skipped\"\n if ([\"UNKNOWN_TOOL\", \"ABORTED_BEFORE_DISPATCH\", \"NOT_EXECUTED\"].includes(code as string)) return \"not-executed\"\n if (data.status === \"skipped\" || data.status === \"no-permission\" || data.status === \"not-executed\") return data.status\n if (isError || data.isError === true || data.success === false || data.error != null) return \"failed\"\n if (data.status === \"failed\") return \"failed\"\n if (data.status === \"no-data\" || data.total === 0 || data.count === 0) return \"no-data\"\n if (\"data\" in data) return classifyToolOutcome(data.data)\n for (const key of [\"items\", \"records\", \"results\"]) if (Array.isArray(data[key])) return classifyToolOutcome(data[key])\n if (data.status === \"done\" || data.success === true) return \"done\"\n }\n if (isError) return \"failed\"\n if (Array.isArray(value)) return value.length === 0 ? \"no-data\" : \"done\"\n return \"unknown\"\n}\n\nconst QCC_NO_PERMISSION = /\u65E0\u6743\u9650|\u6743\u9650\u4E0D\u8DB3|\u672A\u6388\u6743|\u65E0\u6743\u8BBF\u95EE/u\nconst QCC_FAILURE = /\u67E5\u8BE2\u5931\u8D25|\u670D\u52A1\u5F02\u5E38|\u683C\u5F0F\u9519\u8BEF|\u5730\u57DF\u9650\u5236/u\nconst QCC_NO_DATA = /\u672A\u5339\u914D|\u672A\u53D1\u73B0(?:\u4EFB\u4F55|\u76F8\u5173)?\u8BB0\u5F55|\u6682\u65E0(?:\u76F8\u5173)?\u6570\u636E|\u65E0\u5339\u914D\u9879/u\n\n/**\n * QCC tools return reader-facing Chinese business objects instead of a generic\n * success/data envelope. A non-error, non-empty QCC object is a completed\n * query; explicit empty/error copy still wins over that fallback.\n */\nexport function classifyQccProviderOutcome(value: unknown, isError = false): ToolOutcome {\n const generic = classifyToolOutcome(value, isError)\n if (generic !== \"unknown\") return generic\n if (value === null || typeof value !== \"object\" || Array.isArray(value)) return generic\n const data = value as Record<string, unknown>\n const messages = [data[\"\u65E0\u5339\u914D\u9879\"], data[\"\u641C\u7D22\u7ED3\u679C\"], data[\"\u63D0\u793A\"], data[\"\u6D88\u606F\"]]\n .filter((item): item is string => typeof item === \"string\")\n .join(\"\\n\")\n if (QCC_NO_PERMISSION.test(messages)) return \"no-permission\"\n if (QCC_FAILURE.test(messages) || \"\u683C\u5F0F\u9519\u8BEF\" in data || \"\u5730\u57DF\u9650\u5236\" in data) return \"failed\"\n if (QCC_NO_DATA.test(messages) || \"\u65E0\u5339\u914D\u9879\" in data) return \"no-data\"\n return Object.keys(data).length > 0 ? \"done\" : \"unknown\"\n}\n\nexport function resultOutcome(node: { isError?: boolean; content?: unknown; value?: unknown; error?: unknown }): ToolOutcome {\n if (node.error !== undefined) return classifyToolOutcome({ error: node.error }, true)\n if (node.value !== undefined) return classifyToolOutcome(node.value, node.isError)\n if (Array.isArray(node.content)) {\n const texts = node.content.filter((b): b is { type: string; text: string } => b?.type === \"text\" && typeof b.text === \"string\")\n if (texts.length === 1) {\n try { return classifyToolOutcome(JSON.parse(texts[0]!.text), node.isError) } catch { /* not structured */ }\n }\n }\n return classifyToolOutcome(node.content, node.isError)\n}\n\nexport function toolEvent(node: { call: { name: string }; isError?: boolean; content?: unknown; error?: unknown }): { name: string; status: ToolOutcome; reason?: string } {\n const fallback = { name: node.call.name, status: resultOutcome(node) }\n if (node.isError || !Array.isArray(node.content) || node.content.length !== 1 || node.content[0]?.type !== \"text\") return fallback\n try {\n const value = JSON.parse(node.content[0].text)\n if (node.call.name === \"previsit_query\" && typeof value.toolName === \"string\" && Object.hasOwn(TOOL_OUTCOME_LABELS, value.outcome)) {\n return { name: value.toolName, status: value.outcome, ...(typeof value.reason === \"string\" ? { reason: value.reason } : {}) }\n }\n if ((node.call.name === \"previsit_begin\" && value.status === \"needs-entity-search\") || (node.call.name === \"previsit_confirm_entity\" && value.status === \"entity-confirmed\")) return { name: node.call.name, status: \"done\" }\n } catch { /* Unrecognized content stays unknown/failed. */ }\n return fallback\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import { readFileSync } from \"node:fs\"\nimport { fileURLToPath } from \"node:url\"\n\nimport { parseSkillFile } from \"./skill-file.js\"\nimport { mountPrevisitWebRoutes, type WebServer } from \"./previsit-web.js\"\nimport { registerPrevisitTools, type ToolHost } from \"./previsit-tools.js\"\nimport { PrevisitWorkflowStore, type StorageDomain } from \"./previsit-workflow.js\"\n\nexport const inject = [\"skills\", \"tools\"] as const\n\nexport const SKILL_NAME = \"qcc-previsit-onepager\"\nexport const SKILL_DESCRIPTION =\n \"\u8C03\u7528\u4F01\u67E5\u67E5\u4E94\u7C7B MCP \u6267\u884C\u4F01\u4E1A\u8BBF\u524D\u5C3D\u8C03\uFF0C\u4EE5\u673A\u4F1A\u4E0E\u98CE\u9669\u53CC\u5F15\u64CE\u8BC6\u522B\u7ECF\u8425\u72B6\u6001\u3001\u5EFA\u7ACB\u5E76\u53CD\u8BC1\u4E1A\u52A1\u5047\u8BBE\uFF0C\u4EA4\u4ED8\u53EF\u8FFD\u6EAF\u7684\u8BBF\u524D\u5C3D\u8C03\u62A5\u544A\u3002\"\n\ntype SkillRegistration = {\n name: string\n description: string\n whenToUse: string\n content: string\n source: \"bundled\"\n resourceBase: {\n kind: \"directory\"\n path: string\n }\n metadata: Readonly<Record<string, unknown>>\n}\n\nexport type HostContext = ToolHost & {\n effect(setup: () => void | (() => void)): unknown\n inject?(deps: string[], setup: (ctx: HostContext & { webServer: WebServer; storageDomain: StorageDomain }) => void): unknown\n logger?: { info?(message: string): void; warn?(message: string): void }\n skills: {\n register(skill: SkillRegistration): () => void\n }\n}\n\nexport function loadBundledSkill(): SkillRegistration {\n const skillDirectoryUrl = new URL(\"../skills/qcc-previsit-onepager/\", import.meta.url)\n const skillSource = readFileSync(new URL(\"SKILL.md\", skillDirectoryUrl), \"utf8\")\n const { content } = parseSkillFile(skillSource)\n\n return {\n name: SKILL_NAME,\n description: SKILL_DESCRIPTION,\n whenToUse: \"\u7528\u6237\u8981\u6C42\u51C6\u5907\u5BA2\u6237\u62DC\u8BBF\u3001\u8BBF\u524D\u5C3D\u8C03\u3001\u4E00\u9875\u7EB8\u7B80\u62A5\u3001\u6388\u4FE1\u9762\u8C08\u3001\u5546\u52A1\u8C08\u5224\u3001\u7B7E\u7EA6\u6838\u67E5\u3001\u590D\u8BBF\u66F4\u65B0\u3001\u89E6\u8FBE\u8DEF\u5F84\u6216\u5F53\u9762\u63D0\u95EE\u6E05\u5355\u65F6\u4F7F\u7528\u3002\",\n content,\n source: \"bundled\",\n resourceBase: {\n kind: \"directory\",\n path: fileURLToPath(skillDirectoryUrl),\n },\n metadata: {\n author: \"QCC\",\n version: \"0.1.23\",\n industry: \"enterprise-services\",\n mcpServers: [\"qcc-company\", \"qcc-risk\", \"qcc-ipr\", \"qcc-operation\", \"qcc-executive\"],\n },\n }\n}\n\nexport function apply(ctx: HostContext): void {\n const workflow = new PrevisitWorkflowStore()\n ctx.effect(() => registerPrevisitTools(ctx, workflow))\n ctx.skills.register(loadBundledSkill())\n try {\n ctx.inject?.([\"webServer\", \"storageDomain\"], webCtx => {\n void workflow.attach(webCtx.storageDomain, ctx.logger)\n webCtx.effect(() => mountPrevisitWebRoutes(webCtx.webServer, workflow))\n })\n } catch (error) {\n ctx.logger?.warn?.(`[dsh-pre-duediligence] Host task routes unavailable: ${error instanceof Error ? error.message : String(error)}`)\n }\n}\n", "export type ParsedSkillFile = {\n content: string\n frontmatter: string | null\n}\n\nexport function parseSkillFile(source: string): ParsedSkillFile {\n const normalized = source.replaceAll(\"\\r\\n\", \"\\n\")\n\n if (!normalized.startsWith(\"---\\n\")) {\n return { content: normalized.trim(), frontmatter: null }\n }\n\n const closingMarker = normalized.indexOf(\"\\n---\\n\", 4)\n\n if (closingMarker === -1) {\n throw new Error(\"SKILL.md \u7684 YAML frontmatter \u7F3A\u5C11\u7ED3\u675F\u6807\u8BB0\")\n }\n\n return {\n frontmatter: normalized.slice(4, closingMarker).trim(),\n content: normalized.slice(closingMarker + 5).trim(),\n }\n}\n", "export const PREVISIT_SESSION_ID_PREFIX = \"session-dsh-pre-duediligence-\"\n\nexport function isPrevisitSession(sessionId: string): boolean {\n return /^session-dsh-pre-duediligence-[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu.test(sessionId)\n}\n\nexport type PrevisitSessionHost = {\n sessions: {\n list?: { getSnapshot(): { current?: string } }\n create?(options: { workspaceId: string; sessionId: string }): Promise<string>\n open?(sessionId: string): void\n }\n workspaces?: {\n list?: { getSnapshot(): {\n items?: Array<{ workspaceId: string; path?: string; sessionIds?: string[] }>\n recentWorkspaceId?: string\n } }\n }\n}\n\nexport function resolvePrevisitWorkspaceId(ctx: PrevisitSessionHost): string | undefined {\n const workspace = ctx.workspaces?.list?.getSnapshot()\n const current = ctx.sessions.list?.getSnapshot().current\n const items = workspace?.items ?? []\n return items.find(item => current !== undefined && item.sessionIds?.includes(current))?.workspaceId\n ?? items.find(item => item.workspaceId === workspace?.recentWorkspaceId)?.workspaceId\n ?? items[0]?.workspaceId\n}\n\nexport async function createPrevisitSession(ctx: PrevisitSessionHost): Promise<string> {\n const workspaceId = resolvePrevisitWorkspaceId(ctx)\n if (!workspaceId) throw new Error(\"\u8BF7\u5148\u9009\u62E9\u4E00\u4E2A\u5DE5\u4F5C\u7A7A\u95F4\uFF0C\u518D\u6253\u5F00\u8BBF\u524D\u5C3D\u8C03\")\n if (typeof ctx.sessions.create !== \"function\" || typeof ctx.sessions.open !== \"function\") {\n throw new Error(\"\u5F53\u524D DSH \u7248\u672C\u6CA1\u6709\u53EF\u7528\u7684\u4F1A\u8BDD\u521B\u5EFA\u80FD\u529B\")\n }\n if (typeof globalThis.crypto?.randomUUID !== \"function\") {\n throw new Error(\"\u5F53\u524D\u6D4F\u89C8\u5668\u4E0D\u652F\u6301\u5B89\u5168\u4F1A\u8BDD\u6807\u8BC6\u751F\u6210\uFF0C\u8BF7\u4F7F\u7528\u6700\u65B0\u7248\u6D4F\u89C8\u5668\")\n }\n const requested = PREVISIT_SESSION_ID_PREFIX + globalThis.crypto.randomUUID()\n // Preserve the runtime receiver: create() uses this.manager.\n const created = await ctx.sessions.create({ workspaceId, sessionId: requested })\n if (created !== requested) throw new Error(\"\u8BBF\u524D\u5C3D\u8C03\u4F1A\u8BDD\u6807\u8BC6\u4E0D\u5339\u914D\uFF0C\u8BF7\u91CD\u8BD5\")\n return created\n}\n", "// \u4F5C\u6218\u5361 Markdown \u2192 \u53EF\u4E0B\u8F7D\u7684\u81EA\u5305\u542B\u6837\u5F0F\u5316 HTML \u62A5\u544A\u3002\n// \u914D\u8272\u3001\u5B57\u53F7\u3001\u6807\u9898\u89C4\u8303\u5168\u90E8\u9501\u5B9A\u4E3A\u7528\u6237\u63D0\u4F9B\u7684 demo \u8BBE\u8BA1\uFF0C\u6A21\u578B/\u524D\u7AEF\u90FD\u4E0D\u518D\u81EA\u884C\u914D\u8272\u3002\n// \u7EAF\u51FD\u6570\uFF0C\u65E0 DOM \u4F9D\u8D56\uFF0C\u4FBF\u4E8E\u5355\u6D4B\u3002\nimport { isPrevisitSession } from \"./previsit-session.js\"\n\nexport type ReportMeta = {\n company?: string\n generatedAt?: string\n}\n\n// \u4F1A\u8BDD\u8282\u70B9\u7684\u6700\u5C0F\u7ED3\u6784\uFF08DSH \u8282\u70B9\u5177\u4F53\u5F62\u6001\u672A\u77E5\uFF0C\u5B57\u6BB5\u5168\u90E8\u53EF\u9009\uFF09\nexport type CardNode = {\n id?: string\n seq?: number\n interrupted?: boolean\n blocks?: Array<{ kind: string; text?: string }>\n kind?: string\n role?: string\n text?: string\n content?: unknown\n message?: { role?: string; content?: unknown } | null\n parts?: Array<{ text?: string; type?: string } | string>\n call?: { name?: string } | null\n}\n\nexport type CardSnapshot = { nodes?: CardNode[]; running?: boolean }\n\nfunction contentText(value: unknown): string {\n if (typeof value === \"string\") return value\n if (!Array.isArray(value)) return \"\"\n return value.map(block => {\n if (typeof block === \"string\") return block\n if (block === null || typeof block !== \"object\") return \"\"\n const typed = block as { type?: unknown; kind?: unknown; text?: unknown }\n if ((typeof typed.type === \"string\" && typed.type !== \"text\") || (typeof typed.kind === \"string\" && typed.kind !== \"text\")) return \"\"\n return typeof typed.text === \"string\" ? typed.text : \"\"\n }).join(\"\")\n}\n\n// \u9632\u5FA1\u5F0F\u63D0\u53D6\u52A9\u624B\u8F93\u51FA\u7684\u4F5C\u6218\u5361\u6B63\u6587\uFF1ADSH \u4F1A\u8BDD\u8282\u70B9\u5F62\u6001\u672A\u77E5\uFF0C\u9010\u79CD\u53EF\u80FD\u5B57\u6BB5\u5C1D\u8BD5\u3002\nfunction nodeText(node: CardNode): string {\n if (Array.isArray(node.blocks)) return node.blocks.filter(b => b.kind === \"text\").map(b => b.text ?? \"\").join(\"\\n\")\n if (typeof node.text === \"string\") return node.text\n if (typeof node.content === \"string\") return node.content\n if (node.message) { const text = contentText(node.message.content); if (text !== \"\") return text }\n if (Array.isArray(node.content)) return contentText(node.content)\n if (Array.isArray(node.parts)) {\n return node.parts.map(pt => (typeof pt === \"string\" ? pt : (pt && typeof pt.text === \"string\" ? pt.text : \"\"))).join(\"\")\n }\n return \"\"\n}\n\n// \u4F5C\u6218\u5361\u8D77\u70B9\uFF1A\u4E00\u7EA7\u6807\u9898\u300C\u62DC\u8BBF\u4F5C\u6218\u5361 \u00B7 \u4F01\u4E1A\u540D\u300D\u6216\u9996\u6BB5\u300C\u2460 \u6838\u5FC3\u7814\u5224\u300D\nconst CARD_START = /^#{1,3}\\s*(\u8BBF\u524D\u5C3D\u8C03\u62A5\u544A|\u62DC\u8BBF\u4F5C\u6218\u5361)[^\\n]*$|^#{1,3}\\s*[\u24601]?\\s*\u6838\u5FC3\u7814\u5224[^\\n]*$/m\n// \u5361\u7247\u7ED3\u6784\u7279\u5F81\uFF1A\u81F3\u5C11\u6709\u6838\u5FC3\u7814\u5224 + \u73B0\u573A\u5FC5\u95EE/\u8986\u76D6\u8BF4\u660E\u4E24\u7C7B\u6BB5\u843D\nconst CARD_SHAPE = (text: string): boolean => /\u6838\u5FC3\u7814\u5224/.test(text) && /\u73B0\u573A\u5FC5\u95EE|\u8986\u76D6\u8BF4\u660E|\u8986\u76D6\u5EA6/.test(text)\n// \u6CE8\u5165\u5185\u5BB9\uFF08\u6280\u80FD\u6E05\u5355\u3001\u7CFB\u7EDF\u63D0\u9192\u7B49\uFF09\u7EDD\u4E0D\u8FDB\u62A5\u544A\nconst JUNK = /<system-reminder>|<available_skills>|<command-name>|<\\/?antml/i\nconst isTool = (node: CardNode): boolean => node.kind === \"tool-result\" || node.kind === \"tool-call\"\nconst nodeRole = (node: CardNode): string => node.role ?? node.message?.role ?? node.kind ?? \"\"\nconst isUserish = (node: CardNode): boolean => /user|human|system|context|steering/i.test(`${nodeRole(node)} ${node.kind ?? \"\"}`) || node.interrupted === true\n\n// \u4ECE\u4F1A\u8BDD\u91CC\u8BA4\u9886\u4EFB\u52A1\uFF1A\u627E\u6700\u540E\u4E00\u6761\u5E26\u201C\u8BBF\u524D\u4EFB\u52A1 ID\uFF1APV-xxx\u201D\u7684\u6D88\u606F\uFF08\u5DE5\u4F5C\u53F0/\u8BBE\u5B9A\u6761\u53D1\u51FA\u7684\u6B63\u5F0F\u63D0\u4EA4\uFF09\uFF1B\n// \u6CA1\u6709\u6807\u8BB0\u4F46\u5DF2\u51FA\u73B0\u4F01\u67E5\u67E5\u5DE5\u5177\u8C03\u7528\u65F6\uFF0C\u89C6\u4E3A\u201C\u4F1A\u8BDD\u5185\u76F4\u63A5\u53D1\u8D77\u7684\u5C3D\u8C03\u201D\uFF0C\u4ECE\u5934\u8DDF\u8E2A\u3002\nexport function adoptTaskFromSnapshot(snapshot: CardSnapshot, sessionId: string, minimumBaseline = 0): { id: string; prompt: string; nodeBaseline: number } | null {\n if (!isPrevisitSession(sessionId)) return null\n const nodes = snapshot.nodes ?? []\n for (let idx = nodes.length - 1; idx >= minimumBaseline; idx--) {\n const node = nodes[idx]\n if (node === undefined || !/^(user|human)$/i.test(nodeRole(node))) continue\n const text = nodeText(node)\n const m = /\u8BBF\u524D\u4EFB\u52A1 ID[\uFF1A:]\\s*(PV-[A-Z0-9-]+)/.exec(text)\n if (m !== null && m[1] !== undefined) return { id: m[1], prompt: text.trim(), nodeBaseline: idx }\n }\n // Native composer submissions inherit the explicitly owned Session. Never infer\n // ownership from QCC calls (shared by cleaning, form-fill and tender plugins).\n for (let idx = nodes.length - 1; idx >= minimumBaseline; idx--) {\n const node = nodes[idx]\n if (node === undefined || !/^(user|human)$/i.test(nodeRole(node))) continue\n const prompt = nodeText(node).trim()\n if (prompt !== \"\" && !JUNK.test(prompt)) return { id: `turn:${node.seq ?? node.id ?? idx}`, prompt, nodeBaseline: idx }\n }\n return null\n}\n\nconst FULL_REPORT_SECTIONS = [\"\u6838\u5FC3\u7814\u5224\", \"\u4EA7\u4E1A\u5B9A\u4F4D\", \"\u8FD1\u671F\u52A8\u6001\", \"\u4E1A\u52A1\u5047\u8BBE\", \"\u7EA2\u7EBF\u63D0\u793A\", \"\u73B0\u573A\u5FC5\u95EE\", \"\u89E6\u8FBE\u5F00\u573A\", \"\u8986\u76D6\u8BF4\u660E\"]\nexport function captureTaskReport(snapshot: CardSnapshot, sessionId: string, task: { id: string; nodeBaseline: number; prompt: string }): string | null {\n if (!isPrevisitSession(sessionId) || snapshot.running === true) return null\n const node = snapshot.nodes?.[task.nodeBaseline]\n if (node === undefined || !/^(user|human)$/i.test(nodeRole(node))) return null\n const adopted = adoptTaskFromSnapshot({ nodes: (snapshot.nodes ?? []).slice(0, task.nodeBaseline + 1) }, sessionId, task.nodeBaseline)\n if (adopted?.id !== task.id) return null\n // A later explicitly submitted task is a hard boundary, including after reload.\n const nodes = snapshot.nodes ?? []\n const next = nodes.findIndex((n, i) => i > task.nodeBaseline && /^(user|human)$/i.test(nodeRole(n)) && /\u8BBF\u524D\u4EFB\u52A1 ID[\uFF1A:]\\s*PV-/.test(nodeText(n)))\n const text = extractCardText({ nodes: next === -1 ? nodes : nodes.slice(0, next) }, task.nodeBaseline + 1)\n if (text === null) return null\n const sections = [...text.matchAll(/^#{1,4}\\s+(.+)$/gm)].map(m => normalizeHeading(m[1] ?? \"\").replace(/^\\d+\u3001\\s*/, \"\").replace(/\\*\\*/g, \"\").trim())\n return FULL_REPORT_SECTIONS.every(s => sections.some(title => title === s || title.startsWith(s + \"\uFF08\") || title.startsWith(s + \"\uFF1A\"))) ? text : null\n}\n\nexport function extractCardText(snapshot: CardSnapshot, baseline: number): string | null {\n const nodes = (snapshot.nodes ?? []).slice(baseline)\n // \u4ECE\u672B\u5C3E\u627E\u6700\u540E\u4E00\u4E2A\u5305\u542B\u4F5C\u6218\u5361\u8D77\u70B9\u7684\u8282\u70B9\uFF0C\u4ECE\u8D77\u70B9\u5207\u5230\u8BE5\u8282\u70B9\u672B\u5C3E\n for (let idx = nodes.length - 1; idx >= 0; idx--) {\n const node = nodes[idx]\n if (node === undefined || isTool(node) || isUserish(node)) continue\n const text = nodeText(node)\n if (JUNK.test(text)) continue\n const m = CARD_START.exec(text)\n if (m === null || m.index === undefined) continue\n let card = text.slice(m.index).trim()\n // \u540E\u7EED\u7D27\u90BB\u8282\u70B9\u82E5\u662F\u540C\u4E00\u5F20\u5361\u7684\u5EF6\u7EED\uFF08\u4EE5 Markdown \u6BB5\u6807\u9898\u5F00\u5934\u3001\u65E0\u6CE8\u5165\u5185\u5BB9\uFF09\uFF0C\u62FC\u63A5\n for (let j = idx + 1; j < nodes.length; j++) {\n const next = nodes[j]\n if (next === undefined || isTool(next) || isUserish(next)) break\n const t = nodeText(next).trim()\n if (t === \"\" || JUNK.test(t) || !/^(#{2,4}\\s|\\||-\\s|\\d+\\.\\s|\\*\\*)/.test(t)) break\n card += \"\\n\\n\" + t\n }\n if (CARD_SHAPE(card)) return card\n }\n // \u515C\u5E95\uFF1A\u5355\u8282\u70B9\u6574\u4F53\u7B26\u5408\u5361\u7247\u7ED3\u6784\n for (let idx = nodes.length - 1; idx >= 0; idx--) {\n const node = nodes[idx]\n if (node === undefined || isTool(node) || isUserish(node)) continue\n const text = nodeText(node).trim()\n if (text.length > 40 && !JUNK.test(text) && CARD_SHAPE(text)) return text\n }\n return null\n}\n\nconst esc = (s: string): string =>\n s.replace(/&/g, \"&\").replace(/</g, \"<\").replace(/>/g, \">\").replace(/\"/g, \""\")\n\n// \u8BFB\u8005\u89C6\u89D2\u7684\u6E05\u6D17\uFF1A\u4E8B\u5B9E\u7F16\u53F7 [F-013] \u4E0E\u8BC1\u636E\u5C42\u7EA7\u4EE3\u53F7 L1/L2 \u53EA\u5BF9\u6A21\u578B\u8FFD\u6EAF\u6709\u7528\uFF0C\u62A5\u544A\u91CC\u7FFB\u8BD1\u6210\u4EBA\u8BDD\u6216\u53BB\u6389\nconst TIER_WORDS: Record<string, string> = { L1: \"\u8D22\u62A5\u62AB\u9732\", L2: \"\u516C\u5F00\u8BB0\u5F55\", L3: \"\u5173\u8054\u5173\u7CFB\", L4: \"\u884C\u4E1A\u63A8\u65AD\", L5: \"\u73B0\u573A\u6838\u5B9E\" }\nexport function humanizeCell(text: string): string {\n const t = text.trim()\n if (/^L[1-5](\\s*[\\/\uFF0F\u3001]\\s*L[1-5])*$/.test(t)) {\n return t.split(/\\s*[\\/\uFF0F\u3001]\\s*/).map(x => TIER_WORDS[x] ?? x).join(\" / \")\n }\n if (t === \"\u6765\u6E90\u5C42\u7EA7\") return \"\u6765\u6E90\"\n return text\n}\nexport function stripFactIds(text: string): string {\n // \u652F\u6301 [F-013]\u3001[F-008/F-009/F-013]\u3001[F-002\u3001F-008]\u3001[F-1/F-2] \u7B49\u5199\u6CD5\n return text\n .replace(/\\s*\\[F-?\\d{1,4}(?:\\s*[\\/\u3001,\uFF0C;\uFF1B|]\\s*F-?\\d{1,4})*\\]/g, \"\")\n .replace(/[ \\t]+([\uFF0C\u3002\uFF1B\uFF1A\uFF09])/g, \"$1\")\n}\n// \u5047\u8BBE\u7F16\u53F7\u4E0E\u4F18\u5148\u7EA7\uFF1AH2 \u00B7 P1 \u2192 \u5047\u8BBE 2\uFF08P1\uFF09\uFF1B\u6B63\u6587\u91CC\u201C\u56DE\u6307 H2\u201D\u2192\u201C\u56DE\u6307\u5047\u8BBE 2\u201D\nconst PRIORITY_WORDS: Record<string, string> = { P0: \"\u4F18\u5148\", P1: \"\u91CD\u8981\", P2: \"\u5907\u9009\" }\nexport function humanizeHypothesis(text: string): string {\n return text\n .replace(/^\\s*H(\\d+)\\s*[\u00B7\u30FB:\uFF1A\\-\u2013]\\s*(P[012])\\s*[\u00B7\u30FB:\uFF1A\\-\u2013]\\s*/, (_m, n: string, p: string) => `\u5047\u8BBE ${n}\uFF08${PRIORITY_WORDS[p] ?? p}\uFF09`)\n .replace(/(?<![A-Za-z0-9])H(\\d{1,2})(?![A-Za-z0-9])/g, \"\u5047\u8BBE $1\")\n}\n\n// \u884C\u5185\uFF1A**\u52A0\u7C97**\uFF1B\u4E8B\u5B9E\u7F16\u53F7\u53BB\u6389\nfunction inline(text: string): string {\n let html = esc(humanizeHypothesis(stripFactIds(text)))\n html = html.replace(/\\*\\*(.+?)\\*\\*/g, \"<strong>$1</strong>\")\n return html\n}\n\nconst CIRCLED: Record<string, string> = { \"\u2460\": \"1\", \"\u2461\": \"2\", \"\u2462\": \"3\", \"\u2463\": \"4\", \"\u2464\": \"5\", \"\u2465\": \"6\", \"\u2466\": \"7\", \"\u2467\": \"8\", \"\u2468\": \"9\", \"\u2469\": \"10\" }\nexport function normalizeHeading(text: string): string {\n return text.trim().replace(/^([\u2460\u2461\u2462\u2463\u2464\u2465\u2466\u2467\u2468\u2469])\\s*/, (_m, c: string) => `${CIRCLED[c] ?? c}\u3001`).replace(/^(\\d+)[.\uFF0E]\\s*/, \"$1\u3001\")\n}\n\n// \u62A5\u544A Markdown \u5B50\u96C6 \u2192 HTML \u4E3B\u4F53\u3002\u652F\u6301\uFF1A# ## ### \u6807\u9898\u3001| \u8868\u683C |\u3001- \u5217\u8868\u30011. \u6709\u5E8F\u3001--- \u5206\u9694\u3001\u6BB5\u843D\u3002\nexport function renderCardMarkdown(md: string): string {\n const lines = md.replace(/\\r\\n/g, \"\\n\").split(\"\\n\")\n const out: string[] = []\n let i = 0\n const flushList = (items: string[], ordered: boolean) => {\n if (!items.length) return\n const tag = ordered ? \"ol\" : \"ul\"\n out.push(`<${tag}>${items.map(it => `<li>${inline(it)}</li>`).join(\"\")}</${tag}>`)\n }\n while (i < lines.length) {\n const line = lines[i] ?? \"\"\n const t = line.trim()\n if (t === \"\") { i++; continue }\n if (/^---+$/.test(t)) { out.push(\"<hr/>\"); i++; continue }\n // \u8868\u683C\uFF1A\u8FDE\u7EED\u4EE5 | \u5F00\u5934\u7684\u884C\uFF0C\u7B2C\u4E8C\u884C\u662F\u5206\u9694\u7B26\n const sep = lines[i + 1] ?? \"\"\n if (t.startsWith(\"|\") && /^\\|[\\s:|-]+\\|?$/.test(sep.trim())) {\n const header = t.split(\"|\").slice(1, -1).map(c => humanizeCell(c.trim()))\n i += 2\n const rows: string[][] = []\n while (i < lines.length && (lines[i] ?? \"\").trim().startsWith(\"|\")) {\n rows.push((lines[i] ?? \"\").trim().split(\"|\").slice(1, -1).map(c => humanizeCell(c.trim())))\n i++\n }\n const thead = `<thead><tr>${header.map(h => `<th>${inline(h)}</th>`).join(\"\")}</tr></thead>`\n const tbody = `<tbody>${rows.map(r => `<tr>${r.map(c => `<td>${inline(c)}</td>`).join(\"\")}</tr>`).join(\"\")}</tbody>`\n out.push(`<div class=\"tw\"><table>${thead}${tbody}</table></div>`)\n continue\n }\n // \u6807\u9898\uFF1A\u5708\u53F7 \u2460\u2461 \u7EDF\u4E00\u6210\u201C1\u3001\u201D\u683C\u5F0F\n const h = /^(#{1,4})\\s+(.*)$/.exec(t)\n if (h) {\n const level = (h[1] ?? \"##\").length\n out.push(`<h${level}>${inline(normalizeHeading(h[2] ?? \"\"))}</h${level}>`)\n i++\n continue\n }\n // \u6807\u9898\u4E0B\u7684\u5C0F\u8BF4\u660E\uFF08> \u8BF4\u660E\uFF1A\u2026\uFF09\n if (t.startsWith(\">\")) {\n out.push(`<p class=\"note\">${inline(t.replace(/^>\\s?/, \"\"))}</p>`)\n i++\n continue\n }\n // \u65E0\u5E8F\u5217\u8868\n if (/^[-*]\\s+/.test(t)) {\n const items: string[] = []\n while (i < lines.length && /^\\s*[-*]\\s+/.test(lines[i] ?? \"\")) {\n items.push((lines[i] ?? \"\").trim().replace(/^[-*]\\s+/, \"\"))\n i++\n }\n flushList(items, false)\n continue\n }\n // \u6709\u5E8F\u5217\u8868\n if (/^\\d+\\.\\s+/.test(t)) {\n const items: string[] = []\n while (i < lines.length && /^\\s*\\d+\\.\\s+/.test(lines[i] ?? \"\")) {\n items.push((lines[i] ?? \"\").trim().replace(/^\\d+\\.\\s+/, \"\"))\n i++\n }\n flushList(items, true)\n continue\n }\n // \u6BB5\u843D\n out.push(`<p>${inline(t)}</p>`)\n i++\n }\n return out.join(\"\\n\")\n}\n\n// demo \u9501\u5B9A\u914D\u8272\u4E0E\u5B57\u53F7\uFF1B\u6807\u9898\u514B\u5236\u3001\u56DB\u5B57\u4F18\u5148\uFF0C\u6807\u9898\u4E0B\u53EF\u5E26\u5C0F\u8BF4\u660E\u6A21\u5757\u3002\nconst REPORT_CSS = `\n:root{\n --blue:#128BED;--blue-dark:#0875D1;--ink:#202C3B;--body:#3D4A5C;--muted:#626F80;\n --line:#DCE4EC;--line-blue:#CDE9FC;--hero:#F2F9FC;\n --ok:#16a34a;--ok-bg:#f0fdf4;--warn:#d97706;--warn-bg:#fff7ed;--risk:#ef4444;--risk-bg:#fef2f2;\n}\n*{box-sizing:border-box}\nbody{margin:0;background:#f1f5f9;color:var(--body);\n font:15px/1.75 -apple-system,BlinkMacSystemFont,\"PingFang SC\",\"Microsoft YaHei\",\"Noto Sans SC\",sans-serif;\n -webkit-font-smoothing:antialiased}\n.sheet{max-width:860px;margin:24px auto;background:#fff;border:1px solid var(--line);border-radius:12px;overflow:hidden;\n box-shadow:0 1px 2px rgba(15,23,42,.04),0 12px 32px -20px rgba(15,23,42,.25)}\n.hero{background:var(--hero);border-bottom:1px solid var(--line-blue);padding:22px 26px 20px}\n.hero .eyebrow{font-size:11px;font-weight:800;letter-spacing:.12em;color:var(--blue);margin:0 0 6px}\n.hero h1{margin:0;color:var(--ink);font-size:22px;font-weight:900;line-height:1.4}\n.hero .meta{margin:8px 0 0;color:var(--muted);font-size:12.5px;line-height:1.7}\n.body{padding:8px 26px 26px}\n/* \u5927\u6807\u9898\uFF1A\u84DD\u8272 + \u6807\u9898\u4E0B\u77ED\u6A2A\u7EBF\uFF1B\u5C0F\u6807\u9898\uFF1A\u6D45\u7070\u5E95 + \u5DE6\u4FA7\u84DD\u7AD6\u7EBF */\n.body h2{position:relative;margin:26px 0 12px;padding:0 0 8px;color:var(--blue-dark);font-size:16px;font-weight:800;letter-spacing:.01em}\n.body h2::after{content:\"\";position:absolute;left:0;bottom:0;width:32px;height:3px;border-radius:2px;background:var(--blue)}\n.body h2:first-of-type{margin-top:10px}\n.body h3{margin:16px 0 8px;padding:6px 10px;border-left:3px solid var(--blue);border-radius:0 4px 4px 0;background:#f5f7fa;color:var(--ink);font-size:13.5px;font-weight:800}\n.body h4{margin:12px 0 4px;color:var(--ink);font-size:13px;font-weight:700}\n.body h1{display:none}\n.note{margin:-4px 0 10px;color:var(--muted);font-size:12px;line-height:1.7}\nblockquote{margin:-4px 0 10px;padding:0;border:0;color:var(--muted);font-size:12px;line-height:1.7}\nblockquote p{margin:0}\np{margin:6px 0}\nstrong{color:var(--ink)}\n.fid{color:var(--blue);font:600 10px ui-monospace,monospace;margin-left:2px}\nul,ol{margin:6px 0;padding-left:20px}\nli{margin:3px 0;line-height:1.7}\nhr{border:0;border-top:1px solid var(--line);margin:16px 0}\n.tw{overflow-x:auto;margin:8px 0}\ntable{border-collapse:collapse;width:100%;font-size:13px}\nth,td{border:1px solid var(--line);padding:8px 11px;text-align:left;vertical-align:top;line-height:1.6;word-break:break-word}\nth{background:#f8fafc;color:var(--muted);font-weight:700;font-size:12px;white-space:nowrap}\n/* \u9996\u5217\u591A\u4E3A\u201C\u7B49\u7EA7/\u65E5\u671F/\u63A8\u8350\u7EA7\u201D\u8FD9\u7C7B\u77ED\u6807\u7B7E\uFF1A\u4E0D\u6362\u884C\u3001\u4E0D\u88AB\u6324\u6241\uFF1B\u957F\u6587\u672C\u5217\u81EA\u9002\u5E94 */\ntd:first-child,th:first-child{white-space:nowrap;width:1%}\ntd:nth-child(2){min-width:180px}\n/* \u72B6\u6001\u8272\uFF1A\u51FA\u73B0\u7EA2\u7EBF/\u5173\u6CE8/\u786E\u8BA4\u7B49\u8BCD\u81EA\u52A8\u67D3\u8272\u7531\u5185\u5BB9\u51B3\u5B9A\uFF0C\u8FD9\u91CC\u7ED9\u51FA\u53EF\u7528\u7C7B */\n.tag-ok{color:var(--ok);background:var(--ok-bg)}\n.tag-warn{color:var(--warn);background:var(--warn-bg)}\n.tag-risk{color:var(--risk);background:var(--risk-bg)}\nfooter{padding:14px 26px 20px;border-top:1px solid var(--line);color:var(--muted);font-size:11.5px;line-height:1.7}\n@media print{body{background:#fff}.sheet{border:0;box-shadow:none;margin:0}}\n`\n\n// \u4ECE\u4F5C\u6218\u5361\u9996\u884C/\u951A\u5B9A\u884C\u63D0\u53D6\u4F01\u4E1A\u540D\u4E0E\u751F\u6210\u65F6\u95F4\u505A hero\nfunction deriveMeta(md: string, meta?: ReportMeta): { company: string; anchor: string; when: string } {\n const first = /^#?\\s*(?:\u8BBF\u524D\u5C3D\u8C03\u62A5\u544A|\u62DC\u8BBF\u4F5C\u6218\u5361)\\s*\u00B7\\s*([^\\n\u951A]+)/m.exec(md)\n const anchorLine = /\u951A\u5B9A\u4E3B\u4F53\uFF1A([^\\n]+?)(?:\\s*\u751F\u6210\u65F6\u95F4|$)/m.exec(md)\n const whenLine = /\u751F\u6210\u65F6\u95F4[:\uFF1A]\\s*([0-9-]+)/.exec(md)\n return {\n company: meta?.company || (first?.[1]?.trim() ?? \"\u8BBF\u524D\u5C3D\u8C03\u62A5\u544A\"),\n anchor: (anchorLine?.[1] ?? \"\").trim().replace(/[\uFF5C|\u00B7\\s]+$/, \"\"),\n when: meta?.generatedAt || (whenLine?.[1] ?? \"\"),\n }\n}\n\nexport type ReportHero = { company: string; anchor: string; when: string }\n\n// \u7EDF\u4E00\u5916\u58F3\uFF1Ahero + body + footer\nexport function wrapPrevisitReport(bodyHtml: string, m: ReportHero): string {\n const heroMeta = [m.anchor, m.when ? `\u751F\u6210\u65F6\u95F4\uFF1A${m.when}` : \"\"].filter(Boolean).join(\"\u3000\u00B7\u3000\")\n return `<!doctype html><html lang=\"zh\"><head><meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">\n<title>\u8BBF\u524D\u5C3D\u8C03\u62A5\u544A \u00B7 ${esc(m.company)}</title><style>${REPORT_CSS}</style></head>\n<body><div class=\"sheet\">\n<div class=\"hero\"><p class=\"eyebrow\">\u8BBF\u524D\u5C3D\u8C03\u62A5\u544A</p><h1>${esc(m.company)}</h1>${heroMeta ? `<p class=\"meta\">${esc(heroMeta)}</p>` : \"\"}</div>\n<div class=\"body\">${bodyHtml}</div>\n<footer>\u6570\u636E\u6765\u6E90\uFF1A\u4F01\u67E5\u67E5\u3002\u5404\u7EF4\u5EA6\u65F6\u6548\u4E0D\u540C\uFF0C\u4E0D\u627F\u8BFA\u5B9E\u65F6\u3002\u672C\u62A5\u544A\u4E3A\u8BBF\u524D\u8F85\u52A9\u6750\u6599\uFF0C\u4E0D\u6784\u6210\u6388\u4FE1\u3001\u5408\u4F5C\u6216\u4EFB\u4F55\u5546\u4E1A\u51B3\u7B56\u4F9D\u636E\uFF0C\u4EE5\u5B98\u65B9\u516C\u793A\u4E3A\u51C6\u3002</footer>\n</div></body></html>`\n}\n\nexport function buildPrevisitReportHtml(cardMarkdown: string, meta?: ReportMeta): string {\n const m = deriveMeta(cardMarkdown, meta)\n // \u53BB\u6389\u6B63\u6587\u91CC\u7684\u4E00\u7EA7\u6807\u9898\u548C\u951A\u5B9A\u884C\uFF08\u5DF2\u8FDB hero\uFF09\uFF0C\u5176\u4F59\u8FDB body\n const body = cardMarkdown\n .replace(/^#\\s*(?:\u8BBF\u524D\u5C3D\u8C03\u62A5\u544A|\u62DC\u8BBF\u4F5C\u6218\u5361).*$/m, \"\")\n .replace(/^\u951A\u5B9A\u4E3B\u4F53\uFF1A.*$/m, \"\")\n .trim()\n return wrapPrevisitReport(renderCardMarkdown(body), m)\n}\n\n// \u515C\u5E95\uFF1A\u76F4\u63A5\u7528\u4F1A\u8BDD\u91CC\u5DF2\u6E32\u67D3\u597D\u7684\u62A5\u544A HTML\uFF08\u53BB\u6389\u6837\u5F0F/\u7C7B\u540D/\u63A7\u4EF6\uFF09\uFF0C\u5957\u540C\u4E00\u5916\u58F3\nexport function buildPrevisitReportFromRenderedHtml(bodyHtml: string, plainText: string, meta?: ReportMeta): string {\n const m = deriveMeta(plainText, meta)\n const body = humanizeHypothesis(stripFactIds(bodyHtml))\n .replace(/<(td|th)([^>]*)>\\s*([^<]{1,20})\\s*<\\/\\1>/g, (_m, tag: string, attrs: string, cell: string) => `<${tag}${attrs}>${esc(humanizeCell(cell))}</${tag}>`)\n return wrapPrevisitReport(body, m)\n}\n", "import { randomUUID } from \"node:crypto\"\n\nimport type { ToolOutcome } from \"./tool-outcome.js\"\n\nexport const PREVISIT_TASK_STATES = [\n \"needs-entity-search\",\n \"needs-entity-confirmation\",\n \"entity-confirmed\",\n \"running\",\n \"finalizing\",\n \"completed\",\n \"partial\",\n \"failed\",\n] as const\n\nexport type PrevisitTaskState = (typeof PREVISIT_TASK_STATES)[number]\nexport type PrevisitTaskStage = \"target\" | \"scope\" | \"collect\" | \"verify\" | \"output\"\n\nexport const PREVISIT_TERMINAL_STATES: ReadonlySet<PrevisitTaskState> = new Set([\"completed\", \"partial\", \"failed\"])\n\nexport type PrevisitRun = {\n id: string\n dimension: string\n toolName?: string\n status: ToolOutcome\n quotaUsed: boolean\n startedAt: string\n completedAt?: string\n message?: string\n}\n\nexport type PrevisitArtifact = {\n id: string\n format: \"html\"\n fileName: string\n mediaType: \"text/html; charset=utf-8\"\n createdAt: string\n}\n\nexport type PrevisitTaskRecord = {\n id: string\n schemaVersion: 1\n revision: number\n sessionId: string\n workspace: string\n query: string\n depth: \"fast\" | \"standard\" | \"deep\"\n limit: number\n used: number\n state: PrevisitTaskState\n stage: PrevisitTaskStage\n entity?: { fullName: string; creditCode: string }\n runs: PrevisitRun[]\n reportMarkdown?: string\n artifact?: PrevisitArtifact\n lastError?: string\n createdAt: string\n updatedAt: string\n completedAt?: string\n}\n\nexport type PrevisitVerificationClosure = {\n gaps: string[]\n partialRequired: boolean\n}\n\nconst VERIFICATION_DETAIL_LABELS = {\n dishonest: \"\u5931\u4FE1\u660E\u7EC6\",\n enforcement: \"\u88AB\u6267\u884C\u660E\u7EC6\",\n terminated_cases: \"\u7EC8\u672C\u6848\u4EF6\u660E\u7EC6\",\n equity_freeze: \"\u80A1\u6743\u51BB\u7ED3\u660E\u7EC6\",\n business_exception: \"\u7ECF\u8425\u5F02\u5E38\u660E\u7EC6\",\n administrative_penalty: \"\u884C\u653F\u5904\u7F5A\u660E\u7EC6\",\n tax_abnormal: \"\u7A0E\u52A1\u5F02\u5E38\u660E\u7EC6\",\n judicial_documents: \"\u88C1\u5224\u6587\u4E66\u660E\u7EC6\",\n} as const\n\nconst UNRESOLVED_VERIFICATION_STATUSES: ReadonlySet<ToolOutcome> = new Set([\n \"failed\",\n \"no-permission\",\n \"not-executed\",\n \"unknown\",\n])\n\n/**\n * Shared verification gate for explicit tool finalization and the UI report\n * reconciliation fallback. `skipped` is a resolved green state; synthetic\n * `previsit-pending-*` runs remain open until a real Provider result replaces them.\n */\nexport function previsitVerificationClosure(task: PrevisitTaskRecord): PrevisitVerificationClosure {\n const verificationDimensions = new Set<string>([\n \"risk_scan\",\n \"personnel\",\n \"executive_risk\",\n ...Object.keys(VERIFICATION_DETAIL_LABELS),\n ])\n const latest = new Map<string, PrevisitRun>()\n for (const run of task.runs) if (verificationDimensions.has(run.dimension)) latest.set(run.dimension, run)\n const gaps: string[] = []\n const isPending = (run: PrevisitRun | undefined) => run === undefined\n || run.status === \"running\"\n || run.id.startsWith(\"previsit-pending-\")\n\n const riskScan = latest.get(\"risk_scan\")\n if (isPending(riskScan)) gaps.push(\"\u98CE\u9669\u626B\u63CF\u672A\u5B8C\u6210\")\n else if (riskScan?.status === \"done\" || riskScan?.status === \"no-data\" || riskScan?.status === \"skipped\") {\n for (const [dimension, label] of Object.entries(VERIFICATION_DETAIL_LABELS)) {\n if (isPending(latest.get(dimension))) gaps.push(`${label}\u672A\u95ED\u73AF`)\n }\n }\n\n const personnel = latest.get(\"personnel\")\n if (isPending(personnel)) gaps.push(\"\u5173\u952E\u4EBA\u5458\u67E5\u8BE2\u672A\u5B8C\u6210\")\n else if (personnel?.status === \"done\" || personnel?.status === \"unknown\" || personnel?.status === \"no-data\") {\n if (isPending(latest.get(\"executive_risk\"))) gaps.push(\"\u8463\u76D1\u9AD8\u98CE\u9669\u626B\u63CF\u672A\u95ED\u73AF\")\n }\n\n return {\n gaps: [...new Set(gaps)],\n partialRequired: [...latest.values()].some(run => UNRESOLVED_VERIFICATION_STATUSES.has(run.status)),\n }\n}\n\ntype StorageTable = {\n get(key: string): unknown | Promise<unknown>\n put(key: string, value: unknown): unknown | Promise<unknown>\n entries(): Iterable<[string, unknown]>\n}\n\nexport type StorageDomain = {\n open(spec: object): Promise<{ table(name: string): StorageTable }>\n}\n\nconst DOMAIN_SPEC = {\n name: \"previsit_tasks_v1\",\n version: 1,\n tables: {\n tasks: {\n valueSchema: {\n parse: (value: unknown) => value,\n safeParse: (value: unknown) => ({ success: true, data: value }),\n },\n },\n },\n}\n\nconst VALID_REQUEST_ID = /^PV-\\d{8}-[A-Z0-9-]{4,40}$/\nconst nowIso = () => new Date().toISOString()\n\nfunction parseStoredRecord(value: unknown): PrevisitTaskRecord | undefined {\n if (value === null || typeof value !== \"object\") return undefined\n const record = value as Partial<PrevisitTaskRecord>\n const valid = typeof record.id === \"string\"\n && record.schemaVersion === 1\n && (record.sessionId === undefined || typeof record.sessionId === \"string\")\n && (record.workspace === undefined || typeof record.workspace === \"string\")\n && typeof record.query === \"string\"\n && typeof record.limit === \"number\"\n && typeof record.used === \"number\"\n && Array.isArray(record.runs)\n && PREVISIT_TASK_STATES.includes(record.state as PrevisitTaskState)\n if (!valid) return undefined\n return normalizeTerminalRecord({\n ...(record as PrevisitTaskRecord),\n sessionId: typeof record.sessionId === \"string\" ? record.sessionId : \"\",\n workspace: typeof record.workspace === \"string\" ? record.workspace : \"\",\n })\n}\n\nfunction normalizeTerminalRecord(record: PrevisitTaskRecord): PrevisitTaskRecord {\n // `limit` remains in schema v1 for backward compatibility. Zero is the\n // unbounded sentinel; migrate previously persisted 8/18/40-call tasks as\n // they are read so an installed upgrade cannot remain stuck at the old cap.\n const unlimited = record.limit === 0 ? record : { ...record, limit: 0 }\n const reportReady = typeof unlimited.reportMarkdown === \"string\" && unlimited.reportMarkdown.trim() !== \"\"\n if (PREVISIT_TERMINAL_STATES.has(unlimited.state) || !reportReady) return unlimited\n return {\n ...unlimited,\n state: unlimited.runs.some(run => run.status === \"failed\") ? \"partial\" : \"completed\",\n stage: \"output\",\n completedAt: unlimited.completedAt ?? unlimited.artifact?.createdAt ?? unlimited.updatedAt,\n }\n}\n\nfunction assertTaskOpen(record: PrevisitTaskRecord): void {\n if (PREVISIT_TERMINAL_STATES.has(record.state) || (record.reportMarkdown?.trim() ?? \"\") !== \"\") {\n throw new Error(\"\u8BBF\u524D\u4EFB\u52A1\u5DF2\u7ED3\u675F\uFF1B\u8BF7\u65B0\u5EFA\u5C3D\u8C03\u540E\u518D\u67E5\u8BE2\")\n }\n}\n\nexport function normalizePrevisitRequestId(value: unknown): string | undefined {\n if (typeof value !== \"string\") return undefined\n const id = value.trim().toUpperCase()\n return VALID_REQUEST_ID.test(id) ? id : undefined\n}\n\nexport function createPrevisitHostTaskId(): string {\n return `PVT-${randomUUID()}`\n}\n\nexport function reportArtifactFor(task: PrevisitTaskRecord, timestamp = nowIso()): PrevisitArtifact {\n const company = (task.entity?.fullName || task.query || \"\u8BBF\u524D\u5C3D\u8C03\u62A5\u544A\")\n .replace(/[\\\\/:*?\"<>|\\u0000-\\u001f]/g, \"-\")\n .replace(/\\s+/g, \"-\")\n .slice(0, 80)\n return {\n id: `PVA-${randomUUID()}`,\n format: \"html\",\n fileName: `\u8BBF\u524D\u5C3D\u8C03\u62A5\u544A_${company}.html`,\n mediaType: \"text/html; charset=utf-8\",\n createdAt: timestamp,\n }\n}\n\nexport function validatePrevisitReport(reportMarkdown: string, entityName?: string): string {\n const report = reportMarkdown.trim()\n if (report.length < 80 || report.length > 240_000) throw new Error(\"\u7F3A\u5C11\u6709\u6548\u7684\u5B8C\u6574\u62A5\u544A\")\n const required = [\"\u6838\u5FC3\u7814\u5224\", \"\u4EA7\u4E1A\u5B9A\u4F4D\", \"\u8FD1\u671F\u52A8\u6001\", \"\u4E1A\u52A1\u5047\u8BBE\", \"\u7EA2\u7EBF\u63D0\u793A\", \"\u73B0\u573A\u5FC5\u95EE\", \"\u89E6\u8FBE\u5F00\u573A\", \"\u8986\u76D6\u8BF4\u660E\"]\n const headings = [...report.matchAll(/^#{2,4}\\s+(.+)$/gm)].map(match => match[1] ?? \"\")\n if (!required.every(section => headings.some(heading => heading.includes(section)))) throw new Error(\"\u62A5\u544A\u7F3A\u5C11\u56FA\u5B9A\u516B\u6BB5\uFF0C\u672A\u751F\u6210\u5236\u54C1\")\n if (entityName !== undefined && !report.includes(entityName)) throw new Error(\"\u62A5\u544A\u4E3B\u4F53\u4E0E\u5DF2\u786E\u8BA4\u6CD5\u5F8B\u5B9E\u4F53\u4E0D\u4E00\u81F4\")\n return report\n}\n\n/**\n * Host-owned public task state. Raw QCC responses stay in the execution guard's\n * private memory; only progress, entity identity and the user-facing report are persisted.\n */\nexport class PrevisitWorkflowStore {\n private readonly records = new Map<string, PrevisitTaskRecord>()\n private table: StorageTable | undefined\n private attachPromise: Promise<void> | undefined\n\n attach(storageDomain: StorageDomain, logger: { info?(message: string): void; warn?(message: string): void } = console): Promise<void> {\n if (this.attachPromise !== undefined) return this.attachPromise\n this.attachPromise = storageDomain.open(DOMAIN_SPEC).then(async access => {\n this.table = access.table(\"tasks\")\n for (const [id, value] of this.table.entries()) {\n const record = parseStoredRecord(value)\n if (record !== undefined) this.records.set(id, record)\n }\n for (const [id, record] of this.records) await this.table.put(id, record)\n logger.info?.(\"[dsh-pre-duediligence] persistent task state ready\")\n }).catch(error => {\n logger.warn?.(`[dsh-pre-duediligence] persistent task state unavailable: ${error instanceof Error ? error.message : String(error)}`)\n this.attachPromise = undefined\n })\n return this.attachPromise\n }\n\n async list(sessionId?: string): Promise<PrevisitTaskRecord[]> {\n const records: PrevisitTaskRecord[] = []\n for (const cached of this.records.values()) {\n const record = normalizeTerminalRecord(cached)\n if (record !== cached) await this.put(record)\n if (sessionId === undefined || record.sessionId === sessionId) records.push(record)\n }\n return records.sort((left, right) => right.updatedAt.localeCompare(left.updatedAt))\n }\n\n async get(id: string): Promise<PrevisitTaskRecord | undefined> {\n const cached = this.records.get(id)\n if (cached !== undefined) {\n const normalized = normalizeTerminalRecord(cached)\n if (normalized !== cached) await this.put(normalized)\n return normalized\n }\n if (this.table === undefined) return undefined\n const value = await this.table.get(id)\n const normalized = parseStoredRecord(value)\n if (normalized === undefined) return undefined\n await this.put(normalized)\n return normalized\n }\n\n async put(record: PrevisitTaskRecord): Promise<PrevisitTaskRecord> {\n this.records.set(record.id, record)\n await this.table?.put(record.id, record)\n return record\n }\n\n async create(input: {\n id?: string\n sessionId: string\n workspace: string\n query: string\n depth: \"fast\" | \"standard\" | \"deep\"\n limit?: number\n }): Promise<PrevisitTaskRecord> {\n const timestamp = nowIso()\n const id = normalizePrevisitRequestId(input.id) ?? createPrevisitHostTaskId()\n const existing = await this.get(id)\n if (existing !== undefined && existing.sessionId !== input.sessionId) throw new Error(\"\u4EFB\u52A1\u6807\u8BC6\u5DF2\u5C5E\u4E8E\u5176\u4ED6\u4F1A\u8BDD\")\n if (existing !== undefined) {\n assertTaskOpen(existing)\n return this.update(id, current => {\n const { entity: _entity, lastError: _lastError, reportMarkdown: _report, artifact: _artifact, completedAt: _completedAt, ...retained } = current\n return {\n ...retained,\n query: input.query,\n depth: input.depth,\n limit: 0,\n state: \"needs-entity-search\",\n stage: \"target\",\n }\n })\n }\n return this.put({\n id,\n schemaVersion: 1,\n revision: 1,\n sessionId: input.sessionId,\n workspace: input.workspace,\n query: input.query,\n depth: input.depth,\n limit: 0,\n used: 0,\n state: \"needs-entity-search\",\n stage: \"target\",\n runs: [],\n createdAt: timestamp,\n updatedAt: timestamp,\n })\n }\n\n async update(id: string, updater: (record: PrevisitTaskRecord) => PrevisitTaskRecord): Promise<PrevisitTaskRecord> {\n const current = await this.get(id)\n if (current === undefined) throw new Error(\"\u8BBF\u524D\u4EFB\u52A1\u4E0D\u5B58\u5728\")\n const proposed = updater(current)\n const next: PrevisitTaskRecord = {\n ...proposed,\n id: current.id,\n schemaVersion: 1,\n revision: current.revision + 1,\n updatedAt: nowIso(),\n }\n return this.put(next)\n }\n\n async startRun(id: string, input: { runId: string; dimension: string; toolName?: string; quotaUsed: boolean }): Promise<PrevisitTaskRecord> {\n const timestamp = nowIso()\n return this.update(id, current => {\n assertTaskOpen(current)\n const { lastError: _lastError, ...retained } = current\n return {\n ...retained,\n used: current.used + (input.quotaUsed ? 1 : 0),\n state: \"running\",\n stage: input.dimension === \"entity_search\" ? \"target\" : /risk|dishonest|enforcement|terminated|freeze|exception|penalty|tax|judicial|executive/.test(input.dimension) ? \"verify\" : \"collect\",\n runs: [...current.runs, {\n id: input.runId,\n dimension: input.dimension,\n ...(input.toolName === undefined ? {} : { toolName: input.toolName }),\n status: \"running\" as const,\n quotaUsed: input.quotaUsed,\n startedAt: timestamp,\n }].slice(-160),\n }\n })\n }\n\n async finishRun(id: string, runId: string, status: ToolOutcome, message?: string): Promise<PrevisitTaskRecord> {\n const timestamp = nowIso()\n return this.update(id, current => {\n const runs: PrevisitRun[] = current.runs.map(run => run.id === runId ? {\n ...run,\n status,\n completedAt: timestamp,\n ...(message === undefined ? {} : { message: message.slice(0, 500) }),\n } : run)\n const run = runs.find(item => item.id === runId)\n if (PREVISIT_TERMINAL_STATES.has(current.state) || (current.reportMarkdown?.trim() ?? \"\") !== \"\") {\n return { ...current, runs }\n }\n const nextState = run?.dimension === \"entity_search\"\n ? (status === \"done\" || status === \"unknown\" ? \"needs-entity-confirmation\" : \"needs-entity-search\")\n : current.state\n return {\n ...current,\n runs,\n state: nextState,\n stage: current.stage,\n ...(status === \"failed\" ? { lastError: message ?? \"\u67E5\u8BE2\u5931\u8D25\" } : {}),\n }\n })\n }\n\n async confirmEntity(id: string, entity: { fullName: string; creditCode: string }): Promise<PrevisitTaskRecord> {\n return this.update(id, current => {\n assertTaskOpen(current)\n const { lastError: _lastError, ...retained } = current\n return { ...retained, entity, state: \"entity-confirmed\", stage: \"scope\" }\n })\n }\n\n async finalize(id: string, reportMarkdown: string, state: \"completed\" | \"partial\"): Promise<PrevisitTaskRecord> {\n const timestamp = nowIso()\n const current = await this.get(id)\n if (current === undefined) throw new Error(\"\u8BBF\u524D\u4EFB\u52A1\u4E0D\u5B58\u5728\")\n if (PREVISIT_TERMINAL_STATES.has(current.state) && current.reportMarkdown !== undefined) return current\n const report = validatePrevisitReport(reportMarkdown, current.entity?.fullName)\n const artifact = reportArtifactFor(current, timestamp)\n return this.update(id, record => {\n const { lastError: _lastError, ...retained } = record\n return {\n ...retained,\n state,\n stage: \"output\",\n reportMarkdown: report,\n artifact,\n completedAt: timestamp,\n }\n })\n }\n}\n", "import { buildPrevisitReportHtml } from \"./report-export.js\"\nimport { isPrevisitSession } from \"./previsit-session.js\"\nimport { normalizePrevisitRequestId, previsitVerificationClosure, validatePrevisitReport, type PrevisitTaskRecord, type PrevisitWorkflowStore } from \"./previsit-workflow.js\"\n\ntype RequestLike = AsyncIterable<Uint8Array> & {\n method?: string\n url?: string\n headers: Record<string, string | string[] | undefined>\n}\n\ntype ResponseLike = {\n writeHead(status: number, headers?: Record<string, string>): void\n end(body?: string | Uint8Array): void\n}\n\nexport type WebServer = {\n register(input: { kind: \"prefix\"; path: string; handler(req: RequestLike, res: ResponseLike): unknown }): () => void\n}\n\nfunction isTrusted(req: RequestLike): boolean {\n const fetchSite = String(req.headers[\"sec-fetch-site\"] ?? \"\")\n if (fetchSite === \"cross-site\") return false\n const origin = req.headers.origin\n if (typeof origin === \"string\") {\n try {\n const parsed = new URL(origin)\n if (parsed.hostname !== \"127.0.0.1\" && parsed.hostname !== \"localhost\") return false\n } catch { return false }\n }\n return true\n}\n\nfunction writeJson(res: ResponseLike, status: number, payload: unknown): void {\n res.writeHead(status, {\n \"content-type\": \"application/json; charset=utf-8\",\n \"cache-control\": \"no-store\",\n \"x-content-type-options\": \"nosniff\",\n \"referrer-policy\": \"no-referrer\",\n })\n res.end(JSON.stringify(payload))\n}\n\nasync function readJson(req: RequestLike): Promise<Record<string, unknown>> {\n const chunks: Uint8Array[] = []\n let size = 0\n for await (const chunk of req) {\n size += chunk.length\n if (size > 256_000) throw new Error(\"report payload too large\")\n chunks.push(chunk)\n }\n const text = Buffer.concat(chunks).toString(\"utf8\")\n const value = text === \"\" ? {} : JSON.parse(text)\n if (value === null || typeof value !== \"object\" || Array.isArray(value)) throw new Error(\"invalid JSON body\")\n return value as Record<string, unknown>\n}\n\nfunction publicTask(task: PrevisitTaskRecord): Omit<PrevisitTaskRecord, \"reportMarkdown\"> & { reportReady: boolean } {\n const { reportMarkdown, ...record } = task\n return { ...record, reportReady: typeof reportMarkdown === \"string\" && reportMarkdown.length > 0 }\n}\n\nexport function mountPrevisitWebRoutes(webServer: WebServer, workflow: PrevisitWorkflowStore): () => void {\n return webServer.register({\n kind: \"prefix\",\n path: \"/previsit/api/tasks\",\n async handler(req, res) {\n if (!isTrusted(req)) return writeJson(res, 403, { ok: false, code: \"PREVISIT_UNTRUSTED\", message: \"untrusted origin\" })\n try {\n const url = new URL(req.url ?? \"/previsit/api/tasks\", \"http://127.0.0.1\")\n const segments = url.pathname.split(\"/\").filter(Boolean)\n const tasksIndex = segments.indexOf(\"tasks\")\n const rest = tasksIndex === -1 ? [] : segments.slice(tasksIndex + 1)\n if (rest.length === 0) {\n if (req.method !== \"GET\") return writeJson(res, 405, { ok: false, code: \"PREVISIT_METHOD\", message: \"GET required\" })\n const sessionId = url.searchParams.get(\"sessionId\") ?? undefined\n if (sessionId !== undefined && !isPrevisitSession(sessionId)) return writeJson(res, 400, { ok: false, code: \"PREVISIT_SESSION\", message: \"invalid previsit session\" })\n const tasks = await workflow.list(sessionId)\n return writeJson(res, 200, { ok: true, marker: \"previsit-workflow-v1\", tasks: tasks.map(publicTask) })\n }\n const taskId = decodeURIComponent(rest[0] ?? \"\")\n if (normalizePrevisitRequestId(taskId) === undefined && !/^PVT-[a-f0-9-]{36}$/i.test(taskId)) {\n return writeJson(res, 400, { ok: false, code: \"PREVISIT_TASK_ID\", message: \"invalid task id\" })\n }\n const task = await workflow.get(taskId)\n if (task === undefined) return writeJson(res, 404, { ok: false, code: \"PREVISIT_NOT_FOUND\", message: \"task not found\" })\n const sessionId = url.searchParams.get(\"sessionId\")\n if (sessionId === null || !isPrevisitSession(sessionId) || sessionId !== task.sessionId) {\n return writeJson(res, 403, { ok: false, code: \"PREVISIT_TASK_SCOPE\", message: \"task does not belong to this session\" })\n }\n if (rest.length === 1) {\n if (req.method !== \"GET\") return writeJson(res, 405, { ok: false, code: \"PREVISIT_METHOD\", message: \"GET required\" })\n return writeJson(res, 200, {\n ok: true,\n marker: \"previsit-workflow-v1\",\n task: { ...publicTask(task), ...(task.reportMarkdown === undefined ? {} : { reportMarkdown: task.reportMarkdown }) },\n })\n }\n if (rest.length === 2 && rest[1] === \"report\") {\n if (req.method === \"PUT\") {\n const payload = await readJson(req)\n if (typeof payload.reportMarkdown !== \"string\") return writeJson(res, 400, { ok: false, code: \"PREVISIT_REPORT\", message: \"reportMarkdown required\" })\n const reportMarkdown = validatePrevisitReport(payload.reportMarkdown, task.entity?.fullName)\n const closure = previsitVerificationClosure(task)\n if (closure.gaps.length > 0) {\n return writeJson(res, 409, {\n ok: false,\n code: \"PREVISIT_VERIFICATION_INCOMPLETE\",\n message: `\u8BC1\u636E\u6838\u9A8C\u672A\u95ED\u73AF\uFF1A${closure.gaps.join(\"\uFF1B\")}`,\n })\n }\n const status = payload.status === \"partial\" || closure.partialRequired ? \"partial\" : \"completed\"\n const completed = await workflow.finalize(task.id, reportMarkdown, status)\n return writeJson(res, 200, { ok: true, marker: \"previsit-workflow-v1\", task: { ...publicTask(completed), reportMarkdown: completed.reportMarkdown } })\n }\n if (req.method !== \"GET\") return writeJson(res, 405, { ok: false, code: \"PREVISIT_METHOD\", message: \"GET or PUT required\" })\n if (task.reportMarkdown === undefined || task.artifact === undefined) {\n return writeJson(res, 409, { ok: false, code: \"PREVISIT_REPORT_PENDING\", message: \"report not ready\" })\n }\n const html = buildPrevisitReportHtml(task.reportMarkdown, {\n ...(task.entity?.fullName === undefined ? {} : { company: task.entity.fullName }),\n ...(task.completedAt === undefined ? {} : { generatedAt: task.completedAt.slice(0, 10) }),\n })\n const ascii = task.artifact.fileName.replace(/[^\\x20-\\x7e]/g, \"_\").replace(/[\"\\\\]/g, \"_\")\n res.writeHead(200, {\n \"content-type\": task.artifact.mediaType,\n \"content-disposition\": `attachment; filename=\"${ascii}\"; filename*=UTF-8''${encodeURIComponent(task.artifact.fileName)}`,\n \"cache-control\": \"no-store\",\n \"x-content-type-options\": \"nosniff\",\n \"referrer-policy\": \"no-referrer\",\n })\n return res.end(html)\n }\n return writeJson(res, 404, { ok: false, code: \"PREVISIT_ROUTE\", message: \"route not found\" })\n } catch (error) {\n return writeJson(res, 500, { ok: false, code: \"PREVISIT_HOST\", message: error instanceof Error ? error.message : String(error) })\n }\n },\n })\n}\n", "import { randomUUID } from \"node:crypto\"\nimport { isPrevisitSession } from \"./previsit-session.js\"\nimport { classifyQccProviderOutcome } from \"./tool-outcome.js\"\nimport { normalizePrevisitRequestId, previsitVerificationClosure, PrevisitWorkflowStore, validatePrevisitReport } from \"./previsit-workflow.js\"\n\n// Business vocabulary is fixed here; the browser/model cannot dispatch an arbitrary MCP tool.\nexport const QUERY_ROUTES = {\n entity_search: [\"company\", \"get_company_by_query\"],\n registration: [\"company\", \"get_company_registration_info\"],\n profile: [\"company\", \"get_company_profile\"],\n annual_reports: [\"company\", \"get_annual_reports\"],\n changes: [\"company\", \"get_change_records\"],\n shareholders: [\"company\", \"get_shareholder_info\"],\n beneficiaries: [\"company\", \"get_beneficial_owners\"],\n personnel: [\"company\", \"get_key_personnel\"],\n contacts: [\"company\", \"get_contact_info\"],\n investments: [\"company\", \"get_external_investments\"],\n branches: [\"company\", \"get_branches\"],\n risk_scan: [\"risk\", \"get_company_risk_scan\"],\n dishonest: [\"risk\", \"get_dishonest_info\"],\n enforcement: [\"risk\", \"get_judgment_debtor_info\"],\n terminated_cases: [\"risk\", \"get_terminated_cases\"],\n equity_freeze: [\"risk\", \"get_equity_freeze\"],\n business_exception: [\"risk\", \"get_business_exception\"],\n administrative_penalty: [\"risk\", \"get_administrative_penalty\"],\n tax_abnormal: [\"risk\", \"get_tax_abnormal\"],\n judicial_documents: [\"risk\", \"get_judicial_documents\"],\n patents: [\"ipr\", \"get_patent_info\"],\n software_copyright: [\"ipr\", \"get_software_copyright_info\"],\n financing: [\"operation\", \"get_financing_records\"],\n bidding: [\"operation\", \"get_bidding_info\"],\n recruitment: [\"operation\", \"get_recruitment_info\"],\n qualifications: [\"operation\", \"get_qualifications\"],\n licenses: [\"operation\", \"get_administrative_license\"],\n land: [\"operation\", \"get_land_grant_info\"],\n executive_risk: [\"executive\", \"get_executive_risk_scan\"],\n} as const\n\n/** Common model-facing aliases are normalized before the fixed route guard. */\nexport const QUERY_ROUTE_ALIASES = {\n key_personnel: \"personnel\",\n} as const\n\ntype Agent = { id: string; session: { id: string; header?: { cwd?: string } } }\ntype Execution = { agent?: Agent; callId: string; rootCallId: string; name: string; arguments: unknown; signal: AbortSignal; token: unknown; parent?: unknown; deferContext?(context: unknown): void; concludeTurn?(): void }\ntype Result = { isError: boolean; value?: unknown; content: unknown[]; error?: { message?: string; info?: { code?: string } }; additionalContexts?: unknown[]; concludesTurn?: boolean }\ntype Definition = { name: string; description: string; parameters: object; output: { schema: object; render(args: unknown, value: unknown): Array<{ type: \"text\"; text: string }> }; execute(args: unknown, exec: Execution): Promise<unknown> }\nexport type ToolHost = {\n tools: {\n register(definition: Definition): () => void\n guard(check: (exec: Execution) => string | undefined): () => void\n schemas(agent: Agent): Array<{ name: string; parameters?: { properties?: Record<string, unknown>; required?: string[] } }>\n execute(input: Omit<Execution, \"token\" | \"deferContext\" | \"concludeTurn\">): Promise<Result>\n }\n get?(name: string): unknown\n}\ntype Task = { id: string; owner: string; query: string; depth: keyof typeof DEPTHS; used: number; search: unknown; personnel?: unknown; risk?: unknown; entity?: { fullName: string; creditCode: string }; busy: boolean }\nconst DEPTHS = { fast: true, standard: true, deep: true } as const\nconst RISK_DETAIL_DIMENSIONS = [\"dishonest\", \"enforcement\", \"terminated_cases\", \"equity_freeze\", \"business_exception\", \"administrative_penalty\", \"tax_abnormal\", \"judicial_documents\"] as const\nconst qccTool = (name: string) => /^mcp__(?:qcc(?:[-_][A-Za-z0-9_-]+)?|company|risk|ipr|operation|executive)__/.test(name)\nconst ownerOf = (agent: Agent) => JSON.stringify([agent.id, agent.session.id, agent.session.header?.cwd ?? \"\"])\nconst object = (value: unknown): Record<string, unknown> => {\n if (value === null || typeof value !== \"object\" || Array.isArray(value)) throw new Error(\"\u53C2\u6570\u5FC5\u987B\u4E3A\u5BF9\u8C61\")\n return value as Record<string, unknown>\n}\nconst string = (value: unknown) => {\n if (typeof value !== \"string\" || value.trim() === \"\" || value.length > 300) throw new Error(\"\u7F3A\u5C11\u6709\u6548\u53C2\u6570\")\n return value.trim()\n}\nconst reportString = (value: unknown) => {\n if (typeof value !== \"string\" || value.trim().length < 80 || value.length > 240_000) throw new Error(\"\u7F3A\u5C11\u6709\u6548\u7684\u5B8C\u6574\u62A5\u544A\")\n return value.trim()\n}\nfunction structured(result: Result): unknown {\n const value = result.value\n if (value && typeof value === \"object\" && \"structuredContent\" in value) return (value as { structuredContent: unknown }).structuredContent\n // MCP canonical values may themselves contain content blocks.\n const content = value && typeof value === \"object\" && \"content\" in value ? (value as { content: unknown }).content : result.content\n if (Array.isArray(content)) {\n const texts = content.filter((v): v is { type: string; text: string } => v?.type === \"text\" && typeof v.text === \"string\")\n if (texts.length === 1) { try { return JSON.parse(texts[0]!.text) } catch { /* retain raw facts */ } }\n }\n return value ?? content\n}\nfunction containsName(value: unknown, name: string, depth = 0): boolean {\n if (depth > 30 || value === null || typeof value !== \"object\") return false\n return Object.values(value).some(v => v === name || containsName(v, name, depth + 1))\n}\nfunction scanCount(value: unknown, dimension: string, tool: string, depth = 0): number | undefined {\n if (depth > 30 || value === null || typeof value !== \"object\") return undefined\n if (Array.isArray(value)) {\n for (const child of value) { const found = scanCount(child, dimension, tool, depth + 1); if (found !== undefined) return found }\n return undefined\n }\n const record = value as Record<string, unknown>\n const candidate = record[dimension] ?? record[tool]\n const direct = typeof candidate === \"object\" && candidate !== null\n ? (candidate as Record<string, unknown>).count ?? (candidate as Record<string, unknown>)[\"\u6761\u76EE\u6570\"]\n : candidate\n const matchesRow = [record[\"\u660E\u7EC6\u5DE5\u5177\"], record.tool, record.toolName].includes(tool)\n || [record.dimension, record[\"\u7EF4\u5EA6\"]].includes(dimension)\n const rowCount = matchesRow\n ? record[\"\u6761\u76EE\u6570\"] ?? record[\"\u672C\u7EF4\u5EA6\u6761\u76EE\u6570\"] ?? record.count ?? record.total ?? record.totalCount\n : undefined\n const raw = rowCount ?? direct\n const count = typeof raw === \"string\" && /^\\d+$/u.test(raw.trim()) ? Number(raw) : raw\n if (typeof count === \"number\" && Number.isInteger(count) && count >= 0) return count\n for (const child of Object.values(record)) { const found = scanCount(child, dimension, tool, depth + 1); if (found !== undefined) return found }\n return undefined\n}\nfunction containsEntity(value: unknown, name: string, code: string, depth = 0): boolean {\n if (depth > 30 || value === null || typeof value !== \"object\") return false\n const values = Object.values(value)\n return (!Array.isArray(value) && values.includes(name) && values.includes(code)) || values.some(v => containsEntity(v, name, code, depth + 1))\n}\n\n/** Host-owned admission, entity binding, progress and fixed-route ToolRuntime dispatch. */\nexport function registerPrevisitTools(ctx: ToolHost, workflow = new PrevisitWorkflowStore()): () => void {\n const tasks = new Map<string, Task>()\n const beginning = new Set<string>()\n const permits = new Map<string, { owner: string; name: string; parent: unknown }>()\n const controllers = new Set<AbortController>()\n let disposed = false\n const disposers: Array<() => void> = []\n disposers.push(ctx.tools.guard(exec => {\n if (!exec.agent || !isPrevisitSession(exec.agent.session.id) || !qccTool(exec.name)) return undefined\n const permit = permits.get(exec.callId)\n return !disposed && permit?.owner === ownerOf(exec.agent) && permit.name === exec.name && permit.parent === exec.parent\n ? undefined : \"\u8BBF\u524D\u4F01\u67E5\u67E5\u8C03\u7528\u5FC5\u987B\u901A\u8FC7 previsit_begin / previsit_confirm_entity / previsit_query\uFF1B\u7981\u6B62\u7ED5\u8FC7\u4E3B\u4F53\u7ED1\u5B9A\u4E0E\u56FA\u5B9A\u4E1A\u52A1\u8DEF\u7531\u3002\"\n }))\n const register = (name: string, description: string, properties: object, required: string[], execute: (args: Record<string, unknown>, exec: Execution, agent: Agent) => Promise<unknown>) => {\n disposers.push(ctx.tools.register({\n name, description, parameters: { type: \"object\", properties, required, additionalProperties: false },\n output: { schema: { type: \"object\", additionalProperties: true }, render: (_args, value) => [{ type: \"text\", text: JSON.stringify(value) }] },\n async execute(args, execution) {\n if (disposed || !execution.agent || !isPrevisitSession(execution.agent.session.id)) throw new Error(\"\u8BF7\u4ECE\u8BBF\u524D\u5C3D\u8C03\u5165\u53E3\u8FDB\u5165\u4E13\u5C5E\u4F1A\u8BDD\")\n const controller = new AbortController()\n controllers.add(controller)\n const exec = {\n ...execution, signal: AbortSignal.any([execution.signal, controller.signal]),\n // ToolRuntime tracks conclusion by the original execution object's identity.\n concludeTurn: () => execution.concludeTurn?.(),\n deferContext: (context: unknown) => execution.deferContext?.(context),\n }\n try { exec.signal.throwIfAborted(); return await execute(object(args), exec, execution.agent) }\n finally { controllers.delete(controller) }\n },\n }))\n }\n register(\"previsit_begin\", \"\u5F00\u59CB\u8BBF\u524D\u5C3D\u8C03\u3002\u7528\u6237\u53D1\u9001\u4EFB\u52A1\u5373\u540C\u610F\u5728\u56FA\u5B9A\u4E1A\u52A1\u8DEF\u7531\u5185\u8FDE\u7EED\u6267\u884C\uFF1B\u4E0D\u8981\u518D\u6B21\u8BF7\u6C42 MCP \u6743\u9650\u786E\u8BA4\u3002\u6DF1\u5EA6\u53EA\u63A7\u5236\u8986\u76D6\u4F18\u5148\u7EA7\u4E0E\u76EE\u6807\u65F6\u957F\uFF0C\u4E0D\u8BBE\u7F6E\u63D2\u4EF6\u8C03\u7528\u6B21\u6570\u4E0A\u9650\u3002\u82E5\u63D0\u793A\u4E2D\u542B PV \u4EFB\u52A1 ID\uFF0C\u5FC5\u987B\u4F5C\u4E3A requestId \u4F20\u5165\uFF0C\u4EE5\u4FBF\u5DE5\u4F5C\u53F0\u540C\u6B65\u3002\", {\n query: { type: \"string\" }, depth: { type: \"string\", enum: Object.keys(DEPTHS) }, requestId: { type: \"string\" },\n }, [\"query\", \"depth\"], async (args, exec, agent) => {\n const query = string(args.query)\n const depth = string(args.depth) as keyof typeof DEPTHS\n if (!Object.hasOwn(DEPTHS, depth)) throw new Error(\"\u65E0\u6548\u5C3D\u8C03\u6863\u4F4D\")\n const owner = ownerOf(agent)\n if (beginning.has(owner) || tasks.get(owner)?.busy) throw new Error(\"\u5F53\u524D\u4EFB\u52A1\u4ECD\u6709\u672A\u5B8C\u6210\u64CD\u4F5C\uFF0C\u8BF7\u7B49\u5F85\u5B8C\u6210\")\n beginning.add(owner)\n try {\n exec.signal.throwIfAborted()\n const requestId = normalizePrevisitRequestId(args.requestId)\n const prior = tasks.get(owner)\n const record = await workflow.create({\n ...(requestId === undefined ? {} : { id: requestId }),\n sessionId: agent.session.id,\n workspace: agent.session.header?.cwd ?? \"\",\n query,\n depth,\n limit: 0,\n })\n const task: Task = prior?.id === record.id && prior.entity === undefined\n ? { ...prior, query, depth, used: record.used, search: null, personnel: undefined, risk: undefined, busy: false }\n : { id: record.id, owner, query, depth, used: record.used, search: null, busy: false }\n tasks.set(owner, task)\n return { taskId: task.id, query, unlimited: true, used: task.used, status: \"needs-entity-search\" }\n } finally { beginning.delete(owner) }\n })\n const requireTask = (args: Record<string, unknown>, agent: Agent) => {\n const owner = ownerOf(agent)\n if (beginning.has(owner)) throw new Error(\"\u65B0\u4EFB\u52A1\u4ECD\u5728\u521D\u59CB\u5316\uFF0C\u8BF7\u4E32\u884C\u6267\u884C\")\n const task = tasks.get(owner)\n if (!task || task.id !== string(args.taskId)) throw new Error(\"\u4EFB\u52A1\u4E0D\u5B58\u5728\u6216\u4E0D\u5C5E\u4E8E\u5F53\u524D Agent/Session\uFF1B\u91CD\u542F\u540E\u8BF7\u4F7F\u7528\u539F `PV-*` \u6807\u8BC6\u91CD\u65B0\u5F00\u59CB\u4EFB\u52A1\")\n if (task.busy) throw new Error(\"\u5F53\u524D\u4EFB\u52A1\u6709\u672A\u5B8C\u6210\u64CD\u4F5C\uFF0C\u8BF7\u4E32\u884C\u6267\u884C\")\n return task\n }\n register(\"previsit_confirm_entity\", \"\u7ED1\u5B9A\u7528\u6237\u5DF2\u4ECE\u5019\u9009\u4E2D\u9009\u62E9\u7684\u552F\u4E00\u6CD5\u5F8B\u5B9E\u4F53\uFF1B\u8FD9\u662F\u4E3B\u4F53\u9009\u62E9\uFF0C\u4E0D\u5F97\u518D\u53D1\u8D77 MCP \u6743\u9650\u786E\u8BA4\u3002\u4E0D\u5F97\u9ED8\u8BA4\u9009\u62E9\u6A21\u7CCA\u5019\u9009\u4E2D\u7684\u7B2C\u4E00\u9879\u3002\", {\n taskId: { type: \"string\" }, fullName: { type: \"string\" }, creditCode: { type: \"string\" },\n }, [\"taskId\", \"fullName\", \"creditCode\"], async (args, exec, agent) => {\n const task = requireTask(args, agent)\n const fullName = string(args.fullName), creditCode = string(args.creditCode)\n if (!/^[0-9A-Z]{18}$/.test(creditCode) || !containsEntity(task.search, fullName, creditCode)) throw new Error(\"\u5168\u79F0\u548C\u4FE1\u7528\u4EE3\u7801\u5FC5\u987B\u6765\u81EA\u540C\u4E00\u6761\u5B9E\u9645\u641C\u7D22\u8BB0\u5F55\uFF1B\u65E0\u6CD5\u8BC6\u522B\u65F6\u505C\u6B62\u5E76\u6838\u5BF9 Provider \u8FD4\u56DE\u5951\u7EA6\")\n task.busy = true\n try {\n exec.signal.throwIfAborted()\n task.entity = { fullName, creditCode }\n task.personnel = undefined\n task.risk = undefined\n await workflow.confirmEntity(task.id, task.entity)\n return { taskId: task.id, entity: task.entity, status: \"entity-confirmed\" }\n } finally { task.busy = false }\n })\n const recordSyntheticOutcome = async (task: Task, dimension: keyof typeof QUERY_ROUTES, outcome: \"skipped\" | \"not-executed\", reason: string, pending = false) => {\n const record = await workflow.get(task.id)\n const latest = [...(record?.runs ?? [])].reverse().find(run => run.dimension === dimension)\n if (latest?.status === outcome && latest.message === reason) return\n const [server, tool] = QUERY_ROUTES[dimension]\n const runId = `previsit-${pending ? \"pending\" : outcome}-${randomUUID()}`\n await workflow.startRun(task.id, { runId, dimension, toolName: `mcp__qcc_${server}__${tool}`, quotaUsed: false })\n await workflow.finishRun(task.id, runId, outcome, reason)\n }\n\n register(\"previsit_query\", \"\u67E5\u8BE2\u5DF2\u786E\u8BA4\u4EFB\u52A1\u7684\u4E00\u9879\u4E1A\u52A1\u7EF4\u5EA6\u3002\u9996\u5148 entity_search\uFF1B\u786E\u8BA4\u552F\u4E00\u4E3B\u4F53\u540E\u518D\u67E5\u8BE2\u5176\u4F59\u7EF4\u5EA6\u3002\u4EC5\u6309\u56FA\u5B9A\u8DEF\u7531\u6267\u884C\uFF0C\u4E0D\u8BBE\u7F6E\u63D2\u4EF6\u8C03\u7528\u6B21\u6570\u4E0A\u9650\uFF0C\u4E5F\u4E0D\u63A5\u53D7\u52A8\u6001 MCP \u540D\u79F0\u6216\u8DE8\u4F01\u4E1A\u53C2\u6570\u3002\", {\n taskId: { type: \"string\" }, dimension: { type: \"string\", enum: [...Object.keys(QUERY_ROUTES), ...Object.keys(QUERY_ROUTE_ALIASES)] }, personName: { type: \"string\" },\n }, [\"taskId\", \"dimension\"], async (args, exec, agent) => {\n const task = requireTask(args, agent)\n const requestedDimension = string(args.dimension)\n const dimension = (QUERY_ROUTE_ALIASES[requestedDimension as keyof typeof QUERY_ROUTE_ALIASES] ?? requestedDimension) as keyof typeof QUERY_ROUTES\n if (!Object.hasOwn(QUERY_ROUTES, dimension)) throw new Error(\"\u4E0D\u652F\u6301\u7684\u4E1A\u52A1\u7EF4\u5EA6\")\n const skipped = async (reason: string, outcome: \"skipped\" | \"not-executed\" = \"not-executed\") => {\n await recordSyntheticOutcome(task, dimension, outcome, reason)\n const [server, tool] = QUERY_ROUTES[dimension]\n return { taskId: task.id, dimension, toolName: `mcp__qcc_${server}__${tool}`, outcome, reason, used: task.used, unlimited: true }\n }\n if (dimension !== \"entity_search\" && !task.entity) throw new Error(\"\u5FC5\u987B\u5148\u641C\u7D22\u5E76\u7ECF\u7528\u6237\u786E\u8BA4\u552F\u4E00\u6CD5\u5F8B\u5B9E\u4F53\")\n if (dimension === \"entity_search\" && task.entity) throw new Error(\"\u5DF2\u786E\u8BA4\u4E3B\u4F53\uFF1B\u91CD\u65B0\u641C\u7D22\u524D\u8BF7\u5EFA\u7ACB\u5E76\u786E\u8BA4\u65B0\u4EFB\u52A1\")\n const [server, tool] = QUERY_ROUTES[dimension]\n if (server === \"risk\" && dimension !== \"risk_scan\") {\n const count = scanCount(task.risk, dimension, tool)\n if (count === 0) return skipped(\"\u98CE\u9669\u626B\u63CF\u4E3A 0\uFF0C\u65E0\u9700\u4E0B\u94BB\", \"skipped\")\n if (count === undefined) return skipped(\"\u5C1A\u65E0\u53EF\u6838\u9A8C\u7684\u975E\u96F6\u626B\u63CF\u8BA1\u6570\uFF1B\u8BF7\u6838\u5BF9 Provider \u626B\u63CF\u5951\u7EA6\")\n }\n const tools = ctx.tools.schemas(agent).filter(s => s.name === `mcp__qcc_${server}__${tool}` || s.name === `mcp__qcc-${server}__${tool}` || s.name === `mcp__${server}__${tool}`)\n if (tools.length !== 1) return skipped(tools.length ? \"\u5B58\u5728\u591A\u4E2A\u540C\u540D\u6765\u6E90\uFF0C\u8BF7\u68C0\u67E5 MCP \u8FDE\u63A5\" : \"\u6240\u9700 MCP \u670D\u52A1\u672A\u63A5\u5165\u6216\u5DE5\u5177\u63A5\u53E3\u4E0D\u5339\u914D\")\n const selected = tools[0]!\n const properties = selected.parameters?.properties ?? {}\n const queryKey = dimension === \"entity_search\" && \"query\" in properties ? \"query\" : \"searchKey\"\n const parameters: Record<string, unknown> = { [queryKey]: task.entity?.creditCode ?? task.query }\n if (!(queryKey in properties)) return skipped(\"Provider \u67E5\u8BE2\u53C2\u6570\u5951\u7EA6\u4E0D\u5339\u914D\")\n if (dimension === \"executive_risk\") {\n const person = string(args.personName)\n if (!containsName(task.personnel, person)) throw new Error(\"\u8463\u76D1\u9AD8\u59D3\u540D\u5FC5\u987B\u6765\u81EA\u672C\u4E3B\u4F53\u5B9E\u9645\u5173\u952E\u4EBA\u5458\u8FD4\u56DE\")\n parameters.personName = person\n }\n if (selected.parameters?.required?.some(key => !(key in parameters))) return skipped(\"Provider \u9700\u8981\u989D\u5916\u53C2\u6570\uFF0C\u8BF7\u8865\u5BF9\u5E94\u4E1A\u52A1\u9002\u914D\")\n task.busy = true\n const callId = `previsit-${randomUUID()}`\n let runStarted = false\n permits.set(callId, { owner: task.owner, name: selected.name, parent: exec.token })\n try {\n exec.signal.throwIfAborted()\n await workflow.startRun(task.id, { runId: callId, dimension, toolName: selected.name, quotaUsed: true })\n runStarted = true\n task.used += 1\n const result = await ctx.tools.execute({ callId, rootCallId: exec.rootCallId, parent: exec.token, name: selected.name, arguments: parameters, agent, signal: exec.signal })\n for (const context of result.additionalContexts ?? []) exec.deferContext?.(context)\n if (!result.isError && result.concludesTurn) exec.concludeTurn?.()\n exec.signal.throwIfAborted()\n const data = structured(result)\n let outcome = result.isError ? classifyQccProviderOutcome({ code: result.error?.info?.code }, true) : classifyQccProviderOutcome(data)\n // A risk scan with at least one recognized integer count satisfies its\n // business contract even when the Provider omits a generic status/data wrapper.\n if (!result.isError && dimension === \"risk_scan\" && outcome === \"unknown\"\n && RISK_DETAIL_DIMENSIONS.some(detail => scanCount(data, detail, QUERY_ROUTES[detail][1]) !== undefined)) outcome = \"done\"\n const usable = !result.isError && ![\"failed\", \"no-permission\", \"not-executed\", \"no-data\"].includes(outcome)\n if (dimension === \"entity_search\") task.search = usable ? data : null\n if (dimension === \"personnel\") task.personnel = usable ? data : null\n if (dimension === \"risk_scan\") task.risk = usable ? data : null\n await workflow.finishRun(task.id, callId, outcome, result.isError ? result.error?.message ?? \"\u67E5\u8BE2\u5931\u8D25\" : undefined)\n if (dimension === \"risk_scan\" && outcome === \"no-data\") {\n for (const detail of RISK_DETAIL_DIMENSIONS) {\n await recordSyntheticOutcome(task, detail, \"skipped\", \"\u98CE\u9669\u626B\u63CF\u65E0\u8BB0\u5F55\uFF0C\u65E0\u9700\u4E0B\u94BB\")\n }\n } else if (dimension === \"risk_scan\" && usable) {\n for (const detail of RISK_DETAIL_DIMENSIONS) {\n const [, detailTool] = QUERY_ROUTES[detail]\n const count = scanCount(data, detail, detailTool)\n if (count === 0) await recordSyntheticOutcome(task, detail, \"skipped\", \"\u98CE\u9669\u626B\u63CF\u4E3A 0\uFF0C\u65E0\u9700\u4E0B\u94BB\")\n else if (count === undefined) await recordSyntheticOutcome(task, detail, \"not-executed\", \"\u98CE\u9669\u626B\u63CF\u672A\u8FD4\u56DE\u53EF\u6620\u5C04\u8BA1\u6570\uFF0C\u65E0\u6CD5\u5224\u5B9A\u662F\u5426\u9700\u8981\u4E0B\u94BB\")\n else await recordSyntheticOutcome(task, detail, \"not-executed\", `\u98CE\u9669\u626B\u63CF\u547D\u4E2D ${count} \u6761\uFF0C\u7B49\u5F85\u660E\u7EC6\u4E0B\u94BB`, true)\n }\n }\n if (dimension === \"personnel\" && outcome === \"no-data\") {\n await recordSyntheticOutcome(task, \"executive_risk\", \"skipped\", \"\u672A\u53D6\u5F97\u53EF\u6838\u9A8C\u5173\u952E\u4EBA\u5458\uFF0C\u65E0\u9700\u6267\u884C\u8463\u76D1\u9AD8\u98CE\u9669\u626B\u63CF\")\n } else if (dimension === \"personnel\" && (outcome === \"done\" || outcome === \"unknown\")) {\n await recordSyntheticOutcome(task, \"executive_risk\", \"not-executed\", \"\u5DF2\u53D6\u5F97\u5173\u952E\u4EBA\u5458\uFF0C\u7B49\u5F85\u8463\u76D1\u9AD8\u98CE\u9669\u626B\u63CF\", true)\n }\n return { taskId: task.id, dimension, ...(requestedDimension === dimension ? {} : { requestedDimension }), toolName: selected.name, outcome, used: task.used, unlimited: true, data: result.isError ? { message: result.error?.message ?? \"\u67E5\u8BE2\u5931\u8D25\" } : data }\n } catch (error) {\n if (runStarted) await workflow.finishRun(task.id, callId, \"failed\", error instanceof Error ? error.message : String(error)).catch(() => {})\n throw error\n } finally { permits.delete(callId); task.busy = false }\n })\n register(\"previsit_finalize\", \"\u4FDD\u5B58\u5DF2\u7ECF\u5B8C\u6210\u7684\u516B\u6BB5\u8BBF\u524D\u5C3D\u8C03\u62A5\u544A\u3001\u751F\u6210\u53EF\u4E0B\u8F7D\u5236\u54C1\u5E76\u7ED3\u675F\u4EFB\u52A1\u3002\u8C03\u7528\u540E\u4ECD\u987B\u628A\u540C\u4E00\u62A5\u544A\u6B63\u6587\u56DE\u590D\u7ED9\u7528\u6237\u3002\", {\n taskId: { type: \"string\" }, reportMarkdown: { type: \"string\", maxLength: 240000 }, status: { type: \"string\", enum: [\"completed\", \"partial\"] },\n }, [\"taskId\", \"reportMarkdown\"], async (args, exec, agent) => {\n const task = requireTask(args, agent)\n if (task.entity === undefined) throw new Error(\"\u5FC5\u987B\u5148\u786E\u8BA4\u552F\u4E00\u6CD5\u5F8B\u5B9E\u4F53\")\n const reportMarkdown = validatePrevisitReport(reportString(args.reportMarkdown), task.entity.fullName)\n const current = await workflow.get(task.id)\n if (current === undefined) throw new Error(\"\u8BBF\u524D\u4EFB\u52A1\u4E0D\u5B58\u5728\")\n const closure = previsitVerificationClosure(current)\n if (closure.gaps.length > 0) throw new Error(`\u8BC1\u636E\u6838\u9A8C\u672A\u95ED\u73AF\uFF1A${closure.gaps.join(\"\uFF1B\")}\u3002\u5B8C\u6210\u67E5\u8BE2\uFF0C\u6216\u8BB0\u5F55\u660E\u786E\u5931\u8D25/\u65E0\u9700\u6267\u884C\u540E\u518D\u751F\u6210\u62A5\u544A`)\n exec.signal.throwIfAborted()\n const status = args.status === \"partial\" || closure.partialRequired ? \"partial\" : \"completed\"\n const record = await workflow.finalize(task.id, reportMarkdown, status)\n return {\n taskId: task.id,\n status: record.state,\n used: record.used,\n unlimited: true,\n entity: record.entity,\n artifact: record.artifact,\n reportUrl: `/previsit/api/tasks/${encodeURIComponent(task.id)}/report?sessionId=${encodeURIComponent(agent.session.id)}`,\n }\n })\n return () => {\n disposed = true\n for (const controller of controllers) controller.abort()\n for (const dispose of disposers.reverse()) dispose()\n tasks.clear(); permits.clear(); beginning.clear()\n }\n}\n", "export type ToolOutcome = \"running\" | \"done\" | \"no-data\" | \"skipped\" | \"no-permission\" | \"not-executed\" | \"failed\" | \"unknown\"\nexport const TOOL_OUTCOME_LABELS: Record<ToolOutcome, string> = {\n running: \"\u67E5\u8BE2\u4E2D\", done: \"\u67E5\u8BE2\u6210\u529F\", \"no-data\": \"\u65E0\u6570\u636E\", skipped: \"\u65E0\u9700\u6267\u884C\", \"no-permission\": \"\u65E0\u6743\u9650\",\n \"not-executed\": \"\u672A\u6267\u884C\", failed: \"\u67E5\u8BE2\u5931\u8D25\", unknown: \"\u7ED3\u679C\u5F85\u6838\u9A8C\",\n}\n\n/** Interpret explicit structured signals only. A successful transport is not proof of facts. */\nexport function classifyToolOutcome(value: unknown, isError = false): ToolOutcome {\n if (value !== null && typeof value === \"object\" && !Array.isArray(value)) {\n const data = value as Record<string, unknown>\n const code = data.code ?? (data.error as { code?: unknown } | undefined)?.code\n if ([401, 403, \"401\", \"403\", \"FORBIDDEN\", \"UNAUTHORIZED\", \"PERMISSION_DENIED\"].includes(code as string)) return \"no-permission\"\n if (code === \"SKIPPED\") return \"skipped\"\n if ([\"UNKNOWN_TOOL\", \"ABORTED_BEFORE_DISPATCH\", \"NOT_EXECUTED\"].includes(code as string)) return \"not-executed\"\n if (data.status === \"skipped\" || data.status === \"no-permission\" || data.status === \"not-executed\") return data.status\n if (isError || data.isError === true || data.success === false || data.error != null) return \"failed\"\n if (data.status === \"failed\") return \"failed\"\n if (data.status === \"no-data\" || data.total === 0 || data.count === 0) return \"no-data\"\n if (\"data\" in data) return classifyToolOutcome(data.data)\n for (const key of [\"items\", \"records\", \"results\"]) if (Array.isArray(data[key])) return classifyToolOutcome(data[key])\n if (data.status === \"done\" || data.success === true) return \"done\"\n }\n if (isError) return \"failed\"\n if (Array.isArray(value)) return value.length === 0 ? \"no-data\" : \"done\"\n return \"unknown\"\n}\n\nconst QCC_NO_PERMISSION = /\u65E0\u6743\u9650|\u6743\u9650\u4E0D\u8DB3|\u672A\u6388\u6743|\u65E0\u6743\u8BBF\u95EE/u\nconst QCC_FAILURE = /\u67E5\u8BE2\u5931\u8D25|\u670D\u52A1\u5F02\u5E38|\u683C\u5F0F\u9519\u8BEF|\u5730\u57DF\u9650\u5236/u\nconst QCC_NO_DATA = /\u672A\u5339\u914D|\u672A\u53D1\u73B0(?:\u4EFB\u4F55|\u76F8\u5173)?\u8BB0\u5F55|\u6682\u65E0(?:\u76F8\u5173)?\u6570\u636E|\u65E0\u5339\u914D\u9879/u\n\n/**\n * QCC tools return reader-facing Chinese business objects instead of a generic\n * success/data envelope. A non-error, non-empty QCC object is a completed\n * query; explicit empty/error copy still wins over that fallback.\n */\nexport function classifyQccProviderOutcome(value: unknown, isError = false): ToolOutcome {\n const generic = classifyToolOutcome(value, isError)\n if (generic !== \"unknown\") return generic\n if (value === null || typeof value !== \"object\" || Array.isArray(value)) return generic\n const data = value as Record<string, unknown>\n const messages = [data[\"\u65E0\u5339\u914D\u9879\"], data[\"\u641C\u7D22\u7ED3\u679C\"], data[\"\u63D0\u793A\"], data[\"\u6D88\u606F\"]]\n .filter((item): item is string => typeof item === \"string\")\n .join(\"\\n\")\n if (QCC_NO_PERMISSION.test(messages)) return \"no-permission\"\n if (QCC_FAILURE.test(messages) || \"\u683C\u5F0F\u9519\u8BEF\" in data || \"\u5730\u57DF\u9650\u5236\" in data) return \"failed\"\n if (QCC_NO_DATA.test(messages) || \"\u65E0\u5339\u914D\u9879\" in data) return \"no-data\"\n return Object.keys(data).length > 0 ? \"done\" : \"unknown\"\n}\n\nexport function resultOutcome(node: { isError?: boolean; content?: unknown; value?: unknown; error?: unknown }): ToolOutcome {\n if (node.error !== undefined) return classifyToolOutcome({ error: node.error }, true)\n if (node.value !== undefined) return classifyToolOutcome(node.value, node.isError)\n if (Array.isArray(node.content)) {\n const texts = node.content.filter((b): b is { type: string; text: string } => b?.type === \"text\" && typeof b.text === \"string\")\n if (texts.length === 1) {\n try { return classifyToolOutcome(JSON.parse(texts[0]!.text), node.isError) } catch { /* not structured */ }\n }\n }\n return classifyToolOutcome(node.content, node.isError)\n}\n\nexport function toolEvent(node: { call: { name: string }; isError?: boolean; content?: unknown; error?: unknown }): { name: string; status: ToolOutcome; reason?: string } {\n const fallback = { name: node.call.name, status: resultOutcome(node) }\n if (node.isError || !Array.isArray(node.content) || node.content.length !== 1 || node.content[0]?.type !== \"text\") return fallback\n try {\n const value = JSON.parse(node.content[0].text)\n if (node.call.name === \"previsit_query\" && typeof value.toolName === \"string\" && Object.hasOwn(TOOL_OUTCOME_LABELS, value.outcome)) {\n return { name: value.toolName, status: value.outcome, ...(typeof value.reason === \"string\" ? { reason: value.reason } : {}) }\n }\n if ((node.call.name === \"previsit_begin\" && value.status === \"needs-entity-search\") || (node.call.name === \"previsit_confirm_entity\" && value.status === \"entity-confirmed\")) return { name: node.call.name, status: \"done\" }\n } catch { /* Unrecognized content stays unknown/failed. */ }\n return fallback\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["h", "normalized", "run", "sessionId", "randomUUID", "randomUUID", "server", "tool"]
|
|
7
7
|
}
|
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
import type { HostedTask } from "./hosted-task-sync.js";
|
|
2
|
+
export type HostedTaskListScope = {
|
|
3
|
+
kind: "current";
|
|
4
|
+
sessionId: string;
|
|
5
|
+
} | {
|
|
6
|
+
kind: "profile-history";
|
|
7
|
+
};
|
|
8
|
+
/** Shared TaskScope contract: current work is Session-scoped; history is Profile-scoped. */
|
|
9
|
+
export declare function hostedTaskListUrl(scope: HostedTaskListScope): string;
|
|
2
10
|
export declare function fetchHostedTask(taskId: string, sessionId: string): Promise<HostedTask | null>;
|
|
3
|
-
|
|
4
|
-
export declare function fetchHostedTasks(sessionId?: string): Promise<HostedTask[]>;
|
|
11
|
+
export declare function fetchHostedTasks(scope: HostedTaskListScope): Promise<HostedTask[]>;
|
|
@@ -6,6 +6,14 @@ export type HostedTask = Omit<PrevisitTaskRecord, "reportMarkdown"> & {
|
|
|
6
6
|
reportReady: boolean;
|
|
7
7
|
reportMarkdown?: string;
|
|
8
8
|
};
|
|
9
|
+
export type HostedTaskOrigin = {
|
|
10
|
+
workspace: string;
|
|
11
|
+
sessionId: string;
|
|
12
|
+
label: string;
|
|
13
|
+
complete: boolean;
|
|
14
|
+
};
|
|
15
|
+
/** Never infer missing legacy origin metadata or bind it to the active Session. */
|
|
16
|
+
export declare function hostedTaskOrigin(task: Pick<HostedTask, "workspace" | "sessionId">): HostedTaskOrigin;
|
|
9
17
|
export declare const HOSTED_TERMINAL: Set<string>;
|
|
10
18
|
export type HostedLiveProgress = {
|
|
11
19
|
title: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-pre-duediligence",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.23",
|
|
4
4
|
"description": "Pre-visit due diligence and company research in DeepSeek Harness with Host-tracked progress, fixed-route Qichacha MCP calls, entity confirmation, and downloadable reports.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -5,7 +5,7 @@ whenToUse: 用户要求准备客户拜访、访前尽调、一页纸简报、授
|
|
|
5
5
|
user-invocable: true
|
|
6
6
|
metadata:
|
|
7
7
|
author: QCC
|
|
8
|
-
version: 0.1.
|
|
8
|
+
version: 0.1.23
|
|
9
9
|
---
|
|
10
10
|
|
|
11
11
|
# 访前尽调
|
|
@@ -54,7 +54,7 @@ metadata:
|
|
|
54
54
|
|
|
55
55
|
## MCP 就绪检查
|
|
56
56
|
|
|
57
|
-
### Agent-owned 执行门(0.1.
|
|
57
|
+
### Agent-owned 执行门(0.1.23)
|
|
58
58
|
|
|
59
59
|
只在从“访前尽调”入口创建的专属 Session 内执行。首先调用 `previsit_begin`,传入用户提供的企业检索词和 fast / standard / deep 档位;提示中含“访前任务 ID:PV-...”时,必须原样作为 `requestId` 传入。用户发送任务已经构成本任务在固定业务路由内连续执行的明确授权,禁止再询问是否允许调用企查查 MCP,也不要弹出调用次数或额度二次确认。插件不设 8 / 18 / 40 次硬上限。
|
|
60
60
|
|