@joekytc/dsh-swarm 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -21
- package/README.zh-CN.md +20 -19
- package/client/TaskDrawer.tsx +29 -5
- package/client/kanban.css +115 -0
- package/client/timeline-model.ts +201 -0
- package/lib/client.js +192 -12
- package/lib/config.d.ts +11 -3
- package/lib/config.js +13 -3
- package/lib/dispatcher/agent-runner.js +1 -1
- package/lib/dispatcher/v-orchestrator.js +1 -1
- package/lib/domain/delivery-contract.js +1 -1
- package/lib/domain/memory.d.ts +29 -0
- package/lib/domain/memory.js +145 -0
- package/lib/routes/planning-driver.d.ts +5 -6
- package/lib/routes/planning-driver.js +11 -7
- package/lib/routes/prefix-router.d.ts +12 -13
- package/lib/routes/prefix-router.js +30 -0
- package/lib/tools/main-session-tools.js +35 -15
- package/lib/tools/planning-tools.d.ts +5 -0
- package/lib/tools/planning-tools.js +91 -2
- package/lib/wiki/memory-recall.d.ts +16 -0
- package/lib/wiki/memory-recall.js +58 -0
- package/lib/wiki/page-path.d.ts +3 -0
- package/lib/wiki/page-path.js +8 -3
- package/lib/wiki/wiki-vault-client.d.ts +1 -0
- package/package.json +1 -1
- package/personas/kanban-dt/agent.cordis.yml +1 -1
package/lib/client.js
CHANGED
|
@@ -788,6 +788,175 @@ window.__ModuleLoader__.load({
|
|
|
788
788
|
|
|
789
789
|
// client/TaskDrawer.tsx
|
|
790
790
|
var import_react4 = require("react");
|
|
791
|
+
|
|
792
|
+
// client/timeline-model.ts
|
|
793
|
+
var EXCEPTION_KINDS = /* @__PURE__ */ new Set([
|
|
794
|
+
"task/blocked",
|
|
795
|
+
"task/failed",
|
|
796
|
+
"review/failed",
|
|
797
|
+
"review/gave-up",
|
|
798
|
+
"chain/audit-warning",
|
|
799
|
+
"chain/aborted"
|
|
800
|
+
]);
|
|
801
|
+
var STATUS_OF = {
|
|
802
|
+
"chain/created": "neutral",
|
|
803
|
+
"chain/executing": "running",
|
|
804
|
+
"chain/completed": "success",
|
|
805
|
+
"chain/aborted": "exception",
|
|
806
|
+
"chain/root-task-set": "neutral",
|
|
807
|
+
"chain/audit-warning": "exception",
|
|
808
|
+
"chain/audit-confirmed": "neutral",
|
|
809
|
+
"chain/title-updated": "neutral",
|
|
810
|
+
"spec-card/created": "neutral",
|
|
811
|
+
"spec-card/edited": "neutral",
|
|
812
|
+
"spec-card/approved": "success",
|
|
813
|
+
"task/created": "neutral",
|
|
814
|
+
"task/claimed": "running",
|
|
815
|
+
"task/heartbeat": "running",
|
|
816
|
+
"task/commented": "neutral",
|
|
817
|
+
"task/completed": "success",
|
|
818
|
+
"task/blocked": "exception",
|
|
819
|
+
"task/unblocked": "neutral",
|
|
820
|
+
"task/archived": "neutral",
|
|
821
|
+
"task/failed": "exception",
|
|
822
|
+
"task/renamed": "neutral",
|
|
823
|
+
"review/passed": "success",
|
|
824
|
+
"review/failed": "exception",
|
|
825
|
+
"review/gave-up": "exception"
|
|
826
|
+
};
|
|
827
|
+
function timelineStatusOf(kind) {
|
|
828
|
+
return STATUS_OF[kind] ?? "neutral";
|
|
829
|
+
}
|
|
830
|
+
var KIND_LABEL = {
|
|
831
|
+
"chain/created": "\u94FE\u8DEF\u521B\u5EFA",
|
|
832
|
+
"chain/executing": "\u94FE\u8DEF\u5F00\u59CB\u6267\u884C",
|
|
833
|
+
"chain/completed": "\u94FE\u8DEF\u5B8C\u6210",
|
|
834
|
+
"chain/aborted": "\u94FE\u8DEF\u4E2D\u6B62",
|
|
835
|
+
"chain/root-task-set": "\u8BBE\u4E3A\u6839\u4EFB\u52A1",
|
|
836
|
+
"chain/audit-warning": "\u8D8A\u6743\u8B66\u544A",
|
|
837
|
+
"chain/audit-confirmed": "\u8D8A\u6743\u5DF2\u786E\u8BA4",
|
|
838
|
+
"chain/title-updated": "\u94FE\u8DEF\u6539\u540D",
|
|
839
|
+
"spec-card/created": "\u89C4\u683C\u5361\u521B\u5EFA",
|
|
840
|
+
"spec-card/edited": "\u89C4\u683C\u5361\u7F16\u8F91",
|
|
841
|
+
"spec-card/approved": "\u89C4\u683C\u5361\u6279\u51C6",
|
|
842
|
+
"task/created": "\u4EFB\u52A1\u521B\u5EFA",
|
|
843
|
+
"task/claimed": "\u4EFB\u52A1\u8BA4\u9886",
|
|
844
|
+
"task/heartbeat": "\u4EFB\u52A1\u5FC3\u8DF3",
|
|
845
|
+
"task/commented": "\u8BC4\u8BBA",
|
|
846
|
+
"task/completed": "\u4EFB\u52A1\u5B8C\u6210",
|
|
847
|
+
"task/blocked": "\u4EFB\u52A1\u963B\u585E",
|
|
848
|
+
"task/unblocked": "\u89E3\u9664\u963B\u585E",
|
|
849
|
+
"task/archived": "\u4EFB\u52A1\u5F52\u6863",
|
|
850
|
+
"task/failed": "\u4EFB\u52A1\u5931\u8D25",
|
|
851
|
+
"task/renamed": "\u4EFB\u52A1\u6539\u540D",
|
|
852
|
+
"review/passed": "\u8BC4\u5BA1\u901A\u8FC7",
|
|
853
|
+
"review/failed": "\u8BC4\u5BA1\u9A73\u56DE",
|
|
854
|
+
"review/gave-up": "\u8BC4\u5BA1\u8D85\u9650\u653E\u5F03"
|
|
855
|
+
};
|
|
856
|
+
var AUTHOR_NAME = {
|
|
857
|
+
v: "orchestrator",
|
|
858
|
+
p: "planner",
|
|
859
|
+
w: "wiki-bridge",
|
|
860
|
+
d: "fullstack-dev",
|
|
861
|
+
pt: "plan-review",
|
|
862
|
+
dt: "impl-review",
|
|
863
|
+
system: "\u7CFB\u7EDF",
|
|
864
|
+
human: "\u4F60"
|
|
865
|
+
};
|
|
866
|
+
function eventLabelOf(kind) {
|
|
867
|
+
return KIND_LABEL[kind] ?? kind;
|
|
868
|
+
}
|
|
869
|
+
function isExceptionEvent(e) {
|
|
870
|
+
return EXCEPTION_KINDS.has(e.kind);
|
|
871
|
+
}
|
|
872
|
+
function authorNameOf(author) {
|
|
873
|
+
return AUTHOR_NAME[author] ?? author;
|
|
874
|
+
}
|
|
875
|
+
function asRecord(value) {
|
|
876
|
+
return typeof value === "object" && value !== null ? value : {};
|
|
877
|
+
}
|
|
878
|
+
function strField(rec, key) {
|
|
879
|
+
const v = rec[key];
|
|
880
|
+
return typeof v === "string" ? v : "";
|
|
881
|
+
}
|
|
882
|
+
function truncate(text, max = 120) {
|
|
883
|
+
return text.length <= max ? text : `${text.slice(0, max)}\u2026`;
|
|
884
|
+
}
|
|
885
|
+
function eventSummary(e) {
|
|
886
|
+
const payload = asRecord(e.payload);
|
|
887
|
+
switch (e.kind) {
|
|
888
|
+
case "task/completed": {
|
|
889
|
+
const summary = truncate(strField(payload, "summary"));
|
|
890
|
+
return summary;
|
|
891
|
+
}
|
|
892
|
+
case "task/blocked":
|
|
893
|
+
case "task/failed":
|
|
894
|
+
return truncate(strField(payload, "reason"));
|
|
895
|
+
case "task/commented":
|
|
896
|
+
return truncate(strField(payload, "body"));
|
|
897
|
+
case "task/renamed":
|
|
898
|
+
case "chain/title-updated": {
|
|
899
|
+
const from = strField(payload, "from");
|
|
900
|
+
const to = strField(payload, "to");
|
|
901
|
+
return from || to ? `${from} \u2192 ${to}` : "";
|
|
902
|
+
}
|
|
903
|
+
case "review/passed":
|
|
904
|
+
case "review/failed":
|
|
905
|
+
case "review/gave-up": {
|
|
906
|
+
const evidence = asRecord(payload["evidence"]);
|
|
907
|
+
const verdict = strField(evidence, "verdict") || strField(payload, "verdict");
|
|
908
|
+
const issues = Array.isArray(evidence["issues"]) ? evidence["issues"].length : void 0;
|
|
909
|
+
const parts = [];
|
|
910
|
+
if (verdict) parts.push(`verdict: ${verdict}`);
|
|
911
|
+
if (issues !== void 0) parts.push(`issues: ${issues}`);
|
|
912
|
+
const reason = strField(payload, "reason");
|
|
913
|
+
if (reason) parts.push(reason);
|
|
914
|
+
return truncate(parts.join(" \xB7 "));
|
|
915
|
+
}
|
|
916
|
+
default:
|
|
917
|
+
return "";
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
function foldTimeline(events) {
|
|
921
|
+
const sorted = [...events].sort((a, b) => b.seq - a.seq);
|
|
922
|
+
const items = [];
|
|
923
|
+
for (const e of sorted) {
|
|
924
|
+
if (e.kind !== "task/heartbeat") {
|
|
925
|
+
items.push({
|
|
926
|
+
seq: e.seq,
|
|
927
|
+
kind: e.kind,
|
|
928
|
+
label: eventLabelOf(e.kind),
|
|
929
|
+
author: authorNameOf(e.author),
|
|
930
|
+
at: e.at,
|
|
931
|
+
summary: eventSummary(e),
|
|
932
|
+
exception: isExceptionEvent(e),
|
|
933
|
+
status: timelineStatusOf(e.kind)
|
|
934
|
+
});
|
|
935
|
+
continue;
|
|
936
|
+
}
|
|
937
|
+
const prev = items[items.length - 1];
|
|
938
|
+
if (prev && prev.kind === "task/heartbeat") {
|
|
939
|
+
prev.count = (prev.count ?? 1) + 1;
|
|
940
|
+
prev.lastAt = e.at;
|
|
941
|
+
} else {
|
|
942
|
+
items.push({
|
|
943
|
+
seq: e.seq,
|
|
944
|
+
kind: e.kind,
|
|
945
|
+
label: eventLabelOf(e.kind),
|
|
946
|
+
author: authorNameOf(e.author),
|
|
947
|
+
at: e.at,
|
|
948
|
+
lastAt: e.at,
|
|
949
|
+
count: 1,
|
|
950
|
+
summary: "",
|
|
951
|
+
exception: false,
|
|
952
|
+
status: timelineStatusOf(e.kind)
|
|
953
|
+
});
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
return items;
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
// client/TaskDrawer.tsx
|
|
791
960
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
792
961
|
var ROLE_NAME = {
|
|
793
962
|
v: "orchestrator",
|
|
@@ -921,17 +1090,28 @@ window.__ModuleLoader__.load({
|
|
|
921
1090
|
] }),
|
|
922
1091
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { children: task.body || "\u65E0\u9644\u52A0\u4EFB\u52A1\u63CF\u8FF0" })
|
|
923
1092
|
] }),
|
|
924
|
-
tab === "timeline" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("section", { role: "tabpanel", children:
|
|
925
|
-
|
|
926
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.
|
|
927
|
-
"
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
1093
|
+
tab === "timeline" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("section", { role: "tabpanel", children: (() => {
|
|
1094
|
+
const items = foldTimeline(timeline);
|
|
1095
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("ol", { className: "dsh-kb-timeline", children: items.map((item, i) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
1096
|
+
"li",
|
|
1097
|
+
{
|
|
1098
|
+
className: `dsh-kb-timeline__item dsh-kb-timeline__item--${item.status}${i === 0 ? " dsh-kb-timeline__item--latest" : ""}`,
|
|
1099
|
+
"data-exception": item.exception || void 0,
|
|
1100
|
+
children: [
|
|
1101
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "dsh-kb-timeline__axis", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "dsh-kb-timeline__dot", "aria-hidden": "true" }) }),
|
|
1102
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dsh-kb-timeline__body", children: [
|
|
1103
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dsh-kb-timeline__row", children: [
|
|
1104
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { className: "dsh-kb-timeline__label", children: item.count ? `${item.label}\uFF08${item.count} \u6B21\uFF09` : item.label }),
|
|
1105
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("time", { dateTime: new Date(item.at).toISOString(), children: formatTime(item.at) })
|
|
1106
|
+
] }),
|
|
1107
|
+
item.summary && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "dsh-kb-timeline__summary", title: item.summary, children: item.summary }),
|
|
1108
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "dsh-kb-timeline__author", children: item.author })
|
|
1109
|
+
] })
|
|
1110
|
+
]
|
|
1111
|
+
},
|
|
1112
|
+
item.seq
|
|
1113
|
+
)) });
|
|
1114
|
+
})() }),
|
|
935
1115
|
tab === "handoff" && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("section", { role: "tabpanel", children: [
|
|
936
1116
|
props.parentTasks && props.parentTasks.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
|
|
937
1117
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h4", { children: "\u7236\u4EFB\u52A1\u539F\u6587" }),
|
|
@@ -1172,7 +1352,7 @@ window.__ModuleLoader__.load({
|
|
|
1172
1352
|
}
|
|
1173
1353
|
|
|
1174
1354
|
// client/kanban.css
|
|
1175
|
-
var kanban_default = "/* T32\uFF1A\u5361\u7247/\u8FDE\u63A5\u7EBF\u7B49\u5C40\u90E8\u8FC7\u6E21\u4FDD\u6301 120-180ms\uFF1Bprefers-reduced-motion \u5168\u5C40\u5173\u95ED */\n.dsh-kb-tab {\n /* DSH \u8BBE\u8BA1\u4EE4\u724C\uFF08\u6D45/\u6DF1\u8272\u968F body[data-ds-dark-theme] \u81EA\u52A8\u5207\u6362\uFF09\u2014\u2014\u7981\u6B62\u786C\u7F16\u7801\u989C\u8272 */\n --dsh-kb-surface: var(--dsw-alias-bg-layer-1);\n --dsh-kb-surface-elev: var(--dsw-alias-bg-layer-3);\n --dsh-kb-text-primary: var(--dsw-alias-label-primary);\n --dsh-kb-text-secondary: var(--dsw-alias-label-secondary);\n --dsh-kb-text-tertiary: var(--dsw-alias-label-tertiary);\n --dsh-kb-border: var(--dsw-alias-border-l2);\n --dsh-kb-hover: var(--dsw-alias-interactive-bg-hover);\n --dsh-kb-mask: var(--dsw-alias-bg-mask-3);\n --dsh-kb-input: var(--dsw-specific-input-major);\n --dsh-kb-inline-code: var(--dsw-alias-markdown-inline-code);\n /* \u5927\u5706\u89D2\u5951\u7EA6\uFF08\u5BF9\u9F50 DSH \u5361\u7247 16px\uFF09\uFF0C\u540E\u7EED UI \u4E00\u5F8B\u590D\u7528 */\n --dsh-kb-radius-lg: 16px;\n --dsh-kb-radius-md: 10px;\n --dsh-kb-radius-sm: 8px;\n /* \u72B6\u6001\u8272 \u2192 DSH \u8BED\u4E49\u4EE4\u724C */\n --dsh-kb-complete: var(--dsw-alias-state-success-primary);\n --dsh-kb-active: var(--dsw-alias-state-business-primary);\n --dsh-kb-blocked: var(--dsw-alias-state-error-primary);\n --dsh-kb-pending: currentColor;\n /* \u89D2\u8272\u8272\uFF1ADSH \u6709\u7B49\u4EF7\u4EE4\u724C\u5219\u590D\u7528\uFF1Bp/pt/dt \u65E0 DSH \u7B49\u4EF7\u8272\uFF0C\u4FDD\u7559\u539F\u503C */\n --dsh-kb-v: var(--dsw-alias-state-business-primary);\n --dsh-kb-p: #a855f7;\n --dsh-kb-w: var(--dsw-alias-state-success-primary);\n --dsh-kb-d: var(--dsw-alias-state-warn-primary);\n --dsh-kb-pt: #6366f1; /* \u8BA1\u5212\u8BC4\u5BA1\uFF1A\u975B/\u6D45\u84DD */\n --dsh-kb-dt: #ec4899; /* \u5B9E\u73B0\u8BC4\u5BA1\uFF1A\u73AB\u7EA2 */\n height: 100%;\n width: 100%;\n min-width: 715px; /* \u770B\u677F\u6700\u5C0F\u5BBD\u5EA6 */\n max-width: 780px; /* \u770B\u677F\u6700\u5927\u5BBD\u5EA6 */\n margin-inline: auto;\n display: flex;\n flex-direction: column;\n color: inherit;\n background: var(--dsw-alias-bg-base);\n pointer-events: auto;\n font-size: 13px;\n line-height: 1.45;\n overflow: hidden;\n}\n\n.dsh-kb-banner {\n flex: 0 0 auto;\n padding: 6px 12px;\n font-size: 12px;\n border-bottom: 1px solid var(--dsh-kb-border);\n}\n.dsh-kb-banner--reconnecting,\n.dsh-kb-banner--loading {\n color: var(--dsh-kb-active);\n}\n.dsh-kb-banner--error {\n color: var(--dsh-kb-blocked);\n}\n\n.dsh-kb-tab-body {\n flex: 1 1 auto;\n min-height: 0;\n overflow: auto;\n padding: 8px;\n}\n\n.dsh-kb-loading {\n flex: 1 1 auto;\n display: flex;\n align-items: center;\n justify-content: center;\n color: currentColor;\n opacity: 0.7;\n}\n\n.dsh-kb-toolbar {\n position: sticky;\n top: 0;\n z-index: 1;\n padding-bottom: 8px;\n}\n.dsh-kb-toolbar input {\n width: 100%;\n box-sizing: border-box;\n padding: 6px 10px;\n border: 1px solid var(--dsh-kb-border);\n border-radius: var(--dsh-kb-radius-md);\n background: var(--dsh-kb-input);\n color: var(--dsh-kb-text-primary);\n}\n\n.dsh-kb-rail {\n display: flex;\n flex-direction: column;\n}\n/* \u72B6\u6001\u7B5B\u9009 chip \u7EC4\uFF1A\u6267\u884C\u4E2D/\u963B\u585E/\u5931\u8D25/\u5DF2\u5B8C\u6210\uFF08\u591A\u9009\u5E76\u96C6\uFF1B\u7A7A=\u9ED8\u8BA4\u89C6\u56FE\uFF09 */\n.dsh-kb-filters {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n padding: 0 0 8px;\n}\n.dsh-kb-filter {\n display: inline-flex;\n align-items: center;\n padding: 2px 10px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 999px;\n background: transparent;\n color: currentColor;\n font: inherit;\n cursor: pointer;\n user-select: none;\n transition: background-color 150ms ease, border-color 150ms ease, color 150ms ease;\n}\n.dsh-kb-filter:hover {\n background: var(--dsh-kb-hover);\n}\n.dsh-kb-filter--active {\n border-color: var(--dsh-kb-active);\n color: var(--dsh-kb-active);\n background: color-mix(in srgb, var(--dsh-kb-active) 10%, transparent);\n}\n\n.dsh-kb-chain {\n margin-bottom: 10px;\n}\n.dsh-kb-chain__title {\n display: flex;\n align-items: center;\n gap: 8px;\n box-sizing: border-box;\n width: 100%;\n padding: 6px 8px;\n border: 0;\n border-radius: var(--dsh-kb-radius-sm);\n background: transparent;\n color: var(--dsh-kb-text-primary);\n font: inherit;\n text-align: left;\n cursor: pointer;\n transition: background-color 150ms ease;\n}\n.dsh-kb-chain__title:hover {\n background: var(--dsh-kb-hover);\n}\n/* \u6BCF\u6761\u94FE\u8DEF\u524D\u7684\u6298\u53E0\u7BAD\u5934\uFF08\u4E0E DSH \u6298\u53E0\u4EA4\u4E92\u4E00\u81F4\uFF1A\u7EC6 chevron\uFF0C\u5C55\u5F00\u65F6\u65CB\u8F6C\uFF0C150ms \u8FC7\u6E21\uFF09 */\n.dsh-kb-chain__chevron {\n flex: 0 0 auto;\n width: 7px;\n height: 7px;\n border-top: 1.5px solid currentColor;\n border-right: 1.5px solid currentColor;\n transform: rotate(45deg);\n opacity: 0.7;\n transition: transform 150ms ease;\n}\n.dsh-kb-chain__title[aria-expanded='true'] .dsh-kb-chain__chevron {\n transform: rotate(135deg);\n}\n.dsh-kb-chain__name {\n flex: 1 1 auto;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.dsh-kb-chain__meta {\n flex: 0 0 auto;\n white-space: nowrap;\n opacity: 0.7;\n}\n.dsh-kb-chain__warning {\n padding: 4px 8px;\n margin: 2px 0 6px;\n border-left: 3px solid var(--dsh-kb-blocked);\n color: var(--dsh-kb-blocked);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n/* D23\uFF1A\u94FE\u5B8C\u6210\u9A8C\u6536\u6838\u5BF9\u8B66\u544A\u884C\uFF08completed \u94FE\u672A\u786E\u8BA4\u524D\u963B\u585E\u6700\u7EC8\u6C47\u62A5\uFF09 */\n.dsh-kb-chain__audit {\n display: flex;\n align-items: center;\n gap: 8px;\n white-space: normal;\n}\n.dsh-kb-chain__audit span {\n flex: 1 1 auto;\n overflow: hidden;\n}\n.dsh-kb-audit-confirm {\n flex: 0 0 auto;\n border: 1px solid var(--dsh-kb-blocked);\n border-radius: var(--dsh-kb-radius-sm);\n background: transparent;\n color: var(--dsh-kb-blocked);\n padding: 2px 10px;\n cursor: pointer;\n font: inherit;\n transition: background-color 150ms ease, color 150ms ease;\n}\n.dsh-kb-audit-confirm:hover {\n background: var(--dsh-kb-blocked);\n color: #fff;\n}\n\n.dsh-kb-nodes {\n list-style: none;\n margin: 0;\n padding: 0 0 0 12px;\n display: flex;\n flex-direction: column;\n gap: 0;\n}\n.dsh-kb-node {\n position: relative;\n padding-left: 12px;\n}\n.dsh-kb-node::before {\n content: '';\n position: absolute;\n left: 0;\n top: 0;\n bottom: 0;\n width: 2px;\n background: var(--dsh-kb-pending);\n transition: background-color 150ms ease;\n}\n.dsh-kb-node--complete::before { background: var(--dsh-kb-complete); }\n.dsh-kb-node--active::before { background: var(--dsh-kb-active); }\n.dsh-kb-node--pending::before {\n background: repeating-linear-gradient(to bottom, currentColor 0 3px, transparent 3px 6px);\n}\n.dsh-kb-node--blocked::before {\n background: repeating-linear-gradient(to bottom, var(--dsh-kb-blocked) 0 4px, transparent 4px 8px);\n}\n\n.dsh-kb-task {\n display: grid;\n grid-template-columns: 22px 1fr auto;\n grid-template-rows: auto auto;\n gap: 2px 8px;\n width: 100%;\n box-sizing: border-box;\n padding: 6px 8px;\n margin: 4px 0;\n border: 1px solid transparent;\n border-radius: var(--dsh-kb-radius-lg);\n background: transparent;\n color: var(--dsh-kb-text-primary);\n font: inherit;\n text-align: left;\n cursor: pointer;\n transition: border-color 150ms ease, background-color 150ms ease, opacity 150ms ease;\n}\n.dsh-kb-task:hover {\n background: var(--dsh-kb-hover);\n}\n.dsh-kb-task[data-selected],\n.dsh-kb-task--active {\n border-color: var(--dsh-kb-active);\n}\n/* T32\uFF1A\u5B8C\u6210\u4EFB\u52A1\u4FDD\u7559\u5728\u8F68\u9053\u4F46\u89C6\u89C9\u964D\u6743\uFF1B\u72B6\u6001\u8272\u4E0D\u53D8\u3001\u4E0D\u6574\u5361\u67D3\u8272 */\n.dsh-kb-task--complete {\n opacity: 0.72;\n}\n.dsh-kb-task__title {\n grid-column: 2;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.dsh-kb-task__status {\n grid-column: 3;\n color: currentColor;\n opacity: 0.75;\n}\n.dsh-kb-task__meta {\n grid-column: 2 / 4;\n opacity: 0.6;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.dsh-kb-task__warn {\n grid-column: 2 / 4;\n display: inline-flex;\n align-items: center;\n gap: 4px;\n color: var(--dsh-kb-blocked);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.dsh-kb-task__warn svg {\n flex: 0 0 auto;\n}\n.dsh-kb-task__warn span {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.dsh-kb-task--complete .dsh-kb-task__status { color: var(--dsh-kb-complete); }\n.dsh-kb-task--blocked .dsh-kb-task__status { color: var(--dsh-kb-blocked); }\n/* D17\uFF1A\u9009\u4E2D\u4EFB\u52A1\u6240\u5728\u94FE\u8DEF\u7684\u4E0A\u6E38/\u5F53\u524D/\u4E0B\u6E38\u8DEF\u5F84\u5361\u9AD8\u4EAE\uFF1B\u4E0D\u6539\u53D8\u8FDE\u63A5\u7EBF\u8BED\u4E49\uFF0C\u9009\u4E2D\u5361\u4FDD\u6301\u5F3A\u8FB9\u6846 */\n.dsh-kb-task--related:not(.dsh-kb-task--active) {\n border-color: color-mix(in srgb, var(--dsh-kb-active) 35%, transparent);\n background: color-mix(in srgb, var(--dsh-kb-active) 6%, transparent);\n}\n\n.dsh-kb-empty {\n padding: 24px 12px;\n text-align: center;\n color: var(--dsh-kb-text-secondary);\n border: 1px dashed var(--dsh-kb-border);\n border-radius: var(--dsh-kb-radius-lg);\n}\n\n.dsh-kb-profile {\n grid-row: 1 / 3;\n align-self: start;\n width: 20px;\n height: 20px;\n border-radius: var(--dsh-kb-radius-sm);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n font-size: 11px;\n font-weight: 700;\n color: #fff;\n}\n.dsh-kb-profile--v { background: var(--dsh-kb-v); }\n.dsh-kb-profile--p { background: var(--dsh-kb-p); }\n.dsh-kb-profile--w { background: var(--dsh-kb-w); }\n.dsh-kb-profile--d { background: var(--dsh-kb-d); }\n.dsh-kb-profile--pt { background: var(--dsh-kb-pt); }\n.dsh-kb-profile--dt { background: var(--dsh-kb-dt); }\n\n/* T27\uFF1A\u4EFB\u52A1\u5361\u5F39\u7A97\uFF08\u539F\u4F4D\u8BE6\u60C5\uFF09\u2014\u2014DSH \u9762\u677F\u98CE\u683C\uFF1A\u5927\u5706\u89D2 + \u62AC\u5347\u8868\u9762 + \u6D45/\u6DF1\u8272\u4EE4\u724C */\n.dsh-kb-detail {\n display: flex;\n flex-direction: column;\n min-height: calc(100% - 16px);\n margin: 8px;\n padding: 12px 16px;\n box-sizing: border-box;\n border: 1px solid var(--dsh-kb-border);\n border-radius: var(--dsh-kb-radius-lg);\n background: var(--dsh-kb-surface);\n color: var(--dsh-kb-text-primary);\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);\n}\n.dsh-kb-detail__header {\n display: flex;\n align-items: center;\n gap: 8px;\n padding-bottom: 8px;\n border-bottom: 1px solid var(--dsh-kb-border);\n}\n.dsh-kb-detail__header > button:not(.dsh-kb-unread) {\n flex: 0 0 auto;\n width: 28px;\n height: 28px;\n border: 1px solid var(--dsh-kb-border);\n border-radius: var(--dsh-kb-radius-md);\n background: transparent;\n color: var(--dsh-kb-text-primary);\n cursor: pointer;\n font: inherit;\n line-height: 1;\n transition: background-color 150ms ease;\n}\n.dsh-kb-detail__header > button:not(.dsh-kb-unread):hover {\n background: var(--dsh-kb-hover);\n}\n.dsh-kb-detail__identity {\n flex: 1 1 auto;\n min-width: 0;\n}\n.dsh-kb-detail__identity strong,\n.dsh-kb-detail__identity span {\n display: block;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.dsh-kb-detail__actions {\n display: flex;\n gap: 4px;\n flex: 0 0 auto;\n}\n.dsh-kb-detail__actions button {\n border: 1px solid var(--dsh-kb-border);\n border-radius: var(--dsh-kb-radius-md);\n background: transparent;\n color: var(--dsh-kb-text-primary);\n padding: 4px 10px;\n cursor: pointer;\n font: inherit;\n transition: border-color 150ms ease, color 150ms ease, background-color 150ms ease;\n}\n.dsh-kb-detail__actions button:hover {\n background: var(--dsh-kb-hover);\n}\n.dsh-kb-detail__actions button[data-confirming='true'] {\n border-color: var(--dsh-kb-blocked);\n color: var(--dsh-kb-blocked);\n}\n.dsh-kb-detail__actions button:disabled {\n opacity: 0.5;\n cursor: default;\n}\n.dsh-kb-action-form {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n}\n.dsh-kb-action-form input {\n width: 140px;\n padding: 3px 8px;\n border: 1px solid var(--dsh-kb-border);\n border-radius: var(--dsh-kb-radius-sm);\n background: var(--dsh-kb-input);\n color: var(--dsh-kb-text-primary);\n font: inherit;\n font-size: 12px;\n}\n.dsh-kb-unread {\n flex: 0 0 auto;\n border: 1px solid var(--dsh-kb-active);\n border-radius: 999px;\n background: color-mix(in srgb, var(--dsh-kb-active) 12%, transparent);\n color: var(--dsh-kb-active);\n padding: 2px 8px;\n font: inherit;\n font-size: 12px;\n white-space: nowrap;\n cursor: pointer;\n}\n.dsh-kb-action-error {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 6px 8px;\n margin: 4px 0;\n border-left: 3px solid var(--dsh-kb-blocked);\n color: var(--dsh-kb-blocked);\n font-size: 12px;\n}\n.dsh-kb-action-error span {\n flex: 1 1 auto;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.dsh-kb-action-error button {\n flex: 0 0 auto;\n border: 1px solid currentColor;\n border-radius: var(--dsh-kb-radius-sm);\n background: transparent;\n color: inherit;\n padding: 1px 6px;\n cursor: pointer;\n font: inherit;\n}\n.dsh-kb-detail [role='tablist'] {\n display: flex;\n gap: 4px;\n padding: 8px 0;\n border-bottom: 1px solid var(--dsh-kb-border);\n}\n.dsh-kb-detail [role='tab'] {\n border: 0;\n border-radius: var(--dsh-kb-radius-sm);\n background: transparent;\n color: var(--dsh-kb-text-secondary);\n padding: 4px 10px;\n cursor: pointer;\n transition: background-color 150ms ease, color 150ms ease;\n}\n.dsh-kb-detail [role='tab']:hover {\n color: var(--dsh-kb-text-primary);\n background: var(--dsh-kb-hover);\n}\n.dsh-kb-detail [role='tab'][aria-selected='true'] {\n background: var(--dsh-kb-hover);\n color: var(--dsh-kb-text-primary);\n}\n.dsh-kb-detail [role='tabpanel'] {\n padding: 8px 0;\n overflow: auto;\n}\n.dsh-kb-detail h4 {\n margin: 8px 0 4px;\n font-size: 12px;\n text-transform: none;\n color: var(--dsh-kb-text-secondary);\n}\n.dsh-kb-detail code {\n background: var(--dsh-kb-inline-code);\n border-radius: var(--dsh-kb-radius-sm);\n padding: 1px 4px;\n}\n.dsh-kb-detail dl {\n display: grid;\n grid-template-columns: auto 1fr;\n gap: 4px 8px;\n margin: 8px 0;\n}\n.dsh-kb-detail dt { opacity: 0.7; color: var(--dsh-kb-text-tertiary); }\n.dsh-kb-detail dd { margin: 0; }\n.dsh-kb-detail time { opacity: 0.6; font-size: 12px; margin-inline-end: 4px; }\n\n.dsh-kb-spec-attachments {\n list-style: none;\n margin: 4px 0;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n.dsh-kb-spec-attachments li {\n display: flex;\n align-items: baseline;\n gap: 6px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.dsh-kb-spec-attachment__kind {\n font-size: 11px;\n border: 1px solid var(--dsh-kb-border);\n border-radius: var(--dsh-kb-radius-sm);\n padding: 0 4px;\n opacity: 0.8;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .dsh-kb-tab * {\n transition-duration: 0ms !important;\n }\n}\n\n/* \u6574\u94FE\u5220\u9664\u6309\u94AE\uFF1A\u9ED8\u8BA4\u9690\u85CF\uFF0Chover \u9700\u6C42\u6807\u9898\u884C\u65F6\u51FA\u73B0\uFF08GUI \u4EC5 human\uFF0C\u4E8C\u6B21\u786E\u8BA4\uFF09 */\n.dsh-kb-chain__delete {\n flex: 0 0 auto;\n border: 0;\n background: transparent;\n color: currentColor;\n opacity: 0;\n font: inherit;\n line-height: 1;\n padding: 2px 4px;\n cursor: pointer;\n transition: opacity 150ms ease, color 150ms ease;\n}\n.dsh-kb-chain__title:hover .dsh-kb-chain__delete,\n.dsh-kb-chain__delete:focus-visible { opacity: 0.7; }\n.dsh-kb-chain__delete:hover { opacity: 1; color: var(--dsh-kb-blocked); }\n/* \u5220\u9664\u4E8C\u6B21\u786E\u8BA4\u5F39\u7A97\uFF08\u590D\u7528 rename \u5F39\u7A97\u5916\u58F3/\u5706\u89D2\u5951\u7EA6\uFF09 */\n.dsh-kb-delete-modal__text {\n color: var(--dsh-kb-text-secondary);\n font-size: 13px;\n line-height: 1.5;\n}\n.dsh-kb-delete-modal__error {\n color: var(--dsh-kb-blocked);\n font-size: 12px;\n}\n.dsh-kb-rename-modal__actions .dsh-kb-delete-confirm {\n border-color: transparent;\n background: var(--dsw-alias-state-error-primary);\n color: #fff;\n}\n/* T7\uFF1A\u94FE\u6807\u9898\u6539\u540D\u94C5\u7B14\u6309\u94AE + \u8F7B\u91CF\u5F39\u7A97\uFF08GUI \u4EC5 human\uFF1B\u89D2\u8272\u5361\u4E0D\u53EF\u6539\u540D\uFF09 */\n.dsh-kb-chain__rename {\n flex: 0 0 auto;\n border: 0;\n background: transparent;\n color: currentColor;\n opacity: 0.55;\n font: inherit;\n line-height: 1;\n padding: 2px 4px;\n cursor: pointer;\n}\n.dsh-kb-chain__rename:hover { opacity: 1; }\n.dsh-kb-task__status-row {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n.dsh-kb-rename-overlay {\n position: fixed;\n inset: 0;\n z-index: 1000;\n background: var(--dsh-kb-mask);\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.dsh-kb-rename-modal {\n display: flex;\n flex-direction: column;\n gap: 8px;\n min-width: 280px;\n padding: 16px;\n border: 1px solid var(--dsh-kb-border);\n border-radius: var(--dsh-kb-radius-lg);\n background: var(--dsh-kb-surface-elev);\n color: var(--dsh-kb-text-primary);\n box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);\n}\n.dsh-kb-rename-modal__label {\n color: var(--dsh-kb-text-primary);\n font-size: 13px;\n font-weight: 600;\n}\n.dsh-kb-rename-modal__input {\n padding: 6px 10px;\n border: 1px solid var(--dsh-kb-border);\n border-radius: var(--dsh-kb-radius-md);\n background: var(--dsh-kb-input);\n color: var(--dsh-kb-text-primary);\n font: inherit;\n}\n.dsh-kb-rename-modal__input:focus {\n outline: none;\n border-color: var(--dsh-kb-active);\n}\n.dsh-kb-rename-modal__actions {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n}\n.dsh-kb-rename-modal__actions button {\n border: 1px solid var(--dsh-kb-border);\n border-radius: var(--dsh-kb-radius-md);\n background: transparent;\n color: var(--dsh-kb-text-primary);\n font: inherit;\n padding: 4px 14px;\n cursor: pointer;\n transition: background-color 150ms ease;\n}\n.dsh-kb-rename-modal__actions button:hover {\n background: var(--dsh-kb-hover);\n}\n.dsh-kb-rename-modal__actions .dsh-kb-rename-save {\n border-color: transparent;\n background: var(--dsw-alias-button-primary-fill);\n color: var(--dsw-alias-label-primary-foreground);\n}\n";
|
|
1355
|
+
var kanban_default = "/* T32\uFF1A\u5361\u7247/\u8FDE\u63A5\u7EBF\u7B49\u5C40\u90E8\u8FC7\u6E21\u4FDD\u6301 120-180ms\uFF1Bprefers-reduced-motion \u5168\u5C40\u5173\u95ED */\n.dsh-kb-tab {\n /* DSH \u8BBE\u8BA1\u4EE4\u724C\uFF08\u6D45/\u6DF1\u8272\u968F body[data-ds-dark-theme] \u81EA\u52A8\u5207\u6362\uFF09\u2014\u2014\u7981\u6B62\u786C\u7F16\u7801\u989C\u8272 */\n --dsh-kb-surface: var(--dsw-alias-bg-layer-1);\n --dsh-kb-surface-elev: var(--dsw-alias-bg-layer-3);\n --dsh-kb-text-primary: var(--dsw-alias-label-primary);\n --dsh-kb-text-secondary: var(--dsw-alias-label-secondary);\n --dsh-kb-text-tertiary: var(--dsw-alias-label-tertiary);\n --dsh-kb-border: var(--dsw-alias-border-l2);\n --dsh-kb-hover: var(--dsw-alias-interactive-bg-hover);\n --dsh-kb-mask: var(--dsw-alias-bg-mask-3);\n --dsh-kb-input: var(--dsw-specific-input-major);\n --dsh-kb-inline-code: var(--dsw-alias-markdown-inline-code);\n /* \u5927\u5706\u89D2\u5951\u7EA6\uFF08\u5BF9\u9F50 DSH \u5361\u7247 16px\uFF09\uFF0C\u540E\u7EED UI \u4E00\u5F8B\u590D\u7528 */\n --dsh-kb-radius-lg: 16px;\n --dsh-kb-radius-md: 10px;\n --dsh-kb-radius-sm: 8px;\n /* \u72B6\u6001\u8272 \u2192 DSH \u8BED\u4E49\u4EE4\u724C */\n --dsh-kb-complete: var(--dsw-alias-state-success-primary);\n --dsh-kb-active: var(--dsw-alias-state-business-primary);\n --dsh-kb-blocked: var(--dsw-alias-state-error-primary);\n --dsh-kb-pending: currentColor;\n /* \u89D2\u8272\u8272\uFF1ADSH \u6709\u7B49\u4EF7\u4EE4\u724C\u5219\u590D\u7528\uFF1Bp/pt/dt \u65E0 DSH \u7B49\u4EF7\u8272\uFF0C\u4FDD\u7559\u539F\u503C */\n --dsh-kb-v: var(--dsw-alias-state-business-primary);\n --dsh-kb-p: #a855f7;\n --dsh-kb-w: var(--dsw-alias-state-success-primary);\n --dsh-kb-d: var(--dsw-alias-state-warn-primary);\n --dsh-kb-pt: #6366f1; /* \u8BA1\u5212\u8BC4\u5BA1\uFF1A\u975B/\u6D45\u84DD */\n --dsh-kb-dt: #ec4899; /* \u5B9E\u73B0\u8BC4\u5BA1\uFF1A\u73AB\u7EA2 */\n height: 100%;\n width: 100%;\n min-width: 715px; /* \u770B\u677F\u6700\u5C0F\u5BBD\u5EA6 */\n max-width: 780px; /* \u770B\u677F\u6700\u5927\u5BBD\u5EA6 */\n margin-inline: auto;\n display: flex;\n flex-direction: column;\n color: inherit;\n background: var(--dsw-alias-bg-base);\n pointer-events: auto;\n font-size: 13px;\n line-height: 1.45;\n overflow: hidden;\n}\n\n.dsh-kb-banner {\n flex: 0 0 auto;\n padding: 6px 12px;\n font-size: 12px;\n border-bottom: 1px solid var(--dsh-kb-border);\n}\n.dsh-kb-banner--reconnecting,\n.dsh-kb-banner--loading {\n color: var(--dsh-kb-active);\n}\n.dsh-kb-banner--error {\n color: var(--dsh-kb-blocked);\n}\n\n.dsh-kb-tab-body {\n flex: 1 1 auto;\n min-height: 0;\n overflow: auto;\n padding: 8px;\n}\n\n.dsh-kb-loading {\n flex: 1 1 auto;\n display: flex;\n align-items: center;\n justify-content: center;\n color: currentColor;\n opacity: 0.7;\n}\n\n.dsh-kb-toolbar {\n position: sticky;\n top: 0;\n z-index: 1;\n padding-bottom: 8px;\n}\n.dsh-kb-toolbar input {\n width: 100%;\n box-sizing: border-box;\n padding: 6px 10px;\n border: 1px solid var(--dsh-kb-border);\n border-radius: var(--dsh-kb-radius-md);\n background: var(--dsh-kb-input);\n color: var(--dsh-kb-text-primary);\n}\n\n.dsh-kb-rail {\n display: flex;\n flex-direction: column;\n}\n/* \u72B6\u6001\u7B5B\u9009 chip \u7EC4\uFF1A\u6267\u884C\u4E2D/\u963B\u585E/\u5931\u8D25/\u5DF2\u5B8C\u6210\uFF08\u591A\u9009\u5E76\u96C6\uFF1B\u7A7A=\u9ED8\u8BA4\u89C6\u56FE\uFF09 */\n.dsh-kb-filters {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n padding: 0 0 8px;\n}\n.dsh-kb-filter {\n display: inline-flex;\n align-items: center;\n padding: 2px 10px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 999px;\n background: transparent;\n color: currentColor;\n font: inherit;\n cursor: pointer;\n user-select: none;\n transition: background-color 150ms ease, border-color 150ms ease, color 150ms ease;\n}\n.dsh-kb-filter:hover {\n background: var(--dsh-kb-hover);\n}\n.dsh-kb-filter--active {\n border-color: var(--dsh-kb-active);\n color: var(--dsh-kb-active);\n background: color-mix(in srgb, var(--dsh-kb-active) 10%, transparent);\n}\n\n.dsh-kb-chain {\n margin-bottom: 10px;\n}\n.dsh-kb-chain__title {\n display: flex;\n align-items: center;\n gap: 8px;\n box-sizing: border-box;\n width: 100%;\n padding: 6px 8px;\n border: 0;\n border-radius: var(--dsh-kb-radius-sm);\n background: transparent;\n color: var(--dsh-kb-text-primary);\n font: inherit;\n text-align: left;\n cursor: pointer;\n transition: background-color 150ms ease;\n}\n.dsh-kb-chain__title:hover {\n background: var(--dsh-kb-hover);\n}\n/* \u6BCF\u6761\u94FE\u8DEF\u524D\u7684\u6298\u53E0\u7BAD\u5934\uFF08\u4E0E DSH \u6298\u53E0\u4EA4\u4E92\u4E00\u81F4\uFF1A\u7EC6 chevron\uFF0C\u5C55\u5F00\u65F6\u65CB\u8F6C\uFF0C150ms \u8FC7\u6E21\uFF09 */\n.dsh-kb-chain__chevron {\n flex: 0 0 auto;\n width: 7px;\n height: 7px;\n border-top: 1.5px solid currentColor;\n border-right: 1.5px solid currentColor;\n transform: rotate(45deg);\n opacity: 0.7;\n transition: transform 150ms ease;\n}\n.dsh-kb-chain__title[aria-expanded='true'] .dsh-kb-chain__chevron {\n transform: rotate(135deg);\n}\n.dsh-kb-chain__name {\n flex: 1 1 auto;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.dsh-kb-chain__meta {\n flex: 0 0 auto;\n white-space: nowrap;\n opacity: 0.7;\n}\n.dsh-kb-chain__warning {\n padding: 4px 8px;\n margin: 2px 0 6px;\n border-left: 3px solid var(--dsh-kb-blocked);\n color: var(--dsh-kb-blocked);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n/* D23\uFF1A\u94FE\u5B8C\u6210\u9A8C\u6536\u6838\u5BF9\u8B66\u544A\u884C\uFF08completed \u94FE\u672A\u786E\u8BA4\u524D\u963B\u585E\u6700\u7EC8\u6C47\u62A5\uFF09 */\n.dsh-kb-chain__audit {\n display: flex;\n align-items: center;\n gap: 8px;\n white-space: normal;\n}\n.dsh-kb-chain__audit span {\n flex: 1 1 auto;\n overflow: hidden;\n}\n.dsh-kb-audit-confirm {\n flex: 0 0 auto;\n border: 1px solid var(--dsh-kb-blocked);\n border-radius: var(--dsh-kb-radius-sm);\n background: transparent;\n color: var(--dsh-kb-blocked);\n padding: 2px 10px;\n cursor: pointer;\n font: inherit;\n transition: background-color 150ms ease, color 150ms ease;\n}\n.dsh-kb-audit-confirm:hover {\n background: var(--dsh-kb-blocked);\n color: #fff;\n}\n\n.dsh-kb-nodes {\n list-style: none;\n margin: 0;\n padding: 0 0 0 12px;\n display: flex;\n flex-direction: column;\n gap: 0;\n}\n.dsh-kb-node {\n position: relative;\n padding-left: 12px;\n}\n.dsh-kb-node::before {\n content: '';\n position: absolute;\n left: 0;\n top: 0;\n bottom: 0;\n width: 2px;\n background: var(--dsh-kb-pending);\n transition: background-color 150ms ease;\n}\n.dsh-kb-node--complete::before { background: var(--dsh-kb-complete); }\n.dsh-kb-node--active::before { background: var(--dsh-kb-active); }\n.dsh-kb-node--pending::before {\n background: repeating-linear-gradient(to bottom, currentColor 0 3px, transparent 3px 6px);\n}\n.dsh-kb-node--blocked::before {\n background: repeating-linear-gradient(to bottom, var(--dsh-kb-blocked) 0 4px, transparent 4px 8px);\n}\n\n.dsh-kb-task {\n display: grid;\n grid-template-columns: 22px 1fr auto;\n grid-template-rows: auto auto;\n gap: 2px 8px;\n width: 100%;\n box-sizing: border-box;\n padding: 6px 8px;\n margin: 4px 0;\n border: 1px solid transparent;\n border-radius: var(--dsh-kb-radius-lg);\n background: transparent;\n color: var(--dsh-kb-text-primary);\n font: inherit;\n text-align: left;\n cursor: pointer;\n transition: border-color 150ms ease, background-color 150ms ease, opacity 150ms ease;\n}\n.dsh-kb-task:hover {\n background: var(--dsh-kb-hover);\n}\n.dsh-kb-task[data-selected],\n.dsh-kb-task--active {\n border-color: var(--dsh-kb-active);\n}\n/* T32\uFF1A\u5B8C\u6210\u4EFB\u52A1\u4FDD\u7559\u5728\u8F68\u9053\u4F46\u89C6\u89C9\u964D\u6743\uFF1B\u72B6\u6001\u8272\u4E0D\u53D8\u3001\u4E0D\u6574\u5361\u67D3\u8272 */\n.dsh-kb-task--complete {\n opacity: 0.72;\n}\n.dsh-kb-task__title {\n grid-column: 2;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.dsh-kb-task__status {\n grid-column: 3;\n color: currentColor;\n opacity: 0.75;\n}\n.dsh-kb-task__meta {\n grid-column: 2 / 4;\n opacity: 0.6;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.dsh-kb-task__warn {\n grid-column: 2 / 4;\n display: inline-flex;\n align-items: center;\n gap: 4px;\n color: var(--dsh-kb-blocked);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.dsh-kb-task__warn svg {\n flex: 0 0 auto;\n}\n.dsh-kb-task__warn span {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.dsh-kb-task--complete .dsh-kb-task__status { color: var(--dsh-kb-complete); }\n.dsh-kb-task--blocked .dsh-kb-task__status { color: var(--dsh-kb-blocked); }\n/* D17\uFF1A\u9009\u4E2D\u4EFB\u52A1\u6240\u5728\u94FE\u8DEF\u7684\u4E0A\u6E38/\u5F53\u524D/\u4E0B\u6E38\u8DEF\u5F84\u5361\u9AD8\u4EAE\uFF1B\u4E0D\u6539\u53D8\u8FDE\u63A5\u7EBF\u8BED\u4E49\uFF0C\u9009\u4E2D\u5361\u4FDD\u6301\u5F3A\u8FB9\u6846 */\n.dsh-kb-task--related:not(.dsh-kb-task--active) {\n border-color: color-mix(in srgb, var(--dsh-kb-active) 35%, transparent);\n background: color-mix(in srgb, var(--dsh-kb-active) 6%, transparent);\n}\n\n.dsh-kb-empty {\n padding: 24px 12px;\n text-align: center;\n color: var(--dsh-kb-text-secondary);\n border: 1px dashed var(--dsh-kb-border);\n border-radius: var(--dsh-kb-radius-lg);\n}\n\n.dsh-kb-profile {\n grid-row: 1 / 3;\n align-self: start;\n width: 20px;\n height: 20px;\n border-radius: var(--dsh-kb-radius-sm);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n font-size: 11px;\n font-weight: 700;\n color: #fff;\n}\n.dsh-kb-profile--v { background: var(--dsh-kb-v); }\n.dsh-kb-profile--p { background: var(--dsh-kb-p); }\n.dsh-kb-profile--w { background: var(--dsh-kb-w); }\n.dsh-kb-profile--d { background: var(--dsh-kb-d); }\n.dsh-kb-profile--pt { background: var(--dsh-kb-pt); }\n.dsh-kb-profile--dt { background: var(--dsh-kb-dt); }\n\n/* T27\uFF1A\u4EFB\u52A1\u5361\u5F39\u7A97\uFF08\u539F\u4F4D\u8BE6\u60C5\uFF09\u2014\u2014DSH \u9762\u677F\u98CE\u683C\uFF1A\u5927\u5706\u89D2 + \u62AC\u5347\u8868\u9762 + \u6D45/\u6DF1\u8272\u4EE4\u724C */\n.dsh-kb-detail {\n display: flex;\n flex-direction: column;\n min-height: calc(100% - 16px);\n margin: 8px;\n padding: 12px 16px;\n box-sizing: border-box;\n border: 1px solid var(--dsh-kb-border);\n border-radius: var(--dsh-kb-radius-lg);\n background: var(--dsh-kb-surface);\n color: var(--dsh-kb-text-primary);\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);\n}\n.dsh-kb-detail__header {\n display: flex;\n align-items: center;\n gap: 8px;\n padding-bottom: 8px;\n border-bottom: 1px solid var(--dsh-kb-border);\n}\n.dsh-kb-detail__header > button:not(.dsh-kb-unread) {\n flex: 0 0 auto;\n width: 28px;\n height: 28px;\n border: 1px solid var(--dsh-kb-border);\n border-radius: var(--dsh-kb-radius-md);\n background: transparent;\n color: var(--dsh-kb-text-primary);\n cursor: pointer;\n font: inherit;\n line-height: 1;\n transition: background-color 150ms ease;\n}\n.dsh-kb-detail__header > button:not(.dsh-kb-unread):hover {\n background: var(--dsh-kb-hover);\n}\n.dsh-kb-detail__identity {\n flex: 1 1 auto;\n min-width: 0;\n}\n.dsh-kb-detail__identity strong,\n.dsh-kb-detail__identity span {\n display: block;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.dsh-kb-detail__actions {\n display: flex;\n gap: 4px;\n flex: 0 0 auto;\n}\n.dsh-kb-detail__actions button {\n border: 1px solid var(--dsh-kb-border);\n border-radius: var(--dsh-kb-radius-md);\n background: transparent;\n color: var(--dsh-kb-text-primary);\n padding: 4px 10px;\n cursor: pointer;\n font: inherit;\n transition: border-color 150ms ease, color 150ms ease, background-color 150ms ease;\n}\n.dsh-kb-detail__actions button:hover {\n background: var(--dsh-kb-hover);\n}\n.dsh-kb-detail__actions button[data-confirming='true'] {\n border-color: var(--dsh-kb-blocked);\n color: var(--dsh-kb-blocked);\n}\n.dsh-kb-detail__actions button:disabled {\n opacity: 0.5;\n cursor: default;\n}\n.dsh-kb-action-form {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n}\n.dsh-kb-action-form input {\n width: 140px;\n padding: 3px 8px;\n border: 1px solid var(--dsh-kb-border);\n border-radius: var(--dsh-kb-radius-sm);\n background: var(--dsh-kb-input);\n color: var(--dsh-kb-text-primary);\n font: inherit;\n font-size: 12px;\n}\n.dsh-kb-unread {\n flex: 0 0 auto;\n border: 1px solid var(--dsh-kb-active);\n border-radius: 999px;\n background: color-mix(in srgb, var(--dsh-kb-active) 12%, transparent);\n color: var(--dsh-kb-active);\n padding: 2px 8px;\n font: inherit;\n font-size: 12px;\n white-space: nowrap;\n cursor: pointer;\n}\n.dsh-kb-action-error {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 6px 8px;\n margin: 4px 0;\n border-left: 3px solid var(--dsh-kb-blocked);\n color: var(--dsh-kb-blocked);\n font-size: 12px;\n}\n.dsh-kb-action-error span {\n flex: 1 1 auto;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.dsh-kb-action-error button {\n flex: 0 0 auto;\n border: 1px solid currentColor;\n border-radius: var(--dsh-kb-radius-sm);\n background: transparent;\n color: inherit;\n padding: 1px 6px;\n cursor: pointer;\n font: inherit;\n}\n.dsh-kb-detail [role='tablist'] {\n display: flex;\n gap: 4px;\n padding: 8px 0;\n border-bottom: 1px solid var(--dsh-kb-border);\n}\n.dsh-kb-detail [role='tab'] {\n border: 0;\n border-radius: var(--dsh-kb-radius-sm);\n background: transparent;\n color: var(--dsh-kb-text-secondary);\n padding: 4px 10px;\n cursor: pointer;\n transition: background-color 150ms ease, color 150ms ease;\n}\n.dsh-kb-detail [role='tab']:hover {\n color: var(--dsh-kb-text-primary);\n background: var(--dsh-kb-hover);\n}\n.dsh-kb-detail [role='tab'][aria-selected='true'] {\n background: var(--dsh-kb-hover);\n color: var(--dsh-kb-text-primary);\n}\n.dsh-kb-detail [role='tabpanel'] {\n padding: 8px 0;\n overflow: auto;\n}\n.dsh-kb-detail h4 {\n margin: 8px 0 4px;\n font-size: 12px;\n text-transform: none;\n color: var(--dsh-kb-text-secondary);\n}\n.dsh-kb-detail code {\n background: var(--dsh-kb-inline-code);\n border-radius: var(--dsh-kb-radius-sm);\n padding: 1px 4px;\n}\n.dsh-kb-detail dl {\n display: grid;\n grid-template-columns: auto 1fr;\n gap: 4px 8px;\n margin: 8px 0;\n}\n.dsh-kb-detail dt { opacity: 0.7; color: var(--dsh-kb-text-tertiary); }\n.dsh-kb-detail dd { margin: 0; }\n.dsh-kb-detail time { opacity: 0.6; font-size: 12px; margin-inline-end: 4px; }\n\n/* \u8F68\u8FF9 tab \u53EF\u8BFB\u5316\uFF1A\u7269\u6D41\u5F0F\u7EB5\u5411\u65F6\u95F4\u8F74\uFF08\u56DB\u6001\u914D\u8272 + \u6700\u65B0\u8282\u70B9\u9AD8\u4EAE\uFF1B\u5F02\u5E38\u6574\u884C\u6807\u7EA2\uFF09 */\n.dsh-kb-timeline {\n list-style: none;\n margin: 0;\n padding: 0;\n display: flex;\n flex-direction: column;\n}\n.dsh-kb-timeline__item {\n position: relative;\n display: grid;\n grid-template-columns: 16px 1fr;\n gap: 8px;\n padding: 0 0 14px;\n}\n.dsh-kb-timeline__item:last-child {\n padding-bottom: 0;\n}\n/* \u7EB5\u5411\u65F6\u95F4\u7EBF\uFF1A\u8D2F\u7A7F\u8282\u70B9\uFF08\u6700\u65B0\u8282\u70B9\u4E0A\u65B9\u7EBF\u4E0D\u5EF6\u4F38\uFF0C\u6A21\u62DF\u7269\u6D41\u5934\u8282\u70B9\uFF09 */\n.dsh-kb-timeline__axis {\n position: relative;\n}\n.dsh-kb-timeline__item:not(:last-child) .dsh-kb-timeline__axis::after {\n content: '';\n position: absolute;\n left: 50%;\n top: 14px;\n bottom: -4px;\n width: 2px;\n transform: translateX(-50%);\n background: var(--dsh-kb-border);\n}\n.dsh-kb-timeline__dot {\n position: relative;\n z-index: 1;\n display: block;\n width: 10px;\n height: 10px;\n /* \u6C34\u5E73\u5C45\u4E2D\u4E8E 16px \u8F74\u5217\uFF08\u4E2D\u5FC3=8px\uFF09\uFF0C\u4E0E left:50% \u8FDE\u63A5\u7EBF\u5BF9\u9F50 */\n margin: 2px auto 0;\n border-radius: 50%;\n border: 2px solid var(--dsh-kb-surface);\n box-sizing: border-box;\n background: var(--dsh-kb-text-tertiary);\n}\n/* \u56DB\u6001\u914D\u8272\uFF1Aneutral \u7070 / running \u84DD / success \u7EFF / exception \u7EA2 */\n.dsh-kb-timeline__item--running .dsh-kb-timeline__dot {\n background: var(--dsh-kb-active);\n}\n.dsh-kb-timeline__item--success .dsh-kb-timeline__dot {\n background: var(--dsh-kb-complete);\n}\n.dsh-kb-timeline__item--exception .dsh-kb-timeline__dot {\n background: var(--dsh-kb-blocked);\n}\n/* \u6700\u65B0\u8282\u70B9\u9AD8\u4EAE\uFF1A\u4E3B\u8272\u5706\u70B9\u653E\u5927 + \u67D4\u548C\u8F89\u5149 */\n.dsh-kb-timeline__item--latest .dsh-kb-timeline__dot {\n width: 12px;\n height: 12px;\n margin-top: 0;\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--dsh-kb-active) 22%, transparent);\n}\n.dsh-kb-timeline__item--latest.dsh-kb-timeline__item--success .dsh-kb-timeline__dot {\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--dsh-kb-complete) 22%, transparent);\n}\n.dsh-kb-timeline__item--latest.dsh-kb-timeline__item--exception .dsh-kb-timeline__dot {\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--dsh-kb-blocked) 22%, transparent);\n}\n/* \u5F02\u5E38\u884C\uFF1A\u6D45\u7EA2\u5E95 + \u5DE6\u4FA7\u7EA2\u6761\uFF0C\u6458\u8981\u7EA2\u52A0\u7C97 */\n.dsh-kb-timeline__item--exception .dsh-kb-timeline__body {\n background: color-mix(in srgb, var(--dsh-kb-blocked) 8%, transparent);\n border-left: 3px solid var(--dsh-kb-blocked);\n border-radius: var(--dsh-kb-radius-sm);\n padding: 6px 8px;\n}\n.dsh-kb-timeline__body {\n min-width: 0;\n}\n.dsh-kb-timeline__row {\n display: flex;\n align-items: baseline;\n gap: 8px;\n flex-wrap: wrap;\n}\n.dsh-kb-timeline__label {\n font-size: 13px;\n font-weight: 600;\n color: var(--dsh-kb-text-primary);\n}\n.dsh-kb-timeline__item--success .dsh-kb-timeline__label {\n color: var(--dsh-kb-complete);\n}\n.dsh-kb-timeline__item--exception .dsh-kb-timeline__label {\n color: var(--dsh-kb-blocked);\n}\n.dsh-kb-timeline__summary {\n margin: 2px 0 0;\n font-size: 12px;\n color: var(--dsh-kb-text-secondary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.dsh-kb-timeline__item--exception .dsh-kb-timeline__summary {\n color: var(--dsh-kb-blocked);\n font-weight: 600;\n}\n.dsh-kb-timeline__author {\n display: block;\n margin-top: 2px;\n font-size: 11px;\n opacity: 0.7;\n color: var(--dsh-kb-text-tertiary);\n}\n\n.dsh-kb-spec-attachments {\n list-style: none;\n margin: 4px 0;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n.dsh-kb-spec-attachments li {\n display: flex;\n align-items: baseline;\n gap: 6px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.dsh-kb-spec-attachment__kind {\n font-size: 11px;\n border: 1px solid var(--dsh-kb-border);\n border-radius: var(--dsh-kb-radius-sm);\n padding: 0 4px;\n opacity: 0.8;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .dsh-kb-tab * {\n transition-duration: 0ms !important;\n }\n}\n\n/* \u6574\u94FE\u5220\u9664\u6309\u94AE\uFF1A\u9ED8\u8BA4\u9690\u85CF\uFF0Chover \u9700\u6C42\u6807\u9898\u884C\u65F6\u51FA\u73B0\uFF08GUI \u4EC5 human\uFF0C\u4E8C\u6B21\u786E\u8BA4\uFF09 */\n.dsh-kb-chain__delete {\n flex: 0 0 auto;\n border: 0;\n background: transparent;\n color: currentColor;\n opacity: 0;\n font: inherit;\n line-height: 1;\n padding: 2px 4px;\n cursor: pointer;\n transition: opacity 150ms ease, color 150ms ease;\n}\n.dsh-kb-chain__title:hover .dsh-kb-chain__delete,\n.dsh-kb-chain__delete:focus-visible { opacity: 0.7; }\n.dsh-kb-chain__delete:hover { opacity: 1; color: var(--dsh-kb-blocked); }\n/* \u5220\u9664\u4E8C\u6B21\u786E\u8BA4\u5F39\u7A97\uFF08\u590D\u7528 rename \u5F39\u7A97\u5916\u58F3/\u5706\u89D2\u5951\u7EA6\uFF09 */\n.dsh-kb-delete-modal__text {\n color: var(--dsh-kb-text-secondary);\n font-size: 13px;\n line-height: 1.5;\n}\n.dsh-kb-delete-modal__error {\n color: var(--dsh-kb-blocked);\n font-size: 12px;\n}\n.dsh-kb-rename-modal__actions .dsh-kb-delete-confirm {\n border-color: transparent;\n background: var(--dsw-alias-state-error-primary);\n color: #fff;\n}\n/* T7\uFF1A\u94FE\u6807\u9898\u6539\u540D\u94C5\u7B14\u6309\u94AE + \u8F7B\u91CF\u5F39\u7A97\uFF08GUI \u4EC5 human\uFF1B\u89D2\u8272\u5361\u4E0D\u53EF\u6539\u540D\uFF09 */\n.dsh-kb-chain__rename {\n flex: 0 0 auto;\n border: 0;\n background: transparent;\n color: currentColor;\n opacity: 0.55;\n font: inherit;\n line-height: 1;\n padding: 2px 4px;\n cursor: pointer;\n}\n.dsh-kb-chain__rename:hover { opacity: 1; }\n.dsh-kb-task__status-row {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n.dsh-kb-rename-overlay {\n position: fixed;\n inset: 0;\n z-index: 1000;\n background: var(--dsh-kb-mask);\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.dsh-kb-rename-modal {\n display: flex;\n flex-direction: column;\n gap: 8px;\n min-width: 280px;\n padding: 16px;\n border: 1px solid var(--dsh-kb-border);\n border-radius: var(--dsh-kb-radius-lg);\n background: var(--dsh-kb-surface-elev);\n color: var(--dsh-kb-text-primary);\n box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);\n}\n.dsh-kb-rename-modal__label {\n color: var(--dsh-kb-text-primary);\n font-size: 13px;\n font-weight: 600;\n}\n.dsh-kb-rename-modal__input {\n padding: 6px 10px;\n border: 1px solid var(--dsh-kb-border);\n border-radius: var(--dsh-kb-radius-md);\n background: var(--dsh-kb-input);\n color: var(--dsh-kb-text-primary);\n font: inherit;\n}\n.dsh-kb-rename-modal__input:focus {\n outline: none;\n border-color: var(--dsh-kb-active);\n}\n.dsh-kb-rename-modal__actions {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n}\n.dsh-kb-rename-modal__actions button {\n border: 1px solid var(--dsh-kb-border);\n border-radius: var(--dsh-kb-radius-md);\n background: transparent;\n color: var(--dsh-kb-text-primary);\n font: inherit;\n padding: 4px 14px;\n cursor: pointer;\n transition: background-color 150ms ease;\n}\n.dsh-kb-rename-modal__actions button:hover {\n background: var(--dsh-kb-hover);\n}\n.dsh-kb-rename-modal__actions .dsh-kb-rename-save {\n border-color: transparent;\n background: var(--dsw-alias-button-primary-fill);\n color: var(--dsw-alias-label-primary-foreground);\n}\n";
|
|
1176
1356
|
|
|
1177
1357
|
// client/index.ts
|
|
1178
1358
|
var name = "kanban-board";
|
package/lib/config.d.ts
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import Schema from '@deepseek-ai/schemastery';
|
|
2
2
|
import type { Role } from './domain/types.js';
|
|
3
|
+
/** 斜杠命令前缀路由(单一事实源,决策12):plan/openspec/learning 已实现,run/changeset/archive 待落地时追加。 */
|
|
4
|
+
export interface PrefixRoutes {
|
|
5
|
+
plan: string;
|
|
6
|
+
openspec: string;
|
|
7
|
+
learning: string;
|
|
8
|
+
}
|
|
9
|
+
export declare const DEFAULT_PREFIX_ROUTES: PrefixRoutes;
|
|
3
10
|
export interface KanbanConfig {
|
|
4
11
|
storageDir: string;
|
|
5
12
|
wikiVault: {
|
|
@@ -30,9 +37,10 @@ export interface KanbanConfig {
|
|
|
30
37
|
dt: number;
|
|
31
38
|
};
|
|
32
39
|
};
|
|
33
|
-
prefixRoutes:
|
|
34
|
-
|
|
35
|
-
|
|
40
|
+
prefixRoutes: PrefixRoutes;
|
|
41
|
+
memory: {
|
|
42
|
+
enabled: boolean;
|
|
43
|
+
maxIndexEntries: number;
|
|
36
44
|
};
|
|
37
45
|
ui: {
|
|
38
46
|
enabled: boolean;
|
package/lib/config.js
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import Schema from '@deepseek-ai/schemastery';
|
|
2
|
+
export const DEFAULT_PREFIX_ROUTES = {
|
|
3
|
+
plan: '/plan:',
|
|
4
|
+
openspec: '/openspec:',
|
|
5
|
+
learning: '/learning',
|
|
6
|
+
};
|
|
2
7
|
const modelItemSchema = () => Schema.object({
|
|
3
8
|
provider: Schema.string().required(),
|
|
4
9
|
model: Schema.string().required(),
|
|
@@ -12,7 +17,7 @@ const modelItemSchema = () => Schema.object({
|
|
|
12
17
|
export const Config = Schema.object({
|
|
13
18
|
storageDir: Schema.string().default('$DSH_HOME/storages/kanban'),
|
|
14
19
|
wikiVault: Schema.object({
|
|
15
|
-
baseUrl: Schema.string().default('
|
|
20
|
+
baseUrl: Schema.string().default(''),
|
|
16
21
|
pagePrefix: Schema.string().default('projects/'),
|
|
17
22
|
}),
|
|
18
23
|
roles: Schema.object({
|
|
@@ -31,9 +36,14 @@ export const Config = Schema.object({
|
|
|
31
36
|
}),
|
|
32
37
|
}),
|
|
33
38
|
prefixRoutes: Schema.object({
|
|
34
|
-
plan: Schema.string().default(
|
|
35
|
-
openspec: Schema.string().default(
|
|
39
|
+
plan: Schema.string().default(DEFAULT_PREFIX_ROUTES.plan),
|
|
40
|
+
openspec: Schema.string().default(DEFAULT_PREFIX_ROUTES.openspec),
|
|
41
|
+
learning: Schema.string().default(DEFAULT_PREFIX_ROUTES.learning),
|
|
36
42
|
}),
|
|
43
|
+
memory: Schema.object({
|
|
44
|
+
enabled: Schema.boolean().default(true),
|
|
45
|
+
maxIndexEntries: Schema.number().min(1).max(20).default(8),
|
|
46
|
+
}).default({ enabled: true, maxIndexEntries: 8 }),
|
|
37
47
|
ui: Schema.object({
|
|
38
48
|
enabled: Schema.boolean().default(true),
|
|
39
49
|
contentMinWidth: Schema.number().min(320).max(960).default(715), // 看板最小宽度 715px
|
|
@@ -139,7 +139,7 @@ ${task.body}`);
|
|
|
139
139
|
sessionCwd = await resolveOrCreateWorkspace(this.ctx, null, 'task ' + task.id + ' ' + task.assignee + '/' + task.mode);
|
|
140
140
|
}
|
|
141
141
|
if (!sessionCwd) {
|
|
142
|
-
await this.kanban.comment(taskId,
|
|
142
|
+
await this.kanban.comment(taskId, `链未绑定工作区(Chain.workspaceDir 缺失且用户未提供工作区路径)。请重新 ${this.config.prefixRoutes.plan} 绑定主 agent 工作空间后重试。`, 'system');
|
|
143
143
|
await this.kanban.claimTask(taskId, 'system');
|
|
144
144
|
await this.kanban.blockTask(taskId, 'workspace-unknown: 链未绑定工作区(Chain.workspaceDir 缺失)', 'system');
|
|
145
145
|
return;
|
|
@@ -422,7 +422,7 @@ export class VOrchestrator {
|
|
|
422
422
|
ws = await resolveOrCreateWorkspace(this.ctx, null, 'chain ' + orch.chainId + ' V');
|
|
423
423
|
}
|
|
424
424
|
if (!ws)
|
|
425
|
-
throw new Error('workspace-unknown: chain ' + orch.chainId +
|
|
425
|
+
throw new Error('workspace-unknown: chain ' + orch.chainId + ` 无 workspaceDir,需重新 ${this.config.prefixRoutes.plan}`);
|
|
426
426
|
const h = await this.agents.create({ sessionId: `kbn-v-${orch.chainId}`, meta: { cwd: ws }, ...opts, setup });
|
|
427
427
|
orch.sessionId = `kbn-v-${orch.chainId}`;
|
|
428
428
|
await attachSessionToWorkspace(this.ctx, `kbn-v-${orch.chainId}`, ws, 'chain ' + orch.chainId + ' V');
|
|
@@ -56,7 +56,7 @@ export function missingDeliveryKeys(assignee, mode, handoff, kbUrlBase) {
|
|
|
56
56
|
missing.push(`${k} (host 前缀必须为 ${base})`);
|
|
57
57
|
}
|
|
58
58
|
else if (strict && k === 'page_path' && !isAllowedWikiPagePath(v)) {
|
|
59
|
-
missing.push(`${k} (必须为 projects/checklists/、projects/ch_*/t_*.md 或 projects/ch_*/review/ 命名空间)`);
|
|
59
|
+
missing.push(`${k} (必须为 projects/checklists/、projects/learnings/、projects/<slug>/learnings/、projects/ch_*/learnings/、projects/ch_*/t_*.md 或 projects/ch_*/review/ 命名空间)`);
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
62
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { BoardState } from './types.js';
|
|
2
|
+
export interface LearningEntry {
|
|
3
|
+
title: string;
|
|
4
|
+
lesson: string;
|
|
5
|
+
evidence: string;
|
|
6
|
+
tags: string[];
|
|
7
|
+
}
|
|
8
|
+
export declare function validateLearning(raw: unknown): string[];
|
|
9
|
+
export declare function formatLearningBody(entry: LearningEntry, created?: Date): string;
|
|
10
|
+
export interface MemoryIndexEntry {
|
|
11
|
+
kind: 'learning' | 'doc';
|
|
12
|
+
title: string;
|
|
13
|
+
path: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function buildMemoryIndexBlock(entries: MemoryIndexEntry[]): string | null;
|
|
16
|
+
export declare function weightedRank<T>(items: T[], scoreOf: (t: T) => number, timeOf: (t: T) => number): T[];
|
|
17
|
+
export declare function buildRepoSlug(workspaceDir: string): string;
|
|
18
|
+
export type { BoardState };
|
|
19
|
+
/** 机械提取四类信号(事件流/投影,禁 LLM 猜测),渲染紧凑 markdown。 */
|
|
20
|
+
export declare function buildLearningBrief(state: BoardState, chainId: string): string;
|
|
21
|
+
/** /learning rest → 链解析:空→最近链;精确 id→命中;子串匹配→单命中或候选列表(≤3);无→null。 */
|
|
22
|
+
export declare function resolveLearningChainId(state: BoardState, rest: string): {
|
|
23
|
+
chainId: string;
|
|
24
|
+
} | {
|
|
25
|
+
candidates: Array<{
|
|
26
|
+
chainId: string;
|
|
27
|
+
title: string;
|
|
28
|
+
}>;
|
|
29
|
+
} | null;
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { buildChecklistSlug } from '../wiki/page-path.js';
|
|
2
|
+
export function validateLearning(raw) {
|
|
3
|
+
const errors = [];
|
|
4
|
+
if (typeof raw !== 'object' || raw === null)
|
|
5
|
+
return ['learning must be an object'];
|
|
6
|
+
const l = raw;
|
|
7
|
+
for (const [label, key] of [['title', 'title'], ['lesson', 'lesson'], ['evidence', 'evidence']]) {
|
|
8
|
+
if (typeof l[key] !== 'string' || l[key].trim().length === 0)
|
|
9
|
+
errors.push(`learning.${label} must be a non-empty string`);
|
|
10
|
+
}
|
|
11
|
+
if (typeof l['title'] === 'string' && l['title'].length > 80)
|
|
12
|
+
errors.push('learning.title must be <= 80 chars');
|
|
13
|
+
if (l['tags'] !== undefined && !Array.isArray(l['tags']))
|
|
14
|
+
errors.push('learning.tags must be an array of strings');
|
|
15
|
+
if (Array.isArray(l['tags']) && l['tags'].some((v) => typeof v !== 'string'))
|
|
16
|
+
errors.push('learning.tags must be an array of strings');
|
|
17
|
+
return errors;
|
|
18
|
+
}
|
|
19
|
+
export function formatLearningBody(entry, created = new Date()) {
|
|
20
|
+
const date = created.toISOString().slice(0, 10);
|
|
21
|
+
const lines = [
|
|
22
|
+
'---',
|
|
23
|
+
`title: "${entry.title}"`,
|
|
24
|
+
'type: learning',
|
|
25
|
+
entry.tags.length > 0 ? `tags: [${entry.tags.join(', ')}]` : 'tags: []',
|
|
26
|
+
`created: ${date}`,
|
|
27
|
+
'---',
|
|
28
|
+
'',
|
|
29
|
+
`# 【Learning】${entry.title}`,
|
|
30
|
+
'',
|
|
31
|
+
'## 教训',
|
|
32
|
+
entry.lesson,
|
|
33
|
+
'',
|
|
34
|
+
'## 证据',
|
|
35
|
+
entry.evidence,
|
|
36
|
+
];
|
|
37
|
+
if (entry.tags.length > 0)
|
|
38
|
+
lines.push('', '## 适用场景', ...entry.tags.map((t) => `- ${t}`));
|
|
39
|
+
return lines.join('\n');
|
|
40
|
+
}
|
|
41
|
+
export function buildMemoryIndexBlock(entries) {
|
|
42
|
+
if (entries.length === 0)
|
|
43
|
+
return null;
|
|
44
|
+
const lines = ['## KB 记忆索引(自动注入)'];
|
|
45
|
+
for (const e of entries) {
|
|
46
|
+
const title = e.title.length > 60 ? e.title.slice(0, 60) + '…' : e.title;
|
|
47
|
+
lines.push(`- ${e.kind === 'learning' ? 'Learning' : '清单/计划/结果'}:[#/page/${e.path}](#/page/${e.path}) ${title}`);
|
|
48
|
+
}
|
|
49
|
+
lines.push('(需全文调 planning_memory_recall)');
|
|
50
|
+
return lines.join('\n');
|
|
51
|
+
}
|
|
52
|
+
export function weightedRank(items, scoreOf, timeOf) {
|
|
53
|
+
if (items.length === 0)
|
|
54
|
+
return items;
|
|
55
|
+
const scores = items.map(scoreOf);
|
|
56
|
+
const times = items.map(timeOf);
|
|
57
|
+
const sMin = Math.min(...scores), sMax = Math.max(...scores);
|
|
58
|
+
const tMin = Math.min(...times), tMax = Math.max(...times);
|
|
59
|
+
const sRange = sMax - sMin || 1;
|
|
60
|
+
const tRange = tMax - tMin || 1;
|
|
61
|
+
const rank = (x) => 0.7 * ((scoreOf(x) - sMin) / sRange) + 0.3 * ((timeOf(x) - tMin) / tRange);
|
|
62
|
+
return [...items].sort((a, b) => rank(b) - rank(a));
|
|
63
|
+
}
|
|
64
|
+
export function buildRepoSlug(workspaceDir) {
|
|
65
|
+
const base = workspaceDir.replace(/\/+$/, '').split('/').pop() ?? '';
|
|
66
|
+
return buildChecklistSlug(base);
|
|
67
|
+
}
|
|
68
|
+
// ── Task 4:证据包 + 链解析 ──────────────────────────────────────────
|
|
69
|
+
const truncate = (s, n) => (s.length > n ? s.slice(0, n) + '…' : s);
|
|
70
|
+
/** 链上下文头:链标题 + 规格卡 problem 首行。 */
|
|
71
|
+
function chainContext(state, chainId) {
|
|
72
|
+
const chain = state.chains.get(chainId);
|
|
73
|
+
if (!chain)
|
|
74
|
+
return '';
|
|
75
|
+
const spec = chain.specCardId ? state.specCards.get(chain.specCardId) : undefined;
|
|
76
|
+
const problem = spec?.sections.problem ? spec.sections.problem.split('\n')[0].slice(0, 200) : '';
|
|
77
|
+
return [chain.title, problem].filter(Boolean).join(' — ');
|
|
78
|
+
}
|
|
79
|
+
/** 机械提取四类信号(事件流/投影,禁 LLM 猜测),渲染紧凑 markdown。 */
|
|
80
|
+
export function buildLearningBrief(state, chainId) {
|
|
81
|
+
const header = ['## 链上下文', chainContext(state, chainId), ''];
|
|
82
|
+
const sections = [];
|
|
83
|
+
const chainEvents = state.events.filter((e) => e.chainId === chainId);
|
|
84
|
+
const reviewFailed = chainEvents.filter((e) => e.kind === 'review/failed');
|
|
85
|
+
if (reviewFailed.length > 0) {
|
|
86
|
+
const lines = ['### 评审失败'];
|
|
87
|
+
for (const e of reviewFailed.slice(-5)) {
|
|
88
|
+
const issues = e.payload.evidence?.issues ?? [];
|
|
89
|
+
for (const i of issues.slice(0, 5))
|
|
90
|
+
lines.push(`- [${i.severity}] ${i.title} — ${truncate(i.detail, 200)}`);
|
|
91
|
+
}
|
|
92
|
+
sections.push(lines.join('\n'));
|
|
93
|
+
}
|
|
94
|
+
const blocked = chainEvents.filter((e) => e.kind === 'task/blocked');
|
|
95
|
+
if (blocked.length > 0) {
|
|
96
|
+
const lines = ['### 任务阻塞'];
|
|
97
|
+
for (const e of blocked.slice(-5)) {
|
|
98
|
+
const task = e.taskId ? state.tasks.get(e.taskId) : undefined;
|
|
99
|
+
const reason = typeof e.payload.reason === 'string' ? e.payload.reason : '';
|
|
100
|
+
lines.push(`- ${task?.title ?? e.taskId} — ${truncate(reason, 200)}`);
|
|
101
|
+
}
|
|
102
|
+
sections.push(lines.join('\n'));
|
|
103
|
+
}
|
|
104
|
+
const reworks = [...state.tasks.values()].filter((t) => t.chainId === chainId && t.reworkOfTaskId !== null);
|
|
105
|
+
if (reworks.length > 0) {
|
|
106
|
+
const lines = ['### 返工卡'];
|
|
107
|
+
for (const t of reworks.slice(-5))
|
|
108
|
+
lines.push(`- [返工×${t.reviewAttempt}] ${t.title}(原卡 ${t.reworkOfTaskId})`);
|
|
109
|
+
sections.push(lines.join('\n'));
|
|
110
|
+
}
|
|
111
|
+
const audit = chainEvents.filter((e) => e.kind === 'chain/audit-warning');
|
|
112
|
+
if (audit.length > 0) {
|
|
113
|
+
const lines = ['### 审计警告'];
|
|
114
|
+
for (const e of audit.slice(-5)) {
|
|
115
|
+
const evidence = e.payload.evidence ?? [];
|
|
116
|
+
for (const ev of evidence.slice(0, 5))
|
|
117
|
+
lines.push(`- [${ev.source}] ${truncate(ev.detail, 200)}`);
|
|
118
|
+
}
|
|
119
|
+
sections.push(lines.join('\n'));
|
|
120
|
+
}
|
|
121
|
+
if (sections.length === 0)
|
|
122
|
+
return [...header, '(无机械信号,可基于对话观察蒸馏)'].join('\n');
|
|
123
|
+
return [...header, ...sections].join('\n');
|
|
124
|
+
}
|
|
125
|
+
/** /learning rest → 链解析:空→最近链;精确 id→命中;子串匹配→单命中或候选列表(≤3);无→null。 */
|
|
126
|
+
export function resolveLearningChainId(state, rest) {
|
|
127
|
+
const trimmed = rest.trim();
|
|
128
|
+
if (!trimmed) {
|
|
129
|
+
const latest = [...state.chains.values()].at(-1);
|
|
130
|
+
return latest ? { chainId: latest.id } : null;
|
|
131
|
+
}
|
|
132
|
+
if (state.chains.has(trimmed))
|
|
133
|
+
return { chainId: trimmed };
|
|
134
|
+
const matches = [...state.chains.values()].filter((c) => {
|
|
135
|
+
if (c.title.includes(trimmed))
|
|
136
|
+
return true;
|
|
137
|
+
const spec = c.specCardId ? state.specCards.get(c.specCardId) : undefined;
|
|
138
|
+
return spec?.sections.problem.includes(trimmed) ?? false;
|
|
139
|
+
}).slice(0, 3);
|
|
140
|
+
if (matches.length === 1)
|
|
141
|
+
return { chainId: matches[0].id };
|
|
142
|
+
if (matches.length === 0)
|
|
143
|
+
return null;
|
|
144
|
+
return { candidates: matches.map((c) => ({ chainId: c.id, title: c.title })) };
|
|
145
|
+
}
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { KanbanService } from '../domain/kanban-service.js';
|
|
2
2
|
import type { SpecCard, SpecCardAttachment } from '../domain/types.js';
|
|
3
|
-
|
|
3
|
+
import { type PrefixRoutes } from '../config.js';
|
|
4
|
+
/** 阶段 0 规划引导:命令串从 config 派生(决策12),/openspec: 改名时文案自动跟随。 */
|
|
5
|
+
export declare function buildPlanningGuidance(routes: PrefixRoutes): string;
|
|
4
6
|
export declare function validateSpecCardForApproval(card: SpecCard): string[];
|
|
5
|
-
export declare function buildPlanningContext(chainId: string, card: SpecCard, attachments: SpecCardAttachment[]): string;
|
|
6
|
-
export declare function approveIfReady(message: string, service: KanbanService, cfg: {
|
|
7
|
-
plan: string;
|
|
8
|
-
openspec: string;
|
|
9
|
-
}, chainId: string, specCardId: string): Promise<{
|
|
7
|
+
export declare function buildPlanningContext(chainId: string, card: SpecCard, attachments: SpecCardAttachment[], routes?: PrefixRoutes): string;
|
|
8
|
+
export declare function approveIfReady(message: string, service: KanbanService, cfg: PrefixRoutes, chainId: string, specCardId: string): Promise<{
|
|
10
9
|
ok: true;
|
|
11
10
|
card: SpecCard;
|
|
12
11
|
} | {
|