dsh-tender-workbench 0.5.9 → 0.5.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -0
- package/README.en.md +7 -7
- package/README.md +10 -8
- package/docs/RELEASE-0.5.11.md +25 -0
- package/lib/client.js +210 -3
- package/lib/client.js.map +1 -1
- package/lib/index.js +43 -9
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/client/initial-draft-host.d.ts +5 -0
- package/lib/types/client/initial-draft-host.d.ts.map +1 -0
- package/lib/types/client/initial-draft.d.ts +17 -0
- package/lib/types/client/initial-draft.d.ts.map +1 -0
- package/lib/types/client/submission-reveal.d.ts +16 -0
- package/lib/types/client/submission-reveal.d.ts.map +1 -0
- package/lib/types/client/tender-prompt.d.ts.map +1 -1
- package/lib/types/contracts/initial-draft.d.ts +12 -0
- package/lib/types/contracts/initial-draft.d.ts.map +1 -0
- package/lib/types/contracts/query-schema.d.ts.map +1 -1
- package/lib/types/contracts/tool-inputs.d.ts.map +1 -1
- package/lib/types/host/projection.d.ts.map +1 -1
- package/lib/types/host/skills/global-invariants.d.ts.map +1 -1
- package/lib/types/host/tool-contract.d.ts +2 -0
- package/lib/types/host/tool-contract.d.ts.map +1 -1
- package/lib/types/host/tools/query-tool.d.ts.map +1 -1
- package/package.json +2 -2
- package/docs/RELEASE-0.5.9.md +0 -10
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,19 @@ All notable changes to `dsh-tender-workbench` are documented in this file.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.5.11] - 2026-09-15
|
|
8
|
+
|
|
9
|
+
- 采用 UX-49:仅业务入口新建 Session 预填一次原生可编辑引导;双快照保护草稿、附件、IME 与晚到回调,不抢焦点、不自动发送/调用工具/开台,清空及历史恢复不补回。
|
|
10
|
+
- 以稳定模板 ID、版本和精确指纹区分未改系统引导与用户内容;缺项/未替换占位符由本业务澄清,空条件不能发起查询。
|
|
11
|
+
- 普通对话不实例化空业务 Projection;保留 UX-48 接纳后展开、只读 Profile 历史、来源归属、真实 progress、人工复核与不可变交付。
|
|
12
|
+
- 补原生宿主 present/absent、四插件草稿隔离及重启恢复回归,记录公开输入能力缺失时安全跳过的兼容边界。
|
|
13
|
+
|
|
14
|
+
## [0.5.10] - 2026-09-14
|
|
15
|
+
|
|
16
|
+
- Open the current tender workbench once after Host-observed submission admission. Prompt draft fill, failed sends, restored history and later model events do not open it.
|
|
17
|
+
- Preserve session isolation, original admission callbacks and manual closure; contain optional sidebar failures.
|
|
18
|
+
|
|
19
|
+
|
|
7
20
|
## [0.5.9] - 2026-09-14
|
|
8
21
|
|
|
9
22
|
- 按 DSH-UX-001 1.5.4 删除首页副标题及占位,保留原生工作区、模式、输入框和业务导航。
|
package/README.en.md
CHANGED
|
@@ -10,9 +10,9 @@ Related agents: [数据清洗补全](https://github.com/duhu2000/dsh-data-cleani
|
|
|
10
10
|
|
|
11
11
|
`dsh-tender-workbench` is an open-source DeepSeek Harness plugin for finding, screening, reviewing, and delivering tender opportunities. It combines authorized `qcc-tender` data, deterministic screening rules, bounded Agent analysis, explicit human decisions, and immutable Excel/PDF reports in one Session-scoped Better Sidebar workbench.
|
|
12
12
|
|
|
13
|
-
Current stable version: **0.5.
|
|
13
|
+
Current stable version: **0.5.11** (stable release).
|
|
14
14
|
|
|
15
|
-
Version 0.5.
|
|
15
|
+
Version 0.5.11 adds a one-time native introductory draft for new tender Sessions. Existing text, attachments, IME composition and user-cleared drafts are protected; initialization never sends, calls tools or opens the workbench. UX-48 admission reveal, Profile history and actual execution telemetry are retained. See the [release record](docs/RELEASE-0.5.11.md) for publication status and verification boundaries.
|
|
16
16
|
|
|
17
17
|
Base mode targets the full DSH 0.1.2-rc.1 distribution; Better Sidebar 0.18.1 is optional and only provides the visual workbench. Legacy hosts remain unsupported. Back up the complete Profile and verify dependencies before upgrading.
|
|
18
18
|
|
|
@@ -84,11 +84,11 @@ dsh web --no-open
|
|
|
84
84
|
|
|
85
85
|
Optionally enable the visual workbench with `dsh plugin --profile web add dsh-better-sidebar@0.18.1`, enable the tender Tab and fully restart the Profile.
|
|
86
86
|
|
|
87
|
-
To install the exact 0.5.
|
|
87
|
+
To install the exact 0.5.11 release:
|
|
88
88
|
|
|
89
89
|
```sh
|
|
90
90
|
dsh plugin --profile web add 'dsh-mcp-connector@>=0.2.31'
|
|
91
|
-
dsh plugin --profile web add dsh-tender-workbench@0.5.
|
|
91
|
+
dsh plugin --profile web add dsh-tender-workbench@0.5.11
|
|
92
92
|
```
|
|
93
93
|
|
|
94
94
|
To install base mode from an independent checkout:
|
|
@@ -105,7 +105,7 @@ To install a packed build:
|
|
|
105
105
|
|
|
106
106
|
```sh
|
|
107
107
|
dsh plugin --profile web add 'dsh-mcp-connector@>=0.2.31'
|
|
108
|
-
dsh plugin --profile web add ./dsh-tender-workbench-0.5.
|
|
108
|
+
dsh plugin --profile web add ./dsh-tender-workbench-0.5.11.tgz
|
|
109
109
|
dsh web --no-open
|
|
110
110
|
```
|
|
111
111
|
|
|
@@ -122,11 +122,11 @@ dsh plugin --profile web remove dsh-tender-workbench
|
|
|
122
122
|
Upgrade an existing installation by installing the stable version and fully restarting the Web profile:
|
|
123
123
|
|
|
124
124
|
```sh
|
|
125
|
-
dsh plugin --profile web add dsh-tender-workbench@0.5.
|
|
125
|
+
dsh plugin --profile web add dsh-tender-workbench@0.5.11
|
|
126
126
|
dsh web --no-open
|
|
127
127
|
```
|
|
128
128
|
|
|
129
|
-
Version 0.5.
|
|
129
|
+
Version 0.5.11 retains Workspace ownership, the ordinary Session guard and the 0.5.6 snapshotEvents/turn-start authorization contract. Business state remains Session-local; Profile history stores metadata only, never writable projections or download capabilities. Existing unopened Sessions are not scanned: reopening indexes their current task, without restoring old snapshots. Back up the Profile's `.dsh-tender-workbench/history-v1.json` alongside task directories. Live MCP is not verified. Roll back the complete backed-up host/plugin combination, not an old plugin alone on the new host.
|
|
130
130
|
|
|
131
131
|
## Using the workbench
|
|
132
132
|
|
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
招投标智能体:支持招投标搜索、招标查询、投标查询、标讯查询、拟建项目与项目筛选,辅助商机发现、人工复核及 Excel/PDF 导出,使用客户自备授权的企查查 MCP。
|
|
8
8
|
|
|
9
9
|
```sh
|
|
10
|
-
dsh plugin --profile web add dsh-tender-workbench@0.5.
|
|
10
|
+
dsh plugin --profile web add dsh-tender-workbench@0.5.11
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
请先满足下文的 DSH、连接器及侧边栏依赖要求;安装后完整停止并重启对应 Profile。
|
|
@@ -27,9 +27,9 @@ dsh plugin --profile web add dsh-tender-workbench@0.5.9
|
|
|
27
27
|
|
|
28
28
|
> 面向国内招投标团队的 DeepSeek Harness 开源智能体插件:在一个会话级工作台内完成标讯与拟建项目查询、确定性规则初筛、限定范围智能分析、人工复核,以及 Excel/PDF 报告交付。
|
|
29
29
|
>
|
|
30
|
-
> 当前稳定版本:**0.5.
|
|
30
|
+
> 当前稳定版本:**0.5.11**(正式版本)
|
|
31
31
|
|
|
32
|
-
0.5.
|
|
32
|
+
0.5.11 新增 UX-49 一次性原生首页引导,保护已有文字、附件、IME 输入和用户清空;不自动发送、调用工具或打开工作台。保留 UX-48 接纳后展开、Profile 历史和真实执行进度。发布状态及验收边界见 [发布记录](docs/RELEASE-0.5.11.md)。
|
|
33
33
|
|
|
34
34
|
[](https://github.com/duhu2000/dsh-tender-workbench/actions/workflows/ci.yml)
|
|
35
35
|
[](https://www.npmjs.com/package/dsh-tender-workbench)
|
|
@@ -39,6 +39,8 @@ dsh plugin --profile web add dsh-tender-workbench@0.5.9
|
|
|
39
39
|
|
|
40
40
|
## 产品简介
|
|
41
41
|
|
|
42
|
+
UX-49 一次性原生首页引导只对本菜单新建的空业务 Session 生效,不覆盖已有文字/附件、IME 输入或清空后的草稿;不自动查询或打开工作台。依赖 DSH 0.1.2-rc.1 公开输入 shell、编辑器状态与可写浏览器存储,能力缺失时跳过预填。采用与验收边界见 [UX-49 采用记录](https://github.com/duhu2000/dsh-tender-workbench/blob/main/docs/UX49-INITIAL-DRAFT-ADOPTION.md)。
|
|
43
|
+
|
|
42
44
|
`dsh-tender-workbench` 是 DeepSeek Harness 的 Host + Client 插件,适合需要持续发现、筛选、复核和交付招投标机会的国内业务团队。插件连接客户已安装并授权的 `qcc-tender` MCP,以结构化标讯事实为基础,将规则判断、Agent 建议和人工决策明确分开,形成可追溯的工作流。
|
|
43
45
|
|
|
44
46
|
完整业务闭环为:
|
|
@@ -75,10 +77,10 @@ dsh web --no-open
|
|
|
75
77
|
|
|
76
78
|
需要可视化工作台时,再自选安装 `dsh plugin --profile web add dsh-better-sidebar@0.18.1`、在宿主设置启用招投标 Tab,并完整重启。无需侧栏也可使用下方列明的基础功能。
|
|
77
79
|
|
|
78
|
-
安装指定的 `0.5.
|
|
80
|
+
安装指定的 `0.5.11` 版本:
|
|
79
81
|
|
|
80
82
|
```sh
|
|
81
|
-
dsh plugin --profile web add dsh-tender-workbench@0.5.
|
|
83
|
+
dsh plugin --profile web add dsh-tender-workbench@0.5.11
|
|
82
84
|
```
|
|
83
85
|
|
|
84
86
|
移除插件:
|
|
@@ -146,11 +148,11 @@ node scripts/check-host-compatibility.mjs --host-root /实际路径/node_modules
|
|
|
146
148
|
从已有版本升级:
|
|
147
149
|
|
|
148
150
|
```sh
|
|
149
|
-
dsh plugin --profile web add dsh-tender-workbench@0.5.
|
|
151
|
+
dsh plugin --profile web add dsh-tender-workbench@0.5.11
|
|
150
152
|
dsh web --no-open
|
|
151
153
|
```
|
|
152
154
|
|
|
153
|
-
0.5.
|
|
155
|
+
0.5.11 保留 Workspace 归组、0.5.6 可选侧栏与 `snapshotEvents()` / `turn/start` 授权绑定。业务任务仍属于原 Session;Profile 历史只存摘要,不复制旧 projection,也不自动搬迁未分组任务。旧会话在重新打开后才补入当前任务摘要,历史页不恢复旧快照到当前任务。索引位于对应 Profile 的 `.dsh-tender-workbench/history-v1.json`,备份时一并保留。真实 MCP 连接未核验。回退应恢复备份的完整已验证宿主/插件组合,不能在新版宿主上单独安装原始 0.5.4 或更早版本。
|
|
154
156
|
|
|
155
157
|
## 本地开发
|
|
156
158
|
|
|
@@ -165,7 +167,7 @@ corepack pnpm@11.7.0 run check
|
|
|
165
167
|
|
|
166
168
|
`check` 会执行类型检查、完整 Vitest 测试、生产构建、README/发布状态校验以及 npm tarball 白名单预检。配置 npm Trusted Publishing 后,[发布工作流](.github/workflows/release.yml)可使用 OIDC 和 provenance;手工发布不得声称 provenance。
|
|
167
169
|
|
|
168
|
-
省、市、区数据源快照维护在 [resources/area.ts](resources/area.ts)。版本变更见 [CHANGELOG.md](CHANGELOG.md),发布检查见 [0.5.
|
|
170
|
+
省、市、区数据源快照维护在 [resources/area.ts](resources/area.ts)。版本变更见 [CHANGELOG.md](CHANGELOG.md),发布检查见 [0.5.11 发布清单](docs/RELEASE-0.5.11.md)。
|
|
169
171
|
|
|
170
172
|
## 界面演示与市场投稿
|
|
171
173
|
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# 招投标 0.5.11 发布记录
|
|
2
|
+
|
|
3
|
+
Version: **0.5.11**
|
|
4
|
+
Status: **ready for release**
|
|
5
|
+
|
|
6
|
+
本轮在用户明确授权 commit、push、tag、npm 后发布 UX-49(PR #8)。原实现提交 e4b3e4bf21f7f4f423128333a709460f53256f3f 已通过 PR CI;本次同步版本及资料,不修改业务实现。
|
|
7
|
+
|
|
8
|
+
## 更新
|
|
9
|
+
|
|
10
|
+
- 仅本菜单新建的业务 Session 预填一次原生可编辑引导,采用第 11.1 节招投标文案。
|
|
11
|
+
- 双快照检查就绪状态、空草稿/附件、IME 与 Session;异步迟到、用户清空、刷新、重挂载及旧会话不覆盖或补回,不抢焦点。
|
|
12
|
+
- 稳定模板 ID、版本与精确指纹;修改后的内容按用户草稿处理。占位符或缺项先澄清,Host 查询防线拒绝无效条件,不调用 Provider。
|
|
13
|
+
- 不自动发送、创建任务或展开工作台,保留 UX-48 接纳后展开、只读 Profile 历史、origin、真实 progress、人工定案和不可变 Excel/PDF 快照。
|
|
14
|
+
|
|
15
|
+
## 验证与边界
|
|
16
|
+
|
|
17
|
+
实施门禁:311 passed / 1 平台条件 skipped,8 个 UI 场景通过。真实 DSH 0.1.2-rc.1 独立 Profile 下 Sidebar 0.18.1 present/absent、清空刷新、Host 重启及四插件隔离均通过;组合为清洗 0.9.15、尽调 0.1.35、填表 0.2.30。真实 Host 工具使用合成 Provider,验证了人工复核和 Excel/PDF 文件链路,不代表真实收费 MCP 或模型已验证。操作系统中文输入法候选交互仍需人工验收。
|
|
18
|
+
|
|
19
|
+
公开 input shell/编辑器能力、可写浏览器存储缺失或 5 秒未就绪时安全跳过引导,不做 DOM 回退。Projection 缓存版本为 4,宿主从原日志重放;不迁移或重写 Profile 历史及交付文件。完整采用记录见仓库 docs/UX49-INITIAL-DRAFT-ADOPTION.md。
|
|
20
|
+
|
|
21
|
+
## 发布与升级
|
|
22
|
+
|
|
23
|
+
使用 v0.5.11 tag 触发 release.yml,Linux Node 24 执行完整门禁后通过 npm Trusted Publishing/OIDC 发布,附带 provenance;随后由既有工作流生成 GitHub Release。发布成功以 Actions 和 npm registry 的实际结果为准。
|
|
24
|
+
|
|
25
|
+
升级前备份完整 Profile;执行 `dsh plugin --profile web add dsh-tender-workbench@0.5.11` 后完整重启对应 dsh web。既有会话不会补回初始模板,需从「招投标」菜单新建业务 Session 验证。回滚使用完整已验证 Profile 备份。
|
package/lib/client.js
CHANGED
|
@@ -5125,8 +5125,27 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
5125
5125
|
rows: array(NormalizedProjectV1Schema).max(100)
|
|
5126
5126
|
}).strict();
|
|
5127
5127
|
//#endregion
|
|
5128
|
+
//#region src/contracts/initial-draft.ts
|
|
5129
|
+
/** UX-49: versioned copy, not a prompt, task, or query authorization. */
|
|
5130
|
+
const TENDER_INITIAL_DRAFT = {
|
|
5131
|
+
id: "dsh-initial-draft/dsh-tender-workbench/1",
|
|
5132
|
+
version: 1,
|
|
5133
|
+
fingerprint: "sha256:f2bf291eec74a12873fb6178362b61ed032f50389186bc82eec9462fd0e745ed",
|
|
5134
|
+
text: "请帮我查找并评估招投标机会。请填写行业、地区、时间范围和筛选条件,也可点击左上角「提示词生成」整理查询口径。例如:查找近 30 天【地区】软件和数据服务相关招标项目,排除已截止项目,形成候选清单。"
|
|
5135
|
+
};
|
|
5136
|
+
/** Exact bytes only: no trimming, fuzzy matching, or substring exclusion. */
|
|
5137
|
+
function isTenderInitialDraft(text) {
|
|
5138
|
+
return text === TENDER_INITIAL_DRAFT.text;
|
|
5139
|
+
}
|
|
5140
|
+
function hasUnresolvedTenderPlaceholder(value) {
|
|
5141
|
+
if (typeof value === "string") return /【[^】]*】/u.test(value);
|
|
5142
|
+
if (Array.isArray(value)) return value.some(hasUnresolvedTenderPlaceholder);
|
|
5143
|
+
if (typeof value === "object" && value !== null) return Object.values(value).some(hasUnresolvedTenderPlaceholder);
|
|
5144
|
+
return false;
|
|
5145
|
+
}
|
|
5146
|
+
//#endregion
|
|
5128
5147
|
//#region src/contracts/query-schema.ts
|
|
5129
|
-
const shortText = string$1().trim().min(1).max(128);
|
|
5148
|
+
const shortText = string$1().trim().min(1).max(128).refine((value) => !hasUnresolvedTenderPlaceholder(value), "请先替换【】占位符,再查询。");
|
|
5130
5149
|
const dateText = string$1().regex(/^\d{4}-\d{2}-\d{2}$/u);
|
|
5131
5150
|
const optionalAmount = number().finite().nonnegative().optional();
|
|
5132
5151
|
const QccTenderSearchArgsSchema = object({
|
|
@@ -5160,7 +5179,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
5160
5179
|
investmentMax: optionalAmount
|
|
5161
5180
|
}).strict();
|
|
5162
5181
|
function hasSupportedQueryFilter(value) {
|
|
5163
|
-
return Object.
|
|
5182
|
+
return Object.entries(value).some(([key, entry]) => key !== "smartSort" && (Array.isArray(entry) ? entry.length > 0 : entry !== void 0 && entry !== ""));
|
|
5164
5183
|
}
|
|
5165
5184
|
//#endregion
|
|
5166
5185
|
//#region src/contracts/screening.ts
|
|
@@ -28730,6 +28749,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
28730
28749
|
}
|
|
28731
28750
|
/** Replace only an intact previous generated block; edited/manual text needs a choice. */
|
|
28732
28751
|
function planTenderDraftFill(current, generated, previous) {
|
|
28752
|
+
if (isTenderInitialDraft(current)) return generated;
|
|
28733
28753
|
if (!current.trim()) return generated;
|
|
28734
28754
|
if (previous && current.includes(previous)) return current.replace(previous, generated);
|
|
28735
28755
|
}
|
|
@@ -28990,6 +29010,182 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
28990
29010
|
});
|
|
28991
29011
|
}
|
|
28992
29012
|
//#endregion
|
|
29013
|
+
//#region src/client/submission-reveal.ts
|
|
29014
|
+
/** Observe Host admission, never draft edits, model output, or restored history. */
|
|
29015
|
+
function installTenderSubmissionReveal(sessions, reveal) {
|
|
29016
|
+
let stop = () => {};
|
|
29017
|
+
let current;
|
|
29018
|
+
let active = true;
|
|
29019
|
+
let bound;
|
|
29020
|
+
const connect = () => {
|
|
29021
|
+
const id = sessions.list.getSnapshot().current;
|
|
29022
|
+
const face = id === void 0 ? void 0 : sessions.binding(id)?.session;
|
|
29023
|
+
if (id === current && face === bound) return;
|
|
29024
|
+
stop();
|
|
29025
|
+
stop = () => {};
|
|
29026
|
+
current = id;
|
|
29027
|
+
bound = face;
|
|
29028
|
+
if (!id || !isTenderEntrySessionId(id) || typeof face?.beginSubmission !== "function") return;
|
|
29029
|
+
const original = face.beginSubmission;
|
|
29030
|
+
const wrapped = function(input) {
|
|
29031
|
+
let retired = false;
|
|
29032
|
+
return original.call(this, {
|
|
29033
|
+
...input,
|
|
29034
|
+
onRetire: (settlement) => {
|
|
29035
|
+
try {
|
|
29036
|
+
input.onRetire?.(settlement);
|
|
29037
|
+
} finally {
|
|
29038
|
+
if (!retired) {
|
|
29039
|
+
retired = true;
|
|
29040
|
+
if (settlement.reason === "observed" && active && sessions.list.getSnapshot().current === id) try {
|
|
29041
|
+
reveal(id);
|
|
29042
|
+
} catch {}
|
|
29043
|
+
}
|
|
29044
|
+
}
|
|
29045
|
+
}
|
|
29046
|
+
});
|
|
29047
|
+
};
|
|
29048
|
+
face.beginSubmission = wrapped;
|
|
29049
|
+
stop = () => {
|
|
29050
|
+
if (face.beginSubmission === wrapped) face.beginSubmission = original;
|
|
29051
|
+
};
|
|
29052
|
+
};
|
|
29053
|
+
const unsubscribe = sessions.list.subscribe?.(connect);
|
|
29054
|
+
connect();
|
|
29055
|
+
return () => {
|
|
29056
|
+
active = false;
|
|
29057
|
+
unsubscribe?.();
|
|
29058
|
+
stop();
|
|
29059
|
+
};
|
|
29060
|
+
}
|
|
29061
|
+
//#endregion
|
|
29062
|
+
//#region src/client/initial-draft.ts
|
|
29063
|
+
/** Entry-issued capability only. No mount/history observer may create a permit. */
|
|
29064
|
+
function initializeTenderDraft(sessionId, port, storage, schedule = queueMicrotask) {
|
|
29065
|
+
const key = `${TENDER_INITIAL_DRAFT.id}/session/${sessionId}`;
|
|
29066
|
+
let alive = true;
|
|
29067
|
+
let off = () => {};
|
|
29068
|
+
const stop = () => {
|
|
29069
|
+
alive = false;
|
|
29070
|
+
off();
|
|
29071
|
+
};
|
|
29072
|
+
if (!isTenderEntrySessionId(sessionId)) return stop;
|
|
29073
|
+
try {
|
|
29074
|
+
if (storage.getItem(key) !== null) return stop;
|
|
29075
|
+
storage.setItem(key, JSON.stringify({
|
|
29076
|
+
status: "reserved",
|
|
29077
|
+
...TENDER_INITIAL_DRAFT,
|
|
29078
|
+
text: void 0
|
|
29079
|
+
}));
|
|
29080
|
+
} catch {
|
|
29081
|
+
return stop;
|
|
29082
|
+
}
|
|
29083
|
+
const safe = (s) => s.current === sessionId && !s.composing && s.draft === "" && s.revision === 0 && s.attachments === 0 && s.plain;
|
|
29084
|
+
const check = () => {
|
|
29085
|
+
if (!alive) return;
|
|
29086
|
+
let first;
|
|
29087
|
+
try {
|
|
29088
|
+
first = port.snapshot();
|
|
29089
|
+
} catch {
|
|
29090
|
+
stop();
|
|
29091
|
+
return;
|
|
29092
|
+
}
|
|
29093
|
+
if (!safe(first)) {
|
|
29094
|
+
stop();
|
|
29095
|
+
return;
|
|
29096
|
+
}
|
|
29097
|
+
if (!first.ready) return;
|
|
29098
|
+
schedule(() => {
|
|
29099
|
+
if (!alive) return;
|
|
29100
|
+
try {
|
|
29101
|
+
const latest = port.snapshot();
|
|
29102
|
+
if (!safe(latest) || !latest.ready || latest.revision !== first.revision) {
|
|
29103
|
+
stop();
|
|
29104
|
+
return;
|
|
29105
|
+
}
|
|
29106
|
+
stop();
|
|
29107
|
+
port.write(TENDER_INITIAL_DRAFT.text);
|
|
29108
|
+
storage.setItem(key, JSON.stringify({
|
|
29109
|
+
status: "initialized",
|
|
29110
|
+
id: TENDER_INITIAL_DRAFT.id,
|
|
29111
|
+
version: TENDER_INITIAL_DRAFT.version,
|
|
29112
|
+
fingerprint: TENDER_INITIAL_DRAFT.fingerprint
|
|
29113
|
+
}));
|
|
29114
|
+
} catch {
|
|
29115
|
+
stop();
|
|
29116
|
+
}
|
|
29117
|
+
});
|
|
29118
|
+
};
|
|
29119
|
+
off = port.subscribe(check, stop);
|
|
29120
|
+
if (!alive) off();
|
|
29121
|
+
check();
|
|
29122
|
+
return stop;
|
|
29123
|
+
}
|
|
29124
|
+
//#endregion
|
|
29125
|
+
//#region src/client/initial-draft-host.ts
|
|
29126
|
+
/** DSH 0.1.2-rc.1 public input shell + public Lexical lifecycle; no keyboard/private fields. */
|
|
29127
|
+
function initializeTenderHostDraft(ctx, id) {
|
|
29128
|
+
try {
|
|
29129
|
+
const input = ctx.conversation.input;
|
|
29130
|
+
if (typeof input.shell !== "function") return () => {};
|
|
29131
|
+
const shell = input.shell(id);
|
|
29132
|
+
const editor = shell.editor;
|
|
29133
|
+
if (!editor?.registerRootListener || !editor.isComposing || !editor.update) return () => {};
|
|
29134
|
+
const cleanup = initializeTenderDraft(id, {
|
|
29135
|
+
snapshot() {
|
|
29136
|
+
const state = shell.state.getSnapshot();
|
|
29137
|
+
return {
|
|
29138
|
+
current: ctx.sessions.list.getSnapshot().current,
|
|
29139
|
+
ready: editor.getRootElement()?.isConnected === true,
|
|
29140
|
+
composing: editor.isComposing(),
|
|
29141
|
+
draft: state.draft,
|
|
29142
|
+
revision: state.draftRev,
|
|
29143
|
+
plain: state.phase === "plain",
|
|
29144
|
+
attachments: state.imageIds.length + state.occurrences.length
|
|
29145
|
+
};
|
|
29146
|
+
},
|
|
29147
|
+
subscribe(check, cancel) {
|
|
29148
|
+
let detach = () => {};
|
|
29149
|
+
const rootOff = editor.registerRootListener((root) => {
|
|
29150
|
+
detach();
|
|
29151
|
+
if (root) {
|
|
29152
|
+
const events = [
|
|
29153
|
+
"beforeinput",
|
|
29154
|
+
"paste",
|
|
29155
|
+
"drop",
|
|
29156
|
+
"compositionstart"
|
|
29157
|
+
];
|
|
29158
|
+
events.forEach((event) => root.addEventListener(event, cancel, true));
|
|
29159
|
+
detach = () => events.forEach((event) => root.removeEventListener(event, cancel, true));
|
|
29160
|
+
}
|
|
29161
|
+
check();
|
|
29162
|
+
});
|
|
29163
|
+
const stateOff = shell.state.subscribe(check);
|
|
29164
|
+
const sessionOff = ctx.sessions.list.subscribe(check);
|
|
29165
|
+
return () => {
|
|
29166
|
+
detach();
|
|
29167
|
+
rootOff();
|
|
29168
|
+
stateOff();
|
|
29169
|
+
sessionOff();
|
|
29170
|
+
};
|
|
29171
|
+
},
|
|
29172
|
+
write(text) {
|
|
29173
|
+
editor.update(() => shell.setDraft(text), {
|
|
29174
|
+
discrete: true,
|
|
29175
|
+
tag: "skip-dom-selection"
|
|
29176
|
+
});
|
|
29177
|
+
}
|
|
29178
|
+
}, window.localStorage);
|
|
29179
|
+
const timeout = setTimeout(cleanup, 5e3);
|
|
29180
|
+
return () => {
|
|
29181
|
+
clearTimeout(timeout);
|
|
29182
|
+
cleanup();
|
|
29183
|
+
};
|
|
29184
|
+
} catch {
|
|
29185
|
+
return () => {};
|
|
29186
|
+
}
|
|
29187
|
+
}
|
|
29188
|
+
//#endregion
|
|
28993
29189
|
//#region src/client/skill-catalog.ts
|
|
28994
29190
|
var TenderSkillPreflightError = class extends Error {
|
|
28995
29191
|
code;
|
|
@@ -31488,6 +31684,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
31488
31684
|
const projectionPort = createTenderProjectionPort(sessions);
|
|
31489
31685
|
const promptMemory = /* @__PURE__ */ new Map();
|
|
31490
31686
|
let active = true;
|
|
31687
|
+
let stopInitialDraft = () => {};
|
|
31688
|
+
let entryGeneration = 0;
|
|
31491
31689
|
const sendIntent = (sessionId, intent) => sendSessionTenderWorkbenchIntent(sessions, connection, sessionId, intent);
|
|
31492
31690
|
const openSession = (sessionId, phase) => {
|
|
31493
31691
|
if (!active || sidebar === void 0 || reveal === void 0) return false;
|
|
@@ -31500,10 +31698,15 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
31500
31698
|
return opened;
|
|
31501
31699
|
};
|
|
31502
31700
|
const startTenderSession = async () => {
|
|
31701
|
+
const generation = ++entryGeneration;
|
|
31702
|
+
const previousSession = sessions.list.getSnapshot().current;
|
|
31703
|
+
stopInitialDraft();
|
|
31503
31704
|
try {
|
|
31504
31705
|
const sessionId = await createTenderEntrySession(sessions, ctx.workspaces);
|
|
31505
|
-
if (!active) return;
|
|
31706
|
+
if (!active || generation !== entryGeneration || sessions.list.getSnapshot().current !== previousSession) return;
|
|
31707
|
+
stopInitialDraft();
|
|
31506
31708
|
sessions.open(sessionId);
|
|
31709
|
+
stopInitialDraft = initializeTenderHostDraft(ctx, sessionId);
|
|
31507
31710
|
} catch (error) {
|
|
31508
31711
|
if (error instanceof TenderSessionEntryError) {
|
|
31509
31712
|
const key = error.code === "workspace-unavailable" ? "sidebar.workspaceRequired" : error.code === "create-unavailable" ? "sidebar.createUnavailable" : "sidebar.createFailed";
|
|
@@ -31512,6 +31715,9 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
31512
31715
|
throw new Error(t("sidebar.createFailed"), { cause: error });
|
|
31513
31716
|
}
|
|
31514
31717
|
};
|
|
31718
|
+
ctx.effect(() => installTenderSubmissionReveal(sessions, (sessionId) => {
|
|
31719
|
+
openSession(sessionId, "opportunity");
|
|
31720
|
+
}), "dsh-tender-workbench: accepted submission reveal");
|
|
31515
31721
|
ctx.inject(["betterSidebar"], (providerContext) => {
|
|
31516
31722
|
const service = providerContext.betterSidebar;
|
|
31517
31723
|
try {
|
|
@@ -31594,6 +31800,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
31594
31800
|
}, TenderSessionHeaderEntry));
|
|
31595
31801
|
ctx.effect(() => () => {
|
|
31596
31802
|
active = false;
|
|
31803
|
+
stopInitialDraft();
|
|
31597
31804
|
reveal?.dispose();
|
|
31598
31805
|
navigation.dispose();
|
|
31599
31806
|
promptMemory.clear();
|