@linxin666/dsh-client-ui-task-board 0.3.21 → 0.3.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/README.i18n.yaml +2 -2
- package/README.md +5 -0
- package/README.zh.md +5 -0
- package/lib/client.js +723 -29
- package/lib/client.js.map +1 -1
- package/lib/index.js +2629 -158
- package/lib/types/client/board/EditTaskModal.d.ts +7 -1
- package/lib/types/client/board/NewTaskModal.d.ts +6 -1
- package/lib/types/client/board/TaskBoard.d.ts +10 -1
- package/lib/types/client/board/TaskForm.d.ts +18 -0
- package/lib/types/client/host-api.d.ts +23 -1
- package/lib/types/client/locales.d.ts +36 -0
- package/lib/types/core/controller.d.ts +35 -1
- package/lib/types/core/tasks.d.ts +60 -0
- package/lib/types/core/use-cases/task-update.d.ts +8 -1
- package/lib/types/host-ai.d.ts +51 -0
- package/lib/types/host-routes.d.ts +11 -1
- package/lib/types/index.d.ts +9 -0
- package/lib/types/protocol.d.ts +19 -0
- package/package.json +1 -1
- package/src/client/board/EditTaskModal.tsx +52 -3
- package/src/client/board/NewTaskModal.tsx +100 -5
- package/src/client/board/TaskBoard.tsx +150 -6
- package/src/client/board/TaskCard.tsx +17 -1
- package/src/client/board/TaskDetail.tsx +38 -2
- package/src/client/board/TaskForm.tsx +85 -0
- package/src/client/board.module.css +180 -0
- package/src/client/host-api.ts +124 -5
- package/src/client/index.ts +7 -0
- package/src/client/locales.ts +72 -0
- package/src/core/controller.ts +57 -1
- package/src/core/store.ts +5 -1
- package/src/core/tasks.ts +112 -0
- package/src/core/use-cases/task-update.ts +12 -2
- package/src/host-ai.ts +152 -0
- package/src/host-ledger.ts +25 -3
- package/src/host-routes.ts +68 -3
- package/src/host-runner.ts +24 -1
- package/src/index.ts +26 -1
- package/src/protocol.ts +45 -3
package/lib/client.js
CHANGED
|
@@ -7,7 +7,58 @@ window.__ModuleLoader__.load({
|
|
|
7
7
|
let react = require("react");
|
|
8
8
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
9
9
|
let react_dom_client = require("react-dom/client");
|
|
10
|
-
|
|
10
|
+
/**
|
|
11
|
+
* Repair a persisted tag list: keep the well-formed entries, trim, drop
|
|
12
|
+
* blanks and repeats, cap the count, and collapse a blank prompt line to
|
|
13
|
+
* "display-only". Returns undefined when nothing usable remains, so the caller
|
|
14
|
+
* clears the field instead of storing an empty array.
|
|
15
|
+
*/
|
|
16
|
+
function normalizeTags(value) {
|
|
17
|
+
if (!Array.isArray(value)) return void 0;
|
|
18
|
+
const tags = [];
|
|
19
|
+
const seen = /* @__PURE__ */ new Set();
|
|
20
|
+
for (const entry of value) {
|
|
21
|
+
if (typeof entry !== "object" || entry === null || Array.isArray(entry)) continue;
|
|
22
|
+
const row = entry;
|
|
23
|
+
if (typeof row.name !== "string") continue;
|
|
24
|
+
const name = row.name.trim();
|
|
25
|
+
if (name === "" || name.length > 32 || seen.has(name)) continue;
|
|
26
|
+
const raw = typeof row.promptPrefix === "string" ? row.promptPrefix.trim() : "";
|
|
27
|
+
const promptPrefix = raw === "" ? void 0 : raw.slice(0, 200);
|
|
28
|
+
seen.add(name);
|
|
29
|
+
tags.push(promptPrefix === void 0 ? { name } : {
|
|
30
|
+
name,
|
|
31
|
+
promptPrefix
|
|
32
|
+
});
|
|
33
|
+
if (tags.length >= 8) break;
|
|
34
|
+
}
|
|
35
|
+
return tags.length === 0 ? void 0 : tags;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Stable palette slot (0..5) for a tag name. The same label always lands on the
|
|
39
|
+
* same tone, so a badge needs no stored colour and two tasks sharing a label
|
|
40
|
+
* cannot disagree about it.
|
|
41
|
+
*/
|
|
42
|
+
function tagTone(name) {
|
|
43
|
+
let hash = 0;
|
|
44
|
+
for (const char of name) hash = hash * 31 + (char.codePointAt(0) ?? 0) >>> 0;
|
|
45
|
+
return hash % 6;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Union of the labels already carried by `tasks`, first occurrence wins (the
|
|
49
|
+
* oldest task's hint is the one offered). Feeds the editor's name datalist and
|
|
50
|
+
* the board's tag filter, so a label defined once can be reused everywhere.
|
|
51
|
+
*/
|
|
52
|
+
function collectKnownTags(tasks) {
|
|
53
|
+
const known = [];
|
|
54
|
+
const seen = /* @__PURE__ */ new Set();
|
|
55
|
+
for (const task of tasks) for (const tag of task.tags ?? []) {
|
|
56
|
+
if (seen.has(tag.name)) continue;
|
|
57
|
+
seen.add(tag.name);
|
|
58
|
+
known.push(tag);
|
|
59
|
+
}
|
|
60
|
+
return known;
|
|
61
|
+
}
|
|
11
62
|
/**
|
|
12
63
|
* Statuses a task may be archived from: every status but `running`, whose
|
|
13
64
|
* execution the runner still owns until it settles. A settled-only gate made
|
|
@@ -92,6 +143,7 @@ window.__ModuleLoader__.load({
|
|
|
92
143
|
}
|
|
93
144
|
/** Create a task from user input. */
|
|
94
145
|
function createTask(input, now, id) {
|
|
146
|
+
const tags = normalizeTags(input.tags);
|
|
95
147
|
return {
|
|
96
148
|
id,
|
|
97
149
|
title: input.title.trim(),
|
|
@@ -110,7 +162,8 @@ window.__ModuleLoader__.load({
|
|
|
110
162
|
...input.handover === void 0 ? {} : { handover: {
|
|
111
163
|
...input.handover,
|
|
112
164
|
bundledAt: now
|
|
113
|
-
} }
|
|
165
|
+
} },
|
|
166
|
+
...tags === void 0 ? {} : { tags }
|
|
114
167
|
};
|
|
115
168
|
}
|
|
116
169
|
/** Clone a task with an updated status and a fresh updatedAt. */
|
|
@@ -523,7 +576,7 @@ window.__ModuleLoader__.load({
|
|
|
523
576
|
function applyUpdateTask(tasks, id, patch, now) {
|
|
524
577
|
return tasks.map((task) => {
|
|
525
578
|
if (task.id !== id) return task;
|
|
526
|
-
const { freeze: freezePatch, handover: handoverPatch, ...rest } = patch;
|
|
579
|
+
const { freeze: freezePatch, handover: handoverPatch, tags: tagsPatch, ...rest } = patch;
|
|
527
580
|
const workspaceId = "workspaceId" in patch ? normalizeTargetId(patch.workspaceId) : void 0;
|
|
528
581
|
const mode = "mode" in patch ? normalizeTargetId(patch.mode) : void 0;
|
|
529
582
|
const permission = "permission" in patch ? normalizePermission(task.permission, patch.permission) : void 0;
|
|
@@ -543,6 +596,7 @@ window.__ModuleLoader__.load({
|
|
|
543
596
|
...handoverPatch,
|
|
544
597
|
bundledAt: now
|
|
545
598
|
};
|
|
599
|
+
if ("tags" in patch) next.tags = tagsPatch == null ? void 0 : normalizeTags(tagsPatch);
|
|
546
600
|
if ("permission" in patch && patch.permission !== void 0 && patch.permission !== task.permission || "handover" in patch) next.permissionConfirmedAt = void 0;
|
|
547
601
|
if ("reuseSession" in patch) next.reuseSession = patch.reuseSession === true ? true : void 0;
|
|
548
602
|
if (workspaceId !== void 0 || "workspaceId" in patch) next.workspaceId = workspaceId;
|
|
@@ -590,6 +644,7 @@ window.__ModuleLoader__.load({
|
|
|
590
644
|
presets: [],
|
|
591
645
|
models: []
|
|
592
646
|
};
|
|
647
|
+
workspaceCreator;
|
|
593
648
|
listeners = /* @__PURE__ */ new Set();
|
|
594
649
|
disposers = [];
|
|
595
650
|
now;
|
|
@@ -633,6 +688,8 @@ window.__ModuleLoader__.load({
|
|
|
633
688
|
selectedTaskId: this.selectedTaskId,
|
|
634
689
|
executionOptions: this.executionOptions,
|
|
635
690
|
pendingTaskIds: [...this.pendingTaskIds],
|
|
691
|
+
...this.workspaceCreator === void 0 ? {} : { canCreateWorkspace: true },
|
|
692
|
+
...typeof this.deps.transport?.parseDraft === "function" ? { canParseTask: true } : {},
|
|
636
693
|
...this.transportError === void 0 ? {} : { transportError: this.transportError },
|
|
637
694
|
...this.hostState === void 0 ? {} : { host: this.hostState }
|
|
638
695
|
};
|
|
@@ -735,6 +792,33 @@ window.__ModuleLoader__.load({
|
|
|
735
792
|
};
|
|
736
793
|
this.notify();
|
|
737
794
|
}
|
|
795
|
+
/** Wire (or clear) the runtime's project registration face (issue #1536). */
|
|
796
|
+
setWorkspaceCreator(creator) {
|
|
797
|
+
this.workspaceCreator = creator;
|
|
798
|
+
this.notify();
|
|
799
|
+
}
|
|
800
|
+
/**
|
|
801
|
+
* Register an existing host directory as a DSH project, exactly as the GUI's
|
|
802
|
+
* own "add project" does; the runtime's failure message surfaces unchanged.
|
|
803
|
+
*/
|
|
804
|
+
async createWorkspace(path) {
|
|
805
|
+
if (this.workspaceCreator === void 0) throw new Error("workspace creation is unavailable");
|
|
806
|
+
return await this.workspaceCreator(path);
|
|
807
|
+
}
|
|
808
|
+
/** Whether this deployment can parse pasted text into task fields (issue #1540). */
|
|
809
|
+
canParseTask() {
|
|
810
|
+
return typeof this.deps.transport?.parseDraft === "function";
|
|
811
|
+
}
|
|
812
|
+
/**
|
|
813
|
+
* Parse pasted text into task fields through the Host. The transport already
|
|
814
|
+
* phrases every failure for the user, so its message surfaces unchanged.
|
|
815
|
+
*/
|
|
816
|
+
async parseTaskDraft(request, signal) {
|
|
817
|
+
const transport = this.deps.transport;
|
|
818
|
+
const parse = transport?.parseDraft;
|
|
819
|
+
if (transport === void 0 || parse === void 0) throw new Error("task parsing is unavailable");
|
|
820
|
+
return await parse.call(transport, request, signal);
|
|
821
|
+
}
|
|
738
822
|
moveTask(id, status) {
|
|
739
823
|
if (this.deps.transport !== void 0) {
|
|
740
824
|
this.commitRemote({
|
|
@@ -1404,6 +1488,7 @@ window.__ModuleLoader__.load({
|
|
|
1404
1488
|
task.reuseSession = row.reuseSession === true ? true : void 0;
|
|
1405
1489
|
task.freeze = normalizeFreeze(row.freeze);
|
|
1406
1490
|
task.handover = normalizeHandover(row.handover);
|
|
1491
|
+
task.tags = normalizeTags(row.tags);
|
|
1407
1492
|
task.permissionConfirmedAt = typeof row.permissionConfirmedAt === "number" && Number.isFinite(row.permissionConfirmedAt) ? row.permissionConfirmedAt : void 0;
|
|
1408
1493
|
tasks.push(task);
|
|
1409
1494
|
}
|
|
@@ -1518,6 +1603,30 @@ window.__ModuleLoader__.load({
|
|
|
1518
1603
|
"board.updated": "更新于",
|
|
1519
1604
|
"board.created": "创建于",
|
|
1520
1605
|
"board.hostError": "Host 操作失败:{error}",
|
|
1606
|
+
"board.hostError.notMounted": "任务看板的后台接口没有挂载:宿主可能没有加载该插件,也可能后台数据正被另一个 DSH 实例占用。重启 DSH 服务后再试",
|
|
1607
|
+
"board.hostError.unauthorized": "登录状态已失效,请刷新页面后重试",
|
|
1608
|
+
"board.hostError.locked": "任务看板的后台数据被占用:{detail}",
|
|
1609
|
+
"board.hostError.timeout": "后台 {seconds} 秒内没有响应,请稍后重试",
|
|
1610
|
+
"board.hostError.unreachable": "连接不上本机 DSH 服务,请确认它仍在运行",
|
|
1611
|
+
"board.hostError.unexpected": "后台返回了无法识别的响应(HTTP {status})",
|
|
1612
|
+
"board.project": "项目",
|
|
1613
|
+
"board.projectAll": "全部项目",
|
|
1614
|
+
"board.projectNew": "新建项目…",
|
|
1615
|
+
"board.projectNewPath": "项目目录(宿主上的绝对路径)",
|
|
1616
|
+
"board.projectNewPathPlaceholder": "例如 C:\\work\\my-project 或 /home/me/project",
|
|
1617
|
+
"board.projectCreate": "创建项目",
|
|
1618
|
+
"board.projectCreateFailed": "创建项目失败:{error}",
|
|
1619
|
+
"new.aiParse": "AI 解析",
|
|
1620
|
+
"new.aiParseHint": "把从别处复制的一段话粘进来,让模型整理成标题、描述和执行 Prompt;解析结果只填进下面的表单,你可以先改再创建。",
|
|
1621
|
+
"new.aiParsePlaceholder": "粘贴要变成任务的内容…",
|
|
1622
|
+
"new.aiParseModel": "解析用模型",
|
|
1623
|
+
"new.aiParseRun": "解析并填入",
|
|
1624
|
+
"new.aiParseCancel": "取消解析",
|
|
1625
|
+
"new.aiParseEmpty": "先粘贴一段内容再解析",
|
|
1626
|
+
"new.aiParseNoModel": "这个部署还没有可用的模型,请先在 DSH 里配置模型提供商,或换一个模型再试",
|
|
1627
|
+
"new.aiParseUnavailable": "后台没有解析接口可用,重启 DSH 服务后再试",
|
|
1628
|
+
"new.aiParseTimeout": "模型 {seconds} 秒内没有返回结果,请重试或换一个更快的模型",
|
|
1629
|
+
"new.aiParseFailed": "解析失败:{error}",
|
|
1521
1630
|
"board.retryHost": "重试连接 Host",
|
|
1522
1631
|
"board.hostMeta": "Host 时区 {timeZone} · revision {revision}",
|
|
1523
1632
|
"new.title": "标题",
|
|
@@ -1544,11 +1653,23 @@ window.__ModuleLoader__.load({
|
|
|
1544
1653
|
"detail.handover": "交接包",
|
|
1545
1654
|
"detail.handover.bundledAt": "打包于 {time}",
|
|
1546
1655
|
"detail.handover.references": "引用",
|
|
1656
|
+
"new.tags": "标签(可选)",
|
|
1657
|
+
"new.tagsHint": "标签用于卡片徽章与顶栏筛选;填了「执行提示」的行会在每次执行前注入 Prompt,留空则只作展示。",
|
|
1658
|
+
"new.tagName": "标签名",
|
|
1659
|
+
"new.tagNamePlaceholder": "例如:工作",
|
|
1660
|
+
"new.tagPrompt": "执行提示(可选)",
|
|
1661
|
+
"new.tagPromptPlaceholder": "例如:产物归档到 02-工作/",
|
|
1662
|
+
"new.tagAdd": "添加标签",
|
|
1663
|
+
"new.tagRemove": "移除标签 {name}",
|
|
1664
|
+
"board.tagFilter": "按标签筛选",
|
|
1665
|
+
"board.tagFilterClear": "清除标签筛选",
|
|
1666
|
+
"board.tagEmpty": "没有同时带这些标签的任务",
|
|
1547
1667
|
"detail.permissionPending": "权限待确认:本卡有效权限({permission})高于会话默认,手动执行与定时调度都会被拒绝,需人工确认后才能运行。",
|
|
1548
1668
|
"detail.permissionConfirm": "确认权限绑定",
|
|
1549
1669
|
"detail.permissionConfirmed": "已确认权限绑定 · {time}",
|
|
1550
1670
|
"detail.title": "任务详情",
|
|
1551
1671
|
"detail.edit": "编辑",
|
|
1672
|
+
"detail.editTags": "编辑标签",
|
|
1552
1673
|
"detail.duplicate": "复制为新任务",
|
|
1553
1674
|
"detail.duplicateAndEdit": "修改并新建副本",
|
|
1554
1675
|
"detail.close": "关闭",
|
|
@@ -1670,6 +1791,30 @@ window.__ModuleLoader__.load({
|
|
|
1670
1791
|
"board.updated": "Updated",
|
|
1671
1792
|
"board.created": "Created",
|
|
1672
1793
|
"board.hostError": "Host action failed: {error}",
|
|
1794
|
+
"board.hostError.notMounted": "The task board Host API is not mounted: the Host may not have loaded the plugin, or another DSH instance holds the ledger. Restart the DSH service and try again",
|
|
1795
|
+
"board.hostError.unauthorized": "This session is no longer signed in; reload the page and try again",
|
|
1796
|
+
"board.hostError.locked": "The task board ledger is locked: {detail}",
|
|
1797
|
+
"board.hostError.timeout": "The Host did not answer within {seconds}s; try again shortly",
|
|
1798
|
+
"board.hostError.unreachable": "Cannot reach the local DSH service; make sure it is still running",
|
|
1799
|
+
"board.hostError.unexpected": "The Host returned an unrecognized response (HTTP {status})",
|
|
1800
|
+
"board.project": "Project",
|
|
1801
|
+
"board.projectAll": "All projects",
|
|
1802
|
+
"board.projectNew": "New project…",
|
|
1803
|
+
"board.projectNewPath": "Project directory (absolute path on the Host)",
|
|
1804
|
+
"board.projectNewPathPlaceholder": "e.g. C:\\work\\my-project or /home/me/project",
|
|
1805
|
+
"board.projectCreate": "Create project",
|
|
1806
|
+
"board.projectCreateFailed": "Could not create the project: {error}",
|
|
1807
|
+
"new.aiParse": "Parse with AI",
|
|
1808
|
+
"new.aiParseHint": "Paste text copied from somewhere else and let a model turn it into a title, description, and run prompt; the result only fills the form below, so you can edit it before creating the task.",
|
|
1809
|
+
"new.aiParsePlaceholder": "Paste the content to turn into a task…",
|
|
1810
|
+
"new.aiParseModel": "Model used for parsing",
|
|
1811
|
+
"new.aiParseRun": "Parse and fill",
|
|
1812
|
+
"new.aiParseCancel": "Cancel parsing",
|
|
1813
|
+
"new.aiParseEmpty": "Paste something to parse first",
|
|
1814
|
+
"new.aiParseNoModel": "This deployment has no model available; configure a model provider in DSH or pick another model",
|
|
1815
|
+
"new.aiParseUnavailable": "The Host has no parse endpoint; restart the DSH service and try again",
|
|
1816
|
+
"new.aiParseTimeout": "The model did not answer within {seconds}s; try again or pick a faster model",
|
|
1817
|
+
"new.aiParseFailed": "Parsing failed: {error}",
|
|
1673
1818
|
"board.retryHost": "Retry Host connection",
|
|
1674
1819
|
"board.hostMeta": "Host time zone {timeZone} · revision {revision}",
|
|
1675
1820
|
"new.title": "Title",
|
|
@@ -1696,11 +1841,23 @@ window.__ModuleLoader__.load({
|
|
|
1696
1841
|
"detail.handover": "Handover bundle",
|
|
1697
1842
|
"detail.handover.bundledAt": "Bundled at {time}",
|
|
1698
1843
|
"detail.handover.references": "References",
|
|
1844
|
+
"new.tags": "Tags (optional)",
|
|
1845
|
+
"new.tagsHint": "Tags drive the card badges and the board filter; a row with an execution hint is injected ahead of the prompt on every run, an empty one is display-only.",
|
|
1846
|
+
"new.tagName": "Tag name",
|
|
1847
|
+
"new.tagNamePlaceholder": "e.g. Work",
|
|
1848
|
+
"new.tagPrompt": "Execution hint (optional)",
|
|
1849
|
+
"new.tagPromptPlaceholder": "e.g. Archive artefacts under 02-work/",
|
|
1850
|
+
"new.tagAdd": "Add tag",
|
|
1851
|
+
"new.tagRemove": "Remove tag {name}",
|
|
1852
|
+
"board.tagFilter": "Filter by tag",
|
|
1853
|
+
"board.tagFilterClear": "Clear tag filter",
|
|
1854
|
+
"board.tagEmpty": "No task carries all of these tags",
|
|
1699
1855
|
"detail.permissionPending": "Permission pending confirmation: this card's effective permission ({permission}) is above the session default; manual runs and cron are refused until a human confirms.",
|
|
1700
1856
|
"detail.permissionConfirm": "Confirm permission binding",
|
|
1701
1857
|
"detail.permissionConfirmed": "Permission confirmed · {time}",
|
|
1702
1858
|
"detail.title": "Task Detail",
|
|
1703
1859
|
"detail.edit": "Edit",
|
|
1860
|
+
"detail.editTags": "Edit tags",
|
|
1704
1861
|
"detail.duplicate": "Duplicate Task",
|
|
1705
1862
|
"detail.duplicateAndEdit": "Edit as New Copy",
|
|
1706
1863
|
"detail.close": "Close",
|
|
@@ -1823,7 +1980,7 @@ window.__ModuleLoader__.load({
|
|
|
1823
1980
|
}
|
|
1824
1981
|
//#endregion
|
|
1825
1982
|
//#region \0dsh-css:packages/dsh-task-board/src/client/board.module.css.mjs
|
|
1826
|
-
const css$1 = "[data-pane=conversation],[class*=centerCol]{position:relative}[data-dsh-taskboard-view]{z-index:60;background:var(--dsw-alias-bg-base);display:none;position:absolute;inset:0;container:_7D6uKa_task-board-view/inline-size}html[data-dsh-taskboard-active]:not([data-dsh-ssh-active]) [data-dsh-taskboard-view]{display:block}html[data-dsh-taskboard-active]:not([data-dsh-ssh-active]) [data-pane=conversation]>:not([data-dsh-taskboard-view]),html[data-dsh-taskboard-active]:not([data-dsh-ssh-active]) [class*=centerCol]>:not([data-dsh-taskboard-view]){display:none!important}._7D6uKa_entry{box-sizing:border-box;width:100%;height:36px;color:var(--dsw-alias-label-secondary);cursor:pointer;white-space:nowrap;background:0 0;border:none;border-radius:8px;align-items:center;gap:8px;padding:0 10px;font-size:13px;display:flex}._7D6uKa_entry:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}._7D6uKa_entry[data-active]{background:var(--dsw-alias-interactive-bg-active);color:var(--dsw-alias-label-primary);font-weight:600}._7D6uKa_entryIcon{flex:none;justify-content:center;align-items:center;width:24px;height:24px;display:inline-flex}._7D6uKa_entryIcon svg{width:18px;height:18px;display:block}._7D6uKa_entryLabel{text-overflow:ellipsis;overflow:hidden}[data-dsh-frame][data-sidebar-collapsed] ._7D6uKa_entry,[data-sidebar-collapsed] ._7D6uKa_entry{border-radius:50%;justify-content:center;width:36px;height:36px;margin:0 auto 12px;padding:0}[data-dsh-frame][data-sidebar-collapsed] ._7D6uKa_entryLabel,[data-sidebar-collapsed] ._7D6uKa_entryLabel{display:none}._7D6uKa_board{box-sizing:border-box;background:var(--dsw-alias-bg-base);min-width:0;height:100%;min-height:0;color:var(--dsw-alias-label-primary);font-family:var(--dsw-font-family);flex-direction:column;gap:12px;padding:14px 16px 16px;display:flex}._7D6uKa_boardHeader{flex:none;align-items:center;gap:10px;display:flex}._7D6uKa_boardTitle{color:var(--dsw-alias-label-primary);white-space:nowrap;margin:0;font-size:16px;font-weight:700}._7D6uKa_backButton{align-items:center;gap:4px;display:inline-flex}._7D6uKa_search{min-width:120px;color:var(--dsw-alias-label-primary);background:var(--dsw-specific-input-major);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;outline:none;flex:0 260px;padding:6px 10px;font-size:13px}._7D6uKa_search::placeholder{color:var(--dsw-alias-label-tertiary)}._7D6uKa_columns{overscroll-behavior-inline:contain;scrollbar-color:var(--dsw-alias-border-l3) var(--dsw-alias-interactive-bg-hover);scrollbar-width:thin;flex:1;grid-auto-columns:minmax(220px,1fr);grid-auto-flow:column;gap:12px;min-height:0;padding-bottom:6px;display:grid;overflow:auto hidden}._7D6uKa_columns::-webkit-scrollbar{height:10px}._7D6uKa_columns::-webkit-scrollbar-track{background:var(--dsw-alias-interactive-bg-hover);border-radius:999px}._7D6uKa_columns::-webkit-scrollbar-thumb{background:var(--dsw-alias-border-l3);background-clip:content-box;border:2px solid #0000;border-radius:999px}._7D6uKa_columns::-webkit-scrollbar-thumb:hover{background:var(--dsw-alias-border-l4);background-clip:content-box}._7D6uKa_column{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:12px;flex-direction:column;min-height:0;display:flex;overflow:hidden}._7D6uKa_columnHeader{flex:none;align-items:center;gap:6px;padding:10px 12px;display:flex}._7D6uKa_columnTitle{color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;flex:1;margin:0;font-size:13px;font-weight:700;overflow:hidden}._7D6uKa_columnCount{min-width:0;color:var(--dsw-alias-label-tertiary);background:var(--dsw-alias-interactive-bg-hover);border-radius:999px;flex:none;padding:1px 8px;font-size:12px}._7D6uKa_statusDot{border-radius:50%;flex:none;width:8px;height:8px}._7D6uKa_statusDot[data-status=backlog]{background:var(--dsw-alias-label-tertiary)}._7D6uKa_statusDot[data-status=todo]{background:var(--dsw-alias-state-business-primary)}._7D6uKa_statusDot[data-status=running]{background:var(--dsw-alias-state-warn-primary)}._7D6uKa_statusDot[data-status=done]{background:var(--dsw-alias-state-success-primary)}._7D6uKa_statusDot[data-status=failed]{background:var(--dsw-alias-state-error-primary)}._7D6uKa_cards{flex-direction:column;flex:1;gap:8px;min-height:0;padding:2px 8px 10px;display:flex;overflow-y:auto}._7D6uKa_columnEmpty{text-align:center;color:var(--dsw-alias-label-tertiary);padding:24px 8px;font-size:12px}._7D6uKa_card{text-align:left;background:var(--dsw-alias-bg-base);border:1px solid var(--dsw-alias-border-l2);cursor:pointer;color:var(--dsw-alias-label-primary);border-radius:10px;flex-direction:column;gap:6px;padding:10px 12px;font-family:inherit;transition:box-shadow .12s,border-color .12s,transform .12s;display:flex}._7D6uKa_card:hover{box-shadow:var(--dsw-shadow-lv2);border-color:var(--dsw-alias-border-l3);transform:translateY(-1px)}._7D6uKa_card[data-status=running]{border-color:var(--dsw-alias-state-warn-primary)}._7D6uKa_cardTitle{-webkit-line-clamp:2;-webkit-box-orient:vertical;font-size:13px;font-weight:600;line-height:1.35;display:-webkit-box;overflow:hidden}._7D6uKa_cardExcerpt{color:var(--dsw-alias-label-secondary);-webkit-line-clamp:2;-webkit-box-orient:vertical;font-size:12px;line-height:1.4;display:-webkit-box;overflow:hidden}._7D6uKa_cardMeta{color:var(--dsw-alias-label-tertiary);align-items:center;gap:8px;font-size:11px;display:flex}._7D6uKa_cardTime{text-overflow:ellipsis;white-space:nowrap;flex:1;overflow:hidden}._7D6uKa_cardSchedule{white-space:nowrap;min-width:0;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-interactive-bg-hover);border-radius:999px;flex:none;padding:2px 6px;font-size:12px;line-height:1}._7D6uKa_cardRun{flex:none}._7D6uKa_cardRun[data-result=failed]{color:var(--dsw-alias-state-error-primary)}._7D6uKa_cardRun[data-result=succeeded]{color:var(--dsw-alias-state-success-primary)}._7D6uKa_cardSession{color:var(--dsw-alias-state-business-primary);flex:none}._7D6uKa_cardRunningLabel{color:var(--dsw-alias-state-warn-primary);font-size:11px}._7D6uKa_cardSpinner{border:2px solid var(--dsw-alias-state-warn-primary);border-top-color:#0000;border-radius:50%;flex:none;width:10px;height:10px;animation:.8s linear infinite _7D6uKa_dshTbSpin}@keyframes _7D6uKa_dshTbSpin{to{transform:rotate(360deg)}}._7D6uKa_primaryButton{color:var(--dsw-alias-label-primary-foreground);background:var(--dsw-alias-button-info-fill);cursor:pointer;white-space:nowrap;border:none;border-radius:8px;padding:6px 14px;font-size:13px;font-weight:600}._7D6uKa_primaryButton:hover:not(:disabled){background:var(--dsw-alias-button-info-hover)}._7D6uKa_primaryButton:disabled{opacity:.5;cursor:default}._7D6uKa_ghostButton{color:var(--dsw-alias-label-primary);border:1px solid var(--dsw-alias-border-l2);cursor:pointer;white-space:nowrap;background:0 0;border-radius:8px;padding:5px 12px;font-size:12px}._7D6uKa_ghostButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}._7D6uKa_ghostButton:disabled{opacity:.45;cursor:default}._7D6uKa_dangerButton{color:#fff;background:var(--dsw-alias-state-error-primary);cursor:pointer;white-space:nowrap;border:none;border-radius:8px;padding:6px 14px;font-size:13px;font-weight:600}._7D6uKa_dangerButton:hover:not(:disabled){filter:brightness(1.08)}._7D6uKa_dangerButton:active:not(:disabled){filter:brightness(.94)}._7D6uKa_dangerButton:disabled{opacity:.5;cursor:default}._7D6uKa_iconButton{width:26px;height:26px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:6px;justify-content:center;align-items:center;padding:0;font-size:13px;display:inline-flex}._7D6uKa_iconButton:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}._7D6uKa_linkButton{color:var(--dsw-alias-state-business-primary);cursor:pointer;white-space:nowrap;background:0 0;border:none;padding:0;font-size:12px}._7D6uKa_linkButton:hover{text-decoration:underline}._7D6uKa_modalBackdrop{z-index:1300;background:var(--dsw-alias-bg-mask-1);justify-content:center;align-items:center;display:flex;position:fixed;inset:0}._7D6uKa_modal{background:var(--dsw-alias-bg-base);border:1px solid var(--dsw-alias-border-l2);width:min(520px,100vw - 48px);max-height:calc(100vh - 96px);box-shadow:var(--dsw-shadow-lv3);color:var(--dsw-alias-label-primary);border-radius:14px;flex-direction:column;gap:12px;padding:18px;display:flex;overflow-y:auto}._7D6uKa_modalTitle{margin:0;font-size:15px;font-weight:700}._7D6uKa_confirmMessage{color:var(--dsw-alias-label-secondary);white-space:pre-wrap;overflow-wrap:anywhere;margin:0;font-size:13px;line-height:1.5}._7D6uKa_modalFooter{justify-content:flex-end;gap:10px;margin-top:4px;display:flex}._7D6uKa_field{flex-direction:column;gap:5px;display:flex}._7D6uKa_fieldLabel{color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:600}._7D6uKa_input{color:var(--dsw-alias-label-primary);background:var(--dsw-specific-input-major);border:1px solid var(--dsw-alias-border-l2);resize:vertical;border-radius:8px;outline:none;padding:7px 10px;font-family:inherit;font-size:13px}._7D6uKa_input:focus{border-color:var(--dsw-alias-state-business-primary)}._7D6uKa_select{color:var(--dsw-alias-label-primary);background:var(--dsw-specific-input-major);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;outline:none;max-width:100%;padding:7px 10px;font-family:inherit;font-size:13px}._7D6uKa_input::placeholder{color:var(--dsw-alias-label-tertiary)}._7D6uKa_formError{color:var(--dsw-alias-state-error-primary);margin:0;font-size:12px}._7D6uKa_detail{background:var(--dsw-alias-bg-base);border:1px solid var(--dsw-alias-border-l2);width:min(640px,100vw - 48px);max-height:calc(100vh - 80px);box-shadow:var(--dsw-shadow-lv3);color:var(--dsw-alias-label-primary);border-radius:14px;flex-direction:column;display:flex;overflow:hidden}._7D6uKa_detailHeader{border-bottom:1px solid var(--dsw-alias-separator-primary);flex:none;align-items:center;gap:10px;padding:14px 18px;display:flex}._7D6uKa_detailTitle{overflow-wrap:anywhere;flex:1;margin:0;font-size:15px;font-weight:700}._7D6uKa_statusBadge{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);border-radius:999px;flex:none;padding:2px 10px;font-size:12px}._7D6uKa_statusBadge[data-status=running]{color:var(--dsw-alias-state-warn-primary);border-color:var(--dsw-alias-state-warn-primary)}._7D6uKa_statusBadge[data-status=done]{color:var(--dsw-alias-state-success-primary);border-color:var(--dsw-alias-state-success-primary)}._7D6uKa_statusBadge[data-status=failed]{color:var(--dsw-alias-state-error-primary);border-color:var(--dsw-alias-state-error-primary)}._7D6uKa_detailBody{flex-direction:column;flex:1;gap:16px;padding:14px 18px;display:flex;overflow-y:auto}._7D6uKa_detailSection{flex-direction:column;gap:6px;display:flex}._7D6uKa_detailSection h4{color:var(--dsw-alias-label-tertiary);text-transform:none;margin:0;font-size:12px;font-weight:700}._7D6uKa_detailText{color:var(--dsw-alias-label-primary);white-space:pre-wrap;overflow-wrap:anywhere;margin:0;font-size:13px;line-height:1.55}._7D6uKa_scheduleToggle{color:var(--dsw-alias-label-primary);cursor:pointer;user-select:none;align-items:center;gap:8px;font-size:13px;display:flex}._7D6uKa_scheduleToggle input{accent-color:var(--dsw-alias-state-business-primary)}._7D6uKa_scheduleRow{align-items:center;gap:8px;display:flex}._7D6uKa_scheduleInput{min-width:0;font-family:var(--dsw-font-markdown-code-block-small);flex:1;font-size:12.5px}._7D6uKa_scheduleInputInvalid,._7D6uKa_scheduleInputInvalid:focus{border-color:var(--dsw-alias-state-error-primary)}._7D6uKa_schedulePreset{color:var(--dsw-alias-label-primary);background:var(--dsw-specific-input-major);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;outline:none;flex:none;padding:7px 8px;font-size:12.5px}._7D6uKa_scheduleMeta{color:var(--dsw-alias-label-secondary);overflow-wrap:anywhere;margin:0;font-size:12px}._7D6uKa_promptBlock{font-size:12.5px;line-height:1.5;font-family:var(--dsw-font-markdown-code-block-small);color:var(--dsw-alias-label-primary);background:var(--dsw-alias-markdown-code-block);border:1px solid var(--dsw-alias-border-l1);white-space:pre-wrap;overflow-wrap:anywhere;border-radius:8px;max-height:240px;margin:0;padding:10px 12px;overflow-y:auto}._7D6uKa_executionList{flex-direction:column;gap:8px;margin:0;padding:0;list-style:none;display:flex}._7D6uKa_executionRow{border:1px solid var(--dsw-alias-border-l1);border-radius:8px;flex-wrap:wrap;align-items:center;gap:10px;padding:8px 10px;display:flex}._7D6uKa_executionBadge{color:var(--dsw-alias-state-warn-primary);background:var(--dsw-alias-state-warn-secondary);border-radius:999px;flex:none;padding:1px 8px;font-size:11px;font-weight:600}._7D6uKa_executionBadge[data-result=succeeded]{color:var(--dsw-alias-state-success-primary);background:0 0}._7D6uKa_executionBadge[data-result=failed]{color:var(--dsw-alias-state-error-primary);background:0 0}._7D6uKa_executionBadge[data-result=cancelled]{color:var(--dsw-alias-label-tertiary);background:0 0}._7D6uKa_executionTimes{color:var(--dsw-alias-label-secondary);font-size:12px}._7D6uKa_executionError{width:100%;color:var(--dsw-alias-state-error-primary);overflow-wrap:anywhere;font-size:12px}._7D6uKa_moveRow{flex-wrap:wrap;gap:8px;display:flex}._7D6uKa_detailFooter{border-top:1px solid var(--dsw-alias-separator-primary);flex:none;align-items:center;gap:10px;padding:12px 18px;display:flex}._7D6uKa_detailMeta{color:var(--dsw-alias-label-tertiary);margin-left:auto;font-size:11px}@container _7D6uKa_task-board-view (width<=768px){._7D6uKa_board{gap:10px;padding:10px}._7D6uKa_boardHeader{flex-wrap:wrap;align-items:center;gap:8px}._7D6uKa_backButton{flex:none;order:1}._7D6uKa_boardTitle{flex:auto;order:2}._7D6uKa_boardHeader>._7D6uKa_detailMeta{flex:1 0 100%;order:3;margin-left:0}._7D6uKa_search{flex:1 0 100%;order:4;min-width:0}._7D6uKa_boardHeader>button:not(._7D6uKa_backButton){flex:1 1 0;order:5;min-width:0}._7D6uKa_columns{scroll-snap-type:inline mandatory;scrollbar-width:none;-webkit-overflow-scrolling:touch;grid-auto-columns:86cqw;gap:10px;padding-inline:2px 14cqw;scroll-padding-inline:2px}._7D6uKa_columns::-webkit-scrollbar{display:none}._7D6uKa_column{scroll-snap-align:start;scroll-snap-stop:always}}@container _7D6uKa_task-board-view (width<=720px){._7D6uKa_boardHeader>._7D6uKa_detailMeta{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}}@container _7D6uKa_task-board-view (width<=600px){._7D6uKa_board{padding-inline:8px}}@media (width<=768px){[data-dsh-taskboard-view]{height:100dvh}._7D6uKa_entry,._7D6uKa_card,._7D6uKa_primaryButton,._7D6uKa_ghostButton,._7D6uKa_dangerButton,._7D6uKa_iconButton,._7D6uKa_linkButton,._7D6uKa_search,._7D6uKa_input,._7D6uKa_select,._7D6uKa_schedulePreset,._7D6uKa_scheduleToggle{min-height:44px}._7D6uKa_search,._7D6uKa_input,._7D6uKa_select,._7D6uKa_schedulePreset{box-sizing:border-box;font-size:16px}._7D6uKa_modalBackdrop{justify-content:stretch;align-items:stretch;width:100vw;height:100dvh}._7D6uKa_modal,._7D6uKa_detail{box-sizing:border-box;border:0;border-radius:0;width:100vw;height:100dvh;max-height:none}._7D6uKa_modal{padding-top:max(16px, env(safe-area-inset-top));padding-right:max(16px, env(safe-area-inset-right));padding-bottom:max(16px, env(safe-area-inset-bottom));padding-left:max(16px, env(safe-area-inset-left))}._7D6uKa_modalFooter{z-index:1;background:var(--dsw-alias-bg-base);flex-wrap:wrap;padding-top:8px;position:sticky;bottom:0}._7D6uKa_modalFooter>button{flex:120px}._7D6uKa_detailHeader{padding-top:max(12px, env(safe-area-inset-top));padding-right:max(14px, env(safe-area-inset-right));padding-left:max(14px, env(safe-area-inset-left));flex-wrap:wrap}._7D6uKa_detailTitle{min-width:0}._7D6uKa_detailBody{overscroll-behavior-y:contain;padding-right:max(14px, env(safe-area-inset-right));padding-left:max(14px, env(safe-area-inset-left))}._7D6uKa_detailFooter{padding-right:max(14px, env(safe-area-inset-right));padding-bottom:max(12px, env(safe-area-inset-bottom));padding-left:max(14px, env(safe-area-inset-left));flex-wrap:wrap}._7D6uKa_detailFooter>button{flex:96px}._7D6uKa_detailFooter>._7D6uKa_detailMeta{text-align:end;flex:1 0 100%;margin-left:0}._7D6uKa_scheduleRow{flex-direction:column;align-items:stretch}._7D6uKa_schedulePreset{width:100%}}._7D6uKa_entry:focus-visible,._7D6uKa_card:focus-visible,._7D6uKa_primaryButton:focus-visible,._7D6uKa_ghostButton:focus-visible,._7D6uKa_dangerButton:focus-visible,._7D6uKa_iconButton:focus-visible,._7D6uKa_linkButton:focus-visible,._7D6uKa_search:focus-visible,._7D6uKa_input:focus-visible,._7D6uKa_select:focus-visible,._7D6uKa_schedulePreset:focus-visible,._7D6uKa_scheduleToggle input:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:2px}._7D6uKa_entry,._7D6uKa_primaryButton,._7D6uKa_ghostButton,._7D6uKa_dangerButton,._7D6uKa_iconButton,._7D6uKa_linkButton,._7D6uKa_search,._7D6uKa_input,._7D6uKa_select,._7D6uKa_schedulePreset,._7D6uKa_scheduleToggle input{transition:background-color .12s,color .12s,border-color .12s,outline-color .12s,box-shadow .12s,transform .12s}._7D6uKa_card:active{box-shadow:var(--dsw-shadow-lv1);transform:translateY(0)}._7D6uKa_entry:active,._7D6uKa_primaryButton:active:not(:disabled),._7D6uKa_ghostButton:active:not(:disabled),._7D6uKa_dangerButton:active:not(:disabled),._7D6uKa_iconButton:active:not(:disabled),._7D6uKa_linkButton:active:not(:disabled){transform:translateY(1px)}._7D6uKa_entry[data-active]:hover{background:var(--dsw-specific-sidebar-nav-item-active)}._7D6uKa_iconButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}._7D6uKa_linkButton:hover:not(:disabled){text-decoration:underline}._7D6uKa_iconButton:disabled,._7D6uKa_linkButton:disabled{opacity:.45;cursor:default}._7D6uKa_search:focus,._7D6uKa_select:focus,._7D6uKa_schedulePreset:focus{border-color:var(--dsw-alias-state-business-primary)}._7D6uKa_scheduleToggle input{margin:0}@media (prefers-reduced-motion:reduce){._7D6uKa_entry,._7D6uKa_card,._7D6uKa_primaryButton,._7D6uKa_ghostButton,._7D6uKa_dangerButton,._7D6uKa_iconButton,._7D6uKa_linkButton,._7D6uKa_search,._7D6uKa_input,._7D6uKa_select,._7D6uKa_schedulePreset,._7D6uKa_scheduleToggle input{transition:none}._7D6uKa_cardSpinner{animation:none}}";
|
|
1983
|
+
const css$1 = "[data-pane=conversation],[class*=centerCol]{position:relative}[data-dsh-taskboard-view]{z-index:60;background:var(--dsw-alias-bg-base);display:none;position:absolute;inset:0;container:_7D6uKa_task-board-view/inline-size}html[data-dsh-taskboard-active]:not([data-dsh-ssh-active]) [data-dsh-taskboard-view]{display:block}html[data-dsh-taskboard-active]:not([data-dsh-ssh-active]) [data-pane=conversation]>:not([data-dsh-taskboard-view]),html[data-dsh-taskboard-active]:not([data-dsh-ssh-active]) [class*=centerCol]>:not([data-dsh-taskboard-view]){display:none!important}._7D6uKa_entry{box-sizing:border-box;width:100%;height:36px;color:var(--dsw-alias-label-secondary);cursor:pointer;white-space:nowrap;background:0 0;border:none;border-radius:8px;align-items:center;gap:8px;padding:0 10px;font-size:13px;display:flex}._7D6uKa_entry:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}._7D6uKa_entry[data-active]{background:var(--dsw-alias-interactive-bg-active);color:var(--dsw-alias-label-primary);font-weight:600}._7D6uKa_entryIcon{flex:none;justify-content:center;align-items:center;width:24px;height:24px;display:inline-flex}._7D6uKa_entryIcon svg{width:18px;height:18px;display:block}._7D6uKa_entryLabel{text-overflow:ellipsis;overflow:hidden}[data-dsh-frame][data-sidebar-collapsed] ._7D6uKa_entry,[data-sidebar-collapsed] ._7D6uKa_entry{border-radius:50%;justify-content:center;width:36px;height:36px;margin:0 auto 12px;padding:0}[data-dsh-frame][data-sidebar-collapsed] ._7D6uKa_entryLabel,[data-sidebar-collapsed] ._7D6uKa_entryLabel{display:none}._7D6uKa_board{box-sizing:border-box;background:var(--dsw-alias-bg-base);min-width:0;height:100%;min-height:0;color:var(--dsw-alias-label-primary);font-family:var(--dsw-font-family);flex-direction:column;gap:12px;padding:14px 16px 16px;display:flex}._7D6uKa_boardHeader{flex:none;align-items:center;gap:10px;display:flex}._7D6uKa_boardTitle{color:var(--dsw-alias-label-primary);white-space:nowrap;margin:0;font-size:16px;font-weight:700}._7D6uKa_backButton{align-items:center;gap:4px;display:inline-flex}._7D6uKa_search{min-width:120px;color:var(--dsw-alias-label-primary);background:var(--dsw-specific-input-major);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;outline:none;flex:0 260px;padding:6px 10px;font-size:13px}._7D6uKa_search::placeholder{color:var(--dsw-alias-label-tertiary)}._7D6uKa_columns{overscroll-behavior-inline:contain;scrollbar-color:var(--dsw-alias-border-l3) var(--dsw-alias-interactive-bg-hover);scrollbar-width:thin;flex:1;grid-auto-columns:minmax(220px,1fr);grid-auto-flow:column;gap:12px;min-height:0;padding-bottom:6px;display:grid;overflow:auto hidden}._7D6uKa_columns::-webkit-scrollbar{height:10px}._7D6uKa_columns::-webkit-scrollbar-track{background:var(--dsw-alias-interactive-bg-hover);border-radius:999px}._7D6uKa_columns::-webkit-scrollbar-thumb{background:var(--dsw-alias-border-l3);background-clip:content-box;border:2px solid #0000;border-radius:999px}._7D6uKa_columns::-webkit-scrollbar-thumb:hover{background:var(--dsw-alias-border-l4);background-clip:content-box}._7D6uKa_column{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:12px;flex-direction:column;min-height:0;display:flex;overflow:hidden}._7D6uKa_columnHeader{flex:none;align-items:center;gap:6px;padding:10px 12px;display:flex}._7D6uKa_columnTitle{color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;flex:1;margin:0;font-size:13px;font-weight:700;overflow:hidden}._7D6uKa_columnCount{min-width:0;color:var(--dsw-alias-label-tertiary);background:var(--dsw-alias-interactive-bg-hover);border-radius:999px;flex:none;padding:1px 8px;font-size:12px}._7D6uKa_statusDot{border-radius:50%;flex:none;width:8px;height:8px}._7D6uKa_statusDot[data-status=backlog]{background:var(--dsw-alias-label-tertiary)}._7D6uKa_statusDot[data-status=todo]{background:var(--dsw-alias-state-business-primary)}._7D6uKa_statusDot[data-status=running]{background:var(--dsw-alias-state-warn-primary)}._7D6uKa_statusDot[data-status=done]{background:var(--dsw-alias-state-success-primary)}._7D6uKa_statusDot[data-status=failed]{background:var(--dsw-alias-state-error-primary)}._7D6uKa_cards{flex-direction:column;flex:1;gap:8px;min-height:0;padding:2px 8px 10px;display:flex;overflow-y:auto}._7D6uKa_columnEmpty{text-align:center;color:var(--dsw-alias-label-tertiary);padding:24px 8px;font-size:12px}._7D6uKa_card{text-align:left;background:var(--dsw-alias-bg-base);border:1px solid var(--dsw-alias-border-l2);cursor:pointer;color:var(--dsw-alias-label-primary);border-radius:10px;flex-direction:column;gap:6px;padding:10px 12px;font-family:inherit;transition:box-shadow .12s,border-color .12s,transform .12s;display:flex}._7D6uKa_card:hover{box-shadow:var(--dsw-shadow-lv2);border-color:var(--dsw-alias-border-l3);transform:translateY(-1px)}._7D6uKa_card[data-status=running]{border-color:var(--dsw-alias-state-warn-primary)}._7D6uKa_cardTitle{-webkit-line-clamp:2;-webkit-box-orient:vertical;font-size:13px;font-weight:600;line-height:1.35;display:-webkit-box;overflow:hidden}._7D6uKa_cardExcerpt{color:var(--dsw-alias-label-secondary);-webkit-line-clamp:2;-webkit-box-orient:vertical;font-size:12px;line-height:1.4;display:-webkit-box;overflow:hidden}._7D6uKa_cardMeta{color:var(--dsw-alias-label-tertiary);align-items:center;gap:8px;font-size:11px;display:flex}._7D6uKa_cardTime{text-overflow:ellipsis;white-space:nowrap;flex:1;overflow:hidden}._7D6uKa_cardSchedule{white-space:nowrap;min-width:0;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-interactive-bg-hover);border-radius:999px;flex:none;padding:2px 6px;font-size:12px;line-height:1}._7D6uKa_cardRun{flex:none}._7D6uKa_cardRun[data-result=failed]{color:var(--dsw-alias-state-error-primary)}._7D6uKa_cardRun[data-result=succeeded]{color:var(--dsw-alias-state-success-primary)}._7D6uKa_cardSession{color:var(--dsw-alias-state-business-primary);flex:none}._7D6uKa_cardRunningLabel{color:var(--dsw-alias-state-warn-primary);font-size:11px}._7D6uKa_cardSpinner{border:2px solid var(--dsw-alias-state-warn-primary);border-top-color:#0000;border-radius:50%;flex:none;width:10px;height:10px;animation:.8s linear infinite _7D6uKa_dshTbSpin}@keyframes _7D6uKa_dshTbSpin{to{transform:rotate(360deg)}}._7D6uKa_primaryButton{color:var(--dsw-alias-label-primary-foreground);background:var(--dsw-alias-button-info-fill);cursor:pointer;white-space:nowrap;border:none;border-radius:8px;padding:6px 14px;font-size:13px;font-weight:600}._7D6uKa_primaryButton:hover:not(:disabled){background:var(--dsw-alias-button-info-hover)}._7D6uKa_primaryButton:disabled{opacity:.5;cursor:default}._7D6uKa_ghostButton{color:var(--dsw-alias-label-primary);border:1px solid var(--dsw-alias-border-l2);cursor:pointer;white-space:nowrap;background:0 0;border-radius:8px;padding:5px 12px;font-size:12px}._7D6uKa_ghostButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}._7D6uKa_ghostButton:disabled{opacity:.45;cursor:default}._7D6uKa_dangerButton{color:#fff;background:var(--dsw-alias-state-error-primary);cursor:pointer;white-space:nowrap;border:none;border-radius:8px;padding:6px 14px;font-size:13px;font-weight:600}._7D6uKa_dangerButton:hover:not(:disabled){filter:brightness(1.08)}._7D6uKa_dangerButton:active:not(:disabled){filter:brightness(.94)}._7D6uKa_dangerButton:disabled{opacity:.5;cursor:default}._7D6uKa_iconButton{width:26px;height:26px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:6px;justify-content:center;align-items:center;padding:0;font-size:13px;display:inline-flex}._7D6uKa_iconButton:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}._7D6uKa_linkButton{color:var(--dsw-alias-state-business-primary);cursor:pointer;white-space:nowrap;background:0 0;border:none;padding:0;font-size:12px}._7D6uKa_linkButton:hover{text-decoration:underline}._7D6uKa_modalBackdrop{z-index:1300;background:var(--dsw-alias-bg-mask-1);justify-content:center;align-items:center;display:flex;position:fixed;inset:0}._7D6uKa_modal{background:var(--dsw-alias-bg-base);border:1px solid var(--dsw-alias-border-l2);width:min(520px,100vw - 48px);max-height:calc(100vh - 96px);box-shadow:var(--dsw-shadow-lv3);color:var(--dsw-alias-label-primary);border-radius:14px;flex-direction:column;gap:12px;padding:18px;display:flex;overflow-y:auto}._7D6uKa_modalTitle{margin:0;font-size:15px;font-weight:700}._7D6uKa_confirmMessage{color:var(--dsw-alias-label-secondary);white-space:pre-wrap;overflow-wrap:anywhere;margin:0;font-size:13px;line-height:1.5}._7D6uKa_modalFooter{justify-content:flex-end;gap:10px;margin-top:4px;display:flex}._7D6uKa_field{flex-direction:column;gap:5px;display:flex}._7D6uKa_fieldLabel{color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:600}._7D6uKa_input{color:var(--dsw-alias-label-primary);background:var(--dsw-specific-input-major);border:1px solid var(--dsw-alias-border-l2);resize:vertical;border-radius:8px;outline:none;padding:7px 10px;font-family:inherit;font-size:13px}._7D6uKa_input:focus{border-color:var(--dsw-alias-state-business-primary)}._7D6uKa_select{color:var(--dsw-alias-label-primary);background:var(--dsw-specific-input-major);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;outline:none;max-width:100%;padding:7px 10px;font-family:inherit;font-size:13px}._7D6uKa_input::placeholder{color:var(--dsw-alias-label-tertiary)}._7D6uKa_formError{color:var(--dsw-alias-state-error-primary);margin:0;font-size:12px}._7D6uKa_detail{background:var(--dsw-alias-bg-base);border:1px solid var(--dsw-alias-border-l2);width:min(640px,100vw - 48px);max-height:calc(100vh - 80px);box-shadow:var(--dsw-shadow-lv3);color:var(--dsw-alias-label-primary);border-radius:14px;flex-direction:column;display:flex;overflow:hidden}._7D6uKa_detailHeader{border-bottom:1px solid var(--dsw-alias-separator-primary);flex:none;align-items:center;gap:10px;padding:14px 18px;display:flex}._7D6uKa_detailTitle{overflow-wrap:anywhere;flex:1;margin:0;font-size:15px;font-weight:700}._7D6uKa_statusBadge{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);border-radius:999px;flex:none;padding:2px 10px;font-size:12px}._7D6uKa_statusBadge[data-status=running]{color:var(--dsw-alias-state-warn-primary);border-color:var(--dsw-alias-state-warn-primary)}._7D6uKa_statusBadge[data-status=done]{color:var(--dsw-alias-state-success-primary);border-color:var(--dsw-alias-state-success-primary)}._7D6uKa_statusBadge[data-status=failed]{color:var(--dsw-alias-state-error-primary);border-color:var(--dsw-alias-state-error-primary)}._7D6uKa_detailBody{flex-direction:column;flex:1;gap:16px;padding:14px 18px;display:flex;overflow-y:auto}._7D6uKa_detailSection{flex-direction:column;gap:6px;display:flex}._7D6uKa_detailSection h4{color:var(--dsw-alias-label-tertiary);text-transform:none;margin:0;font-size:12px;font-weight:700}._7D6uKa_detailText{color:var(--dsw-alias-label-primary);white-space:pre-wrap;overflow-wrap:anywhere;margin:0;font-size:13px;line-height:1.55}._7D6uKa_scheduleToggle{color:var(--dsw-alias-label-primary);cursor:pointer;user-select:none;align-items:center;gap:8px;font-size:13px;display:flex}._7D6uKa_scheduleToggle input{accent-color:var(--dsw-alias-state-business-primary)}._7D6uKa_scheduleRow{align-items:center;gap:8px;display:flex}._7D6uKa_scheduleInput{min-width:0;font-family:var(--dsw-font-markdown-code-block-small);flex:1;font-size:12.5px}._7D6uKa_scheduleInputInvalid,._7D6uKa_scheduleInputInvalid:focus{border-color:var(--dsw-alias-state-error-primary)}._7D6uKa_schedulePreset{color:var(--dsw-alias-label-primary);background:var(--dsw-specific-input-major);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;outline:none;flex:none;padding:7px 8px;font-size:12.5px}._7D6uKa_scheduleMeta{color:var(--dsw-alias-label-secondary);overflow-wrap:anywhere;margin:0;font-size:12px}._7D6uKa_promptBlock{font-size:12.5px;line-height:1.5;font-family:var(--dsw-font-markdown-code-block-small);color:var(--dsw-alias-label-primary);background:var(--dsw-alias-markdown-code-block);border:1px solid var(--dsw-alias-border-l1);white-space:pre-wrap;overflow-wrap:anywhere;border-radius:8px;max-height:240px;margin:0;padding:10px 12px;overflow-y:auto}._7D6uKa_executionList{flex-direction:column;gap:8px;margin:0;padding:0;list-style:none;display:flex}._7D6uKa_executionRow{border:1px solid var(--dsw-alias-border-l1);border-radius:8px;flex-wrap:wrap;align-items:center;gap:10px;padding:8px 10px;display:flex}._7D6uKa_executionBadge{color:var(--dsw-alias-state-warn-primary);background:var(--dsw-alias-state-warn-secondary);border-radius:999px;flex:none;padding:1px 8px;font-size:11px;font-weight:600}._7D6uKa_executionBadge[data-result=succeeded]{color:var(--dsw-alias-state-success-primary);background:0 0}._7D6uKa_executionBadge[data-result=failed]{color:var(--dsw-alias-state-error-primary);background:0 0}._7D6uKa_executionBadge[data-result=cancelled]{color:var(--dsw-alias-label-tertiary);background:0 0}._7D6uKa_executionTimes{color:var(--dsw-alias-label-secondary);font-size:12px}._7D6uKa_executionError{width:100%;color:var(--dsw-alias-state-error-primary);overflow-wrap:anywhere;font-size:12px}._7D6uKa_moveRow{flex-wrap:wrap;gap:8px;display:flex}._7D6uKa_detailFooter{border-top:1px solid var(--dsw-alias-separator-primary);flex:none;align-items:center;gap:10px;padding:12px 18px;display:flex}._7D6uKa_detailMeta{color:var(--dsw-alias-label-tertiary);margin-left:auto;font-size:11px}@container _7D6uKa_task-board-view (width<=768px){._7D6uKa_board{gap:10px;padding:10px}._7D6uKa_boardHeader{flex-wrap:wrap;align-items:center;gap:8px}._7D6uKa_backButton{flex:none;order:1}._7D6uKa_boardTitle{flex:auto;order:2}._7D6uKa_boardHeader>._7D6uKa_detailMeta{flex:1 0 100%;order:3;margin-left:0}._7D6uKa_search{flex:1 0 100%;order:4;min-width:0}._7D6uKa_boardHeader>button:not(._7D6uKa_backButton){flex:1 1 0;order:5;min-width:0}._7D6uKa_columns{scroll-snap-type:inline mandatory;scrollbar-width:none;-webkit-overflow-scrolling:touch;grid-auto-columns:86cqw;gap:10px;padding-inline:2px 14cqw;scroll-padding-inline:2px}._7D6uKa_columns::-webkit-scrollbar{display:none}._7D6uKa_column{scroll-snap-align:start;scroll-snap-stop:always}}@container _7D6uKa_task-board-view (width<=720px){._7D6uKa_boardHeader>._7D6uKa_detailMeta{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}}@container _7D6uKa_task-board-view (width<=600px){._7D6uKa_board{padding-inline:8px}}@media (width<=768px){[data-dsh-taskboard-view]{height:100dvh}._7D6uKa_entry,._7D6uKa_card,._7D6uKa_primaryButton,._7D6uKa_ghostButton,._7D6uKa_dangerButton,._7D6uKa_iconButton,._7D6uKa_linkButton,._7D6uKa_search,._7D6uKa_input,._7D6uKa_select,._7D6uKa_schedulePreset,._7D6uKa_scheduleToggle{min-height:44px}._7D6uKa_search,._7D6uKa_input,._7D6uKa_select,._7D6uKa_schedulePreset{box-sizing:border-box;font-size:16px}._7D6uKa_modalBackdrop{justify-content:stretch;align-items:stretch;width:100vw;height:100dvh}._7D6uKa_modal,._7D6uKa_detail{box-sizing:border-box;border:0;border-radius:0;width:100vw;height:100dvh;max-height:none}._7D6uKa_modal{padding-top:max(16px, env(safe-area-inset-top));padding-right:max(16px, env(safe-area-inset-right));padding-bottom:max(16px, env(safe-area-inset-bottom));padding-left:max(16px, env(safe-area-inset-left))}._7D6uKa_modalFooter{z-index:1;background:var(--dsw-alias-bg-base);flex-wrap:wrap;padding-top:8px;position:sticky;bottom:0}._7D6uKa_modalFooter>button{flex:120px}._7D6uKa_detailHeader{padding-top:max(12px, env(safe-area-inset-top));padding-right:max(14px, env(safe-area-inset-right));padding-left:max(14px, env(safe-area-inset-left));flex-wrap:wrap}._7D6uKa_detailTitle{min-width:0}._7D6uKa_detailBody{overscroll-behavior-y:contain;padding-right:max(14px, env(safe-area-inset-right));padding-left:max(14px, env(safe-area-inset-left))}._7D6uKa_detailFooter{padding-right:max(14px, env(safe-area-inset-right));padding-bottom:max(12px, env(safe-area-inset-bottom));padding-left:max(14px, env(safe-area-inset-left));flex-wrap:wrap}._7D6uKa_detailFooter>button{flex:96px}._7D6uKa_detailFooter>._7D6uKa_detailMeta{text-align:end;flex:1 0 100%;margin-left:0}._7D6uKa_scheduleRow{flex-direction:column;align-items:stretch}._7D6uKa_schedulePreset{width:100%}}._7D6uKa_entry:focus-visible,._7D6uKa_card:focus-visible,._7D6uKa_primaryButton:focus-visible,._7D6uKa_ghostButton:focus-visible,._7D6uKa_dangerButton:focus-visible,._7D6uKa_iconButton:focus-visible,._7D6uKa_linkButton:focus-visible,._7D6uKa_search:focus-visible,._7D6uKa_input:focus-visible,._7D6uKa_select:focus-visible,._7D6uKa_schedulePreset:focus-visible,._7D6uKa_scheduleToggle input:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:2px}._7D6uKa_entry,._7D6uKa_primaryButton,._7D6uKa_ghostButton,._7D6uKa_dangerButton,._7D6uKa_iconButton,._7D6uKa_linkButton,._7D6uKa_search,._7D6uKa_input,._7D6uKa_select,._7D6uKa_schedulePreset,._7D6uKa_scheduleToggle input{transition:background-color .12s,color .12s,border-color .12s,outline-color .12s,box-shadow .12s,transform .12s}._7D6uKa_card:active{box-shadow:var(--dsw-shadow-lv1);transform:translateY(0)}._7D6uKa_entry:active,._7D6uKa_primaryButton:active:not(:disabled),._7D6uKa_ghostButton:active:not(:disabled),._7D6uKa_dangerButton:active:not(:disabled),._7D6uKa_iconButton:active:not(:disabled),._7D6uKa_linkButton:active:not(:disabled){transform:translateY(1px)}._7D6uKa_entry[data-active]:hover{background:var(--dsw-specific-sidebar-nav-item-active)}._7D6uKa_iconButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}._7D6uKa_linkButton:hover:not(:disabled){text-decoration:underline}._7D6uKa_iconButton:disabled,._7D6uKa_linkButton:disabled{opacity:.45;cursor:default}._7D6uKa_search:focus,._7D6uKa_select:focus,._7D6uKa_schedulePreset:focus{border-color:var(--dsw-alias-state-business-primary)}._7D6uKa_scheduleToggle input{margin:0}@media (prefers-reduced-motion:reduce){._7D6uKa_entry,._7D6uKa_card,._7D6uKa_primaryButton,._7D6uKa_ghostButton,._7D6uKa_dangerButton,._7D6uKa_iconButton,._7D6uKa_linkButton,._7D6uKa_search,._7D6uKa_input,._7D6uKa_select,._7D6uKa_schedulePreset,._7D6uKa_scheduleToggle input{transition:none}._7D6uKa_cardSpinner{animation:none}}._7D6uKa_cardTags{flex-wrap:wrap;gap:4px;display:flex}._7D6uKa_cardTag{border:1px solid var(--dsh-task-tag-border);background:var(--dsh-task-tag-fill);max-width:100%;color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;border-radius:999px;padding:0 7px;font-size:10px;line-height:16px;overflow:hidden}._7D6uKa_tagFilter{flex-wrap:wrap;align-items:center;gap:6px;margin:0 0 10px;display:flex}._7D6uKa_tagFilterLabel{color:var(--dsw-alias-label-tertiary);font-size:11px}._7D6uKa_tagChip{border:1px solid var(--dsh-task-tag-border);color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border-radius:999px;padding:1px 9px;font-family:inherit;font-size:11px;line-height:18px}._7D6uKa_tagChip[data-active=true]{background:var(--dsh-task-tag-fill);color:var(--dsw-alias-label-primary)}._7D6uKa_cardTag[data-tag-tone=\"0\"],._7D6uKa_tagChip[data-tag-tone=\"0\"]{--dsh-task-tag-fill:#4e93e82e;--dsh-task-tag-border:#4e93e866}._7D6uKa_cardTag[data-tag-tone=\"1\"],._7D6uKa_tagChip[data-tag-tone=\"1\"]{--dsh-task-tag-fill:#2ea36a2e;--dsh-task-tag-border:#2ea36a66}._7D6uKa_cardTag[data-tag-tone=\"2\"],._7D6uKa_tagChip[data-tag-tone=\"2\"]{--dsh-task-tag-fill:#d08a2a2e;--dsh-task-tag-border:#d08a2a66}._7D6uKa_cardTag[data-tag-tone=\"3\"],._7D6uKa_tagChip[data-tag-tone=\"3\"]{--dsh-task-tag-fill:#b456c82e;--dsh-task-tag-border:#b456c866}._7D6uKa_cardTag[data-tag-tone=\"4\"],._7D6uKa_tagChip[data-tag-tone=\"4\"]{--dsh-task-tag-fill:#cf5f7a2e;--dsh-task-tag-border:#cf5f7a66}._7D6uKa_cardTag[data-tag-tone=\"5\"],._7D6uKa_tagChip[data-tag-tone=\"5\"]{--dsh-task-tag-fill:#4a9fb52e;--dsh-task-tag-border:#4a9fb566}._7D6uKa_fieldHint{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:1.4}._7D6uKa_tagRow{align-items:center;gap:6px;display:flex}._7D6uKa_tagRow ._7D6uKa_input{flex:1 1 0;min-width:0}._7D6uKa_tagRow ._7D6uKa_ghostButton{flex:none}._7D6uKa_tagAddButton{align-self:flex-start}._7D6uKa_projectFilter{flex:none;align-items:center;gap:6px;display:flex}._7D6uKa_projectFilterLabel{color:var(--dsw-alias-label-secondary);white-space:nowrap;font-size:12px}._7D6uKa_projectDialog{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:10px;flex-direction:column;flex:none;gap:8px;margin-bottom:8px;padding:10px 12px;display:flex}._7D6uKa_projectDialogActions{justify-content:flex-end;gap:8px;display:flex}._7D6uKa_aiParse{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:10px;flex-direction:column;gap:6px;padding:10px 12px;display:flex}._7D6uKa_aiParseRow{align-items:center;gap:8px;display:flex}._7D6uKa_aiParseRow ._7D6uKa_select{flex:1 1 0;min-width:0}._7D6uKa_aiParseRow ._7D6uKa_ghostButton,._7D6uKa_aiParseRow ._7D6uKa_primaryButton{flex:none}";
|
|
1827
1984
|
const tagId$1 = "@linxin666/dsh-client-ui-task-board/packages/dsh-task-board/src/client/board.module.css";
|
|
1828
1985
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
|
|
1829
1986
|
const tag = document.createElement("style");
|
|
@@ -1833,6 +1990,8 @@ window.__ModuleLoader__.load({
|
|
|
1833
1990
|
document.head.appendChild(tag);
|
|
1834
1991
|
}
|
|
1835
1992
|
var board_module_css_default = {
|
|
1993
|
+
"aiParse": "_7D6uKa_aiParse",
|
|
1994
|
+
"aiParseRow": "_7D6uKa_aiParseRow",
|
|
1836
1995
|
"backButton": "_7D6uKa_backButton",
|
|
1837
1996
|
"board": "_7D6uKa_board",
|
|
1838
1997
|
"boardHeader": "_7D6uKa_boardHeader",
|
|
@@ -1845,6 +2004,8 @@ window.__ModuleLoader__.load({
|
|
|
1845
2004
|
"cardSchedule": "_7D6uKa_cardSchedule",
|
|
1846
2005
|
"cardSession": "_7D6uKa_cardSession",
|
|
1847
2006
|
"cardSpinner": "_7D6uKa_cardSpinner",
|
|
2007
|
+
"cardTag": "_7D6uKa_cardTag",
|
|
2008
|
+
"cardTags": "_7D6uKa_cardTags",
|
|
1848
2009
|
"cardTime": "_7D6uKa_cardTime",
|
|
1849
2010
|
"cardTitle": "_7D6uKa_cardTitle",
|
|
1850
2011
|
"cards": "_7D6uKa_cards",
|
|
@@ -1874,6 +2035,7 @@ window.__ModuleLoader__.load({
|
|
|
1874
2035
|
"executionRow": "_7D6uKa_executionRow",
|
|
1875
2036
|
"executionTimes": "_7D6uKa_executionTimes",
|
|
1876
2037
|
"field": "_7D6uKa_field",
|
|
2038
|
+
"fieldHint": "_7D6uKa_fieldHint",
|
|
1877
2039
|
"fieldLabel": "_7D6uKa_fieldLabel",
|
|
1878
2040
|
"formError": "_7D6uKa_formError",
|
|
1879
2041
|
"ghostButton": "_7D6uKa_ghostButton",
|
|
@@ -1886,6 +2048,10 @@ window.__ModuleLoader__.load({
|
|
|
1886
2048
|
"modalTitle": "_7D6uKa_modalTitle",
|
|
1887
2049
|
"moveRow": "_7D6uKa_moveRow",
|
|
1888
2050
|
"primaryButton": "_7D6uKa_primaryButton",
|
|
2051
|
+
"projectDialog": "_7D6uKa_projectDialog",
|
|
2052
|
+
"projectDialogActions": "_7D6uKa_projectDialogActions",
|
|
2053
|
+
"projectFilter": "_7D6uKa_projectFilter",
|
|
2054
|
+
"projectFilterLabel": "_7D6uKa_projectFilterLabel",
|
|
1889
2055
|
"promptBlock": "_7D6uKa_promptBlock",
|
|
1890
2056
|
"scheduleInput": "_7D6uKa_scheduleInput",
|
|
1891
2057
|
"scheduleInputInvalid": "_7D6uKa_scheduleInputInvalid",
|
|
@@ -1897,6 +2063,11 @@ window.__ModuleLoader__.load({
|
|
|
1897
2063
|
"select": "_7D6uKa_select",
|
|
1898
2064
|
"statusBadge": "_7D6uKa_statusBadge",
|
|
1899
2065
|
"statusDot": "_7D6uKa_statusDot",
|
|
2066
|
+
"tagAddButton": "_7D6uKa_tagAddButton",
|
|
2067
|
+
"tagChip": "_7D6uKa_tagChip",
|
|
2068
|
+
"tagFilter": "_7D6uKa_tagFilter",
|
|
2069
|
+
"tagFilterLabel": "_7D6uKa_tagFilterLabel",
|
|
2070
|
+
"tagRow": "_7D6uKa_tagRow",
|
|
1900
2071
|
"task-board-view": "_7D6uKa_task-board-view"
|
|
1901
2072
|
};
|
|
1902
2073
|
//#endregion
|
|
@@ -1922,6 +2093,8 @@ window.__ModuleLoader__.load({
|
|
|
1922
2093
|
];
|
|
1923
2094
|
//#endregion
|
|
1924
2095
|
//#region src/client/board/TaskForm.tsx
|
|
2096
|
+
/** DOM id shared by the tag-name inputs and their datalist (one board at a time). */
|
|
2097
|
+
const TAG_NAME_LIST_ID = "dsh-task-board-tag-names";
|
|
1925
2098
|
/** Modal overlay: closes on backdrop press, submits through the form. */
|
|
1926
2099
|
function ModalShell({ ariaLabel, title, error, pending, submitLabel, onSubmit, onClose, children }) {
|
|
1927
2100
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
@@ -2009,6 +2182,94 @@ window.__ModuleLoader__.load({
|
|
|
2009
2182
|
})
|
|
2010
2183
|
] });
|
|
2011
2184
|
}
|
|
2185
|
+
/**
|
|
2186
|
+
* Task labels (issue #1521): one row per label holding the badge name and an
|
|
2187
|
+
* optional execution hint. The name inputs offer the labels already used on the
|
|
2188
|
+
* board through a datalist, and picking one adopts its hint when the row has
|
|
2189
|
+
* none — so a business line is defined once and reused by every later task.
|
|
2190
|
+
*/
|
|
2191
|
+
function TaskTagFields({ tags, knownTags, onChange }) {
|
|
2192
|
+
const update = (index, patch) => {
|
|
2193
|
+
onChange(tags.map((tag, position) => position === index ? {
|
|
2194
|
+
...tag,
|
|
2195
|
+
...patch
|
|
2196
|
+
} : tag));
|
|
2197
|
+
};
|
|
2198
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2199
|
+
className: board_module_css_default.field,
|
|
2200
|
+
children: [
|
|
2201
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2202
|
+
className: board_module_css_default.fieldLabel,
|
|
2203
|
+
children: t("new.tags")
|
|
2204
|
+
}),
|
|
2205
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2206
|
+
className: board_module_css_default.fieldHint,
|
|
2207
|
+
children: t("new.tagsHint")
|
|
2208
|
+
}),
|
|
2209
|
+
tags.map((tag, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2210
|
+
className: board_module_css_default.tagRow,
|
|
2211
|
+
children: [
|
|
2212
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
2213
|
+
className: board_module_css_default.input,
|
|
2214
|
+
list: TAG_NAME_LIST_ID,
|
|
2215
|
+
value: tag.name,
|
|
2216
|
+
maxLength: 32,
|
|
2217
|
+
placeholder: t("new.tagNamePlaceholder"),
|
|
2218
|
+
"aria-label": t("new.tagName"),
|
|
2219
|
+
onChange: (event) => {
|
|
2220
|
+
const name = event.target.value;
|
|
2221
|
+
const known = knownTags.find((candidate) => candidate.name === name);
|
|
2222
|
+
const adoptsHint = known?.promptPrefix !== void 0 && (tag.promptPrefix ?? "").trim() === "";
|
|
2223
|
+
update(index, adoptsHint ? {
|
|
2224
|
+
name,
|
|
2225
|
+
promptPrefix: known.promptPrefix
|
|
2226
|
+
} : { name });
|
|
2227
|
+
}
|
|
2228
|
+
}),
|
|
2229
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
2230
|
+
className: board_module_css_default.input,
|
|
2231
|
+
value: tag.promptPrefix ?? "",
|
|
2232
|
+
maxLength: 200,
|
|
2233
|
+
placeholder: t("new.tagPromptPlaceholder"),
|
|
2234
|
+
"aria-label": t("new.tagPrompt"),
|
|
2235
|
+
onChange: (event) => {
|
|
2236
|
+
update(index, { promptPrefix: event.target.value });
|
|
2237
|
+
}
|
|
2238
|
+
}),
|
|
2239
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2240
|
+
type: "button",
|
|
2241
|
+
className: board_module_css_default.ghostButton,
|
|
2242
|
+
"aria-label": t("new.tagRemove", { name: tag.name }),
|
|
2243
|
+
onClick: () => {
|
|
2244
|
+
onChange(tags.filter((_, position) => position !== index));
|
|
2245
|
+
},
|
|
2246
|
+
children: "×"
|
|
2247
|
+
})
|
|
2248
|
+
]
|
|
2249
|
+
}, index)),
|
|
2250
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("datalist", {
|
|
2251
|
+
id: TAG_NAME_LIST_ID,
|
|
2252
|
+
children: knownTags.map((tag) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", { value: tag.name }, tag.name))
|
|
2253
|
+
}),
|
|
2254
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
2255
|
+
type: "button",
|
|
2256
|
+
className: board_module_css_default.ghostButton + " " + board_module_css_default.tagAddButton,
|
|
2257
|
+
disabled: tags.length >= 8,
|
|
2258
|
+
onClick: () => {
|
|
2259
|
+
onChange([...tags, { name: "" }]);
|
|
2260
|
+
},
|
|
2261
|
+
children: ["+ ", t("new.tagAdd")]
|
|
2262
|
+
})
|
|
2263
|
+
]
|
|
2264
|
+
});
|
|
2265
|
+
}
|
|
2266
|
+
/**
|
|
2267
|
+
* Clean a tag list via normalizeTags: trim, drop blanks and duplicates, cap
|
|
2268
|
+
* lengths and count, so the wire always carries a valid tag list.
|
|
2269
|
+
*/
|
|
2270
|
+
function cleanTags(tags) {
|
|
2271
|
+
return normalizeTags(tags) ?? [];
|
|
2272
|
+
}
|
|
2012
2273
|
//#endregion
|
|
2013
2274
|
//#region src/client/board/NewTaskModal.tsx
|
|
2014
2275
|
/**
|
|
@@ -2016,12 +2277,12 @@ window.__ModuleLoader__.load({
|
|
|
2016
2277
|
* Creates through the Host and closes only after the Host confirms it.
|
|
2017
2278
|
*/
|
|
2018
2279
|
/** New-task form overlay. */
|
|
2019
|
-
function NewTaskModal({ controller, onClose, initialTask, onDuplicateSuccess }) {
|
|
2280
|
+
function NewTaskModal({ controller, onClose, initialTask, defaultWorkspaceId, onDuplicateSuccess }) {
|
|
2020
2281
|
const isDuplicate = initialTask !== void 0;
|
|
2021
2282
|
const [title, setTitle] = (0, react.useState)(initialTask?.title ?? "");
|
|
2022
2283
|
const [description, setDescription] = (0, react.useState)(initialTask?.description ?? "");
|
|
2023
2284
|
const [prompt, setPrompt] = (0, react.useState)(initialTask?.prompt ?? "");
|
|
2024
|
-
const [workspaceId, setWorkspaceId] = (0, react.useState)(initialTask?.workspaceId ?? "");
|
|
2285
|
+
const [workspaceId, setWorkspaceId] = (0, react.useState)(initialTask?.workspaceId ?? defaultWorkspaceId ?? "");
|
|
2025
2286
|
const [mode, setMode] = (0, react.useState)(initialTask?.mode ?? "");
|
|
2026
2287
|
const [permission, setPermission] = (0, react.useState)(initialTask?.permission ?? "");
|
|
2027
2288
|
const [model, setModel] = (0, react.useState)(initialTask?.model ?? "");
|
|
@@ -2032,11 +2293,47 @@ window.__ModuleLoader__.load({
|
|
|
2032
2293
|
const [freezeText, setFreezeText] = (0, react.useState)("");
|
|
2033
2294
|
const [freezeError, setFreezeError] = (0, react.useState)(void 0);
|
|
2034
2295
|
const [handoverText, setHandoverText] = (0, react.useState)(initialTask?.handover?.references !== void 0 ? initialTask.handover.references.join("\n") : "");
|
|
2296
|
+
const [tags, setTags] = (0, react.useState)(initialTask?.tags ?? []);
|
|
2035
2297
|
const [archiveOriginal, setArchiveOriginal] = (0, react.useState)(true);
|
|
2036
2298
|
const [error, setError] = (0, react.useState)(void 0);
|
|
2037
2299
|
const [pending, setPending] = (0, react.useState)(false);
|
|
2038
2300
|
const [options, setOptions] = (0, react.useState)(controller.getSnapshot().executionOptions);
|
|
2301
|
+
const [canParse] = (0, react.useState)(controller.getSnapshot().canParseTask === true);
|
|
2302
|
+
const [parseText, setParseText] = (0, react.useState)("");
|
|
2303
|
+
const [parseModel, setParseModel] = (0, react.useState)("");
|
|
2304
|
+
const [parsePending, setParsePending] = (0, react.useState)(false);
|
|
2305
|
+
const [parseError, setParseError] = (0, react.useState)(void 0);
|
|
2306
|
+
const parseAbort = (0, react.useRef)(void 0);
|
|
2307
|
+
const parseModels = options.models ?? [];
|
|
2039
2308
|
(0, react.useEffect)(() => controller.subscribe(() => setOptions(controller.getSnapshot().executionOptions)), [controller]);
|
|
2309
|
+
(0, react.useEffect)(() => {
|
|
2310
|
+
if (parseModel === "" && parseModels.length > 0) setParseModel(parseModels[0].id);
|
|
2311
|
+
}, [parseModel, options.models]);
|
|
2312
|
+
const runParse = async () => {
|
|
2313
|
+
const text = parseText.trim();
|
|
2314
|
+
if (text === "") {
|
|
2315
|
+
setParseError(t("new.aiParseEmpty"));
|
|
2316
|
+
return;
|
|
2317
|
+
}
|
|
2318
|
+
const abort = new AbortController();
|
|
2319
|
+
parseAbort.current = abort;
|
|
2320
|
+
setParsePending(true);
|
|
2321
|
+
setParseError(void 0);
|
|
2322
|
+
try {
|
|
2323
|
+
const draft = await controller.parseTaskDraft({
|
|
2324
|
+
text,
|
|
2325
|
+
...parseModel === "" ? {} : { model: parseModel }
|
|
2326
|
+
}, abort.signal);
|
|
2327
|
+
setTitle(draft.title);
|
|
2328
|
+
setDescription(draft.description);
|
|
2329
|
+
setPrompt(draft.prompt);
|
|
2330
|
+
} catch (parseFailure) {
|
|
2331
|
+
if (!abort.signal.aborted) setParseError(parseFailure instanceof Error ? parseFailure.message : String(parseFailure));
|
|
2332
|
+
} finally {
|
|
2333
|
+
parseAbort.current = void 0;
|
|
2334
|
+
setParsePending(false);
|
|
2335
|
+
}
|
|
2336
|
+
};
|
|
2040
2337
|
const submit = async () => {
|
|
2041
2338
|
if (scheduleEnabled) {
|
|
2042
2339
|
const cron = scheduleCron.trim();
|
|
@@ -2064,6 +2361,7 @@ window.__ModuleLoader__.load({
|
|
|
2064
2361
|
mode: mode === "" ? void 0 : mode,
|
|
2065
2362
|
permission: permission === "" ? void 0 : permission
|
|
2066
2363
|
};
|
|
2364
|
+
const tagList = cleanTags(tags);
|
|
2067
2365
|
setPending(true);
|
|
2068
2366
|
if (await controller.createTaskConfirmed({
|
|
2069
2367
|
title,
|
|
@@ -2076,6 +2374,7 @@ window.__ModuleLoader__.load({
|
|
|
2076
2374
|
permission: permission === "" ? void 0 : permission,
|
|
2077
2375
|
model: model === "" ? void 0 : model,
|
|
2078
2376
|
...reuseSession ? { reuseSession: true } : {},
|
|
2377
|
+
...tagList.length > 0 ? { tags: tagList } : {},
|
|
2079
2378
|
schedule: scheduleEnabled ? {
|
|
2080
2379
|
enabled: true,
|
|
2081
2380
|
cron: scheduleCron.trim()
|
|
@@ -2103,6 +2402,65 @@ window.__ModuleLoader__.load({
|
|
|
2103
2402
|
},
|
|
2104
2403
|
onClose,
|
|
2105
2404
|
children: [
|
|
2405
|
+
canParse && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
2406
|
+
className: board_module_css_default.aiParse,
|
|
2407
|
+
"data-dsh-part": "ai-parse",
|
|
2408
|
+
children: [
|
|
2409
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2410
|
+
className: board_module_css_default.fieldLabel,
|
|
2411
|
+
children: t("new.aiParse")
|
|
2412
|
+
}),
|
|
2413
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2414
|
+
className: board_module_css_default.fieldHint,
|
|
2415
|
+
children: t("new.aiParseHint")
|
|
2416
|
+
}),
|
|
2417
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
|
|
2418
|
+
className: board_module_css_default.input,
|
|
2419
|
+
rows: 3,
|
|
2420
|
+
value: parseText,
|
|
2421
|
+
placeholder: t("new.aiParsePlaceholder"),
|
|
2422
|
+
spellCheck: false,
|
|
2423
|
+
onChange: (event) => {
|
|
2424
|
+
setParseText(event.target.value);
|
|
2425
|
+
setParseError(void 0);
|
|
2426
|
+
}
|
|
2427
|
+
}),
|
|
2428
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2429
|
+
className: board_module_css_default.aiParseRow,
|
|
2430
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("select", {
|
|
2431
|
+
className: board_module_css_default.select,
|
|
2432
|
+
value: parseModel,
|
|
2433
|
+
"aria-label": t("new.aiParseModel"),
|
|
2434
|
+
onChange: (event) => {
|
|
2435
|
+
setParseModel(event.target.value);
|
|
2436
|
+
},
|
|
2437
|
+
children: parseModels.map((option) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
2438
|
+
value: option.id,
|
|
2439
|
+
children: option.name ?? option.id
|
|
2440
|
+
}, option.id))
|
|
2441
|
+
}), parsePending ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2442
|
+
type: "button",
|
|
2443
|
+
className: board_module_css_default.ghostButton,
|
|
2444
|
+
onClick: () => {
|
|
2445
|
+
parseAbort.current?.abort();
|
|
2446
|
+
},
|
|
2447
|
+
children: t("new.aiParseCancel")
|
|
2448
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2449
|
+
type: "button",
|
|
2450
|
+
className: board_module_css_default.primaryButton,
|
|
2451
|
+
disabled: parseText.trim() === "",
|
|
2452
|
+
onClick: () => {
|
|
2453
|
+
runParse();
|
|
2454
|
+
},
|
|
2455
|
+
children: t("new.aiParseRun")
|
|
2456
|
+
})]
|
|
2457
|
+
}),
|
|
2458
|
+
parseError !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2459
|
+
className: board_module_css_default.formError,
|
|
2460
|
+
children: parseError
|
|
2461
|
+
})
|
|
2462
|
+
]
|
|
2463
|
+
}),
|
|
2106
2464
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(TaskContentFields, {
|
|
2107
2465
|
title,
|
|
2108
2466
|
description,
|
|
@@ -2114,6 +2472,11 @@ window.__ModuleLoader__.load({
|
|
|
2114
2472
|
onDescriptionChange: setDescription,
|
|
2115
2473
|
onPromptChange: setPrompt
|
|
2116
2474
|
}),
|
|
2475
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(TaskTagFields, {
|
|
2476
|
+
tags,
|
|
2477
|
+
knownTags: collectKnownTags(controller.getSnapshot().tasks),
|
|
2478
|
+
onChange: setTags
|
|
2479
|
+
}),
|
|
2117
2480
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
2118
2481
|
className: board_module_css_default.field,
|
|
2119
2482
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
@@ -2390,6 +2753,17 @@ window.__ModuleLoader__.load({
|
|
|
2390
2753
|
className: board_module_css_default.cardTitle,
|
|
2391
2754
|
children: task.title
|
|
2392
2755
|
}),
|
|
2756
|
+
task.tags !== void 0 && task.tags.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2757
|
+
className: board_module_css_default.cardTags,
|
|
2758
|
+
children: task.tags.map((tag) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2759
|
+
className: board_module_css_default.cardTag,
|
|
2760
|
+
"data-tag-tone": tagTone(tag.name),
|
|
2761
|
+
"data-dsh-part": "tag-badge",
|
|
2762
|
+
"data-tag-hint": tag.promptPrefix === void 0 ? void 0 : tag.promptPrefix,
|
|
2763
|
+
title: tag.promptPrefix === void 0 ? tag.name : tag.promptPrefix,
|
|
2764
|
+
children: tag.name
|
|
2765
|
+
}, tag.name))
|
|
2766
|
+
}),
|
|
2393
2767
|
task.description !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2394
2768
|
className: board_module_css_default.cardExcerpt,
|
|
2395
2769
|
children: task.description
|
|
@@ -2505,6 +2879,7 @@ window.__ModuleLoader__.load({
|
|
|
2505
2879
|
const [title, setTitle] = (0, react.useState)(task.title);
|
|
2506
2880
|
const [description, setDescription] = (0, react.useState)(task.description);
|
|
2507
2881
|
const [prompt, setPrompt] = (0, react.useState)(task.prompt);
|
|
2882
|
+
const [tags, setTags] = (0, react.useState)(task.tags ?? []);
|
|
2508
2883
|
const [error, setError] = (0, react.useState)(void 0);
|
|
2509
2884
|
const [pending, setPending] = (0, react.useState)(false);
|
|
2510
2885
|
const submit = async () => {
|
|
@@ -2513,18 +2888,21 @@ window.__ModuleLoader__.load({
|
|
|
2513
2888
|
return;
|
|
2514
2889
|
}
|
|
2515
2890
|
setPending(true);
|
|
2516
|
-
|
|
2891
|
+
const tagList = cleanTags(tags);
|
|
2892
|
+
const patch = {
|
|
2517
2893
|
title,
|
|
2518
2894
|
description,
|
|
2519
|
-
prompt
|
|
2520
|
-
|
|
2895
|
+
prompt,
|
|
2896
|
+
...tagList.length > 0 ? { tags: tagList } : task.tags === void 0 ? {} : { tags: null }
|
|
2897
|
+
};
|
|
2898
|
+
if (await controller.updateTask(task.id, patch)) {
|
|
2521
2899
|
onClose();
|
|
2522
2900
|
return;
|
|
2523
2901
|
}
|
|
2524
2902
|
setPending(false);
|
|
2525
2903
|
setError(controller.getSnapshot().transportError ?? t("new.required"));
|
|
2526
2904
|
};
|
|
2527
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.
|
|
2905
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(ModalShell, {
|
|
2528
2906
|
ariaLabel: t("edit.title"),
|
|
2529
2907
|
title: t("edit.title"),
|
|
2530
2908
|
error,
|
|
@@ -2534,7 +2912,7 @@ window.__ModuleLoader__.load({
|
|
|
2534
2912
|
submit();
|
|
2535
2913
|
},
|
|
2536
2914
|
onClose,
|
|
2537
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TaskContentFields, {
|
|
2915
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(TaskContentFields, {
|
|
2538
2916
|
title,
|
|
2539
2917
|
description,
|
|
2540
2918
|
prompt,
|
|
@@ -2544,6 +2922,43 @@ window.__ModuleLoader__.load({
|
|
|
2544
2922
|
},
|
|
2545
2923
|
onDescriptionChange: setDescription,
|
|
2546
2924
|
onPromptChange: setPrompt
|
|
2925
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TaskTagFields, {
|
|
2926
|
+
tags,
|
|
2927
|
+
knownTags: collectKnownTags(controller.getSnapshot().tasks),
|
|
2928
|
+
onChange: setTags
|
|
2929
|
+
})]
|
|
2930
|
+
});
|
|
2931
|
+
}
|
|
2932
|
+
/** Edit-tags modal: edit labels only, shown for tasks after first execution. */
|
|
2933
|
+
function EditTagsModal({ controller, task, onClose }) {
|
|
2934
|
+
const [tags, setTags] = (0, react.useState)(task.tags ?? []);
|
|
2935
|
+
const [error, setError] = (0, react.useState)(void 0);
|
|
2936
|
+
const [pending, setPending] = (0, react.useState)(false);
|
|
2937
|
+
const submit = async () => {
|
|
2938
|
+
setPending(true);
|
|
2939
|
+
const tagList = cleanTags(tags);
|
|
2940
|
+
const patch = { tags: tagList.length > 0 ? tagList : null };
|
|
2941
|
+
if (await controller.updateTask(task.id, patch)) {
|
|
2942
|
+
onClose();
|
|
2943
|
+
return;
|
|
2944
|
+
}
|
|
2945
|
+
setPending(false);
|
|
2946
|
+
setError(controller.getSnapshot().transportError ?? t("new.required"));
|
|
2947
|
+
};
|
|
2948
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModalShell, {
|
|
2949
|
+
ariaLabel: t("detail.editTags"),
|
|
2950
|
+
title: t("detail.editTags"),
|
|
2951
|
+
error,
|
|
2952
|
+
pending,
|
|
2953
|
+
submitLabel: t("edit.save"),
|
|
2954
|
+
onSubmit: () => {
|
|
2955
|
+
submit();
|
|
2956
|
+
},
|
|
2957
|
+
onClose,
|
|
2958
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TaskTagFields, {
|
|
2959
|
+
tags,
|
|
2960
|
+
knownTags: collectKnownTags(controller.getSnapshot().tasks),
|
|
2961
|
+
onChange: setTags
|
|
2547
2962
|
})
|
|
2548
2963
|
});
|
|
2549
2964
|
}
|
|
@@ -2878,6 +3293,7 @@ window.__ModuleLoader__.load({
|
|
|
2878
3293
|
function TaskDetail({ controller, task }) {
|
|
2879
3294
|
const [confirmDelete, setConfirmDelete] = (0, react.useState)(false);
|
|
2880
3295
|
const [showEdit, setShowEdit] = (0, react.useState)(false);
|
|
3296
|
+
const [showEditTags, setShowEditTags] = (0, react.useState)(false);
|
|
2881
3297
|
const [showDuplicate, setShowDuplicate] = (0, react.useState)(false);
|
|
2882
3298
|
const [latest, setLatest] = (0, react.useState)(task);
|
|
2883
3299
|
(0, react.useEffect)(() => {
|
|
@@ -2885,6 +3301,7 @@ window.__ModuleLoader__.load({
|
|
|
2885
3301
|
}, [task]);
|
|
2886
3302
|
(0, react.useEffect)(() => {
|
|
2887
3303
|
setShowEdit(false);
|
|
3304
|
+
setShowEditTags(false);
|
|
2888
3305
|
setShowDuplicate(false);
|
|
2889
3306
|
}, [task.id]);
|
|
2890
3307
|
const current = latest;
|
|
@@ -2954,6 +3371,21 @@ window.__ModuleLoader__.load({
|
|
|
2954
3371
|
children: current.description !== "" ? current.description : "—"
|
|
2955
3372
|
})]
|
|
2956
3373
|
}),
|
|
3374
|
+
current.tags !== void 0 && current.tags.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
3375
|
+
className: board_module_css_default.detailSection,
|
|
3376
|
+
"data-dsh-part": "tags",
|
|
3377
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h4", { children: t("new.tags") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3378
|
+
className: board_module_css_default.cardTags,
|
|
3379
|
+
children: current.tags.map((tag) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3380
|
+
className: board_module_css_default.cardTag,
|
|
3381
|
+
"data-tag-tone": tagTone(tag.name),
|
|
3382
|
+
"data-dsh-part": "tag-badge",
|
|
3383
|
+
"data-tag-hint": tag.promptPrefix === void 0 ? void 0 : tag.promptPrefix,
|
|
3384
|
+
title: tag.promptPrefix === void 0 ? tag.name : tag.promptPrefix,
|
|
3385
|
+
children: tag.name
|
|
3386
|
+
}, tag.name))
|
|
3387
|
+
})]
|
|
3388
|
+
}),
|
|
2957
3389
|
current.freeze !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
2958
3390
|
className: board_module_css_default.detailSection,
|
|
2959
3391
|
"data-dsh-part": "freeze",
|
|
@@ -3120,6 +3552,15 @@ window.__ModuleLoader__.load({
|
|
|
3120
3552
|
},
|
|
3121
3553
|
children: t("detail.edit")
|
|
3122
3554
|
}),
|
|
3555
|
+
!archived && !canEditTaskContent(current) && current.status !== "running" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3556
|
+
type: "button",
|
|
3557
|
+
className: board_module_css_default.ghostButton,
|
|
3558
|
+
disabled: pending,
|
|
3559
|
+
onClick: () => {
|
|
3560
|
+
setShowEditTags(true);
|
|
3561
|
+
},
|
|
3562
|
+
children: t("detail.editTags")
|
|
3563
|
+
}),
|
|
3123
3564
|
!archived && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3124
3565
|
type: "button",
|
|
3125
3566
|
className: board_module_css_default.ghostButton,
|
|
@@ -3200,6 +3641,13 @@ window.__ModuleLoader__.load({
|
|
|
3200
3641
|
setShowEdit(false);
|
|
3201
3642
|
}
|
|
3202
3643
|
}),
|
|
3644
|
+
showEditTags && !archived && current.status !== "running" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EditTagsModal, {
|
|
3645
|
+
controller,
|
|
3646
|
+
task: current,
|
|
3647
|
+
onClose: () => {
|
|
3648
|
+
setShowEditTags(false);
|
|
3649
|
+
}
|
|
3650
|
+
}),
|
|
3203
3651
|
showDuplicate && !archived && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(NewTaskModal, {
|
|
3204
3652
|
controller,
|
|
3205
3653
|
initialTask: current,
|
|
@@ -3214,22 +3662,30 @@ window.__ModuleLoader__.load({
|
|
|
3214
3662
|
]
|
|
3215
3663
|
});
|
|
3216
3664
|
}
|
|
3217
|
-
|
|
3218
|
-
//#region src/client/board/TaskBoard.tsx
|
|
3219
|
-
/**
|
|
3220
|
-
* Board view: the multi-column kanban that replaces the middle column while
|
|
3221
|
-
* active. Cards open the task detail (never execute directly); the header
|
|
3222
|
-
* offers filter, new-task, and a back-to-chat escape.
|
|
3223
|
-
*/
|
|
3224
|
-
/** Case-insensitive title/description/freeze-snapshot match. */
|
|
3665
|
+
/** Case-insensitive title/description/tag/freeze-snapshot match. */
|
|
3225
3666
|
function matchesFilter(task, filter) {
|
|
3226
3667
|
if (filter.trim() === "") return true;
|
|
3227
3668
|
const needle = filter.trim().toLowerCase();
|
|
3228
|
-
const haystacks = [
|
|
3669
|
+
const haystacks = [
|
|
3670
|
+
task.title,
|
|
3671
|
+
task.description,
|
|
3672
|
+
...(task.tags ?? []).map((tag) => tag.name)
|
|
3673
|
+
];
|
|
3229
3674
|
if (task.freeze !== void 0) haystacks.push(task.freeze.goal, task.freeze.progress, task.freeze.next);
|
|
3230
3675
|
return haystacks.some((text) => text.toLowerCase().includes(needle));
|
|
3231
3676
|
}
|
|
3232
3677
|
/**
|
|
3678
|
+
* Whether a task carries every selected label (issue #1521). Multi-select is
|
|
3679
|
+
* conjunctive: adding a label narrows the board instead of widening it, which
|
|
3680
|
+
* is the only reading that keeps "工作" selected from dragging unrelated cards
|
|
3681
|
+
* back in when a second label is added.
|
|
3682
|
+
*/
|
|
3683
|
+
function matchesTagFilter(task, selected) {
|
|
3684
|
+
if (selected.length === 0) return true;
|
|
3685
|
+
const names = new Set((task.tags ?? []).map((tag) => tag.name));
|
|
3686
|
+
return selected.every((name) => names.has(name));
|
|
3687
|
+
}
|
|
3688
|
+
/**
|
|
3233
3689
|
* Memoized per-card adapter: with a stable `onOpen` from the board and an
|
|
3234
3690
|
* immutable task record (only the changed card gets a new object ref), a card
|
|
3235
3691
|
* re-renders only when its own task changes — not when a sibling card status,
|
|
@@ -3250,10 +3706,38 @@ window.__ModuleLoader__.load({
|
|
|
3250
3706
|
const [snapshot, setSnapshot] = (0, react.useState)(controller.getSnapshot());
|
|
3251
3707
|
(0, react.useEffect)(() => controller.subscribe(() => setSnapshot(controller.getSnapshot())), [controller]);
|
|
3252
3708
|
const [filter, setFilter] = (0, react.useState)("");
|
|
3709
|
+
const [tagFilter, setTagFilter] = (0, react.useState)([]);
|
|
3253
3710
|
const [showNew, setShowNew] = (0, react.useState)(false);
|
|
3711
|
+
const [projectId, setProjectId] = (0, react.useState)("");
|
|
3712
|
+
const [showNewProject, setShowNewProject] = (0, react.useState)(false);
|
|
3713
|
+
const [newProjectPath, setNewProjectPath] = (0, react.useState)("");
|
|
3714
|
+
const [newProjectError, setNewProjectError] = (0, react.useState)(void 0);
|
|
3715
|
+
const [newProjectPending, setNewProjectPending] = (0, react.useState)(false);
|
|
3254
3716
|
const selected = selectedTaskOf(snapshot);
|
|
3255
3717
|
const archiveView = snapshot.archiveView;
|
|
3256
|
-
const
|
|
3718
|
+
const knownTags = collectKnownTags(snapshot.tasks);
|
|
3719
|
+
const visible = snapshot.tasks.filter((task) => (archiveView ? task.archivedAt !== void 0 : task.archivedAt === void 0) && (projectId === "" || task.workspaceId === projectId) && matchesFilter(task, filter) && matchesTagFilter(task, tagFilter));
|
|
3720
|
+
const projects = snapshot.executionOptions.workspaces;
|
|
3721
|
+
const canCreateProject = snapshot.canCreateWorkspace === true;
|
|
3722
|
+
const submitNewProject = async () => {
|
|
3723
|
+
const path = newProjectPath.trim();
|
|
3724
|
+
if (path === "") return;
|
|
3725
|
+
setNewProjectPending(true);
|
|
3726
|
+
setNewProjectError(void 0);
|
|
3727
|
+
try {
|
|
3728
|
+
const created = await controller.createWorkspace(path);
|
|
3729
|
+
setProjectId(created.workspaceId);
|
|
3730
|
+
setShowNewProject(false);
|
|
3731
|
+
setNewProjectPath("");
|
|
3732
|
+
} catch (error) {
|
|
3733
|
+
setNewProjectError(error instanceof Error ? error.message : String(error));
|
|
3734
|
+
} finally {
|
|
3735
|
+
setNewProjectPending(false);
|
|
3736
|
+
}
|
|
3737
|
+
};
|
|
3738
|
+
const toggleTag = (0, react.useCallback)((name) => {
|
|
3739
|
+
setTagFilter((current) => current.includes(name) ? current.filter((entry) => entry !== name) : [...current, name]);
|
|
3740
|
+
}, []);
|
|
3257
3741
|
const openTask = (0, react.useCallback)((id) => {
|
|
3258
3742
|
controller.openTask(id);
|
|
3259
3743
|
}, [controller]);
|
|
@@ -3289,6 +3773,41 @@ window.__ModuleLoader__.load({
|
|
|
3289
3773
|
timeZone: snapshot.host.scheduler.timeZone
|
|
3290
3774
|
})
|
|
3291
3775
|
}),
|
|
3776
|
+
(projects.length > 0 || canCreateProject) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
3777
|
+
className: board_module_css_default.projectFilter,
|
|
3778
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3779
|
+
className: board_module_css_default.projectFilterLabel,
|
|
3780
|
+
children: t("board.project")
|
|
3781
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
|
|
3782
|
+
className: board_module_css_default.select,
|
|
3783
|
+
"data-dsh-part": "project-filter",
|
|
3784
|
+
value: projectId,
|
|
3785
|
+
"aria-label": t("board.project"),
|
|
3786
|
+
onChange: (event) => {
|
|
3787
|
+
const value = event.target.value;
|
|
3788
|
+
if (value === "__dsh_new_project__") {
|
|
3789
|
+
setNewProjectError(void 0);
|
|
3790
|
+
setShowNewProject(true);
|
|
3791
|
+
return;
|
|
3792
|
+
}
|
|
3793
|
+
setProjectId(value);
|
|
3794
|
+
},
|
|
3795
|
+
children: [
|
|
3796
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
3797
|
+
value: "",
|
|
3798
|
+
children: t("board.projectAll")
|
|
3799
|
+
}),
|
|
3800
|
+
projects.map((project) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
3801
|
+
value: project.workspaceId,
|
|
3802
|
+
children: project.title
|
|
3803
|
+
}, project.workspaceId)),
|
|
3804
|
+
canCreateProject && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
3805
|
+
value: "__dsh_new_project__",
|
|
3806
|
+
children: t("board.projectNew")
|
|
3807
|
+
})
|
|
3808
|
+
]
|
|
3809
|
+
})]
|
|
3810
|
+
}),
|
|
3292
3811
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
3293
3812
|
className: board_module_css_default.search,
|
|
3294
3813
|
type: "search",
|
|
@@ -3317,6 +3836,86 @@ window.__ModuleLoader__.load({
|
|
|
3317
3836
|
})
|
|
3318
3837
|
]
|
|
3319
3838
|
}),
|
|
3839
|
+
showNewProject && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3840
|
+
className: board_module_css_default.projectDialog,
|
|
3841
|
+
"data-dsh-part": "project-dialog",
|
|
3842
|
+
children: [
|
|
3843
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
3844
|
+
className: board_module_css_default.field,
|
|
3845
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3846
|
+
className: board_module_css_default.fieldLabel,
|
|
3847
|
+
children: t("board.projectNewPath")
|
|
3848
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
3849
|
+
className: board_module_css_default.input,
|
|
3850
|
+
value: newProjectPath,
|
|
3851
|
+
placeholder: t("board.projectNewPathPlaceholder"),
|
|
3852
|
+
spellCheck: false,
|
|
3853
|
+
onChange: (event) => {
|
|
3854
|
+
setNewProjectPath(event.target.value);
|
|
3855
|
+
setNewProjectError(void 0);
|
|
3856
|
+
}
|
|
3857
|
+
})]
|
|
3858
|
+
}),
|
|
3859
|
+
newProjectError !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3860
|
+
className: board_module_css_default.formError,
|
|
3861
|
+
children: t("board.projectCreateFailed", { error: newProjectError })
|
|
3862
|
+
}),
|
|
3863
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3864
|
+
className: board_module_css_default.projectDialogActions,
|
|
3865
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3866
|
+
type: "button",
|
|
3867
|
+
className: board_module_css_default.ghostButton,
|
|
3868
|
+
onClick: () => {
|
|
3869
|
+
setShowNewProject(false);
|
|
3870
|
+
setNewProjectError(void 0);
|
|
3871
|
+
},
|
|
3872
|
+
children: t("new.cancel")
|
|
3873
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3874
|
+
type: "button",
|
|
3875
|
+
className: board_module_css_default.primaryButton,
|
|
3876
|
+
disabled: newProjectPending || newProjectPath.trim() === "",
|
|
3877
|
+
onClick: () => {
|
|
3878
|
+
submitNewProject();
|
|
3879
|
+
},
|
|
3880
|
+
children: t("board.projectCreate")
|
|
3881
|
+
})]
|
|
3882
|
+
})
|
|
3883
|
+
]
|
|
3884
|
+
}),
|
|
3885
|
+
!archiveView && knownTags.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3886
|
+
className: board_module_css_default.tagFilter,
|
|
3887
|
+
"data-dsh-part": "tag-filter",
|
|
3888
|
+
children: [
|
|
3889
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3890
|
+
className: board_module_css_default.tagFilterLabel,
|
|
3891
|
+
children: t("board.tagFilter")
|
|
3892
|
+
}),
|
|
3893
|
+
knownTags.map((tag) => {
|
|
3894
|
+
const active = tagFilter.includes(tag.name);
|
|
3895
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3896
|
+
type: "button",
|
|
3897
|
+
className: board_module_css_default.tagChip,
|
|
3898
|
+
"data-dsh-part": "tag-chip",
|
|
3899
|
+
"data-tag-tone": tagTone(tag.name),
|
|
3900
|
+
"data-active": active ? "true" : void 0,
|
|
3901
|
+
"aria-pressed": active,
|
|
3902
|
+
title: tag.promptPrefix === void 0 ? tag.name : tag.promptPrefix,
|
|
3903
|
+
onClick: () => {
|
|
3904
|
+
toggleTag(tag.name);
|
|
3905
|
+
},
|
|
3906
|
+
children: tag.name
|
|
3907
|
+
}, tag.name);
|
|
3908
|
+
}),
|
|
3909
|
+
tagFilter.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3910
|
+
type: "button",
|
|
3911
|
+
className: board_module_css_default.linkButton,
|
|
3912
|
+
onClick: () => {
|
|
3913
|
+
setTagFilter([]);
|
|
3914
|
+
},
|
|
3915
|
+
children: t("board.tagFilterClear")
|
|
3916
|
+
})
|
|
3917
|
+
]
|
|
3918
|
+
}),
|
|
3320
3919
|
snapshot.transportError !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3321
3920
|
className: board_module_css_default.formError,
|
|
3322
3921
|
children: [
|
|
@@ -3356,7 +3955,7 @@ window.__ModuleLoader__.load({
|
|
|
3356
3955
|
onOpen: openTask
|
|
3357
3956
|
}, task.id)), visible.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3358
3957
|
className: board_module_css_default.columnEmpty,
|
|
3359
|
-
children: t("archive.empty")
|
|
3958
|
+
children: tagFilter.length > 0 ? t("board.tagEmpty") : t("archive.empty")
|
|
3360
3959
|
})]
|
|
3361
3960
|
})]
|
|
3362
3961
|
}) : COLUMNS.map((column) => {
|
|
@@ -3403,7 +4002,7 @@ window.__ModuleLoader__.load({
|
|
|
3403
4002
|
onOpen: openTask
|
|
3404
4003
|
}, task.id)), tasks.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3405
4004
|
className: board_module_css_default.columnEmpty,
|
|
3406
|
-
children: t("board.empty")
|
|
4005
|
+
children: tagFilter.length > 0 ? t("board.tagEmpty") : t("board.empty")
|
|
3407
4006
|
})]
|
|
3408
4007
|
})]
|
|
3409
4008
|
}, column.status);
|
|
@@ -3415,6 +4014,7 @@ window.__ModuleLoader__.load({
|
|
|
3415
4014
|
}),
|
|
3416
4015
|
showNew && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(NewTaskModal, {
|
|
3417
4016
|
controller,
|
|
4017
|
+
...projectId === "" ? {} : { defaultWorkspaceId: projectId },
|
|
3418
4018
|
onClose: () => {
|
|
3419
4019
|
setShowNew(false);
|
|
3420
4020
|
}
|
|
@@ -4636,19 +5236,64 @@ window.__ModuleLoader__.load({
|
|
|
4636
5236
|
//#endregion
|
|
4637
5237
|
//#region src/protocol.ts
|
|
4638
5238
|
const TASK_BOARD_API_PREFIX = "/api/task-board";
|
|
5239
|
+
/** Whether a decoded reply carries the three draft strings the form accepts. */
|
|
5240
|
+
function isTaskParseDraft(value) {
|
|
5241
|
+
if (typeof value !== "object" || value === null) return false;
|
|
5242
|
+
const record = value;
|
|
5243
|
+
return typeof record.title === "string" && typeof record.description === "string" && typeof record.prompt === "string";
|
|
5244
|
+
}
|
|
4639
5245
|
//#endregion
|
|
4640
5246
|
//#region src/client/host-api.ts
|
|
4641
5247
|
const IMPORT_MARKER = "dsh.taskBoard.v2.hostImported";
|
|
4642
5248
|
const SOURCE_KEY = "dsh.taskBoard.v2.sourceId";
|
|
4643
5249
|
const IMPORT_REQUEST_KEY = "dsh.taskBoard.v2.importRequestId";
|
|
4644
5250
|
const REQUEST_TIMEOUT_MS = 15e3;
|
|
5251
|
+
/** Re-notify the panel at most this often while the event stream stays broken. */
|
|
5252
|
+
const STREAM_ERROR_NOTIFY_MS = 15e3;
|
|
5253
|
+
/** Mirrors the Host's own parse budget; only used to phrase the timeout. */
|
|
5254
|
+
const TASK_PARSE_TIMEOUT_SECONDS = 45;
|
|
5255
|
+
/** Transport failure carrying a stable class next to its user-facing message. */
|
|
5256
|
+
var HostApiError = class extends Error {
|
|
5257
|
+
failure;
|
|
5258
|
+
status;
|
|
5259
|
+
constructor(failure, message, status) {
|
|
5260
|
+
super(message);
|
|
5261
|
+
this.failure = failure;
|
|
5262
|
+
this.status = status;
|
|
5263
|
+
this.name = "HostApiError";
|
|
5264
|
+
}
|
|
5265
|
+
};
|
|
4645
5266
|
function uuid() {
|
|
4646
5267
|
return globalThis.crypto?.randomUUID?.() ?? `browser-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
|
|
4647
5268
|
}
|
|
5269
|
+
/**
|
|
5270
|
+
* Read one Host response without ever handing a non-JSON body to JSON.parse:
|
|
5271
|
+
* the core webserver answers an unmounted `/api/*` path with the plain text
|
|
5272
|
+
* "not found", which used to surface as a JavaScript parse error in the panel.
|
|
5273
|
+
*/
|
|
4648
5274
|
async function readJson(response) {
|
|
4649
|
-
const
|
|
4650
|
-
|
|
4651
|
-
|
|
5275
|
+
const text = await response.text();
|
|
5276
|
+
let parsed;
|
|
5277
|
+
let readable = false;
|
|
5278
|
+
if (text.trim() !== "") try {
|
|
5279
|
+
parsed = JSON.parse(text);
|
|
5280
|
+
readable = true;
|
|
5281
|
+
} catch {
|
|
5282
|
+
readable = false;
|
|
5283
|
+
}
|
|
5284
|
+
const hostError = readable && typeof parsed === "object" && parsed !== null && typeof parsed.error === "string" ? parsed.error : void 0;
|
|
5285
|
+
if (response.ok) {
|
|
5286
|
+
if (!readable) throw new HostApiError("unexpected", t("board.hostError.unexpected", { status: String(response.status) }), response.status);
|
|
5287
|
+
return parsed;
|
|
5288
|
+
}
|
|
5289
|
+
if (hostError !== void 0) {
|
|
5290
|
+
if (hostError === "forbidden") throw new HostApiError("unauthorized", t("board.hostError.unauthorized"), response.status);
|
|
5291
|
+
if (response.status === 503 || /lock/i.test(hostError)) throw new HostApiError("locked", t("board.hostError.locked", { detail: hostError }), response.status);
|
|
5292
|
+
throw new HostApiError("rejected", hostError, response.status);
|
|
5293
|
+
}
|
|
5294
|
+
if (response.status === 404) throw new HostApiError("not-mounted", t("board.hostError.notMounted"), 404);
|
|
5295
|
+
if (response.status === 401 || response.status === 403) throw new HostApiError("unauthorized", t("board.hostError.unauthorized"), response.status);
|
|
5296
|
+
throw new HostApiError("unexpected", t("board.hostError.unexpected", { status: String(response.status) }), response.status);
|
|
4652
5297
|
}
|
|
4653
5298
|
var HttpTaskBoardHostTransport = class {
|
|
4654
5299
|
storage;
|
|
@@ -4708,14 +5353,54 @@ window.__ModuleLoader__.load({
|
|
|
4708
5353
|
signal: controller.signal
|
|
4709
5354
|
}));
|
|
4710
5355
|
} catch (error) {
|
|
4711
|
-
if (
|
|
4712
|
-
throw
|
|
5356
|
+
if (error instanceof HostApiError) throw error;
|
|
5357
|
+
if (controller.signal.aborted) throw new HostApiError("timeout", t("board.hostError.timeout", { seconds: String(REQUEST_TIMEOUT_MS / 1e3) }));
|
|
5358
|
+
throw new HostApiError("unreachable", t("board.hostError.unreachable"));
|
|
4713
5359
|
} finally {
|
|
4714
5360
|
globalThis.clearTimeout(timeout);
|
|
4715
5361
|
}
|
|
4716
5362
|
}
|
|
5363
|
+
/**
|
|
5364
|
+
* Ask the Host to turn pasted text into task fields. The route answers a
|
|
5365
|
+
* typed failure (no model, timeout, unparseable reply) already phrased for
|
|
5366
|
+
* the form, so the UI never renders a raw status code (issue #1540).
|
|
5367
|
+
*/
|
|
5368
|
+
async parseDraft(request, signal) {
|
|
5369
|
+
let response;
|
|
5370
|
+
try {
|
|
5371
|
+
response = await fetch(`${TASK_BOARD_API_PREFIX}/parse`, {
|
|
5372
|
+
method: "POST",
|
|
5373
|
+
headers: { "content-type": "application/json" },
|
|
5374
|
+
body: JSON.stringify(request),
|
|
5375
|
+
...signal === void 0 ? {} : { signal }
|
|
5376
|
+
});
|
|
5377
|
+
} catch {
|
|
5378
|
+
throw new HostApiError("unreachable", t("board.hostError.unreachable"));
|
|
5379
|
+
}
|
|
5380
|
+
const text = await response.text();
|
|
5381
|
+
let parsed;
|
|
5382
|
+
let readable = false;
|
|
5383
|
+
if (text.trim() !== "") try {
|
|
5384
|
+
parsed = JSON.parse(text);
|
|
5385
|
+
readable = true;
|
|
5386
|
+
} catch {
|
|
5387
|
+
readable = false;
|
|
5388
|
+
}
|
|
5389
|
+
const record = readable && typeof parsed === "object" && parsed !== null ? parsed : void 0;
|
|
5390
|
+
if (response.ok) {
|
|
5391
|
+
if (record !== void 0 && isTaskParseDraft(record.draft)) return record.draft;
|
|
5392
|
+
throw new HostApiError("unexpected", t("new.aiParseFailed", { error: t("board.hostError.unexpected", { status: String(response.status) }) }), response.status);
|
|
5393
|
+
}
|
|
5394
|
+
if (response.status === 404) throw new HostApiError("not-mounted", t("new.aiParseUnavailable"), 404);
|
|
5395
|
+
if (response.status === 401 || response.status === 403) throw new HostApiError("unauthorized", t("board.hostError.unauthorized"), response.status);
|
|
5396
|
+
const code = typeof record?.code === "string" ? record.code : void 0;
|
|
5397
|
+
if (code === "no-model") throw new HostApiError("rejected", t("new.aiParseNoModel"), response.status);
|
|
5398
|
+
if (code === "timeout") throw new HostApiError("timeout", t("new.aiParseTimeout", { seconds: String(TASK_PARSE_TIMEOUT_SECONDS) }), response.status);
|
|
5399
|
+
throw new HostApiError("rejected", t("new.aiParseFailed", { error: typeof record?.error === "string" && record.error !== "" ? record.error : String(response.status) }), response.status);
|
|
5400
|
+
}
|
|
4717
5401
|
subscribe(listener) {
|
|
4718
5402
|
const events = new EventSource(`${TASK_BOARD_API_PREFIX}/events`);
|
|
5403
|
+
let lastStreamErrorNotify = 0;
|
|
4719
5404
|
events.onmessage = (message) => {
|
|
4720
5405
|
try {
|
|
4721
5406
|
const parsed = JSON.parse(message.data);
|
|
@@ -4725,6 +5410,12 @@ window.__ModuleLoader__.load({
|
|
|
4725
5410
|
listener();
|
|
4726
5411
|
}
|
|
4727
5412
|
};
|
|
5413
|
+
events.onerror = () => {
|
|
5414
|
+
const now = Date.now();
|
|
5415
|
+
if (now - lastStreamErrorNotify < STREAM_ERROR_NOTIFY_MS) return;
|
|
5416
|
+
lastStreamErrorNotify = now;
|
|
5417
|
+
listener();
|
|
5418
|
+
};
|
|
4728
5419
|
const onVisible = () => {
|
|
4729
5420
|
if (document.visibilityState === "visible") listener();
|
|
4730
5421
|
};
|
|
@@ -4743,7 +5434,7 @@ window.__ModuleLoader__.load({
|
|
|
4743
5434
|
/** The building package's version, when the bundle carries it. */
|
|
4744
5435
|
function bakedVersion() {
|
|
4745
5436
|
try {
|
|
4746
|
-
return "0.3.
|
|
5437
|
+
return "0.3.23";
|
|
4747
5438
|
} catch {
|
|
4748
5439
|
return;
|
|
4749
5440
|
}
|
|
@@ -4894,6 +5585,9 @@ window.__ModuleLoader__.load({
|
|
|
4894
5585
|
};
|
|
4895
5586
|
pushWorkspaceOptions();
|
|
4896
5587
|
disposers.push(workspaces.list.subscribe(pushWorkspaceOptions));
|
|
5588
|
+
controller.setWorkspaceCreator(async (path) => {
|
|
5589
|
+
return { workspaceId: (await workspaces.create({ path })).workspaceId };
|
|
5590
|
+
});
|
|
4897
5591
|
const pushModelOptions = async () => {
|
|
4898
5592
|
try {
|
|
4899
5593
|
let models = [];
|