dsh-tender-workbench 0.2.2-beta.0 → 0.2.2-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/lib/client.js +267 -185
- package/lib/client.js.map +1 -1
- package/lib/types/client/TenderEntry.d.ts +10 -17
- package/lib/types/client/TenderEntry.d.ts.map +1 -1
- package/lib/types/client/better-sidebar-adapter.d.ts +1 -1
- package/lib/types/client/better-sidebar-adapter.d.ts.map +1 -1
- package/lib/types/client/index.d.ts +1 -1
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/client/locales.d.ts +7 -1
- package/lib/types/client/locales.d.ts.map +1 -1
- package/lib/types/client/tender-session-entry.d.ts +13 -0
- package/lib/types/client/tender-session-entry.d.ts.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -101,7 +101,7 @@ dsh plugin --profile web remove dsh-tender-workbench
|
|
|
101
101
|
|
|
102
102
|
## Using the workbench
|
|
103
103
|
|
|
104
|
-
The plugin exposes a top-left “招投标” launcher,
|
|
104
|
+
The plugin exposes a top-left “招投标” launcher and a Session Header recovery action. Every top-left activation creates a distinct native Session in the current Session's workspace, the recent workspace, or the first available workspace, gives that blank Session the “招投标” hero label and goal icon, and opens its Better Sidebar workbench. Other Sessions keep their existing host/provider hero label and the fish mark. The composer-bottom shortcuts are intentionally absent; the Header action only reopens the workbench for its existing Session.
|
|
105
105
|
|
|
106
106
|
Navigation only changes the visible workbench phase. It does not mutate business state or run a later action. Criteria are proposed, edited, previewed, and confirmed as distinct steps. Agent recommendations never become user decisions automatically. Report generation always shows the reviewed and pending scope before creating a delivery snapshot.
|
|
107
107
|
|
package/lib/client.js
CHANGED
|
@@ -5,8 +5,8 @@ window.__ModuleLoader__.load({
|
|
|
5
5
|
var exports = module.exports;
|
|
6
6
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
7
7
|
let react = require("react");
|
|
8
|
-
let react_dom = require("react-dom");
|
|
9
8
|
let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
9
|
+
let react_dom = require("react-dom");
|
|
10
10
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
11
11
|
let _deepseek_ai_dsh_client_runtime_client = require("@deepseek-ai/dsh-client-runtime/client");
|
|
12
12
|
//#region node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/core.js
|
|
@@ -4357,94 +4357,46 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
4357
4357
|
return (0, react.useSyncExternalStore)(subscribe, source.getSnapshot, source.getSnapshot);
|
|
4358
4358
|
}
|
|
4359
4359
|
//#endregion
|
|
4360
|
-
//#region src/client/
|
|
4361
|
-
|
|
4362
|
-
|
|
4363
|
-
|
|
4364
|
-
|
|
4365
|
-
|
|
4366
|
-
|
|
4367
|
-
|
|
4368
|
-
implemented: true,
|
|
4369
|
-
completionNode: "overview"
|
|
4370
|
-
},
|
|
4371
|
-
{
|
|
4372
|
-
id: "screening",
|
|
4373
|
-
labelKey: "workbench.phase.screening",
|
|
4374
|
-
icon: "screening",
|
|
4375
|
-
nodes: [
|
|
4376
|
-
"rules",
|
|
4377
|
-
"classification",
|
|
4378
|
-
"analysis"
|
|
4379
|
-
],
|
|
4380
|
-
implemented: true,
|
|
4381
|
-
completionNode: "classification"
|
|
4382
|
-
},
|
|
4383
|
-
{
|
|
4384
|
-
id: "decision",
|
|
4385
|
-
labelKey: "workbench.phase.decision",
|
|
4386
|
-
icon: "decision",
|
|
4387
|
-
nodes: ["review"],
|
|
4388
|
-
implemented: true,
|
|
4389
|
-
completionNode: "review"
|
|
4390
|
-
},
|
|
4391
|
-
{
|
|
4392
|
-
id: "delivery",
|
|
4393
|
-
labelKey: "workbench.phase.delivery",
|
|
4394
|
-
icon: "delivery",
|
|
4395
|
-
nodes: ["report"],
|
|
4396
|
-
implemented: true,
|
|
4397
|
-
completionNode: "report"
|
|
4360
|
+
//#region src/client/tender-session-entry.ts
|
|
4361
|
+
const TENDER_ENTRY_SESSION_ID_PREFIX = "session-dsh-tender-workbench-";
|
|
4362
|
+
var TenderSessionEntryError = class extends Error {
|
|
4363
|
+
code;
|
|
4364
|
+
constructor(code) {
|
|
4365
|
+
super(code);
|
|
4366
|
+
this.code = code;
|
|
4367
|
+
this.name = "TenderSessionEntryError";
|
|
4398
4368
|
}
|
|
4399
|
-
|
|
4400
|
-
|
|
4401
|
-
function
|
|
4402
|
-
|
|
4403
|
-
|
|
4404
|
-
|
|
4405
|
-
|
|
4406
|
-
|
|
4407
|
-
|
|
4408
|
-
|
|
4409
|
-
if (
|
|
4410
|
-
|
|
4411
|
-
|
|
4412
|
-
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
|
|
4417
|
-
|
|
4418
|
-
|
|
4419
|
-
|
|
4420
|
-
|
|
4421
|
-
const
|
|
4422
|
-
|
|
4423
|
-
|
|
4424
|
-
|
|
4425
|
-
|
|
4426
|
-
|
|
4427
|
-
|
|
4428
|
-
|
|
4429
|
-
|
|
4430
|
-
}
|
|
4431
|
-
return () => {
|
|
4432
|
-
if (targets.get(sessionId) === select) targets.delete(sessionId);
|
|
4433
|
-
};
|
|
4434
|
-
},
|
|
4435
|
-
request(sessionId, phase) {
|
|
4436
|
-
const select = targets.get(sessionId);
|
|
4437
|
-
if (select === void 0) pending.set(sessionId, phase);
|
|
4438
|
-
else select(phase);
|
|
4439
|
-
}
|
|
4440
|
-
};
|
|
4441
|
-
}
|
|
4442
|
-
function useTenderWorkbenchNavigation(controller, sessionId, select) {
|
|
4443
|
-
(0, react.useEffect)(() => controller.attach(sessionId, select), [
|
|
4444
|
-
controller,
|
|
4445
|
-
select,
|
|
4446
|
-
sessionId
|
|
4447
|
-
]);
|
|
4369
|
+
};
|
|
4370
|
+
const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu;
|
|
4371
|
+
function browserUuid() {
|
|
4372
|
+
if (typeof globalThis.crypto?.randomUUID !== "function") throw new TenderSessionEntryError("create-unavailable");
|
|
4373
|
+
return globalThis.crypto.randomUUID();
|
|
4374
|
+
}
|
|
4375
|
+
function isTenderEntrySessionId(sessionId) {
|
|
4376
|
+
return sessionId?.startsWith("session-dsh-tender-workbench-") === true && UUID_PATTERN.test(sessionId.slice(29));
|
|
4377
|
+
}
|
|
4378
|
+
function createTenderEntrySessionId(uuid) {
|
|
4379
|
+
if (!UUID_PATTERN.test(uuid)) throw new TenderSessionEntryError("invalid-session-id");
|
|
4380
|
+
return `${TENDER_ENTRY_SESSION_ID_PREFIX}${uuid}`;
|
|
4381
|
+
}
|
|
4382
|
+
function resolveTenderEntryWorkspace(sessions, workspaces) {
|
|
4383
|
+
const current = sessions.list.getSnapshot().current;
|
|
4384
|
+
const workspaceSnapshot = workspaces.list.getSnapshot();
|
|
4385
|
+
return (current === void 0 ? void 0 : workspaceSnapshot.items.find((workspace) => workspace.sessionIds.includes(current)))?.workspaceId ?? workspaceSnapshot.recentWorkspaceId ?? workspaceSnapshot.items[0]?.workspaceId;
|
|
4386
|
+
}
|
|
4387
|
+
/** Create a distinct native Session without falling back to blank-Session reuse. */
|
|
4388
|
+
async function createTenderEntrySession(sessions, workspaces, uuid = browserUuid) {
|
|
4389
|
+
const workspaceId = resolveTenderEntryWorkspace(sessions, workspaces);
|
|
4390
|
+
if (workspaceId === void 0) throw new TenderSessionEntryError("workspace-unavailable");
|
|
4391
|
+
const capability = sessions;
|
|
4392
|
+
if (typeof capability.create !== "function") throw new TenderSessionEntryError("create-unavailable");
|
|
4393
|
+
const requestedId = createTenderEntrySessionId(uuid());
|
|
4394
|
+
const createdId = await capability.create({
|
|
4395
|
+
workspaceId,
|
|
4396
|
+
sessionId: requestedId
|
|
4397
|
+
});
|
|
4398
|
+
if (createdId !== requestedId) throw new TenderSessionEntryError("invalid-session-id");
|
|
4399
|
+
return createdId;
|
|
4448
4400
|
}
|
|
4449
4401
|
//#endregion
|
|
4450
4402
|
//#region src/client/workbench/workbench-status.ts
|
|
@@ -4471,7 +4423,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
4471
4423
|
}
|
|
4472
4424
|
//#endregion
|
|
4473
4425
|
//#region \0dsh-tender-workbench-css:C:\workspace_github\dsh-tender-workbench\src\client\workbench-entry.module.css.mjs
|
|
4474
|
-
const css$1 = ".hbWcya_topMount{flex:none;width:100%;min-width:0}.hbWcya_topEntry{box-sizing:border-box;width:100%;padding-right:var(--dsh-sidebar-inline-padding,12px)}.
|
|
4426
|
+
const css$1 = ".hbWcya_topMount{flex:none;width:100%;min-width:0}.hbWcya_topEntry{box-sizing:border-box;width:100%;padding-right:var(--dsh-sidebar-inline-padding,12px)}.hbWcya_headerButton{color:var(--text-secondary,#475467);cursor:pointer;font:inherit;background:0 0;border:0;justify-content:center;align-items:center;gap:6px;display:inline-flex}.hbWcya_headerButton:hover,.hbWcya_headerButton:focus-visible{color:var(--text-primary,#1f2430);background:var(--background-secondary,#f2f4f7)}.hbWcya_sidebarButton:disabled{cursor:wait;opacity:.62}.hbWcya_sidebarButton{box-sizing:border-box;white-space:nowrap;border-radius:12px;flex:none;justify-content:flex-start;gap:5px;width:100%;min-width:0;height:42px;margin:0 0 8px;padding:0 10px;overflow:hidden}.hbWcya_sidebarRail{border-radius:50%;justify-content:center;width:36px;height:36px;padding:0}.hbWcya_sidebarError{color:#b42318;overflow-wrap:anywhere;padding:2px 12px 7px;font-size:11px;line-height:16px;display:block}.hbWcya_headerButton{border:1px solid var(--border-color,#e5e7eb);border-radius:999px;min-height:26px;padding:4px 8px;font-size:11px}.hbWcya_headerButton[data-workbench-status=running]{border-color:color-mix(in srgb, var(--color-primary,#4f6ef7) 40%, transparent);color:var(--color-primary,#4f6ef7)}.hbWcya_headerButton[data-workbench-status=failed],.hbWcya_headerButton[data-workbench-status=unavailable]{color:#b42318;border-color:#d92d2066}.hbWcya_topEntry[data-wide=false] .hbWcya_sidebarError{clip:rect(0, 0, 0, 0);white-space:nowrap;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}";
|
|
4475
4427
|
const tagId$1 = "dsh-tender-workbench/workbench-entry.module.css";
|
|
4476
4428
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
|
|
4477
4429
|
const tag = document.createElement("style");
|
|
@@ -4481,13 +4433,9 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
4481
4433
|
document.head.appendChild(tag);
|
|
4482
4434
|
}
|
|
4483
4435
|
var workbench_entry_module_css_default = {
|
|
4484
|
-
"dockActions": "hbWcya_dockActions",
|
|
4485
|
-
"dockBar": "hbWcya_dockBar",
|
|
4486
|
-
"dockBrand": "hbWcya_dockBrand",
|
|
4487
|
-
"dockButton": "hbWcya_dockButton",
|
|
4488
|
-
"dockHost": "hbWcya_dockHost",
|
|
4489
4436
|
"headerButton": "hbWcya_headerButton",
|
|
4490
4437
|
"sidebarButton": "hbWcya_sidebarButton",
|
|
4438
|
+
"sidebarError": "hbWcya_sidebarError",
|
|
4491
4439
|
"sidebarRail": "hbWcya_sidebarRail",
|
|
4492
4440
|
"topEntry": "hbWcya_topEntry",
|
|
4493
4441
|
"topMount": "hbWcya_topMount"
|
|
@@ -4495,97 +4443,99 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
4495
4443
|
//#endregion
|
|
4496
4444
|
//#region src/client/TenderEntry.tsx
|
|
4497
4445
|
const SIDEBAR_WORKSPACES_SELECTOR = "[data-slot=\"sidebar.workspaces\"]";
|
|
4498
|
-
const DATA_CLEANING_TOP_MOUNT_SELECTOR = "[data-data-cleaning-top-mount=\"true\"]";
|
|
4499
4446
|
const TENDER_TOP_MOUNT_SELECTOR = "[data-dsh-tender-top-mount=\"true\"]";
|
|
4500
|
-
|
|
4501
|
-
|
|
4502
|
-
|
|
4503
|
-
|
|
4504
|
-
|
|
4505
|
-
|
|
4506
|
-
|
|
4507
|
-
|
|
4508
|
-
|
|
4509
|
-
|
|
4510
|
-
|
|
4511
|
-
|
|
4512
|
-
|
|
4513
|
-
|
|
4514
|
-
|
|
4515
|
-
|
|
4516
|
-
|
|
4517
|
-
|
|
4518
|
-
|
|
4519
|
-
|
|
4520
|
-
|
|
4521
|
-
|
|
4522
|
-
|
|
4523
|
-
|
|
4524
|
-
|
|
4525
|
-
|
|
4526
|
-
|
|
4527
|
-
|
|
4528
|
-
|
|
4529
|
-
|
|
4530
|
-
|
|
4531
|
-
|
|
4532
|
-
|
|
4533
|
-
|
|
4534
|
-
|
|
4535
|
-
|
|
4536
|
-
})]
|
|
4447
|
+
const KNOWN_HERO_HEADLINES = /* @__PURE__ */ new Set([
|
|
4448
|
+
"探索未至之境",
|
|
4449
|
+
"Into the Unknown",
|
|
4450
|
+
"访前尽调智能体"
|
|
4451
|
+
]);
|
|
4452
|
+
/** Preserve the native mark everywhere except Sessions created by the tender entry. */
|
|
4453
|
+
function TenderHeroBrandMark({ size, className, useSessions }) {
|
|
4454
|
+
return isTenderEntrySessionId(useSessions((snapshot) => snapshot.current)) ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconGoalOutline16, {
|
|
4455
|
+
size,
|
|
4456
|
+
className
|
|
4457
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.FishLogo, {
|
|
4458
|
+
size,
|
|
4459
|
+
className
|
|
4460
|
+
});
|
|
4461
|
+
}
|
|
4462
|
+
function rewriteTenderHeroHeadline(anchor, enabled, replacement) {
|
|
4463
|
+
if (!enabled) return () => {};
|
|
4464
|
+
const hero = anchor.closest("[data-phase=\"hero\"]");
|
|
4465
|
+
if (hero === null) return () => {};
|
|
4466
|
+
const title = [...hero.querySelectorAll("span")].find((element) => element.dataset.dshTenderHeroHeadline === "true" || KNOWN_HERO_HEADLINES.has(element.textContent?.trim() ?? ""));
|
|
4467
|
+
if (title === void 0) return () => {};
|
|
4468
|
+
let original = title.dataset.dshTenderOriginalHeadline ?? title.textContent ?? "";
|
|
4469
|
+
title.dataset.dshTenderHeroHeadline = "true";
|
|
4470
|
+
title.dataset.dshTenderOriginalHeadline = original;
|
|
4471
|
+
title.textContent = replacement;
|
|
4472
|
+
const Observer = anchor.ownerDocument.defaultView?.MutationObserver;
|
|
4473
|
+
const observer = Observer === void 0 ? void 0 : new Observer(() => {
|
|
4474
|
+
if (title.textContent === replacement) return;
|
|
4475
|
+
original = title.textContent ?? original;
|
|
4476
|
+
title.dataset.dshTenderOriginalHeadline = original;
|
|
4477
|
+
title.textContent = replacement;
|
|
4478
|
+
});
|
|
4479
|
+
observer?.observe(title, {
|
|
4480
|
+
childList: true,
|
|
4481
|
+
characterData: true,
|
|
4482
|
+
subtree: true
|
|
4537
4483
|
});
|
|
4484
|
+
return () => {
|
|
4485
|
+
observer?.disconnect();
|
|
4486
|
+
if (title.dataset.dshTenderOriginalHeadline !== original) return;
|
|
4487
|
+
if (title.textContent === replacement) title.textContent = original;
|
|
4488
|
+
delete title.dataset.dshTenderOriginalHeadline;
|
|
4489
|
+
delete title.dataset.dshTenderHeroHeadline;
|
|
4490
|
+
};
|
|
4538
4491
|
}
|
|
4539
|
-
/**
|
|
4540
|
-
function
|
|
4492
|
+
/** Narrow, reversible bridge for the headline that DSH does not expose as a Slot. */
|
|
4493
|
+
function TenderHeroTitleBridge({ sessionId, t, useSession }) {
|
|
4541
4494
|
const anchorRef = (0, react.useRef)(null);
|
|
4542
|
-
const
|
|
4543
|
-
const
|
|
4495
|
+
const blank = useSession((snapshot) => snapshot.composerPhase === "blank");
|
|
4496
|
+
const replacement = t("sidebar.label");
|
|
4544
4497
|
(0, react.useEffect)(() => {
|
|
4545
4498
|
const anchor = anchorRef.current;
|
|
4546
4499
|
if (anchor === null) return;
|
|
4547
|
-
|
|
4548
|
-
|
|
4549
|
-
|
|
4550
|
-
|
|
4551
|
-
|
|
4552
|
-
|
|
4553
|
-
|
|
4554
|
-
return () => {
|
|
4555
|
-
nextHost.remove();
|
|
4556
|
-
setHost((current) => current === nextHost ? null : current);
|
|
4557
|
-
};
|
|
4558
|
-
}, [sessionId]);
|
|
4559
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4500
|
+
return rewriteTenderHeroHeadline(anchor, blank && isTenderEntrySessionId(sessionId), replacement);
|
|
4501
|
+
}, [
|
|
4502
|
+
blank,
|
|
4503
|
+
replacement,
|
|
4504
|
+
sessionId
|
|
4505
|
+
]);
|
|
4506
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4560
4507
|
ref: anchorRef,
|
|
4561
4508
|
hidden: true,
|
|
4562
|
-
"data-dsh-tender-
|
|
4563
|
-
})
|
|
4564
|
-
openWorkbench,
|
|
4565
|
-
projection,
|
|
4566
|
-
t
|
|
4567
|
-
}), host)] });
|
|
4509
|
+
"data-dsh-tender-hero-anchor": "true"
|
|
4510
|
+
});
|
|
4568
4511
|
}
|
|
4569
4512
|
function ensureTenderTopMount() {
|
|
4570
4513
|
const workspaceSlot = document.querySelector(SIDEBAR_WORKSPACES_SELECTOR);
|
|
4571
4514
|
if (workspaceSlot === null) return null;
|
|
4572
4515
|
const parent = workspaceSlot.parentElement;
|
|
4573
4516
|
if (parent === null) return null;
|
|
4574
|
-
let mount =
|
|
4517
|
+
let mount = document.querySelector(TENDER_TOP_MOUNT_SELECTOR);
|
|
4575
4518
|
if (mount === null) {
|
|
4576
4519
|
mount = document.createElement("div");
|
|
4577
4520
|
mount.dataset.dshTenderTopMount = "true";
|
|
4578
4521
|
mount.className = workbench_entry_module_css_default.topMount ?? "";
|
|
4579
4522
|
}
|
|
4580
|
-
|
|
4581
|
-
if (dataCleaningMount !== null) {
|
|
4582
|
-
if (mount.parentElement !== parent || mount.previousSibling !== dataCleaningMount) parent.insertBefore(mount, dataCleaningMount.nextSibling);
|
|
4583
|
-
} else if (mount.parentElement !== parent) parent.insertBefore(mount, workspaceSlot);
|
|
4523
|
+
if (mount.parentElement !== parent) parent.prepend(mount);
|
|
4584
4524
|
return mount;
|
|
4585
4525
|
}
|
|
4586
|
-
/** Global launcher portalled
|
|
4587
|
-
function TenderSidebarEntry({ wide,
|
|
4526
|
+
/** Global launcher portalled at the start of the sidebar's primary action region. */
|
|
4527
|
+
function TenderSidebarEntry({ wide, startTenderSession, t }) {
|
|
4588
4528
|
const [topMount, setTopMount] = (0, react.useState)(null);
|
|
4529
|
+
const [creating, setCreating] = (0, react.useState)(false);
|
|
4530
|
+
const [error, setError] = (0, react.useState)();
|
|
4531
|
+
const creatingRef = (0, react.useRef)(false);
|
|
4532
|
+
const mountedRef = (0, react.useRef)(true);
|
|
4533
|
+
(0, react.useEffect)(() => {
|
|
4534
|
+
mountedRef.current = true;
|
|
4535
|
+
return () => {
|
|
4536
|
+
mountedRef.current = false;
|
|
4537
|
+
};
|
|
4538
|
+
}, []);
|
|
4589
4539
|
(0, react.useEffect)(() => {
|
|
4590
4540
|
if (typeof document === "undefined") return;
|
|
4591
4541
|
let disposed = false;
|
|
@@ -4610,17 +4560,39 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
4610
4560
|
};
|
|
4611
4561
|
}, []);
|
|
4612
4562
|
if (topMount === null) return null;
|
|
4613
|
-
|
|
4563
|
+
const start = () => {
|
|
4564
|
+
if (creatingRef.current) return;
|
|
4565
|
+
creatingRef.current = true;
|
|
4566
|
+
setCreating(true);
|
|
4567
|
+
setError(void 0);
|
|
4568
|
+
startTenderSession().catch((reason) => {
|
|
4569
|
+
if (mountedRef.current) setError(reason instanceof Error ? reason.message : t("sidebar.createFailed"));
|
|
4570
|
+
}).finally(() => {
|
|
4571
|
+
creatingRef.current = false;
|
|
4572
|
+
if (mountedRef.current) setCreating(false);
|
|
4573
|
+
});
|
|
4574
|
+
};
|
|
4575
|
+
return (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4614
4576
|
className: workbench_entry_module_css_default.topEntry,
|
|
4577
|
+
"data-wide": wide,
|
|
4615
4578
|
"data-dsh-plugin": "tender-workbench",
|
|
4616
4579
|
"data-dsh-part": "top-entry",
|
|
4617
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(
|
|
4580
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
4618
4581
|
type: "button",
|
|
4582
|
+
variant: "ghost",
|
|
4619
4583
|
className: wide ? workbench_entry_module_css_default.sidebarButton : `${workbench_entry_module_css_default.sidebarButton} ${workbench_entry_module_css_default.sidebarRail}`,
|
|
4584
|
+
"data-wide": wide,
|
|
4620
4585
|
"aria-label": t("sidebar.aria"),
|
|
4621
|
-
|
|
4586
|
+
"aria-busy": creating,
|
|
4587
|
+
disabled: creating,
|
|
4588
|
+
title: error,
|
|
4589
|
+
onClick: start,
|
|
4622
4590
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconGoalOutline16, { size: wide ? 16 : 18 }), wide && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("sidebar.label") })]
|
|
4623
|
-
})
|
|
4591
|
+
}), error !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4592
|
+
className: workbench_entry_module_css_default.sidebarError,
|
|
4593
|
+
role: "alert",
|
|
4594
|
+
children: error
|
|
4595
|
+
})]
|
|
4624
4596
|
}), topMount);
|
|
4625
4597
|
}
|
|
4626
4598
|
function TenderSessionHeaderEntry({ openWorkbench, t, useProjection }) {
|
|
@@ -4708,11 +4680,12 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
4708
4680
|
if (!features.includes("stateSubscription")) throw new Error("dsh-tender-workbench requires the Better Sidebar stateSubscription capability");
|
|
4709
4681
|
}
|
|
4710
4682
|
/** Register the single Session-scoped workbench tab through Better Sidebar's public service. */
|
|
4711
|
-
function registerTenderWorkbenchTab(service, component, title = "招投标") {
|
|
4683
|
+
function registerTenderWorkbenchTab(service, component, title = "招投标", icon) {
|
|
4712
4684
|
assertBetterSidebarContract(service);
|
|
4713
4685
|
return service.registerTab({
|
|
4714
4686
|
id: TENDER_WORKBENCH_TAB_ID,
|
|
4715
4687
|
title,
|
|
4688
|
+
icon,
|
|
4716
4689
|
order: 40,
|
|
4717
4690
|
single: true,
|
|
4718
4691
|
component
|
|
@@ -20408,7 +20381,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
20408
20381
|
"trigger.label": "搜索招投标",
|
|
20409
20382
|
"trigger.aria": "打开招投标工作台",
|
|
20410
20383
|
"sidebar.label": "招投标",
|
|
20411
|
-
"sidebar.aria": "
|
|
20384
|
+
"sidebar.aria": "新建招投标会话",
|
|
20385
|
+
"sidebar.createFailed": "未能新建招投标会话,请重试。",
|
|
20386
|
+
"sidebar.createUnavailable": "当前 DSH 不支持新建招投标专属会话。",
|
|
20387
|
+
"sidebar.workspaceRequired": "请先选择或创建一个工作区。",
|
|
20412
20388
|
"header.reopen": "招投标工作台",
|
|
20413
20389
|
"workbench.title": "招投标工作台",
|
|
20414
20390
|
"workbench.subtitle": "与当前 Session 联动 · 所有结论可追溯",
|
|
@@ -21467,7 +21443,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
21467
21443
|
"trigger.label": "Search tenders",
|
|
21468
21444
|
"trigger.aria": "Open tender workbench",
|
|
21469
21445
|
"sidebar.label": "Tenders",
|
|
21470
|
-
"sidebar.aria": "
|
|
21446
|
+
"sidebar.aria": "Start a tender session",
|
|
21447
|
+
"sidebar.createFailed": "The tender session could not be created. Try again.",
|
|
21448
|
+
"sidebar.createUnavailable": "This DSH runtime cannot create a dedicated tender session.",
|
|
21449
|
+
"sidebar.workspaceRequired": "Select or create a workspace first.",
|
|
21471
21450
|
"header.reopen": "Tender workbench",
|
|
21472
21451
|
"workbench.title": "Tender workbench",
|
|
21473
21452
|
"workbench.subtitle": "Linked to this Session · Every conclusion remains traceable",
|
|
@@ -23008,6 +22987,96 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
23008
22987
|
return errors;
|
|
23009
22988
|
}
|
|
23010
22989
|
//#endregion
|
|
22990
|
+
//#region src/client/workbench/navigation-controller.ts
|
|
22991
|
+
/** Single front-stage mapping for the seven non-linear Projection nodes. */
|
|
22992
|
+
const TENDER_WORKBENCH_PHASES = [
|
|
22993
|
+
{
|
|
22994
|
+
id: "opportunity",
|
|
22995
|
+
labelKey: "workbench.phase.opportunity",
|
|
22996
|
+
icon: "search",
|
|
22997
|
+
nodes: ["query", "overview"],
|
|
22998
|
+
implemented: true,
|
|
22999
|
+
completionNode: "overview"
|
|
23000
|
+
},
|
|
23001
|
+
{
|
|
23002
|
+
id: "screening",
|
|
23003
|
+
labelKey: "workbench.phase.screening",
|
|
23004
|
+
icon: "screening",
|
|
23005
|
+
nodes: [
|
|
23006
|
+
"rules",
|
|
23007
|
+
"classification",
|
|
23008
|
+
"analysis"
|
|
23009
|
+
],
|
|
23010
|
+
implemented: true,
|
|
23011
|
+
completionNode: "classification"
|
|
23012
|
+
},
|
|
23013
|
+
{
|
|
23014
|
+
id: "decision",
|
|
23015
|
+
labelKey: "workbench.phase.decision",
|
|
23016
|
+
icon: "decision",
|
|
23017
|
+
nodes: ["review"],
|
|
23018
|
+
implemented: true,
|
|
23019
|
+
completionNode: "review"
|
|
23020
|
+
},
|
|
23021
|
+
{
|
|
23022
|
+
id: "delivery",
|
|
23023
|
+
labelKey: "workbench.phase.delivery",
|
|
23024
|
+
icon: "delivery",
|
|
23025
|
+
nodes: ["report"],
|
|
23026
|
+
implemented: true,
|
|
23027
|
+
completionNode: "report"
|
|
23028
|
+
}
|
|
23029
|
+
];
|
|
23030
|
+
TENDER_WORKBENCH_PHASES.map((phase) => phase.id);
|
|
23031
|
+
function tenderWorkbenchPhaseProgress(projection, phase) {
|
|
23032
|
+
const config = TENDER_WORKBENCH_PHASES.find((candidate) => candidate.id === phase);
|
|
23033
|
+
if (config === void 0) return "not-started";
|
|
23034
|
+
if (!config.implemented) return "unavailable";
|
|
23035
|
+
if (projection === void 0) return "not-started";
|
|
23036
|
+
const statuses = config.nodes.map((stage) => projection.stages[stage].status);
|
|
23037
|
+
if (statuses.includes("running") || statuses.includes("waiting-agent")) return "running";
|
|
23038
|
+
if (statuses.includes("failed")) return "failed";
|
|
23039
|
+
if (statuses.includes("blocked")) return "blocked";
|
|
23040
|
+
if (config.completionNode !== void 0 && projection.stages[config.completionNode].status === "succeeded") return "completed";
|
|
23041
|
+
if (statuses.includes("succeeded")) return "progress";
|
|
23042
|
+
if (phase === "decision" && projection.stages.classification.status === "succeeded") return "progress";
|
|
23043
|
+
return "not-started";
|
|
23044
|
+
}
|
|
23045
|
+
function tenderWorkbenchPhaseForStage(stage) {
|
|
23046
|
+
if (stage === void 0) return "opportunity";
|
|
23047
|
+
return TENDER_WORKBENCH_PHASES.find((phase) => phase.nodes.includes(stage))?.id ?? "opportunity";
|
|
23048
|
+
}
|
|
23049
|
+
/** Session-scoped transient navigation; it never represents workflow progress. */
|
|
23050
|
+
function createTenderWorkbenchNavigationController() {
|
|
23051
|
+
const targets = /* @__PURE__ */ new Map();
|
|
23052
|
+
const pending = /* @__PURE__ */ new Map();
|
|
23053
|
+
return {
|
|
23054
|
+
attach(sessionId, select) {
|
|
23055
|
+
targets.set(sessionId, select);
|
|
23056
|
+
const requested = pending.get(sessionId);
|
|
23057
|
+
if (requested !== void 0) {
|
|
23058
|
+
pending.delete(sessionId);
|
|
23059
|
+
select(requested);
|
|
23060
|
+
}
|
|
23061
|
+
return () => {
|
|
23062
|
+
if (targets.get(sessionId) === select) targets.delete(sessionId);
|
|
23063
|
+
};
|
|
23064
|
+
},
|
|
23065
|
+
request(sessionId, phase) {
|
|
23066
|
+
const select = targets.get(sessionId);
|
|
23067
|
+
if (select === void 0) pending.set(sessionId, phase);
|
|
23068
|
+
else select(phase);
|
|
23069
|
+
}
|
|
23070
|
+
};
|
|
23071
|
+
}
|
|
23072
|
+
function useTenderWorkbenchNavigation(controller, sessionId, select) {
|
|
23073
|
+
(0, react.useEffect)(() => controller.attach(sessionId, select), [
|
|
23074
|
+
controller,
|
|
23075
|
+
select,
|
|
23076
|
+
sessionId
|
|
23077
|
+
]);
|
|
23078
|
+
}
|
|
23079
|
+
//#endregion
|
|
23011
23080
|
//#region src/client/workbench/session-write-flight.ts
|
|
23012
23081
|
const IDLE_PHASES = /* @__PURE__ */ new Set([
|
|
23013
23082
|
"idle",
|
|
@@ -30266,7 +30335,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
30266
30335
|
t
|
|
30267
30336
|
});
|
|
30268
30337
|
}
|
|
30269
|
-
/** Register the workbench Tab,
|
|
30338
|
+
/** Register the dedicated Session entry, workbench Tab, Hero brand, and Header recovery action. */
|
|
30270
30339
|
function apply(ctx) {
|
|
30271
30340
|
ctx.conversationEvents.register(tenderSearchDefinition);
|
|
30272
30341
|
ctx.effect(() => ctx.locale.register(NS, {
|
|
@@ -30280,6 +30349,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
30280
30349
|
const reveal = createTenderWorkbenchRevealController();
|
|
30281
30350
|
const navigation = createTenderWorkbenchNavigationController();
|
|
30282
30351
|
const projectionPort = createTenderProjectionPort(sessions);
|
|
30352
|
+
let active = true;
|
|
30283
30353
|
const sendIntent = (sessionId, intent) => sendSessionTenderWorkbenchIntent(sessions, sessionId, intent);
|
|
30284
30354
|
const openSession = (sessionId, phase) => {
|
|
30285
30355
|
const summary = sessions.list.getSnapshot().byId[sessionId];
|
|
@@ -30290,13 +30360,19 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
30290
30360
|
if (opened && phase !== void 0) navigation.request(sessionId, phase);
|
|
30291
30361
|
return opened;
|
|
30292
30362
|
};
|
|
30293
|
-
const
|
|
30294
|
-
|
|
30295
|
-
|
|
30296
|
-
|
|
30297
|
-
|
|
30363
|
+
const startTenderSession = async () => {
|
|
30364
|
+
try {
|
|
30365
|
+
const sessionId = await createTenderEntrySession(sessions, ctx.workspaces);
|
|
30366
|
+
if (!active) return;
|
|
30367
|
+
sessions.open(sessionId);
|
|
30368
|
+
if (openSession(sessionId)) reveal.request(sessionId);
|
|
30369
|
+
} catch (error) {
|
|
30370
|
+
if (error instanceof TenderSessionEntryError) {
|
|
30371
|
+
const key = error.code === "workspace-unavailable" ? "sidebar.workspaceRequired" : error.code === "create-unavailable" ? "sidebar.createUnavailable" : "sidebar.createFailed";
|
|
30372
|
+
throw new Error(t(key), { cause: error });
|
|
30373
|
+
}
|
|
30374
|
+
throw new Error(t("sidebar.createFailed"), { cause: error });
|
|
30298
30375
|
}
|
|
30299
|
-
return openSession(current);
|
|
30300
30376
|
};
|
|
30301
30377
|
ctx.effect(() => registerTenderWorkbenchTab(ctx.betterSidebar, (props) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RegisteredTenderWorkbenchTab, {
|
|
30302
30378
|
...props,
|
|
@@ -30306,21 +30382,24 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
30306
30382
|
projectionPort,
|
|
30307
30383
|
reveal,
|
|
30308
30384
|
navigation
|
|
30309
|
-
}), () => t("sidebar.label")), "dsh-tender-workbench: Better Sidebar tab");
|
|
30385
|
+
}), () => t("sidebar.label"), (size) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconGoalOutline16, { size })), "dsh-tender-workbench: Better Sidebar tab");
|
|
30386
|
+
ctx.slots.inject("conversation.hero.brand.mark", () => ctx.slots.register({
|
|
30387
|
+
name: "conversation.hero.brand.mark",
|
|
30388
|
+
priority: -10
|
|
30389
|
+
}, TenderHeroBrandMark));
|
|
30390
|
+
ctx.slots.inject("conversation.input.dock", () => ctx.slots.register({
|
|
30391
|
+
name: "conversation.input.dock",
|
|
30392
|
+
id: "dsh-tender-workbench:hero-title",
|
|
30393
|
+
order: 120,
|
|
30394
|
+
locale: NS
|
|
30395
|
+
}, TenderHeroTitleBridge));
|
|
30310
30396
|
ctx.slots.inject("sidebar.footer.action", () => ctx.slots.register({
|
|
30311
30397
|
name: "sidebar.footer.action",
|
|
30312
30398
|
id: "dsh-tender-workbench:sidebar",
|
|
30313
30399
|
order: 40,
|
|
30314
30400
|
locale: NS,
|
|
30315
|
-
inject: () => ({
|
|
30401
|
+
inject: () => ({ startTenderSession })
|
|
30316
30402
|
}, TenderSidebarEntry));
|
|
30317
|
-
ctx.slots.inject("conversation.input.dock", () => ctx.slots.register({
|
|
30318
|
-
name: "conversation.input.dock",
|
|
30319
|
-
id: "dsh-tender-workbench:dock",
|
|
30320
|
-
order: 120,
|
|
30321
|
-
locale: NS,
|
|
30322
|
-
inject: (sessionId) => ({ openWorkbench: (phase) => openSession(sessionId, phase) })
|
|
30323
|
-
}, TenderDockEntry));
|
|
30324
30403
|
ctx.slots.inject("conversation.session.header.actions", () => ctx.slots.register({
|
|
30325
30404
|
name: "conversation.session.header.actions",
|
|
30326
30405
|
id: "dsh-tender-workbench:reopen",
|
|
@@ -30328,6 +30407,9 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
30328
30407
|
locale: NS,
|
|
30329
30408
|
inject: (sessionId) => ({ openWorkbench: () => openSession(sessionId) })
|
|
30330
30409
|
}, TenderSessionHeaderEntry));
|
|
30410
|
+
ctx.effect(() => () => {
|
|
30411
|
+
active = false;
|
|
30412
|
+
}, "dsh-tender-workbench: Session entry lifetime");
|
|
30331
30413
|
}
|
|
30332
30414
|
//#endregion
|
|
30333
30415
|
exports.apply = apply;
|