@godv61/dsh-task-engine 0.25.0 → 0.26.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/.acceptance.mjs +150 -150
  2. package/.assessment-batch1.mjs +20 -20
  3. package/.enforce-test.mjs +138 -138
  4. package/.evidence-test.mjs +118 -119
  5. package/.filter-test.mjs +92 -92
  6. package/.hook-test.mjs +195 -195
  7. package/.p0-test.mjs +59 -59
  8. package/.preset-test.mjs +160 -160
  9. package/.revision-test.mjs +30 -16
  10. package/.roundtrip-test.mjs +178 -63
  11. package/.workflow-test.mjs +86 -0
  12. package/README.md +8 -8
  13. package/cordis.patch.yml +10 -10
  14. package/defaults/eng.json +70 -22
  15. package/docs/BRIEF-FOR-REVIEW.md +162 -162
  16. package/docs/CHANGELOG.md +18 -0
  17. package/docs/README.md +40 -40
  18. package/docs/configuration.md +14 -9
  19. package/docs/development.md +1 -1
  20. package/docs/faq.md +4 -4
  21. package/docs/listing/godv61__dsh-task-engine.yml +5 -5
  22. package/docs/listing/submission.md +83 -83
  23. package/docs/manual.html +32 -27
  24. package/docs/releases/0.23.2.md +21 -21
  25. package/docs/roadmap.md +34 -34
  26. package/docs/testing/0.23.2/R02/344/270/232/345/212/241/346/265/213/350/257/225/346/230/216/347/273/206.md +56 -56
  27. package/docs/testing/0.23.2/R03/344/270/232/345/212/241/346/265/213/350/257/225/346/230/216/347/273/206.md +38 -38
  28. package/docs/testing/0.23.2//346/265/213/350/257/225/346/212/245/345/221/212.md +65 -65
  29. package/hooks/commit-msg +70 -1
  30. package/lib/client.js +870 -571
  31. package/lib/client.js.map +3 -3
  32. package/lib/controller.d.ts +2 -1
  33. package/lib/controller.js +6 -3
  34. package/lib/controller.js.map +1 -1
  35. package/lib/dev-task.js +83 -15
  36. package/lib/dev-task.js.map +1 -1
  37. package/lib/engine.d.ts +15 -0
  38. package/lib/engine.js +29 -5
  39. package/lib/engine.js.map +1 -1
  40. package/lib/hook.js +3 -0
  41. package/lib/hook.js.map +1 -1
  42. package/lib/skill-audit.js +3 -3
  43. package/lib/skill-audit.js.map +1 -1
  44. package/lib/workflows.d.ts +4 -1
  45. package/lib/workflows.js +90 -2
  46. package/lib/workflows.js.map +1 -1
  47. package/package.json +1 -1
  48. package/preset/agent.cordis.yml +22 -22
  49. package/preset/enable.mjs +87 -87
  50. package/preset/persona.md +5 -5
  51. package/preset/preset.yml +1 -1
  52. package/rules/coding-conventions.md +6 -6
  53. package/rules/commit-conventions.md +6 -6
  54. package/rules/security-redlines.md +5 -5
  55. package/scripts/verify-dsh-compat.mjs +144 -144
  56. package/skills/code-implement/SKILL.md +1 -1
  57. package/skills/code-verify/SKILL.md +3 -3
  58. package/skills/eng-delivery/SKILL.md +10 -31
package/lib/client.js CHANGED
@@ -4536,8 +4536,8 @@ var TYPERT_REMOTE = {
4536
4536
  var remote_default = TYPERT_REMOTE;
4537
4537
 
4538
4538
  // src/client/Workbench.tsx
4539
- var import_react8 = require("react");
4540
- var import_dsh_client_ui_primitives6 = require("@deepseek-ai/dsh-client-ui-primitives");
4539
+ var import_react9 = require("react");
4540
+ var import_dsh_client_ui_primitives7 = require("@deepseek-ai/dsh-client-ui-primitives");
4541
4541
 
4542
4542
  // src/client/workbench-theme.ts
4543
4543
  var workbenchTheme = `
@@ -4576,8 +4576,35 @@ var workbenchTheme = `
4576
4576
  .te-binding-name { font-size:13px; font-weight:600; overflow-wrap:anywhere; }
4577
4577
  .te-binding-description { color:var(--dsw-alias-label-secondary); font-size:12px; line-height:1.4; display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden; overflow-wrap:anywhere; }
4578
4578
  .te-binding-empty { margin:0; padding:18px 8px; font-size:13px; }
4579
+ .te-transfer { display:grid; grid-template-columns:minmax(0,1fr) 24px minmax(0,1fr); gap:12px; align-items:stretch; }
4580
+ .te-transfer-pane { display:flex; flex-direction:column; min-width:0; gap:10px; padding:14px; border:1px solid var(--dsw-alias-border-l2); border-radius:12px; background:var(--dsw-alias-bg-layer-1); }
4581
+ .te-transfer-pane h4 { margin:0; font-size:14px; }
4582
+ .te-transfer-arrow { display:grid; place-items:center; color:var(--dsw-alias-label-tertiary); font-size:20px; }
4583
+ .te-transfer-search,.te-transfer-caption { min-height:38px; width:100%; }
4584
+ .te-transfer-caption { display:flex; align-items:center; margin:0; color:var(--dsw-alias-label-secondary); font-size:12px; }
4585
+ .te-transfer-list { display:flex; flex-direction:column; gap:4px; min-height:180px; max-height:310px; overflow:auto; overscroll-behavior:contain; scrollbar-gutter:stable; }
4586
+ .te-transfer-row { width:100%; display:flex; align-items:center; justify-content:space-between; gap:12px; border:1px solid transparent; border-radius:8px; padding:9px 11px; background:var(--dsw-alias-bg-layer-2); color:var(--dsw-alias-label-primary); text-align:left; cursor:pointer; }
4587
+ .te-transfer-row:hover { border-color:var(--dsw-alias-state-business-primary); }
4588
+ .te-transfer-row.is-bound { background:var(--dsw-alias-bg-layer-1); border-color:var(--dsw-alias-border-l2); cursor:default; }
4589
+ .te-transfer-row-main { min-width:0; display:flex; flex-direction:column; gap:2px; }
4590
+ .te-transfer-row-main strong { font-size:13px; font-weight:600; overflow-wrap:anywhere; }
4591
+ .te-transfer-row-main small { color:var(--dsw-alias-label-secondary); font-size:11px; line-height:1.35; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
4592
+ .te-transfer-action { flex:none; display:grid; place-items:center; width:27px; height:27px; border-radius:7px; background:var(--dsw-alias-bg-layer-1); color:var(--dsw-alias-state-business-primary); font-size:18px; }
4593
+ .te-transfer-actions { flex:none; display:flex; align-items:center; gap:6px; }
4594
+ .te-transfer-config,.te-transfer-remove { border:0; border-radius:7px; padding:6px 8px; background:var(--dsw-alias-bg-layer-2); color:var(--dsw-alias-label-primary); cursor:pointer; font-size:12px; white-space:nowrap; }
4595
+ .te-transfer-config:hover,.te-transfer-remove:hover { color:var(--dsw-alias-state-business-primary); }
4596
+ .te-transfer-remove { width:27px; height:27px; padding:0; font-size:19px; line-height:1; }
4597
+ .te-dialog-error { color:var(--dsw-alias-state-error-primary); font-size:12px; margin-right:auto; }
4598
+ .te-skill-config { display:flex; flex:1; flex-direction:column; gap:12px; min-width:0; min-height:0; }
4599
+ .te-skill-evidence { display:flex; align-items:center; justify-content:space-between; gap:12px; font-size:13px; font-weight:600; }
4600
+ .te-skill-evidence .te-input { min-width:210px; }
4601
+ .te-skill-rule-list { display:flex; flex:1; flex-direction:column; gap:4px; min-height:0; overflow:auto; padding:4px; }
4602
+ .te-skill-rule-row { display:flex; align-items:center; gap:10px; padding:9px 10px; border:1px solid var(--dsw-alias-border-l2); border-radius:8px; cursor:pointer; }
4603
+ .te-skill-rule-row:hover { background:var(--dsw-alias-bg-layer-1); }
4604
+ .te-skill-rule-row span { flex:1; min-width:0; overflow-wrap:anywhere; }
4605
+ .te-skill-rule-row small { color:var(--dsw-alias-label-secondary); }
4579
4606
  .te-workbench p,.te-modal p { color:var(--dsw-alias-label-secondary); line-height:1.65; }
4580
- .te-content { max-width:1120px; margin:auto; width:100%; }
4607
+ .te-content { max-width:1600px; margin:auto; width:100%; }
4581
4608
  .te-resource { display:flex; flex-direction:column; gap:20px; }
4582
4609
  .te-section-heading { display:flex; justify-content:space-between; align-items:center; gap:16px; flex-wrap:wrap; }
4583
4610
  .te-section-heading p { margin:0; }
@@ -4585,7 +4612,7 @@ var workbenchTheme = `
4585
4612
  .te-toolbar { display:flex; flex-wrap:wrap; align-items:center; gap:12px; }
4586
4613
  .te-toolbar>input { flex:1; min-width:180px; }
4587
4614
  .te-input { background:var(--dsw-alias-bg-layer-1); border:1px solid var(--dsw-alias-border-l2); border-radius:10px; padding:10px 12px; font:inherit; color:var(--dsw-alias-label-primary); min-width:0; }
4588
- .te-resource-grid { display:grid; grid-template-columns:repeat(auto-fill,minmax(min(100%,280px),1fr)); gap:16px; }
4615
+ .te-resource-grid { display:grid; grid-template-columns:repeat(auto-fill,minmax(min(100%,320px),1fr)); gap:16px; }
4589
4616
  .te-resource-card { display:flex; flex-direction:column; gap:14px; background:var(--dsw-alias-bg-layer-1); border:1px solid var(--dsw-alias-border-l2); border-radius:16px; padding:20px; transition:border-color .15s; }
4590
4617
  .te-resource-card:hover { border-color:var(--dsw-alias-state-business-primary); }
4591
4618
  .te-resource-card p { margin:0; font-size:13px; flex:1; }
@@ -4616,7 +4643,8 @@ var workbenchTheme = `
4616
4643
  .te-form { display:flex; flex-direction:column; gap:16px; }
4617
4644
  .te-form label { display:flex; flex-direction:column; gap:8px; font-size:13px; }
4618
4645
  .te-editor { min-height:260px; resize:vertical; line-height:1.6; font-family:monospace; }
4619
- @media(max-width:640px) { .te-targets {grid-template-columns:1fr;} .te-resource {gap:14px;} .te-section-heading h2 {font-size:21px;} .te-modal {padding:10px !important;} }
4646
+ @media(max-width:760px) { .te-transfer {grid-template-columns:1fr;} .te-transfer-arrow {transform:rotate(90deg); height:20px;} .te-transfer-list {max-height:210px;} }
4647
+ @media(max-width:640px) { .te-targets {grid-template-columns:1fr;} .te-resource {gap:14px;} .te-section-heading h2 {font-size:21px;} .te-modal:not(.te-drawer) {padding:10px !important;} .te-drawer [role=dialog] {border-radius:0 !important;} .te-skill-evidence {align-items:stretch; flex-direction:column;} .te-skill-evidence .te-input {min-width:0;} }
4620
4648
  `;
4621
4649
 
4622
4650
  // src/client/styles.ts
@@ -4630,8 +4658,8 @@ var success = "var(--dsw-alias-state-success-primary)";
4630
4658
  var warn = "var(--dsw-alias-state-warn-primary)";
4631
4659
  var brand = "var(--dsw-alias-state-business-primary)";
4632
4660
  var styles = {
4633
- wrap: { display: "flex", flexDirection: "column", gap: 16, padding: 20, maxWidth: 900 },
4634
- head: { display: "flex", flexDirection: "column", gap: 4 },
4661
+ wrap: { display: "flex", flexDirection: "column", gap: 14, padding: "0 0 24px", width: "100%" },
4662
+ head: { display: "flex", flexDirection: "column", gap: 4, maxWidth: 1e3 },
4635
4663
  title: { margin: 0, color: text },
4636
4664
  muted: { margin: 0, color: textSecondary, fontSize: 13, lineHeight: 1.5 },
4637
4665
  sourceRow: { display: "flex", alignItems: "center", gap: 8 },
@@ -4702,7 +4730,7 @@ var styles = {
4702
4730
  borderTop: `1px solid ${border}`
4703
4731
  },
4704
4732
  // ── flow preset picker ────────────────────────────────────────────────────
4705
- flowGrid: { display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(230px, 1fr))", gap: 10 },
4733
+ flowGrid: { display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(230px, 1fr))", gap: 10, maxWidth: 1200 },
4706
4734
  // The adoption row is deliberately separated from the flow picker: choosing a
4707
4735
  // skeleton and adopting a recommended setup are different decisions, and the
4708
4736
  // button is the only thing that writes method into the user's config.
@@ -4748,8 +4776,8 @@ var styles = {
4748
4776
  };
4749
4777
 
4750
4778
  // src/client/TaskEngineSection.tsx
4751
- var import_react = require("react");
4752
- var import_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
4779
+ var import_react3 = require("react");
4780
+ var import_dsh_client_ui_primitives3 = require("@deepseek-ai/dsh-client-ui-primitives");
4753
4781
 
4754
4782
  // src/engine.ts
4755
4783
  function formatResourceRef(ref) {
@@ -4769,7 +4797,7 @@ var GUARD_NAMES = [
4769
4797
  "artifacts_present"
4770
4798
  ];
4771
4799
  function validateWorkflow(config) {
4772
- const problems = [];
4800
+ const problems = [...config.configuration_errors ?? []];
4773
4801
  if (config.stages.length === 0) problems.push("stages must not be empty");
4774
4802
  const seen = /* @__PURE__ */ new Set();
4775
4803
  for (const stage of config.stages) {
@@ -4816,6 +4844,7 @@ function validateWorkflow(config) {
4816
4844
  }
4817
4845
  });
4818
4846
  const bindings = config.stage_bindings ?? {};
4847
+ const skillMethods = /* @__PURE__ */ new Map();
4819
4848
  for (const [stage, binding] of Object.entries(bindings)) {
4820
4849
  if (!config.stages.includes(stage)) {
4821
4850
  problems.push(`stage_bindings: stage "${stage}" is not a stage`);
@@ -4828,6 +4857,19 @@ function validateWorkflow(config) {
4828
4857
  if (!["bundled", "project", "user"].includes(entry.skill.source)) {
4829
4858
  problems.push(`stage_bindings "${stage}": skill "${entry.skill.name}" has unknown source "${String(entry.skill.source)}"`);
4830
4859
  }
4860
+ const skillKey = formatResourceRef(entry.skill);
4861
+ const method = JSON.stringify({ rules: entry.rules ?? [], evidence: entry.evidence });
4862
+ const existing = skillMethods.get(skillKey);
4863
+ if (existing !== void 0 && existing !== method) {
4864
+ problems.push(`skill "${skillKey}" has different rules or evidence in multiple stages; copy it as a distinct skill`);
4865
+ }
4866
+ skillMethods.set(skillKey, method);
4867
+ if (entry.evidence === "artifact" && !config.artifacts.some((artifact) => artifact.stage === stage)) {
4868
+ problems.push(`skill "${skillKey}" requires artifact evidence, but stage "${stage}" declares no artifact`);
4869
+ }
4870
+ if (entry.evidence !== void 0 && !["command", "artifact", "review", "manual", "none"].includes(entry.evidence)) {
4871
+ problems.push(`skill "${skillKey}" has unknown evidence type "${String(entry.evidence)}"`);
4872
+ }
4831
4873
  for (const rule of entry.rules ?? []) {
4832
4874
  if (typeof rule?.name !== "string" || rule.name.trim() === "") {
4833
4875
  problems.push(`stage_bindings "${stage}": skill "${entry.skill.name}" has a rule with no name`);
@@ -5019,15 +5061,80 @@ function applyProjectConfig(base, project) {
5019
5061
  if (project === void 0) return base;
5020
5062
  const next = { ...base };
5021
5063
  if (project.stage_bindings !== void 0) {
5064
+ const profiles = { ...project.skill_profiles ?? {} };
5065
+ const explicitProfiles = new Set(Object.keys(project.skill_profiles ?? {}));
5066
+ const problems = [];
5022
5067
  const bindings = {};
5023
5068
  for (const [stage, binding] of Object.entries(project.stage_bindings)) {
5024
5069
  const entry = {};
5025
- if ((binding.skills ?? []).length > 0) entry.skills = [...binding.skills];
5070
+ if (binding === null || typeof binding !== "object") {
5071
+ problems.push(`stage_bindings "${stage}" must be an object`);
5072
+ bindings[stage] = entry;
5073
+ continue;
5074
+ }
5075
+ if (binding.skill_refs !== void 0 && binding.skills !== void 0) {
5076
+ problems.push(`stage_bindings "${stage}" has both skill_refs and legacy skills`);
5077
+ }
5078
+ if (binding.skill_refs !== void 0) {
5079
+ if (!Array.isArray(binding.skill_refs)) {
5080
+ problems.push(`stage_bindings "${stage}" skill_refs must be an array`);
5081
+ }
5082
+ entry.skills = (Array.isArray(binding.skill_refs) ? binding.skill_refs : []).flatMap((ref) => {
5083
+ if (ref === null || typeof ref !== "object") {
5084
+ problems.push(`stage_bindings "${stage}" has an invalid skill reference`);
5085
+ return [];
5086
+ }
5087
+ const key = formatResourceRef(ref);
5088
+ const profile = profiles[key];
5089
+ if (profile === void 0) {
5090
+ problems.push(`skill profile "${key}" is missing`);
5091
+ return [];
5092
+ }
5093
+ if (profile === null || !Array.isArray(profile.rules)) {
5094
+ problems.push(`skill profile "${key}" must declare a rules array`);
5095
+ return [];
5096
+ }
5097
+ return [{ skill: ref, rules: profile.rules, ...profile.evidence !== void 0 ? { evidence: profile.evidence } : {} }];
5098
+ });
5099
+ } else if (binding.skills !== void 0) {
5100
+ if (!Array.isArray(binding.skills)) {
5101
+ problems.push(`stage_bindings "${stage}" skills must be an array`);
5102
+ }
5103
+ entry.skills = (Array.isArray(binding.skills) ? binding.skills : []).flatMap((skill) => {
5104
+ if (skill === null || typeof skill !== "object" || skill.skill === null || typeof skill.skill !== "object") {
5105
+ problems.push(`stage_bindings "${stage}" has an invalid skill binding`);
5106
+ return [];
5107
+ }
5108
+ const key = formatResourceRef(skill.skill);
5109
+ if (explicitProfiles.has(key)) {
5110
+ const profile = profiles[key];
5111
+ if (profile === null || !Array.isArray(profile?.rules)) {
5112
+ problems.push(`skill profile "${key}" must declare a rules array`);
5113
+ return [];
5114
+ }
5115
+ return [{
5116
+ skill: skill.skill,
5117
+ rules: profile.rules,
5118
+ ...profile.evidence !== void 0 ? { evidence: profile.evidence } : {}
5119
+ }];
5120
+ }
5121
+ const candidate = { rules: skill.rules ?? [], ...skill.evidence !== void 0 ? { evidence: skill.evidence } : {} };
5122
+ const existing = profiles[key];
5123
+ if (existing !== void 0 && JSON.stringify(existing) !== JSON.stringify(candidate)) {
5124
+ problems.push(`skill "${key}" has different rules or evidence in multiple stages; copy it as a distinct skill`);
5125
+ } else profiles[key] = candidate;
5126
+ return [skill];
5127
+ });
5128
+ }
5026
5129
  const legacy = dedupe(binding.legacy_rules ?? []);
5027
5130
  if (legacy.length > 0) entry.legacy_rules = legacy;
5028
5131
  bindings[stage] = entry;
5029
5132
  }
5030
5133
  next.stage_bindings = bindings;
5134
+ next.skill_profiles = profiles;
5135
+ if (problems.length > 0) next.configuration_errors = problems;
5136
+ } else if (project.skill_profiles !== void 0) {
5137
+ next.skill_profiles = project.skill_profiles;
5031
5138
  }
5032
5139
  if (project.commit !== void 0) next.commit = project.commit;
5033
5140
  if (project.artifacts !== void 0) next.artifacts = project.artifacts;
@@ -5048,6 +5155,7 @@ function adoptRecommendation(presetId, current) {
5048
5155
  const config = {
5049
5156
  flow: presetId,
5050
5157
  stage_bindings: current?.stage_bindings ?? rec.stage_bindings ?? {},
5158
+ ...current?.skill_profiles !== void 0 ? { skill_profiles: current.skill_profiles } : {},
5051
5159
  commit,
5052
5160
  artifacts: current?.artifacts ?? rec.artifacts ?? preset2.config.artifacts,
5053
5161
  ...current?.review_depth !== void 0 ? { review_depth: current.review_depth } : rec.review_depth !== void 0 ? { review_depth: rec.review_depth } : {},
@@ -5055,6 +5163,19 @@ function adoptRecommendation(presetId, current) {
5055
5163
  };
5056
5164
  return config;
5057
5165
  }
5166
+ function compactProjectConfig(project) {
5167
+ const resolved = resolveFlow(project.flow, project);
5168
+ if (!resolved.ok) return project;
5169
+ const profiles = resolved.config.skill_profiles ?? {};
5170
+ const bindings = {};
5171
+ for (const [stage, binding] of Object.entries(resolved.config.stage_bindings ?? {})) {
5172
+ bindings[stage] = {
5173
+ skill_refs: (binding.skills ?? []).map((entry) => entry.skill),
5174
+ ...binding.legacy_rules?.length ? { legacy_rules: binding.legacy_rules } : {}
5175
+ };
5176
+ }
5177
+ return { ...project, stage_bindings: bindings, skill_profiles: profiles };
5178
+ }
5058
5179
  function resolveFlow(flow, project) {
5059
5180
  const preset2 = FLOW_PRESETS[flow];
5060
5181
  if (preset2 === void 0) {
@@ -5071,33 +5192,296 @@ function describeError(error) {
5071
5192
  return "\u672A\u77E5\u9519\u8BEF";
5072
5193
  }
5073
5194
 
5074
- // src/client/TaskEngineSection.tsx
5195
+ // src/client/SkillRuleDialog.tsx
5196
+ var import_react2 = require("react");
5197
+ var import_dsh_client_ui_primitives2 = require("@deepseek-ai/dsh-client-ui-primitives");
5198
+
5199
+ // src/client/ResourceModal.tsx
5200
+ var import_react = require("react");
5201
+ var import_react_dom = require("react-dom");
5202
+ var import_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
5203
+ var rootStyle = {
5204
+ position: "fixed",
5205
+ inset: 0,
5206
+ zIndex: 1e3,
5207
+ display: "flex",
5208
+ alignItems: "center",
5209
+ justifyContent: "center",
5210
+ padding: 24
5211
+ };
5212
+ var maskStyle = {
5213
+ position: "absolute",
5214
+ inset: 0,
5215
+ background: "var(--dsw-alias-bg-mask-1)",
5216
+ backdropFilter: "var(--dsw-mask-blur)"
5217
+ };
5218
+ var dialogStyle = {
5219
+ position: "relative",
5220
+ zIndex: 1,
5221
+ display: "flex",
5222
+ flexDirection: "column",
5223
+ width: "min(760px, 100%)",
5224
+ maxHeight: "85vh",
5225
+ borderRadius: 24,
5226
+ background: "var(--dsw-alias-bg-layer-2)",
5227
+ boxShadow: "var(--dsw-elevation-prominent)",
5228
+ overflow: "hidden"
5229
+ };
5230
+ var drawerStyle = {
5231
+ ...dialogStyle,
5232
+ width: "min(560px, 100%)",
5233
+ height: "100%",
5234
+ maxHeight: "100%",
5235
+ borderRadius: "16px 0 0 16px"
5236
+ };
5237
+ var headerStyle = {
5238
+ display: "flex",
5239
+ alignItems: "center",
5240
+ justifyContent: "space-between",
5241
+ gap: 8,
5242
+ padding: "18px 18px 10px 24px",
5243
+ flex: "none"
5244
+ };
5245
+ var titleStyle = {
5246
+ margin: 0,
5247
+ fontSize: 16,
5248
+ lineHeight: "24px",
5249
+ fontWeight: 500,
5250
+ color: "var(--dsw-alias-label-primary)"
5251
+ };
5252
+ var closeBtnStyle = {
5253
+ flex: "none",
5254
+ display: "inline-flex",
5255
+ alignItems: "center",
5256
+ justifyContent: "center",
5257
+ width: 28,
5258
+ height: 28,
5259
+ border: "none",
5260
+ borderRadius: 8,
5261
+ background: "transparent",
5262
+ cursor: "pointer",
5263
+ color: "var(--dsw-alias-label-secondary)",
5264
+ padding: 0
5265
+ };
5266
+ var descStyle = {
5267
+ margin: 0,
5268
+ padding: "0 24px",
5269
+ fontSize: 13,
5270
+ lineHeight: "20px",
5271
+ color: "var(--dsw-alias-label-secondary)",
5272
+ flex: "none"
5273
+ };
5274
+ var bodyStyle = {
5275
+ flex: "1 1 auto",
5276
+ minHeight: 0,
5277
+ overflowY: "auto",
5278
+ padding: "16px 24px 4px",
5279
+ display: "flex",
5280
+ flexDirection: "column"
5281
+ };
5282
+ var footerStyle = {
5283
+ display: "flex",
5284
+ alignItems: "center",
5285
+ justifyContent: "flex-end",
5286
+ gap: 8,
5287
+ padding: "12px 24px 20px",
5288
+ flex: "none"
5289
+ };
5290
+ function ResourceModal({ title, description, onClose, footer, children, placement = "center" }) {
5291
+ const dialog = (0, import_react.useRef)(null);
5292
+ const closer = (0, import_react.useRef)(onClose);
5293
+ closer.current = onClose;
5294
+ (0, import_react.useEffect)(() => {
5295
+ const previous = document.activeElement;
5296
+ dialog.current?.focus();
5297
+ const onKey = (e) => {
5298
+ if (!dialog.current?.contains(document.activeElement)) return;
5299
+ if (e.key === "Escape") {
5300
+ e.preventDefault();
5301
+ e.stopPropagation();
5302
+ closer.current();
5303
+ return;
5304
+ }
5305
+ if (e.key !== "Tab") return;
5306
+ const nodes = Array.from(dialog.current.querySelectorAll('button:not(:disabled),input:not(:disabled):not([hidden]),select:not(:disabled),textarea:not(:disabled),[tabindex="0"]')).filter((el) => el.getClientRects().length);
5307
+ const first = nodes[0], last = nodes[nodes.length - 1];
5308
+ if (!first || !last) {
5309
+ e.preventDefault();
5310
+ return;
5311
+ }
5312
+ if (e.shiftKey && (document.activeElement === first || document.activeElement === dialog.current)) {
5313
+ e.preventDefault();
5314
+ last.focus();
5315
+ } else if (!e.shiftKey && (document.activeElement === last || document.activeElement === dialog.current)) {
5316
+ e.preventDefault();
5317
+ first.focus();
5318
+ }
5319
+ };
5320
+ document.addEventListener("keydown", onKey);
5321
+ return () => {
5322
+ document.removeEventListener("keydown", onKey);
5323
+ if (previous?.isConnected) previous.focus();
5324
+ };
5325
+ }, []);
5326
+ return (0, import_react_dom.createPortal)(
5327
+ (0, import_react.createElement)(
5328
+ "div",
5329
+ { style: placement === "right" ? { ...rootStyle, justifyContent: "flex-end", padding: 0 } : rootStyle, className: `te-modal${placement === "right" ? " te-drawer" : ""}`, role: "presentation" },
5330
+ (0, import_react.createElement)("div", { style: placement === "right" ? { ...maskStyle, background: "rgba(0, 0, 0, 0.18)" } : maskStyle, "aria-hidden": true, onClick: onClose }),
5331
+ (0, import_react.createElement)(
5332
+ "div",
5333
+ { style: placement === "right" ? drawerStyle : dialogStyle, ref: dialog, tabIndex: -1, role: "dialog", "aria-modal": true, "aria-label": title },
5334
+ (0, import_react.createElement)(
5335
+ "div",
5336
+ { style: headerStyle },
5337
+ (0, import_react.createElement)("h2", { style: titleStyle }, title),
5338
+ (0, import_react.createElement)(
5339
+ "button",
5340
+ { type: "button", style: closeBtnStyle, "aria-label": "\u5173\u95ED", onClick: onClose },
5341
+ (0, import_react.createElement)(import_dsh_client_ui_primitives.IconCloseOutline16, { size: 14 })
5342
+ )
5343
+ ),
5344
+ description !== void 0 && description !== "" ? (0, import_react.createElement)("p", { style: descStyle }, description) : null,
5345
+ (0, import_react.createElement)("div", { style: bodyStyle }, children),
5346
+ footer !== void 0 ? (0, import_react.createElement)("div", { style: footerStyle }, footer) : null
5347
+ )
5348
+ ),
5349
+ document.body
5350
+ );
5351
+ }
5352
+
5353
+ // src/client/SkillRuleDialog.tsx
5075
5354
  var import_jsx_runtime = require("react/jsx-runtime");
5355
+ function SkillRuleDialog({ skill, profile, rules, description, saveLabel, onSave, onClose }) {
5356
+ const [draftRules, setDraftRules] = (0, import_react2.useState)(profile?.rules ?? []);
5357
+ const [evidence, setEvidence] = (0, import_react2.useState)(profile?.evidence ?? "");
5358
+ const [query, setQuery] = (0, import_react2.useState)("");
5359
+ const [dirty, setDirty] = (0, import_react2.useState)(false);
5360
+ const [busy, setBusy] = (0, import_react2.useState)(false);
5361
+ const [error, setError] = (0, import_react2.useState)("");
5362
+ const close = () => {
5363
+ if (busy) return;
5364
+ if (dirty && !window.confirm("\u6280\u80FD\u89C4\u5219\u914D\u7F6E\u5C1A\u672A\u4FDD\u5B58\uFF0C\u786E\u5B9A\u653E\u5F03\u4FEE\u6539\uFF1F")) return;
5365
+ onClose();
5366
+ };
5367
+ const toggle = (rule) => {
5368
+ const key = formatResourceRef(rule);
5369
+ setDraftRules((previous) => previous.some((item) => formatResourceRef(item) === key) ? previous.filter((item) => formatResourceRef(item) !== key) : [...previous, rule].sort((a, b) => formatResourceRef(a).localeCompare(formatResourceRef(b))));
5370
+ setDirty(true);
5371
+ setError("");
5372
+ };
5373
+ const save2 = async () => {
5374
+ if (busy || !dirty) return;
5375
+ setBusy(true);
5376
+ setError("");
5377
+ try {
5378
+ await onSave({ rules: draftRules, ...evidence ? { evidence } : {} });
5379
+ } catch (failure) {
5380
+ setError(failure instanceof Error ? failure.message : "\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002");
5381
+ } finally {
5382
+ setBusy(false);
5383
+ }
5384
+ };
5385
+ const filtered = rules.filter((rule) => {
5386
+ const key = formatResourceRef(rule.ref);
5387
+ const chosen = draftRules.some((item) => formatResourceRef(item) === key);
5388
+ return chosen || `${rule.name} ${rule.sourceLabel}`.toLowerCase().includes(query.trim().toLowerCase());
5389
+ });
5390
+ const catalogKeys = new Set(rules.map((rule) => formatResourceRef(rule.ref)));
5391
+ const missingRules = draftRules.filter((rule) => !catalogKeys.has(formatResourceRef(rule)));
5392
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
5393
+ ResourceModal,
5394
+ {
5395
+ placement: "right",
5396
+ title: `\u914D\u7F6E\u89C4\u5219 \xB7 ${skill.name}`,
5397
+ description: description ?? "\u89C4\u5219\u5C5E\u4E8E\u6280\u80FD\uFF1B\u6B64\u5904\u7684\u914D\u7F6E\u4F1A\u7528\u4E8E\u6240\u6709\u7ED1\u5B9A\u8BE5\u6280\u80FD\u7684\u8282\u70B9\u3002",
5398
+ onClose: close,
5399
+ footer: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
5400
+ error ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { role: "alert", className: "te-dialog-error", children: error }) : null,
5401
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives2.Button, { variant: "ghost", disabled: busy, onClick: close, children: "\u53D6\u6D88" }),
5402
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives2.Button, { variant: "primary", disabled: busy || !dirty, onClick: () => {
5403
+ void save2();
5404
+ }, children: busy ? "\u5904\u7406\u4E2D\u2026" : saveLabel ?? "\u4FDD\u5B58\u914D\u7F6E" })
5405
+ ] }),
5406
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "te-skill-config", children: [
5407
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "te-skill-evidence", children: [
5408
+ "\u5B8C\u6210\u51ED\u8BC1",
5409
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("select", { className: "te-input", "aria-label": "\u6280\u80FD\u5B8C\u6210\u51ED\u8BC1", value: evidence, onChange: (event) => {
5410
+ setEvidence(event.target.value);
5411
+ setDirty(true);
5412
+ }, children: [
5413
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "", children: "\u6CBF\u7528\u65E7\u914D\u7F6E\u9ED8\u8BA4\u503C" }),
5414
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "command", children: "\u547D\u4EE4\u6267\u884C\u8BB0\u5F55" }),
5415
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "artifact", children: "\u4EA7\u7269\u5185\u5BB9" }),
5416
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "review", children: "\u5BA1\u6838\u7ED3\u679C" }),
5417
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "manual", children: "\u4EBA\u5DE5\u786E\u8BA4" }),
5418
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "none", children: "\u65E0\u9700\u51ED\u8BC1" })
5419
+ ] })
5420
+ ] }),
5421
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "te-binding-heading", children: [
5422
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: "\u9002\u7528\u89C4\u5219" }),
5423
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "te-binding-count", children: [
5424
+ "\u5DF2\u9009 ",
5425
+ draftRules.length
5426
+ ] })
5427
+ ] }),
5428
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { className: "te-input", type: "search", "aria-label": "\u641C\u7D22\u89C4\u5219", placeholder: "\u641C\u7D22\u89C4\u5219\u540D\u79F0\u6216\u6765\u6E90", value: query, onChange: (event) => setQuery(event.target.value) }),
5429
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "te-skill-rule-list", role: "group", "aria-label": "\u89C4\u5219\u5217\u8868", children: [
5430
+ rules.length === 0 && missingRules.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "te-binding-empty", children: "\u89C4\u5219\u5E93\u4E3A\u7A7A\uFF0C\u8BF7\u5148\u5230\u201C\u89C4\u5219\u201D\u9875\u521B\u5EFA\u6216\u5B89\u88C5\u3002" }) : null,
5431
+ rules.length > 0 && filtered.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "te-binding-empty", children: "\u6CA1\u6709\u5339\u914D\u7684\u89C4\u5219\u3002" }) : null,
5432
+ missingRules.map((rule) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "te-skill-rule-row", children: [
5433
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { type: "checkbox", checked: true, onChange: () => toggle(rule) }),
5434
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: rule.name }),
5435
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("small", { children: [
5436
+ rule.source,
5437
+ " \xB7 \u89C4\u5219\u6587\u4EF6\u672A\u627E\u5230"
5438
+ ] })
5439
+ ] }, formatResourceRef(rule))),
5440
+ filtered.map((rule) => {
5441
+ const key = formatResourceRef(rule.ref);
5442
+ const checked = draftRules.some((item) => formatResourceRef(item) === key);
5443
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "te-skill-rule-row", children: [
5444
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { type: "checkbox", checked, onChange: () => toggle(rule.ref) }),
5445
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: rule.name }),
5446
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("small", { children: rule.sourceLabel })
5447
+ ] }, key);
5448
+ })
5449
+ ] })
5450
+ ] })
5451
+ }
5452
+ );
5453
+ }
5454
+
5455
+ // src/client/TaskEngineSection.tsx
5456
+ var import_jsx_runtime2 = require("react/jsx-runtime");
5076
5457
  function refFromText(text2) {
5077
5458
  return parseResourceRef(text2) ?? { source: "bundled", name: text2 };
5078
5459
  }
5079
- function resolvedConfig(flow, stageBindings) {
5080
- const resolved = resolveFlow(flow, { flow, stage_bindings: stageBindings });
5460
+ function resolvedConfig(flow, stageBindings, skillProfiles) {
5461
+ const resolved = resolveFlow(flow, { flow, stage_bindings: stageBindings, skill_profiles: skillProfiles });
5081
5462
  return resolved.ok ? resolved.config : FLOW_PRESETS.standard.config;
5082
5463
  }
5083
5464
  function TaskEngineSection(props) {
5084
5465
  const { remote, workspace } = props;
5085
- const [flow, setFlow] = (0, import_react.useState)("standard");
5086
- const [stageBindings, setStageBindings] = (0, import_react.useState)({});
5087
- const [commitRule, setCommitRule] = (0, import_react.useState)(void 0);
5088
- const [artifacts, setArtifacts] = (0, import_react.useState)(void 0);
5089
- const [reviewDepth, setReviewDepth] = (0, import_react.useState)(void 0);
5090
- const [source, setSource] = (0, import_react.useState)("default");
5091
- const [savedAt, setSavedAt] = (0, import_react.useState)("");
5092
- const [dirty, setDirty] = (0, import_react.useState)(false);
5093
- const [loadError, setLoadError] = (0, import_react.useState)("");
5094
- const [saving, setSaving] = (0, import_react.useState)(false);
5095
- const [loading, setLoading] = (0, import_react.useState)(true);
5096
- const [loadAttempt, setLoadAttempt] = (0, import_react.useState)(0);
5097
- const [configProblems, setConfigProblems] = (0, import_react.useState)([]);
5098
- const [skills, setSkills] = (0, import_react.useState)([]);
5099
- const [rules, setRules] = (0, import_react.useState)([]);
5100
- (0, import_react.useEffect)(() => {
5466
+ const [flow, setFlow] = (0, import_react3.useState)("standard");
5467
+ const [stageBindings, setStageBindings] = (0, import_react3.useState)({});
5468
+ const [skillProfiles, setSkillProfiles] = (0, import_react3.useState)({});
5469
+ const [commitRule, setCommitRule] = (0, import_react3.useState)(void 0);
5470
+ const [artifacts, setArtifacts] = (0, import_react3.useState)(void 0);
5471
+ const [reviewDepth, setReviewDepth] = (0, import_react3.useState)(void 0);
5472
+ const [commitRequired, setCommitRequired] = (0, import_react3.useState)(void 0);
5473
+ const [source, setSource] = (0, import_react3.useState)("default");
5474
+ const [savedAt, setSavedAt] = (0, import_react3.useState)("");
5475
+ const [dirty, setDirty] = (0, import_react3.useState)(false);
5476
+ const [loadError, setLoadError] = (0, import_react3.useState)("");
5477
+ const [saving, setSaving] = (0, import_react3.useState)(false);
5478
+ const [loading, setLoading] = (0, import_react3.useState)(true);
5479
+ const [loadAttempt, setLoadAttempt] = (0, import_react3.useState)(0);
5480
+ const [configProblems, setConfigProblems] = (0, import_react3.useState)([]);
5481
+ const [skills, setSkills] = (0, import_react3.useState)([]);
5482
+ const [rules, setRules] = (0, import_react3.useState)([]);
5483
+ const [configuringSkill, setConfiguringSkill] = (0, import_react3.useState)(null);
5484
+ (0, import_react3.useEffect)(() => {
5101
5485
  if (workspace === "") return;
5102
5486
  let alive = true;
5103
5487
  setLoadError("");
@@ -5108,9 +5492,11 @@ function TaskEngineSection(props) {
5108
5492
  if (result.ok) {
5109
5493
  setFlow(result.value.flow);
5110
5494
  setStageBindings(result.value.config.stage_bindings ?? {});
5495
+ setSkillProfiles(result.value.config.skill_profiles ?? {});
5111
5496
  setCommitRule(result.value.config.commit);
5112
5497
  setArtifacts(result.value.config.artifacts);
5113
5498
  setReviewDepth(result.value.config.review_depth);
5499
+ setCommitRequired(result.value.config.commit_required);
5114
5500
  setSource(result.value.source);
5115
5501
  setConfigProblems(result.value.problems);
5116
5502
  setSavedAt("");
@@ -5127,7 +5513,7 @@ function TaskEngineSection(props) {
5127
5513
  alive = false;
5128
5514
  };
5129
5515
  }, [remote, workspace, loadAttempt]);
5130
- const refreshCatalogs = (0, import_react.useCallback)(() => {
5516
+ const refreshCatalogs = (0, import_react3.useCallback)(() => {
5131
5517
  if (workspace === "") return;
5132
5518
  void remote.listSkills(workspace).then((result) => {
5133
5519
  if (result.ok) setSkills(result.value.skills);
@@ -5138,13 +5524,13 @@ function TaskEngineSection(props) {
5138
5524
  }, () => {
5139
5525
  });
5140
5526
  }, [remote, workspace]);
5141
- (0, import_react.useEffect)(() => {
5527
+ (0, import_react3.useEffect)(() => {
5142
5528
  refreshCatalogs();
5143
5529
  }, [refreshCatalogs]);
5144
- const stages = (0, import_react.useMemo)(() => (FLOW_PRESETS[flow] ?? FLOW_PRESETS.standard).config.stages, [flow]);
5145
- const problems = (0, import_react.useMemo)(
5146
- () => validateWorkflow(resolvedConfig(flow, stageBindings)),
5147
- [flow, stageBindings]
5530
+ const stages = (0, import_react3.useMemo)(() => (FLOW_PRESETS[flow] ?? FLOW_PRESETS.standard).config.stages, [flow]);
5531
+ const problems = (0, import_react3.useMemo)(
5532
+ () => validateWorkflow(resolvedConfig(flow, stageBindings, skillProfiles)),
5533
+ [flow, stageBindings, skillProfiles]
5148
5534
  );
5149
5535
  const selectFlow = (id) => {
5150
5536
  if (id === flow) return;
@@ -5158,53 +5544,68 @@ function TaskEngineSection(props) {
5158
5544
  if (adopted === void 0) return;
5159
5545
  if (dirty && !window.confirm("\u91C7\u7528\u63A8\u8350\u914D\u7F6E\u4F1A\u66FF\u6362\u5F53\u524D\u7684\u6280\u80FD\u4E0E\u89C4\u5219\u8BBE\u7F6E\u3002\u7EE7\u7EED\uFF1F")) return;
5160
5546
  setStageBindings({ ...adopted.stage_bindings ?? {} });
5547
+ const adoptedFlow = resolveFlow(flow, adopted);
5548
+ setSkillProfiles(adoptedFlow.ok ? adoptedFlow.config.skill_profiles ?? {} : {});
5161
5549
  setCommitRule(adopted.commit);
5162
5550
  setArtifacts(adopted.artifacts);
5163
5551
  setReviewDepth(adopted.review_depth);
5164
5552
  setDirty(true);
5165
5553
  setSavedAt("");
5166
5554
  };
5555
+ const updateSkillProfile = async (profile) => {
5556
+ if (!configuringSkill) return;
5557
+ const key = formatResourceRef(configuringSkill);
5558
+ const bindings = {};
5559
+ for (const [name, binding] of Object.entries(stageBindings)) {
5560
+ bindings[name] = { ...binding, skills: binding.skills?.map((entry) => formatResourceRef(entry.skill) === key ? { skill: entry.skill, rules: profile.rules, ...profile.evidence ? { evidence: profile.evidence } : {} } : entry) };
5561
+ }
5562
+ setStageBindings(bindings);
5563
+ setSkillProfiles({ ...skillProfiles, [key]: profile });
5564
+ setDirty(true);
5565
+ setSavedAt("");
5566
+ setConfiguringSkill(null);
5567
+ };
5167
5568
  if (loadError !== "") {
5168
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.wrap, children: [
5169
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { style: styles.title, children: "\u5DE5\u7A0B\u6D41\u7A0B\u914D\u7F6E" }),
5170
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.problems, children: [
5171
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { style: styles.problemsTitle, children: [
5172
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.StateDot, { state: "error" }),
5569
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: styles.wrap, children: [
5570
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h2", { style: styles.title, children: "\u5DE5\u7A0B\u6D41\u7A0B\u914D\u7F6E" }),
5571
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: styles.problems, children: [
5572
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { style: styles.problemsTitle, children: [
5573
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_dsh_client_ui_primitives3.StateDot, { state: "error" }),
5173
5574
  "\u8BFB\u53D6\u5931\u8D25"
5174
5575
  ] }),
5175
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: styles.muted, children: loadError }),
5176
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Button, { onClick: () => setLoadAttempt((n) => n + 1), children: "\u91CD\u8BD5" })
5576
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { style: styles.muted, children: loadError }),
5577
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_dsh_client_ui_primitives3.Button, { onClick: () => setLoadAttempt((n) => n + 1), children: "\u91CD\u8BD5" })
5177
5578
  ] })
5178
5579
  ] });
5179
5580
  }
5180
- if (loading) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { role: "status", children: "\u6B63\u5728\u8BFB\u53D6\u6D41\u7A0B\u914D\u7F6E\u2026" });
5181
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.wrap, children: [
5182
- configProblems.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { role: "alert", style: styles.problems, children: [
5581
+ if (loading) return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { role: "status", children: "\u6B63\u5728\u8BFB\u53D6\u6D41\u7A0B\u914D\u7F6E\u2026" });
5582
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: styles.wrap, children: [
5583
+ configProblems.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { role: "alert", style: styles.problems, children: [
5183
5584
  "\u539F\u914D\u7F6E\u6709\u95EE\u9898\uFF1A",
5184
5585
  configProblems.join("\uFF1B"),
5185
5586
  "\u3002\u8BF7\u9009\u62E9\u6709\u6548\u9884\u8BBE\u5E76\u4FDD\u5B58\u4FEE\u590D\u3002"
5186
5587
  ] }),
5187
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.head, children: [
5188
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { style: styles.title, children: "\u5DE5\u7A0B\u6D41\u7A0B\u914D\u7F6E" }),
5189
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: styles.muted, children: "\u6D41\u7A0B\u51B3\u5B9A\u5DE5\u4F5C\u600E\u4E48\u6D41\u8F6C\uFF08\u9636\u6BB5\u4E0E\u95E8\u7981\uFF09\uFF1B\u6280\u80FD\u3001\u89C4\u5219\u3001\u63D0\u4EA4\u683C\u5F0F\u548C\u4EA7\u7269\u5B57\u6BB5\u7531\u4F60\u81EA\u5DF1\u914D\u7F6E\u3002 \u9700\u8981\u4E00\u4EFD\u73B0\u6210\u7684\u8D77\u70B9\u65F6\uFF0C\u53EF\u4EE5\u300C\u91C7\u7528\u63A8\u8350\u914D\u7F6E\u300D\u2014\u2014\u91C7\u7528\u540E\u8FD9\u4E9B\u5C31\u5B8C\u5168\u5C5E\u4E8E\u4F60\uFF0C\u53EF\u968F\u610F\u4FEE\u6539\u6216\u5220\u9664\u3002" })
5588
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: styles.head, children: [
5589
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h2", { style: styles.title, children: "\u5DE5\u7A0B\u6D41\u7A0B\u914D\u7F6E" }),
5590
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { style: styles.muted, children: "\u6D41\u7A0B\u51B3\u5B9A\u5DE5\u4F5C\u600E\u4E48\u6D41\u8F6C\uFF08\u9636\u6BB5\u4E0E\u95E8\u7981\uFF09\uFF1B\u6280\u80FD\u3001\u89C4\u5219\u3001\u63D0\u4EA4\u683C\u5F0F\u548C\u4EA7\u7269\u5B57\u6BB5\u7531\u4F60\u81EA\u5DF1\u914D\u7F6E\u3002 \u9700\u8981\u4E00\u4EFD\u73B0\u6210\u7684\u8D77\u70B9\u65F6\uFF0C\u53EF\u4EE5\u300C\u91C7\u7528\u63A8\u8350\u914D\u7F6E\u300D\u2014\u2014\u91C7\u7528\u540E\u8FD9\u4E9B\u5C31\u5B8C\u5168\u5C5E\u4E8E\u4F60\uFF0C\u53EF\u968F\u610F\u4FEE\u6539\u6216\u5220\u9664\u3002" })
5190
5591
  ] }),
5191
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.adoptRow, children: [
5192
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_dsh_client_ui_primitives.Button, { size: "sm", onClick: adopt, children: [
5592
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: styles.adoptRow, children: [
5593
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_dsh_client_ui_primitives3.Button, { size: "sm", onClick: adopt, children: [
5193
5594
  "\u91C7\u7528\u300C",
5194
5595
  FLOW_PRESETS[flow]?.label ?? flow,
5195
5596
  "\u300D\u7684\u63A8\u8350\u914D\u7F6E"
5196
5597
  ] }),
5197
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: styles.muted, children: "\u5199\u5165\u63A8\u8350\u6280\u80FD\u3001\u63D0\u4EA4\u4FE1\u606F\u683C\u5F0F\u4E0E\u4EA7\u7269\u5B57\u6BB5\u3002\u4EC5\u5728\u4F60\u70B9\u51FB\u65F6\u53D1\u751F\u4E00\u6B21\uFF1B\u5220\u9664\u540E\u4E0D\u4F1A\u81EA\u52A8\u8865\u56DE\u3002" })
5598
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: styles.muted, children: "\u5199\u5165\u63A8\u8350\u6280\u80FD\u3001\u63D0\u4EA4\u4FE1\u606F\u683C\u5F0F\u4E0E\u4EA7\u7269\u5B57\u6BB5\u3002\u4EC5\u5728\u4F60\u70B9\u51FB\u65F6\u53D1\u751F\u4E00\u6B21\uFF1B\u5220\u9664\u540E\u4E0D\u4F1A\u81EA\u52A8\u8865\u56DE\u3002" })
5198
5599
  ] }),
5199
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.sourceRow, children: [
5200
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.StateDot, { state: source === "project" ? "done" : source === "invalid" ? "warning" : "ongoing" }),
5201
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: styles.sourceText, children: sourceText(source) })
5600
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: styles.sourceRow, children: [
5601
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_dsh_client_ui_primitives3.StateDot, { state: source === "project" ? "done" : source === "invalid" ? "warning" : "ongoing" }),
5602
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: styles.sourceText, children: sourceText(source) })
5202
5603
  ] }),
5203
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.field, children: [
5204
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { children: "\u6D41\u7A0B\u9884\u8BBE" }),
5205
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: styles.flowGrid, children: FLOW_OPTIONS.map((option) => {
5604
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: styles.field, children: [
5605
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h3", { children: "\u6D41\u7A0B\u9884\u8BBE" }),
5606
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: styles.flowGrid, children: FLOW_OPTIONS.map((option) => {
5206
5607
  const active = flow === option.id;
5207
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
5608
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
5208
5609
  "button",
5209
5610
  {
5210
5611
  type: "button",
@@ -5214,45 +5615,49 @@ function TaskEngineSection(props) {
5214
5615
  },
5215
5616
  style: { ...styles.flowOption, ...active ? styles.flowOptionActive : {} },
5216
5617
  children: [
5217
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { style: styles.flowOptionTitle, children: [
5218
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.StateDot, { state: active ? "done" : "ongoing", size: 8 }),
5618
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { style: styles.flowOptionTitle, children: [
5619
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_dsh_client_ui_primitives3.StateDot, { state: active ? "done" : "ongoing", size: 8 }),
5219
5620
  option.label
5220
5621
  ] }),
5221
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: styles.flowOptionDesc, children: option.description })
5622
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { style: styles.flowOptionDesc, children: option.description })
5222
5623
  ]
5223
5624
  },
5224
5625
  option.id
5225
5626
  );
5226
5627
  }) })
5227
5628
  ] }),
5228
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SectionCard, { icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.IconSettingsOutline16, { size: 16 }), title: "\u9636\u6BB5\u6280\u80FD / \u89C4\u5219", hint: "\u9009\u62E9\u8282\u70B9\uFF0C\u518D\u52FE\u9009\u9644\u52A0\u6280\u80FD\u4E0E\u89C4\u5219\u3002\u9884\u8BBE\u9ED8\u8BA4\u7ED1\u5B9A\u56FA\u5B9A\u4FDD\u7559\uFF1B\u65B0\u5EFA\u6216\u7F16\u8F91\u5185\u5BB9\u8BF7\u524D\u5F80\u4E0A\u65B9\u201C\u6280\u80FD\u201D\u6216\u201C\u89C4\u5219\u201D\u9875\u3002", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BindingEditor, { stages, defaults: (FLOW_PRESETS[flow] ?? FLOW_PRESETS.standard).config.stage_bindings ?? {}, stageBindings, setStageBindings: (next) => {
5629
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(SectionCard, { icon: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_dsh_client_ui_primitives3.IconSettingsOutline16, { size: 16 }), title: "\u9636\u6BB5\u6280\u80FD", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(BindingEditor, { stages, stageBindings, setStageBindings: (next) => {
5229
5630
  setStageBindings(next);
5230
5631
  setDirty(true);
5231
5632
  setSavedAt("");
5232
- }, skills, rules }) }),
5233
- problems.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.problems, children: [
5234
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { style: styles.problemsTitle, children: [
5235
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.StateDot, { state: "error" }),
5633
+ }, skillProfiles, setSkillProfiles: (next) => {
5634
+ setSkillProfiles(next);
5635
+ setDirty(true);
5636
+ setSavedAt("");
5637
+ }, skills, onConfigureSkill: setConfiguringSkill }) }),
5638
+ problems.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: styles.problems, children: [
5639
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { style: styles.problemsTitle, children: [
5640
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_dsh_client_ui_primitives3.StateDot, { state: "error" }),
5236
5641
  "\u6709 ",
5237
5642
  problems.length,
5238
5643
  " \u4E2A\u95EE\u9898\uFF08\u4FDD\u5B58\u4F1A\u88AB\u62D2\u7EDD\uFF09"
5239
5644
  ] }),
5240
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { style: styles.problemsList, children: problems.map((p) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", { children: p }, p)) })
5241
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { style: styles.okText, children: [
5242
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.StateDot, { state: "done" }),
5243
- source === "project" ? "\u914D\u7F6E\u6709\u6548" : "\u4F7F\u7528\u6D41\u7A0B\u9884\u8BBE\u9ED8\u8BA4\u7ED1\u5B9A\uFF08\u5C1A\u672A\u4FDD\u5B58\uFF09"
5645
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("ul", { style: styles.problemsList, children: problems.map((p) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("li", { children: p }, p)) })
5646
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { style: styles.okText, children: [
5647
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_dsh_client_ui_primitives3.StateDot, { state: "done" }),
5648
+ source === "project" ? "\u914D\u7F6E\u6709\u6548" : "\u4F7F\u7528\u7A7A\u767D\u6D41\u7A0B\u914D\u7F6E\uFF08\u5C1A\u672A\u4FDD\u5B58\uFF09"
5244
5649
  ] }),
5245
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.actions, children: [
5246
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
5247
- import_dsh_client_ui_primitives.Button,
5650
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: styles.actions, children: [
5651
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
5652
+ import_dsh_client_ui_primitives3.Button,
5248
5653
  {
5249
5654
  variant: "primary",
5250
5655
  size: "md",
5251
- icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.IconCheckOutline16, { size: 16 }),
5656
+ icon: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_dsh_client_ui_primitives3.IconCheckOutline16, { size: 16 }),
5252
5657
  disabled: problems.length > 0 || saving,
5253
5658
  onClick: () => {
5254
5659
  setSaving(true);
5255
- void save(remote, { flow, stage_bindings: stageBindings, ...commitRule !== void 0 ? { commit: commitRule } : {}, ...artifacts !== void 0 ? { artifacts } : {}, ...reviewDepth !== void 0 ? { review_depth: reviewDepth } : {} }, workspace, setSavedAt, setSource).then((ok) => {
5660
+ void save(remote, { flow, stage_bindings: stageBindings, skill_profiles: skillProfiles, ...commitRule !== void 0 ? { commit: commitRule } : {}, ...artifacts !== void 0 ? { artifacts } : {}, ...reviewDepth !== void 0 ? { review_depth: reviewDepth } : {}, ...commitRequired !== void 0 ? { commit_required: commitRequired } : {} }, workspace, setSavedAt, setSource).then((ok) => {
5256
5661
  if (ok) {
5257
5662
  setConfigProblems([]);
5258
5663
  setDirty(false);
@@ -5262,11 +5667,24 @@ function TaskEngineSection(props) {
5262
5667
  children: saving ? "\u6B63\u5728\u4FDD\u5B58\u2026" : dirty ? "\u4FDD\u5B58\u5230 .dsh/eng.json" : "\u5DF2\u4FDD\u5B58 \xB7 \u65E0\u9700\u4FDD\u5B58"
5263
5668
  }
5264
5669
  ),
5265
- savedAt !== "" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { style: styles.okText, children: [
5266
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.StateDot, { state: savedAt.startsWith("\u5DF2") ? "done" : "error" }),
5670
+ savedAt !== "" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { style: styles.okText, children: [
5671
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_dsh_client_ui_primitives3.StateDot, { state: savedAt.startsWith("\u5DF2") ? "done" : "error" }),
5267
5672
  savedAt
5268
5673
  ] }) : null
5269
- ] })
5674
+ ] }),
5675
+ configuringSkill ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
5676
+ SkillRuleDialog,
5677
+ {
5678
+ skill: configuringSkill,
5679
+ profile: skillProfiles[formatResourceRef(configuringSkill)],
5680
+ rules,
5681
+ description: "\u89C4\u5219\u5C5E\u4E8E\u6280\u80FD\uFF0C\u6240\u6709\u5F15\u7528\u6B64\u6280\u80FD\u7684\u8282\u70B9\u90FD\u4F1A\u540C\u6B65\u3002\u5E94\u7528\u540E\u8BF7\u70B9\u51FB\u9875\u9762\u5E95\u90E8\u4FDD\u5B58\u3002",
5682
+ saveLabel: "\u5E94\u7528\u5230\u5F53\u524D\u914D\u7F6E",
5683
+ onSave: updateSkillProfile,
5684
+ onClose: () => setConfiguringSkill(null)
5685
+ },
5686
+ formatResourceRef(configuringSkill)
5687
+ ) : null
5270
5688
  ] });
5271
5689
  }
5272
5690
  function sourceText(source) {
@@ -5280,9 +5698,9 @@ function sourceText(source) {
5280
5698
  }
5281
5699
  }
5282
5700
  function SectionCard({ icon, title, hint, children }) {
5283
- const [open, setOpen] = (0, import_react.useState)(true);
5284
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: styles.section, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
5285
- import_dsh_client_ui_primitives.DisclosureRow,
5701
+ const [open, setOpen] = (0, import_react3.useState)(true);
5702
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: styles.section, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
5703
+ import_dsh_client_ui_primitives3.DisclosureRow,
5286
5704
  {
5287
5705
  icon,
5288
5706
  title,
@@ -5294,187 +5712,115 @@ function SectionCard({ icon, title, hint, children }) {
5294
5712
  setOpen(!open);
5295
5713
  },
5296
5714
  keepContentWhenOpen: true,
5297
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.cardBody, children: [
5298
- hint !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: styles.muted, children: hint }) : null,
5715
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: styles.cardBody, children: [
5716
+ hint !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { style: styles.muted, children: hint }) : null,
5299
5717
  children
5300
5718
  ] })
5301
5719
  }
5302
5720
  ) });
5303
5721
  }
5304
- function BindingEditor({ stages, defaults, stageBindings, setStageBindings, skills, rules }) {
5305
- const [stage, setStage] = (0, import_react.useState)(stages[0] ?? "");
5306
- const [expanded, setExpanded] = (0, import_react.useState)(null);
5307
- const [query, setQuery] = (0, import_react.useState)("");
5308
- const [onlySelected, setOnlySelected] = (0, import_react.useState)(false);
5309
- const [ruleQuery, setRuleQuery] = (0, import_react.useState)("");
5310
- const [ruleOnlySelected, setRuleOnlySelected] = (0, import_react.useState)(false);
5722
+ function BindingEditor({ stages, stageBindings, setStageBindings, skillProfiles, setSkillProfiles, skills, onConfigureSkill }) {
5723
+ const [stage, setStage] = (0, import_react3.useState)(stages[0] ?? "");
5724
+ const [query, setQuery] = (0, import_react3.useState)("");
5311
5725
  const currentStage = stages.includes(stage) ? stage : stages[0] ?? "";
5312
5726
  const bindingFor = (name) => stageBindings[name] ?? {};
5313
- const presetSkills = (name) => defaults[name]?.skills ?? [];
5314
- const isPresetSkill = (name, raw) => presetSkills(name).some((entry) => formatResourceRef(entry.skill) === raw);
5315
- const visibleSkills = () => {
5316
- const bound = bindingFor(currentStage).skills ?? [];
5317
- const boundKeys = new Set(bound.map((entry) => formatResourceRef(entry.skill)));
5318
- const needle = query.trim().toLowerCase();
5319
- return skills.filter((entry) => {
5320
- const raw = formatResourceRef(entry.ref);
5321
- const inForce = boundKeys.has(raw) || isPresetSkill(currentStage, raw);
5322
- if (onlySelected && !inForce) return false;
5323
- if (needle === "") return true;
5324
- return inForce || entry.name.toLowerCase().includes(needle) || entry.description.toLowerCase().includes(needle) || entry.sourceLabel.toLowerCase().includes(needle);
5325
- });
5326
- };
5327
- const visibleRulesFor = (bound) => {
5328
- const chosen = new Set(bound.rules.map((rule) => formatResourceRef(rule)));
5329
- const needle = ruleQuery.trim().toLowerCase();
5330
- return rules.filter((rule) => {
5331
- const raw = formatResourceRef(rule.ref);
5332
- if (ruleOnlySelected && !chosen.has(raw)) return false;
5333
- if (needle === "") return true;
5334
- return chosen.has(raw) || rule.name.toLowerCase().includes(needle) || rule.sourceLabel.toLowerCase().includes(needle);
5335
- });
5336
- };
5337
5727
  const setSkills = (name, next) => {
5338
5728
  setStageBindings({ ...stageBindings, [name]: { ...bindingFor(name), skills: next } });
5339
5729
  };
5340
5730
  const toggleSkill = (raw) => {
5341
- if (currentStage === "" || isPresetSkill(currentStage, raw)) return;
5342
- const current = bindingFor(currentStage).skills ?? [];
5343
- const next = current.some((entry) => formatResourceRef(entry.skill) === raw) ? current.filter((entry) => formatResourceRef(entry.skill) !== raw) : [...current, { skill: refFromText(raw), rules: [] }].sort((a, b) => formatResourceRef(a.skill).localeCompare(formatResourceRef(b.skill)));
5344
- setSkills(currentStage, next);
5345
- };
5346
- const toggleRule = (skillRaw, ruleRaw) => {
5347
5731
  if (currentStage === "") return;
5348
5732
  const current = bindingFor(currentStage).skills ?? [];
5349
- setSkills(currentStage, current.map((entry) => {
5350
- if (formatResourceRef(entry.skill) !== skillRaw) return entry;
5351
- const has = entry.rules.some((rule) => formatResourceRef(rule) === ruleRaw);
5352
- const next = has ? entry.rules.filter((rule) => formatResourceRef(rule) !== ruleRaw) : [...entry.rules, refFromText(ruleRaw)].sort((a, b) => formatResourceRef(a).localeCompare(formatResourceRef(b)));
5353
- return { ...entry, rules: next };
5354
- }));
5733
+ const profile = skillProfiles[raw];
5734
+ const alreadyBound = current.some((entry) => formatResourceRef(entry.skill) === raw);
5735
+ const next = alreadyBound ? current.filter((entry) => formatResourceRef(entry.skill) !== raw) : [...current, { skill: refFromText(raw), rules: profile?.rules ?? [], ...profile?.evidence !== void 0 ? { evidence: profile.evidence } : {} }].sort((a, b) => formatResourceRef(a.skill).localeCompare(formatResourceRef(b.skill)));
5736
+ if (!alreadyBound && profile === void 0) setSkillProfiles({ ...skillProfiles, [raw]: { rules: [] } });
5737
+ setSkills(currentStage, next);
5355
5738
  };
5356
5739
  if (currentStage === "") {
5357
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: styles.muted, children: "\u5F53\u524D\u6D41\u7A0B\u6CA1\u6709\u8282\u70B9\u3002" });
5740
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { style: styles.muted, children: "\u5F53\u524D\u6D41\u7A0B\u6CA1\u6709\u8282\u70B9\u3002" });
5358
5741
  }
5359
5742
  const boundSkills = bindingFor(currentStage).skills ?? [];
5360
5743
  const unassigned = bindingFor(currentStage).legacy_rules ?? [];
5361
- const presetCount = presetSkills(currentStage).length;
5362
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.section, children: [
5363
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: styles.hint, children: "\u8282\u70B9\u53EA\u9009\u62E9\u6280\u80FD\uFF1B\u89C4\u5219\u5C5E\u4E8E\u6280\u80FD\u2014\u2014\u70B9\u5F00\u4E00\u4E2A\u6280\u80FD\u5C31\u80FD\u770B\u5230\u5B83\u5B8C\u6574\u7684\u89C4\u5219\u5217\u8868\uFF0C\u6302\u5230\u4EFB\u4F55\u8282\u70B9\u90FD\u662F\u540C\u4E00\u5957\u89C4\u5219\u3002 \u9700\u8981\u540C\u4E00\u6280\u80FD\u7528\u4E0D\u540C\u89C4\u5219\u65F6\uFF0C\u590D\u5236\u6210\u53E6\u4E00\u4E2A\u6280\u80FD\u518D\u5206\u522B\u914D\u7F6E\u3002" }),
5364
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.field, children: [
5365
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: styles.bindingLabel, children: "\u9009\u62E9\u8282\u70B9" }),
5366
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: styles.chips, children: stages.map((s) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Pill, { active: s === currentStage, onClick: () => {
5744
+ const boundKeys = new Set(boundSkills.map((entry) => formatResourceRef(entry.skill)));
5745
+ const needle = query.trim().toLowerCase();
5746
+ const available = skills.filter((entry) => !boundKeys.has(formatResourceRef(entry.ref)) && `${entry.name} ${entry.description} ${entry.sourceLabel}`.toLowerCase().includes(needle));
5747
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: styles.section, children: [
5748
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: styles.field, children: [
5749
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: styles.bindingLabel, children: "\u9009\u62E9\u8282\u70B9" }),
5750
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: styles.chips, children: stages.map((s) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_dsh_client_ui_primitives3.Pill, { active: s === currentStage, onClick: () => {
5367
5751
  setStage(s);
5368
5752
  }, children: s }, s)) })
5369
5753
  ] }),
5370
- unassigned.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "te-alert", children: [
5754
+ unassigned.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "te-alert", children: [
5371
5755
  "\u4EE5\u4E0B\u89C4\u5219\u5C5E\u4E8E",
5372
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: "\u8282\u70B9" }),
5756
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("strong", { children: "\u8282\u70B9" }),
5373
5757
  "\u800C\u4E0D\u662F\u4EFB\u4F55\u6280\u80FD\uFF08\u65E7\u914D\u7F6E\uFF09\uFF1A",
5374
5758
  unassigned.join("\u3001"),
5375
5759
  "\u3002 \u5B83\u4EEC\u4ECD\u7136\u751F\u6548\uFF0C\u4F46\u9700\u8981\u6307\u5B9A\u5F52\u5C5E\u2014\u2014\u628A\u6BCF\u6761\u89C4\u5219\u52A0\u5230\u4F60\u5E0C\u671B\u627F\u8F7D\u5B83\u7684\u6280\u80FD\u4E0B\uFF0C\u7136\u540E\u4ECE\u8FD9\u91CC\u79FB\u9664\uFF1B \u82E5\u540C\u4E00\u6280\u80FD\u5728\u4E0D\u540C\u8282\u70B9\u9700\u8981\u4E0D\u540C\u89C4\u5219\uFF0C\u8BF7\u590D\u5236\u8BE5\u6280\u80FD\u518D\u5206\u522B\u914D\u7F6E\u3002"
5376
5760
  ] }) : null,
5377
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "te-binding-grid", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { className: "te-binding-picker", "aria-label": "\u6280\u80FD\u7ED1\u5B9A", children: [
5378
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "te-binding-heading", children: [
5379
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h4", { children: "\u6280\u80FD" }),
5380
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "te-binding-count", children: [
5381
- "\u5DF2\u9009 ",
5382
- boundSkills.length,
5383
- presetCount > 0 ? `\uFF08\u542B ${presetCount} \u9879\u9884\u8BBE\uFF09` : "",
5384
- visibleSkills().length !== skills.length ? ` \xB7 \u663E\u793A ${visibleSkills().length}/${skills.length}` : ""
5385
- ] })
5386
- ] }),
5387
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "te-binding-controls", children: [
5388
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
5389
- "input",
5390
- {
5391
- className: "te-binding-search",
5392
- type: "search",
5393
- value: query,
5394
- placeholder: "\u641C\u7D22\u6280\u80FD\u540D\u6216\u8BF4\u660E\u2026",
5395
- "aria-label": "\u641C\u7D22\u6280\u80FD",
5396
- onChange: (event) => setQuery(event.target.value)
5397
- }
5398
- ),
5399
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "te-binding-filter", children: [
5400
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { type: "checkbox", checked: onlySelected, onChange: () => setOnlySelected((value) => !value) }),
5401
- " ",
5402
- "\u4EC5\u770B\u5DF2\u9009"
5761
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "te-transfer", children: [
5762
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("section", { className: "te-transfer-pane", "aria-label": "\u53EF\u7528\u6280\u80FD", children: [
5763
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "te-binding-heading", children: [
5764
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h4", { children: "\u53EF\u7528\u6280\u80FD" }),
5765
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "te-binding-count", children: [
5766
+ skills.filter((entry) => !boundKeys.has(formatResourceRef(entry.ref))).length,
5767
+ " \u9879"
5768
+ ] })
5769
+ ] }),
5770
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { className: "te-input te-transfer-search", type: "search", value: query, placeholder: "\u641C\u7D22\u6280\u80FD\u540D\u79F0\u6216\u8BF4\u660E", "aria-label": "\u641C\u7D22\u53EF\u7528\u6280\u80FD", onChange: (event) => setQuery(event.target.value) }),
5771
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "te-transfer-list", role: "group", "aria-label": "\u53EF\u7528\u6280\u80FD\u5217\u8868", children: [
5772
+ skills.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "te-binding-empty", children: "\u6682\u65E0\u6280\u80FD\uFF0C\u8BF7\u5148\u5728\u201C\u6280\u80FD\u201D\u9875\u6DFB\u52A0\u3002" }) : null,
5773
+ skills.length > 0 && available.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "te-binding-empty", children: "\u6CA1\u6709\u53EF\u6DFB\u52A0\u7684\u6280\u80FD\u3002" }) : null,
5774
+ available.map((entry) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("button", { type: "button", className: "te-transfer-row", onClick: () => toggleSkill(formatResourceRef(entry.ref)), "aria-label": `\u6DFB\u52A0\u6280\u80FD ${entry.name}`, children: [
5775
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "te-transfer-row-main", children: [
5776
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("strong", { children: entry.name }),
5777
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("small", { children: [
5778
+ entry.sourceLabel,
5779
+ entry.description ? ` \xB7 ${entry.description}` : ""
5780
+ ] })
5781
+ ] }),
5782
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "te-transfer-action", "aria-hidden": "true", children: "\uFF0B" })
5783
+ ] }, formatResourceRef(entry.ref)))
5403
5784
  ] })
5404
5785
  ] }),
5405
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "te-binding-list", role: "group", "aria-label": "\u6280\u80FD\u5217\u8868", tabIndex: 0, children: [
5406
- skills.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "te-binding-empty", children: "\u6682\u65E0\u6280\u80FD\uFF0C\u8BF7\u5728\u4E0A\u65B9\u201C\u6280\u80FD\u201D\u9875\u6DFB\u52A0\u3002" }) : null,
5407
- skills.length > 0 && visibleSkills().length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "te-binding-empty", children: "\u6CA1\u6709\u5339\u914D\u7684\u6280\u80FD\u3002" }) : null,
5408
- visibleSkills().map((entry) => {
5409
- const raw = formatResourceRef(entry.ref);
5410
- const bound = boundSkills.find((candidate) => formatResourceRef(candidate.skill) === raw);
5411
- const preset2 = isPresetSkill(currentStage, raw);
5412
- const open = expanded === raw;
5413
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: `te-binding-option${bound !== void 0 ? " is-selected" : ""}`, children: [
5414
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
5415
- "input",
5416
- {
5417
- type: "checkbox",
5418
- "aria-label": raw,
5419
- checked: bound !== void 0,
5420
- disabled: preset2,
5421
- onChange: () => toggleSkill(raw)
5422
- }
5423
- ),
5424
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "te-binding-detail", children: [
5425
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "te-binding-name", children: [
5426
- entry.name,
5427
- preset2 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "te-source-badge", children: "\u9884\u8BBE" }) : null
5428
- ] }),
5429
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "te-binding-meta", children: [
5430
- entry.sourceLabel,
5431
- " \xB7 ",
5432
- bound === void 0 ? "\u672A\u7ED1\u5B9A" : `${bound.rules.length} \u6761\u89C4\u5219`
5786
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "te-transfer-arrow", "aria-hidden": "true", children: "\u2192" }),
5787
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("section", { className: "te-transfer-pane", "aria-label": "\u5F53\u524D\u8282\u70B9\u6280\u80FD", children: [
5788
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "te-binding-heading", children: [
5789
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("h4", { children: [
5790
+ currentStage,
5791
+ " \xB7 \u5DF2\u7ED1\u5B9A"
5792
+ ] }),
5793
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "te-binding-count", children: [
5794
+ boundSkills.length,
5795
+ " \u9879"
5796
+ ] })
5797
+ ] }),
5798
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "te-transfer-caption", children: "\u89C4\u5219\u5C5E\u4E8E\u6280\u80FD\uFF1B\u70B9\u201C\u914D\u7F6E\u89C4\u5219\u201D\u5373\u53EF\u7EDF\u4E00\u4FEE\u6539\u3002" }),
5799
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "te-transfer-list", role: "group", "aria-label": "\u5DF2\u7ED1\u5B9A\u6280\u80FD\u5217\u8868", children: [
5800
+ boundSkills.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "te-binding-empty", children: "\u6B64\u8282\u70B9\u5C1A\u672A\u7ED1\u5B9A\u6280\u80FD\u3002\u70B9\u51FB\u5DE6\u4FA7 \uFF0B \u6DFB\u52A0\u3002" }) : null,
5801
+ boundSkills.map((entry) => {
5802
+ const raw = formatResourceRef(entry.skill);
5803
+ const catalog = skills.find((skill) => formatResourceRef(skill.ref) === raw);
5804
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "te-transfer-row is-bound", children: [
5805
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "te-transfer-row-main", children: [
5806
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("strong", { children: entry.skill.name }),
5807
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("small", { children: [
5808
+ catalog?.sourceLabel ?? entry.skill.source,
5809
+ " \xB7 ",
5810
+ entry.rules.length,
5811
+ " \u6761\u89C4\u5219",
5812
+ catalog ? "" : " \xB7 \u8D44\u6E90\u672A\u627E\u5230"
5813
+ ] })
5433
5814
  ] }),
5434
- bound !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "te-link", onClick: () => setExpanded(open ? null : raw), children: open ? "\u6536\u8D77\u89C4\u5219" : "\u89C4\u5219\u8BBE\u7F6E" }) : null,
5435
- open && bound !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "te-rule-list", children: [
5436
- ruleQuery !== "" || ruleOnlySelected ? null : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "te-binding-meta", children: [
5437
- rules.length,
5438
- " \u6761\u53EF\u7528\u89C4\u5219"
5439
- ] }),
5440
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
5441
- "input",
5442
- {
5443
- className: "te-binding-search",
5444
- type: "search",
5445
- value: ruleQuery,
5446
- placeholder: "\u8FC7\u6EE4\u89C4\u5219\u2026",
5447
- "aria-label": `\u8FC7\u6EE4 ${entry.name} \u7684\u89C4\u5219`,
5448
- onChange: (event) => setRuleQuery(event.target.value)
5449
- }
5450
- ),
5451
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "te-binding-filter", children: [
5452
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { type: "checkbox", checked: ruleOnlySelected, onChange: () => setRuleOnlySelected((value) => !value) }),
5453
- " ",
5454
- "\u4EC5\u770B\u5DF2\u9009"
5455
- ] }),
5456
- rules.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "te-binding-meta", children: "\u89C4\u5219\u5E93\u4E3A\u7A7A\u3002" }) : null,
5457
- rules.length > 0 && visibleRulesFor(bound).length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "te-binding-meta", children: "\u6CA1\u6709\u5339\u914D\u7684\u89C4\u5219\u3002" }) : null,
5458
- visibleRulesFor(bound).map((rule) => {
5459
- const ruleRaw = formatResourceRef(rule.ref);
5460
- const on = bound.rules.some((candidate) => formatResourceRef(candidate) === ruleRaw);
5461
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "te-binding-filter", children: [
5462
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { type: "checkbox", checked: on, onChange: () => toggleRule(raw, ruleRaw) }),
5463
- " ",
5464
- rule.name,
5465
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "te-binding-meta", children: [
5466
- "\uFF08",
5467
- rule.sourceLabel,
5468
- "\uFF09"
5469
- ] })
5470
- ] }, ruleRaw);
5471
- })
5472
- ] }) : null
5473
- ] })
5474
- ] }, raw);
5475
- })
5815
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "te-transfer-actions", children: [
5816
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", className: "te-transfer-config", onClick: () => onConfigureSkill(entry.skill), children: "\u914D\u7F6E\u89C4\u5219" }),
5817
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", className: "te-transfer-remove", onClick: () => toggleSkill(raw), "aria-label": `\u79FB\u9664\u6280\u80FD ${entry.skill.name}`, children: "\xD7" })
5818
+ ] })
5819
+ ] }, raw);
5820
+ })
5821
+ ] })
5476
5822
  ] })
5477
- ] }) }, currentStage)
5823
+ ] }, currentStage)
5478
5824
  ] });
5479
5825
  }
5480
5826
  async function save(remote, config, workspace, setSavedAt, setSource) {
@@ -5498,8 +5844,8 @@ async function save(remote, config, workspace, setSavedAt, setSource) {
5498
5844
  }
5499
5845
 
5500
5846
  // src/client/InitPanel.tsx
5501
- var import_react2 = require("react");
5502
- var import_dsh_client_ui_primitives2 = require("@deepseek-ai/dsh-client-ui-primitives");
5847
+ var import_react4 = require("react");
5848
+ var import_dsh_client_ui_primitives4 = require("@deepseek-ai/dsh-client-ui-primitives");
5503
5849
  var MD_LABELS = { code: { copyLabel: "\u590D\u5236", copiedLabel: "\u5DF2\u590D\u5236" }, footnotes: "\u811A\u6CE8" };
5504
5850
  var INIT_TIMEOUT_S = 150;
5505
5851
  var card = {
@@ -5511,14 +5857,14 @@ var card = {
5511
5857
  padding: "12px 14px"
5512
5858
  };
5513
5859
  function InitPanel({ workspace, remote }) {
5514
- const [view, setView] = (0, import_react2.useState)(null);
5515
- const [generating, setGenerating] = (0, import_react2.useState)(false);
5516
- const [elapsed, setElapsed] = (0, import_react2.useState)(0);
5517
- const [draft, setDraft] = (0, import_react2.useState)(null);
5518
- const [editing, setEditing] = (0, import_react2.useState)(false);
5519
- const [body2, setBody] = (0, import_react2.useState)("");
5520
- const [msg, setMsg] = (0, import_react2.useState)("");
5521
- (0, import_react2.useEffect)(() => {
5860
+ const [view, setView] = (0, import_react4.useState)(null);
5861
+ const [generating, setGenerating] = (0, import_react4.useState)(false);
5862
+ const [elapsed, setElapsed] = (0, import_react4.useState)(0);
5863
+ const [draft, setDraft] = (0, import_react4.useState)(null);
5864
+ const [editing, setEditing] = (0, import_react4.useState)(false);
5865
+ const [body2, setBody] = (0, import_react4.useState)("");
5866
+ const [msg, setMsg] = (0, import_react4.useState)("");
5867
+ (0, import_react4.useEffect)(() => {
5522
5868
  if (!generating) {
5523
5869
  setElapsed(0);
5524
5870
  return;
@@ -5532,13 +5878,13 @@ function InitPanel({ workspace, remote }) {
5532
5878
  clearInterval(timer);
5533
5879
  };
5534
5880
  }, [generating]);
5535
- const refresh = (0, import_react2.useCallback)(() => {
5881
+ const refresh = (0, import_react4.useCallback)(() => {
5536
5882
  void remote.readInit(workspace).then((r) => {
5537
5883
  if (r.ok) setView(r.value);
5538
5884
  }, () => {
5539
5885
  });
5540
5886
  }, [remote, workspace]);
5541
- (0, import_react2.useEffect)(() => {
5887
+ (0, import_react4.useEffect)(() => {
5542
5888
  refresh();
5543
5889
  }, [refresh]);
5544
5890
  const generate = async () => {
@@ -5581,45 +5927,45 @@ function InitPanel({ workspace, remote }) {
5581
5927
  setMsg("");
5582
5928
  };
5583
5929
  const exists = view?.exists === true;
5584
- return (0, import_react2.createElement)(
5930
+ return (0, import_react4.createElement)(
5585
5931
  "div",
5586
5932
  { style: styles.section },
5587
- (0, import_react2.createElement)(
5933
+ (0, import_react4.createElement)(
5588
5934
  "div",
5589
5935
  { style: card },
5590
- (0, import_react2.createElement)(
5936
+ (0, import_react4.createElement)(
5591
5937
  "div",
5592
5938
  { style: { display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" } },
5593
- (0, import_react2.createElement)(import_dsh_client_ui_primitives2.StateDot, { state: exists ? "done" : "ongoing" }),
5594
- (0, import_react2.createElement)("span", { style: styles.bindingLabel }, exists ? `\u5DF2\u521D\u59CB\u5316 \xB7 ${view.lines} \u884C\uFF08\u4E0A\u9650 200\uFF09` : "\u672A\u521D\u59CB\u5316"),
5595
- view?.path !== void 0 ? (0, import_react2.createElement)("span", { style: styles.sourceBadge }, `\u5DF2\u5B9A\u4F4D\u5230 ${view.path}`) : null
5939
+ (0, import_react4.createElement)(import_dsh_client_ui_primitives4.StateDot, { state: exists ? "done" : "ongoing" }),
5940
+ (0, import_react4.createElement)("span", { style: styles.bindingLabel }, exists ? `\u5DF2\u521D\u59CB\u5316 \xB7 ${view.lines} \u884C\uFF08\u4E0A\u9650 200\uFF09` : "\u672A\u521D\u59CB\u5316"),
5941
+ view?.path !== void 0 ? (0, import_react4.createElement)("span", { style: styles.sourceBadge }, `\u5DF2\u5B9A\u4F4D\u5230 ${view.path}`) : null
5596
5942
  ),
5597
- (0, import_react2.createElement)(
5943
+ (0, import_react4.createElement)(
5598
5944
  "p",
5599
5945
  { style: styles.muted },
5600
5946
  "\u9879\u76EE\u6839 AGENTS.md \u4F1A\u88AB DSH \u81EA\u52A8\u6CE8\u5165\u5230\u6BCF\u4E2A\u4F1A\u8BDD\u3002\u521D\u59CB\u5316\u4E00\u6B21\uFF0C\u4E4B\u540E\u6BCF\u6B21\u4EFB\u52A1\u5F00\u5DE5 AI \u90FD\u81EA\u5E26\u8FD9\u4EFD\u9879\u76EE\u8BA4\u77E5\uFF08\u9879\u76EE\u662F\u4EC0\u4E48 \u2192 \u600E\u4E48\u8DD1 \u2192 \u7ED3\u6784 \u2192 \u7EA6\u5B9A \u2192 \u5751\uFF09\u3002"
5601
5947
  ),
5602
- exists && !editing && draft === null ? (0, import_react2.createElement)(
5948
+ exists && !editing && draft === null ? (0, import_react4.createElement)(
5603
5949
  "div",
5604
5950
  { style: styles.mdPreview },
5605
- (0, import_react2.createElement)(import_dsh_client_ui_primitives2.MarkdownText, { text: view.content, labels: MD_LABELS })
5951
+ (0, import_react4.createElement)(import_dsh_client_ui_primitives4.MarkdownText, { text: view.content, labels: MD_LABELS })
5606
5952
  ) : null,
5607
- draft !== null ? (0, import_react2.createElement)(
5953
+ draft !== null ? (0, import_react4.createElement)(
5608
5954
  "div",
5609
5955
  { style: styles.section },
5610
- (0, import_react2.createElement)(
5956
+ (0, import_react4.createElement)(
5611
5957
  "div",
5612
5958
  { style: styles.sourceRow },
5613
- (0, import_react2.createElement)(import_dsh_client_ui_primitives2.StateDot, { state: "ongoing", size: 8 }),
5614
- (0, import_react2.createElement)("span", { style: styles.sourceBadge }, `AI \u8349\u7A3F \xB7 ${draft.lines} \u884C \xB7 \u5C1A\u672A\u5199\u5165`)
5959
+ (0, import_react4.createElement)(import_dsh_client_ui_primitives4.StateDot, { state: "ongoing", size: 8 }),
5960
+ (0, import_react4.createElement)("span", { style: styles.sourceBadge }, `AI \u8349\u7A3F \xB7 ${draft.lines} \u884C \xB7 \u5C1A\u672A\u5199\u5165`)
5615
5961
  ),
5616
- (0, import_react2.createElement)(
5962
+ (0, import_react4.createElement)(
5617
5963
  "div",
5618
5964
  { style: styles.mdPreview },
5619
- (0, import_react2.createElement)(import_dsh_client_ui_primitives2.MarkdownText, { text: draft.content, labels: MD_LABELS })
5965
+ (0, import_react4.createElement)(import_dsh_client_ui_primitives4.MarkdownText, { text: draft.content, labels: MD_LABELS })
5620
5966
  )
5621
5967
  ) : null,
5622
- editing ? (0, import_react2.createElement)("textarea", {
5968
+ editing ? (0, import_react4.createElement)("textarea", {
5623
5969
  style: { ...styles.textarea, minHeight: 300 },
5624
5970
  placeholder: "AGENTS.md \u6B63\u6587\uFF08Markdown\uFF0C\u2264200 \u884C\uFF09",
5625
5971
  value: body2,
@@ -5627,16 +5973,16 @@ function InitPanel({ workspace, remote }) {
5627
5973
  setBody(ev.target.value);
5628
5974
  }
5629
5975
  }) : null,
5630
- generating ? (0, import_react2.createElement)(
5976
+ generating ? (0, import_react4.createElement)(
5631
5977
  "p",
5632
5978
  { style: styles.status },
5633
5979
  `AI \u6B63\u5728\u626B\u63CF\u9879\u76EE\u5E76\u751F\u6210\u8349\u7A3F\u2026 \u5DF2\u8017\u65F6 ${elapsed} \u79D2\uFF08\u6700\u957F ${INIT_TIMEOUT_S} \u79D2\uFF09\uFF0C\u8BF7\u7A0D\u5019`
5634
5980
  ) : null,
5635
- msg !== "" ? (0, import_react2.createElement)("p", { style: styles.status }, msg) : null,
5636
- draft !== null ? (0, import_react2.createElement)(
5981
+ msg !== "" ? (0, import_react4.createElement)("p", { style: styles.status }, msg) : null,
5982
+ draft !== null ? (0, import_react4.createElement)(
5637
5983
  "div",
5638
5984
  { style: styles.row },
5639
- (0, import_react2.createElement)(import_dsh_client_ui_primitives2.Button, {
5985
+ (0, import_react4.createElement)(import_dsh_client_ui_primitives4.Button, {
5640
5986
  variant: "primary",
5641
5987
  size: "md",
5642
5988
  disabled: draft.lines > 200,
@@ -5645,14 +5991,14 @@ function InitPanel({ workspace, remote }) {
5645
5991
  void write(draft.content, exists);
5646
5992
  }
5647
5993
  }, exists ? "\u4FDD\u5B58\u5E76\u8986\u76D6" : "\u4FDD\u5B58"),
5648
- draft.lines > 200 ? (0, import_react2.createElement)("span", { style: styles.sourceBadge }, `\u8349\u7A3F ${draft.lines} \u884C\u8D85\u9650\uFF0C\u8BF7\u70B9\u300C\u653E\u5F03\u300D\u540E\u91CD\u8BD5`) : null,
5649
- (0, import_react2.createElement)(import_dsh_client_ui_primitives2.Button, { variant: "ghost", size: "md", onClick: () => {
5994
+ draft.lines > 200 ? (0, import_react4.createElement)("span", { style: styles.sourceBadge }, `\u8349\u7A3F ${draft.lines} \u884C\u8D85\u9650\uFF0C\u8BF7\u70B9\u300C\u653E\u5F03\u300D\u540E\u91CD\u8BD5`) : null,
5995
+ (0, import_react4.createElement)(import_dsh_client_ui_primitives4.Button, { variant: "ghost", size: "md", onClick: () => {
5650
5996
  setDraft(null);
5651
5997
  } }, "\u653E\u5F03")
5652
- ) : editing ? (0, import_react2.createElement)(
5998
+ ) : editing ? (0, import_react4.createElement)(
5653
5999
  "div",
5654
6000
  { style: styles.row },
5655
- (0, import_react2.createElement)(import_dsh_client_ui_primitives2.Button, {
6001
+ (0, import_react4.createElement)(import_dsh_client_ui_primitives4.Button, {
5656
6002
  variant: "primary",
5657
6003
  size: "md",
5658
6004
  disabled: body2.trim() === "",
@@ -5661,13 +6007,13 @@ function InitPanel({ workspace, remote }) {
5661
6007
  void write(body2, exists);
5662
6008
  }
5663
6009
  }, exists ? "\u4FDD\u5B58\u5E76\u8986\u76D6" : "\u4FDD\u5B58"),
5664
- (0, import_react2.createElement)(import_dsh_client_ui_primitives2.Button, { variant: "ghost", size: "md", onClick: () => {
6010
+ (0, import_react4.createElement)(import_dsh_client_ui_primitives4.Button, { variant: "ghost", size: "md", onClick: () => {
5665
6011
  setEditing(false);
5666
6012
  } }, "\u53D6\u6D88")
5667
- ) : (0, import_react2.createElement)(
6013
+ ) : (0, import_react4.createElement)(
5668
6014
  "div",
5669
6015
  { style: styles.row },
5670
- (0, import_react2.createElement)(import_dsh_client_ui_primitives2.Button, {
6016
+ (0, import_react4.createElement)(import_dsh_client_ui_primitives4.Button, {
5671
6017
  variant: "primary",
5672
6018
  size: "md",
5673
6019
  disabled: generating,
@@ -5676,203 +6022,55 @@ function InitPanel({ workspace, remote }) {
5676
6022
  void generate();
5677
6023
  }
5678
6024
  }, exists ? "\u91CD\u65B0\u521D\u59CB\u5316\uFF08AI \u626B\u63CF\u8986\u76D6\uFF09" : "\u8BA9 AI \u521D\u59CB\u5316"),
5679
- exists ? (0, import_react2.createElement)(import_dsh_client_ui_primitives2.Button, { variant: "outline", size: "md", onClick: startEdit }, "\u624B\u52A8\u7F16\u8F91") : null
6025
+ exists ? (0, import_react4.createElement)(import_dsh_client_ui_primitives4.Button, { variant: "outline", size: "md", onClick: startEdit }, "\u624B\u52A8\u7F16\u8F91") : null
5680
6026
  )
5681
6027
  )
5682
6028
  );
5683
6029
  }
5684
6030
 
5685
6031
  // src/client/SkillManager.tsx
5686
- var import_react5 = require("react");
5687
-
5688
- // src/client/ResourceManager.tsx
5689
- var import_react4 = require("react");
5690
- var import_dsh_client_ui_primitives4 = require("@deepseek-ai/dsh-client-ui-primitives");
5691
-
5692
- // src/client/ResourceModal.tsx
5693
- var import_react3 = require("react");
5694
- var import_react_dom = require("react-dom");
5695
- var import_dsh_client_ui_primitives3 = require("@deepseek-ai/dsh-client-ui-primitives");
5696
- var rootStyle = {
5697
- position: "fixed",
5698
- inset: 0,
5699
- zIndex: 1e3,
5700
- display: "flex",
5701
- alignItems: "center",
5702
- justifyContent: "center",
5703
- padding: 24
5704
- };
5705
- var maskStyle = {
5706
- position: "absolute",
5707
- inset: 0,
5708
- background: "var(--dsw-alias-bg-mask-1)",
5709
- backdropFilter: "var(--dsw-mask-blur)"
5710
- };
5711
- var dialogStyle = {
5712
- position: "relative",
5713
- zIndex: 1,
5714
- display: "flex",
5715
- flexDirection: "column",
5716
- width: "min(760px, 100%)",
5717
- maxHeight: "85vh",
5718
- borderRadius: 24,
5719
- background: "var(--dsw-alias-bg-layer-2)",
5720
- boxShadow: "var(--dsw-elevation-prominent)",
5721
- overflow: "hidden"
5722
- };
5723
- var headerStyle = {
5724
- display: "flex",
5725
- alignItems: "center",
5726
- justifyContent: "space-between",
5727
- gap: 8,
5728
- padding: "18px 18px 10px 24px",
5729
- flex: "none"
5730
- };
5731
- var titleStyle = {
5732
- margin: 0,
5733
- fontSize: 16,
5734
- lineHeight: "24px",
5735
- fontWeight: 500,
5736
- color: "var(--dsw-alias-label-primary)"
5737
- };
5738
- var closeBtnStyle = {
5739
- flex: "none",
5740
- display: "inline-flex",
5741
- alignItems: "center",
5742
- justifyContent: "center",
5743
- width: 28,
5744
- height: 28,
5745
- border: "none",
5746
- borderRadius: 8,
5747
- background: "transparent",
5748
- cursor: "pointer",
5749
- color: "var(--dsw-alias-label-secondary)",
5750
- padding: 0
5751
- };
5752
- var descStyle = {
5753
- margin: 0,
5754
- padding: "0 24px",
5755
- fontSize: 13,
5756
- lineHeight: "20px",
5757
- color: "var(--dsw-alias-label-secondary)",
5758
- flex: "none"
5759
- };
5760
- var bodyStyle = {
5761
- flex: "1 1 auto",
5762
- minHeight: 0,
5763
- overflowY: "auto",
5764
- padding: "16px 24px 4px",
5765
- display: "flex",
5766
- flexDirection: "column"
5767
- };
5768
- var footerStyle = {
5769
- display: "flex",
5770
- alignItems: "center",
5771
- justifyContent: "flex-end",
5772
- gap: 8,
5773
- padding: "12px 24px 20px",
5774
- flex: "none"
5775
- };
5776
- function ResourceModal({ title, description, onClose, footer, children }) {
5777
- const dialog = (0, import_react3.useRef)(null);
5778
- const closer = (0, import_react3.useRef)(onClose);
5779
- closer.current = onClose;
5780
- (0, import_react3.useEffect)(() => {
5781
- const previous = document.activeElement;
5782
- dialog.current?.focus();
5783
- const onKey = (e) => {
5784
- if (!dialog.current?.contains(document.activeElement)) return;
5785
- if (e.key === "Escape") {
5786
- e.preventDefault();
5787
- e.stopPropagation();
5788
- closer.current();
5789
- return;
5790
- }
5791
- if (e.key !== "Tab") return;
5792
- const nodes = Array.from(dialog.current.querySelectorAll('button:not(:disabled),input:not(:disabled):not([hidden]),select:not(:disabled),textarea:not(:disabled),[tabindex="0"]')).filter((el) => el.getClientRects().length);
5793
- const first = nodes[0], last = nodes[nodes.length - 1];
5794
- if (!first || !last) {
5795
- e.preventDefault();
5796
- return;
5797
- }
5798
- if (e.shiftKey && (document.activeElement === first || document.activeElement === dialog.current)) {
5799
- e.preventDefault();
5800
- last.focus();
5801
- } else if (!e.shiftKey && (document.activeElement === last || document.activeElement === dialog.current)) {
5802
- e.preventDefault();
5803
- first.focus();
5804
- }
5805
- };
5806
- document.addEventListener("keydown", onKey);
5807
- return () => {
5808
- document.removeEventListener("keydown", onKey);
5809
- if (previous?.isConnected) previous.focus();
5810
- };
5811
- }, []);
5812
- return (0, import_react_dom.createPortal)(
5813
- (0, import_react3.createElement)(
5814
- "div",
5815
- { style: rootStyle, className: "te-modal", role: "presentation" },
5816
- (0, import_react3.createElement)("div", { style: maskStyle, "aria-hidden": true, onClick: onClose }),
5817
- (0, import_react3.createElement)(
5818
- "div",
5819
- { style: dialogStyle, ref: dialog, tabIndex: -1, role: "dialog", "aria-modal": true, "aria-label": title },
5820
- (0, import_react3.createElement)(
5821
- "div",
5822
- { style: headerStyle },
5823
- (0, import_react3.createElement)("h2", { style: titleStyle }, title),
5824
- (0, import_react3.createElement)(
5825
- "button",
5826
- { type: "button", style: closeBtnStyle, "aria-label": "\u5173\u95ED", onClick: onClose },
5827
- (0, import_react3.createElement)(import_dsh_client_ui_primitives3.IconCloseOutline16, { size: 14 })
5828
- )
5829
- ),
5830
- description !== void 0 && description !== "" ? (0, import_react3.createElement)("p", { style: descStyle }, description) : null,
5831
- (0, import_react3.createElement)("div", { style: bodyStyle }, children),
5832
- footer !== void 0 ? (0, import_react3.createElement)("div", { style: footerStyle }, footer) : null
5833
- )
5834
- ),
5835
- document.body
5836
- );
5837
- }
6032
+ var import_react6 = require("react");
5838
6033
 
5839
6034
  // src/client/ResourceManager.tsx
6035
+ var import_react5 = require("react");
6036
+ var import_dsh_client_ui_primitives5 = require("@deepseek-ai/dsh-client-ui-primitives");
5840
6037
  var labels = { code: { copyLabel: "\u590D\u5236", copiedLabel: "\u5DF2\u590D\u5236" }, footnotes: "\u811A\u6CE8" };
5841
6038
  var levelOf = (row) => row.source === "bundled" ? "bundled" : row.source.startsWith("user") ? "user" : "project";
5842
6039
  var sourceText2 = (source) => source === "bundled" ? "\u5185\u7F6E" : source.startsWith("user") ? "\u4E2A\u4EBA" : "\u9879\u76EE";
5843
6040
  var sizeText = (bytes) => bytes < 1024 ? `${bytes} B` : bytes < 1024 * 1024 ? `${(bytes / 1024).toFixed(1)} KB` : `${(bytes / 1024 / 1024).toFixed(1)} MB`;
5844
6041
  var fail = (r) => describeError(r.error ?? "\u64CD\u4F5C\u5931\u8D25");
5845
- function ResourceManager({ workspace, remote, kind }) {
6042
+ function ResourceManager({ workspace, remote, kind, onConfigureSkill }) {
5846
6043
  const noun = kind === "skill" ? "\u6280\u80FD" : "\u89C4\u5219";
5847
- const [rows, setRows] = (0, import_react4.useState)([]);
5848
- const [query, setQuery] = (0, import_react4.useState)("");
5849
- const [filter, setFilter] = (0, import_react4.useState)("all");
5850
- const [notice, setNotice] = (0, import_react4.useState)("");
5851
- const [error, setError] = (0, import_react4.useState)("");
5852
- const [loading, setLoading] = (0, import_react4.useState)(true);
5853
- const [revision, refresh] = (0, import_react4.useState)(0);
5854
- const [busy, setBusy] = (0, import_react4.useState)(false);
5855
- const [roots, setRoots] = (0, import_react4.useState)(null);
5856
- const [importing, setImporting] = (0, import_react4.useState)(false);
5857
- const [request, setRequest] = (0, import_react4.useState)(null);
5858
- const [preview, setPreview] = (0, import_react4.useState)(null);
5859
- const [level, setLevel] = (0, import_react4.useState)("project");
5860
- const [manual, setManual] = (0, import_react4.useState)(false);
5861
- const [sourceDir, setSourceDir] = (0, import_react4.useState)("");
5862
- const [dirs, setDirs] = (0, import_react4.useState)([]);
5863
- const [browsePath, setBrowsePath] = (0, import_react4.useState)("");
5864
- const [editing, setEditing] = (0, import_react4.useState)(null);
5865
- const [viewing, setViewing] = (0, import_react4.useState)(false);
5866
- const [name, setName] = (0, import_react4.useState)("");
5867
- const [description, setDescription] = (0, import_react4.useState)("");
5868
- const [whenToUse, setWhenToUse] = (0, import_react4.useState)("");
5869
- const [body2, setBody] = (0, import_react4.useState)("");
5870
- const [deleting, setDeleting] = (0, import_react4.useState)(null);
5871
- const input = (0, import_react4.useRef)(null);
5872
- const fileEpoch = (0, import_react4.useRef)(0);
5873
- const browseEpoch = (0, import_react4.useRef)(0);
6044
+ const [rows, setRows] = (0, import_react5.useState)([]);
6045
+ const [query, setQuery] = (0, import_react5.useState)("");
6046
+ const [filter, setFilter] = (0, import_react5.useState)("all");
6047
+ const [notice, setNotice] = (0, import_react5.useState)("");
6048
+ const [error, setError] = (0, import_react5.useState)("");
6049
+ const [loading, setLoading] = (0, import_react5.useState)(true);
6050
+ const [revision, refresh] = (0, import_react5.useState)(0);
6051
+ const [busy, setBusy] = (0, import_react5.useState)(false);
6052
+ const [roots, setRoots] = (0, import_react5.useState)(null);
6053
+ const [importing, setImporting] = (0, import_react5.useState)(false);
6054
+ const [request, setRequest] = (0, import_react5.useState)(null);
6055
+ const [preview, setPreview] = (0, import_react5.useState)(null);
6056
+ const [level, setLevel] = (0, import_react5.useState)("project");
6057
+ const [manual, setManual] = (0, import_react5.useState)(false);
6058
+ const [sourceDir, setSourceDir] = (0, import_react5.useState)("");
6059
+ const [dirs, setDirs] = (0, import_react5.useState)([]);
6060
+ const [browsePath, setBrowsePath] = (0, import_react5.useState)("");
6061
+ const [editing, setEditing] = (0, import_react5.useState)(null);
6062
+ const [viewing, setViewing] = (0, import_react5.useState)(false);
6063
+ const [name, setName] = (0, import_react5.useState)("");
6064
+ const [description, setDescription] = (0, import_react5.useState)("");
6065
+ const [whenToUse, setWhenToUse] = (0, import_react5.useState)("");
6066
+ const [body2, setBody] = (0, import_react5.useState)("");
6067
+ const [templateSource, setTemplateSource] = (0, import_react5.useState)(null);
6068
+ const [deleting, setDeleting] = (0, import_react5.useState)(null);
6069
+ const input = (0, import_react5.useRef)(null);
6070
+ const fileEpoch = (0, import_react5.useRef)(0);
6071
+ const browseEpoch = (0, import_react5.useRef)(0);
5874
6072
  const readonly = editing !== null && editing !== "new" && levelOf(editing) === "bundled";
5875
- (0, import_react4.useEffect)(() => {
6073
+ (0, import_react5.useEffect)(() => {
5876
6074
  let active = true;
5877
6075
  setLoading(true);
5878
6076
  setRows([]);
@@ -5899,7 +6097,7 @@ function ResourceManager({ workspace, remote, kind }) {
5899
6097
  fileEpoch.current++;
5900
6098
  };
5901
6099
  }, [workspace, remote, kind, revision]);
5902
- (0, import_react4.useEffect)(() => {
6100
+ (0, import_react5.useEffect)(() => {
5903
6101
  let active = true;
5904
6102
  setPreview(null);
5905
6103
  if (!request) return;
@@ -5924,6 +6122,7 @@ function ResourceManager({ workspace, remote, kind }) {
5924
6122
  fileEpoch.current++;
5925
6123
  setImporting(false);
5926
6124
  setEditing(null);
6125
+ setTemplateSource(null);
5927
6126
  setDeleting(null);
5928
6127
  setRequest(null);
5929
6128
  setError("");
@@ -5996,6 +6195,7 @@ function ResourceManager({ workspace, remote, kind }) {
5996
6195
  }
5997
6196
  };
5998
6197
  const edit = async (row, view = false) => {
6198
+ setTemplateSource(null);
5999
6199
  setEditing(row);
6000
6200
  setViewing(view);
6001
6201
  setName(row === "new" ? "" : row.name);
@@ -6026,6 +6226,39 @@ function ResourceManager({ workspace, remote, kind }) {
6026
6226
  setBusy(false);
6027
6227
  }
6028
6228
  };
6229
+ const copyTemplate = async (row) => {
6230
+ if (busy || levelOf(row) !== "bundled") return;
6231
+ setBusy(true);
6232
+ setError("");
6233
+ try {
6234
+ const r = kind === "skill" ? await remote.readSkill({ name: row.name, level: "bundled", path: workspace }) : await remote.readRule({ name: row.name, level: "bundled", path: workspace });
6235
+ if (!r.ok) throw new Error(fail(r));
6236
+ if (!r.value.ok) throw new Error(r.value.error ?? "\u8BFB\u53D6\u5185\u7F6E\u6837\u672C\u5931\u8D25");
6237
+ const used = new Set(rows.map((item) => item.name));
6238
+ const base = `${row.name}-copy`;
6239
+ let candidate = base;
6240
+ for (let index = 2; used.has(candidate); index++) candidate = `${base}-${index}`;
6241
+ setName(candidate);
6242
+ setBody(r.value.content);
6243
+ setLevel("project");
6244
+ setViewing(false);
6245
+ if (kind === "skill") {
6246
+ const skill = r.value;
6247
+ setDescription(skill.description);
6248
+ setWhenToUse(skill.whenToUse);
6249
+ } else {
6250
+ setDescription("");
6251
+ setWhenToUse("");
6252
+ }
6253
+ setTemplateSource(row);
6254
+ setEditing("new");
6255
+ setNotice("");
6256
+ } catch (e) {
6257
+ setError("\u590D\u5236\u6837\u672C\u5931\u8D25\uFF1A" + describeError(e));
6258
+ } finally {
6259
+ setBusy(false);
6260
+ }
6261
+ };
6029
6262
  const save2 = async () => {
6030
6263
  if (busy) return;
6031
6264
  setBusy(true);
@@ -6035,9 +6268,12 @@ function ResourceManager({ workspace, remote, kind }) {
6035
6268
  const r = kind === "skill" ? await remote.writeSkill({ name, description, whenToUse, content: body2, level, path: workspace }) : await remote.writeRule({ name, content: body2, level, path: workspace });
6036
6269
  if (!r.ok) throw new Error(fail(r));
6037
6270
  if (!r.value.ok) throw new Error(r.value.error ?? "\u4FDD\u5B58\u5931\u8D25");
6038
- setNotice(`\u5DF2\u4FDD\u5B58${noun} \xB7 ${r.value.path}`);
6271
+ const copied = templateSource !== null;
6272
+ setNotice(`\u5DF2\u4FDD\u5B58${noun} \xB7 ${r.value.path}${copied ? "\uFF1B\u8BF7\u6309\u9700\u914D\u7F6E\u5B8C\u6210\u51ED\u8BC1\u3001\u89C4\u5219\u4E0E\u9636\u6BB5\u7ED1\u5B9A" : ""}`);
6039
6273
  setEditing(null);
6274
+ setTemplateSource(null);
6040
6275
  refresh((n) => n + 1);
6276
+ if (copied && kind === "skill") onConfigureSkill?.({ source: level, name: r.value.name });
6041
6277
  } catch (e) {
6042
6278
  setError(describeError(e));
6043
6279
  } finally {
@@ -6063,105 +6299,168 @@ function ResourceManager({ workspace, remote, kind }) {
6063
6299
  setBusy(false);
6064
6300
  }
6065
6301
  };
6066
- const status = () => error ? (0, import_react4.createElement)("div", { className: "te-alert", role: "alert" }, error) : null;
6067
- const targets = () => (0, import_react4.createElement)(
6302
+ const status = () => error ? (0, import_react5.createElement)("div", { className: "te-alert", role: "alert" }, error) : null;
6303
+ const targets = () => (0, import_react5.createElement)(
6068
6304
  "div",
6069
6305
  { className: "te-targets" },
6070
- ...["project", "user"].map((lvl) => (0, import_react4.createElement)(
6306
+ ...["project", "user"].map((lvl) => (0, import_react5.createElement)(
6071
6307
  "button",
6072
6308
  { type: "button", key: lvl, className: `te-target ${level === lvl ? "selected" : ""}`, "aria-pressed": level === lvl, disabled: busy || editing !== null && editing !== "new", onClick: () => {
6073
6309
  setPreview(null);
6074
6310
  setLevel(lvl);
6075
6311
  } },
6076
- (0, import_react4.createElement)("strong", null, lvl === "project" ? "\u9879\u76EE\u5171\u4EAB" : "\u4E2A\u4EBA\u5168\u5C40"),
6077
- (0, import_react4.createElement)("small", null, lvl === "project" ? "\u4EC5\u5F53\u524D\u5DE5\u4F5C\u533A\u4F7F\u7528" : "\u6B64\u4E3B\u673A\u4E0A\u7684\u6240\u6709\u9879\u76EE\u53EF\u7528")
6312
+ (0, import_react5.createElement)("strong", null, lvl === "project" ? "\u9879\u76EE\u5171\u4EAB" : "\u4E2A\u4EBA\u5168\u5C40"),
6313
+ (0, import_react5.createElement)("small", null, lvl === "project" ? "\u4EC5\u5F53\u524D\u5DE5\u4F5C\u533A\u4F7F\u7528" : "\u6B64\u4E3B\u673A\u4E0A\u7684\u6240\u6709\u9879\u76EE\u53EF\u7528")
6078
6314
  )),
6079
- (0, import_react4.createElement)("code", { className: "te-path" }, roots?.[level] ?? (level === "project" ? `${workspace}/.dsh/${kind}s` : `DSH_HOME/${kind}s`))
6315
+ (0, import_react5.createElement)("code", { className: "te-path" }, roots?.[level] ?? (level === "project" ? `${workspace}/.dsh/${kind}s` : `DSH_HOME/${kind}s`))
6080
6316
  );
6081
6317
  const visible = rows.filter((r) => `${r.name} ${r.description ?? ""}`.toLowerCase().includes(query.toLowerCase()) && (filter === "all" || levelOf(r) === filter));
6082
- return (0, import_react4.createElement)(
6318
+ return (0, import_react5.createElement)(
6083
6319
  "section",
6084
6320
  { className: "te-resource" },
6085
- (0, import_react4.createElement)("input", { type: "file", ref: input, hidden: true, "aria-label": kind === "skill" ? "\u9009\u62E9\u6280\u80FD\u6587\u4EF6\u5939" : "\u9009\u62E9\u89C4\u5219\u6587\u4EF6", ...kind === "skill" ? { webkitdirectory: "", multiple: true } : { accept: ".md,text/markdown" }, onChange: (e) => {
6321
+ (0, import_react5.createElement)("input", { type: "file", ref: input, hidden: true, "aria-label": kind === "skill" ? "\u9009\u62E9\u6280\u80FD\u6587\u4EF6\u5939" : "\u9009\u62E9\u89C4\u5219\u6587\u4EF6", ...kind === "skill" ? { webkitdirectory: "", multiple: true } : { accept: ".md,text/markdown" }, onChange: (e) => {
6086
6322
  void selected(Array.from(e.target.files ?? []));
6087
6323
  } }),
6088
- (0, import_react4.createElement)("div", { className: "te-section-heading" }, (0, import_react4.createElement)("div", null, (0, import_react4.createElement)("h2", null, `${noun}\u5E93`), (0, import_react4.createElement)("p", null, kind === "skill" ? "\u628A\u53EF\u590D\u7528\u7684\u5DE5\u4F5C\u65B9\u6CD5\u5E26\u5165\u9879\u76EE\u3002" : "\u4E3A\u9879\u76EE\u660E\u786E\u7EA6\u5B9A\uFF0C\u8BA9\u6BCF\u6B21\u4EA4\u4ED8\u4FDD\u6301\u4E00\u81F4\u3002")), (0, import_react4.createElement)("div", { className: "te-actions" }, (0, import_react4.createElement)(import_dsh_client_ui_primitives4.Button, { variant: "outline", onClick: () => {
6324
+ (0, import_react5.createElement)("div", { className: "te-section-heading" }, (0, import_react5.createElement)("div", null, (0, import_react5.createElement)("h2", null, `${noun}\u5E93`), (0, import_react5.createElement)("p", null, kind === "skill" ? "\u628A\u53EF\u590D\u7528\u7684\u5DE5\u4F5C\u65B9\u6CD5\u5E26\u5165\u9879\u76EE\u3002" : "\u4E3A\u9879\u76EE\u660E\u786E\u7EA6\u5B9A\uFF0C\u8BA9\u6BCF\u6B21\u4EA4\u4ED8\u4FDD\u6301\u4E00\u81F4\u3002")), (0, import_react5.createElement)("div", { className: "te-actions" }, (0, import_react5.createElement)(import_dsh_client_ui_primitives5.Button, { variant: "outline", onClick: () => {
6089
6325
  void edit("new");
6090
- } }, `\u65B0\u5EFA${noun}`), (0, import_react4.createElement)(import_dsh_client_ui_primitives4.Button, { variant: "primary", onClick: choose }, `\u5B89\u88C5${noun}`))),
6091
- (0, import_react4.createElement)("div", { className: "te-toolbar" }, (0, import_react4.createElement)("input", { className: "te-input", placeholder: `\u641C\u7D22${noun}\u540D\u79F0${kind === "skill" ? "\u6216\u63CF\u8FF0" : ""}`, value: query, onChange: (e) => setQuery(e.target.value) }), (0, import_react4.createElement)("select", { className: "te-input", "aria-label": "\u7B5B\u9009\u6765\u6E90", value: filter, onChange: (e) => setFilter(e.target.value) }, (0, import_react4.createElement)("option", { value: "all" }, `\u5168\u90E8\u6765\u6E90 \xB7 ${rows.length}`), (0, import_react4.createElement)("option", { value: "bundled" }, "\u5185\u7F6E"), (0, import_react4.createElement)("option", { value: "project" }, "\u9879\u76EE"), (0, import_react4.createElement)("option", { value: "user" }, "\u4E2A\u4EBA")), (0, import_react4.createElement)(import_dsh_client_ui_primitives4.Button, { variant: "ghost", onClick: () => refresh((n) => n + 1), disabled: loading }, "\u5237\u65B0")),
6092
- notice ? (0, import_react4.createElement)("div", { className: "te-success", role: "status" }, notice) : null,
6326
+ } }, `\u65B0\u5EFA${noun}`), (0, import_react5.createElement)(import_dsh_client_ui_primitives5.Button, { variant: "primary", onClick: choose }, `\u5B89\u88C5${noun}`))),
6327
+ (0, import_react5.createElement)("div", { className: "te-toolbar" }, (0, import_react5.createElement)("input", { className: "te-input", placeholder: `\u641C\u7D22${noun}\u540D\u79F0${kind === "skill" ? "\u6216\u63CF\u8FF0" : ""}`, value: query, onChange: (e) => setQuery(e.target.value) }), (0, import_react5.createElement)("select", { className: "te-input", "aria-label": "\u7B5B\u9009\u6765\u6E90", value: filter, onChange: (e) => setFilter(e.target.value) }, (0, import_react5.createElement)("option", { value: "all" }, `\u5168\u90E8\u6765\u6E90 \xB7 ${rows.length}`), (0, import_react5.createElement)("option", { value: "bundled" }, "\u5185\u7F6E"), (0, import_react5.createElement)("option", { value: "project" }, "\u9879\u76EE"), (0, import_react5.createElement)("option", { value: "user" }, "\u4E2A\u4EBA")), (0, import_react5.createElement)(import_dsh_client_ui_primitives5.Button, { variant: "ghost", onClick: () => refresh((n) => n + 1), disabled: loading }, "\u5237\u65B0")),
6328
+ notice ? (0, import_react5.createElement)("div", { className: "te-success", role: "status" }, notice) : null,
6093
6329
  !importing && !editing && !deleting ? status() : null,
6094
- loading ? (0, import_react4.createElement)("div", { className: "te-empty", role: "status" }, "\u6B63\u5728\u52A0\u8F7D\u2026") : visible.length === 0 ? (0, import_react4.createElement)("div", { className: "te-empty" }, (0, import_react4.createElement)("h3", null, query || filter !== "all" ? "\u6CA1\u6709\u5339\u914D\u7684\u7ED3\u679C" : `\u8FD8\u6CA1\u6709${noun}`), (0, import_react4.createElement)("p", null, "\u8C03\u6574\u7B5B\u9009\uFF0C\u6216\u4F7F\u7528\u53F3\u4E0A\u89D2\u6309\u94AE\u6DFB\u52A0\u3002")) : (0, import_react4.createElement)("div", { className: "te-resource-grid" }, ...visible.map((row) => (0, import_react4.createElement)(
6330
+ loading ? (0, import_react5.createElement)("div", { className: "te-empty", role: "status" }, "\u6B63\u5728\u52A0\u8F7D\u2026") : visible.length === 0 ? (0, import_react5.createElement)("div", { className: "te-empty" }, (0, import_react5.createElement)("h3", null, query || filter !== "all" ? "\u6CA1\u6709\u5339\u914D\u7684\u7ED3\u679C" : `\u8FD8\u6CA1\u6709${noun}`), (0, import_react5.createElement)("p", null, "\u8C03\u6574\u7B5B\u9009\uFF0C\u6216\u4F7F\u7528\u53F3\u4E0A\u89D2\u6309\u94AE\u6DFB\u52A0\u3002")) : (0, import_react5.createElement)("div", { className: "te-resource-grid" }, ...visible.map((row) => (0, import_react5.createElement)(
6095
6331
  "article",
6096
6332
  { className: "te-resource-card", key: row.source + "/" + row.name },
6097
- (0, import_react4.createElement)("div", { className: "te-card-top" }, (0, import_react4.createElement)("span", { className: "te-resource-icon", "aria-hidden": true }, kind === "skill" ? "\u25C7" : "\u2261"), (0, import_react4.createElement)("span", { className: "te-badge" }, sourceText2(row.source))),
6098
- (0, import_react4.createElement)("h3", null, row.name),
6099
- (0, import_react4.createElement)("p", null, row.description || "\u9879\u76EE\u7EA6\u5B9A\u4E0E\u6267\u884C\u89C4\u5219"),
6100
- (0, import_react4.createElement)("div", { className: "te-actions" }, (0, import_react4.createElement)(import_dsh_client_ui_primitives4.Button, { variant: "outline", size: "sm", onClick: () => {
6333
+ (0, import_react5.createElement)("div", { className: "te-card-top" }, (0, import_react5.createElement)("span", { className: "te-resource-icon", "aria-hidden": true }, kind === "skill" ? "\u25C7" : "\u2261"), (0, import_react5.createElement)("span", { className: "te-badge" }, sourceText2(row.source))),
6334
+ (0, import_react5.createElement)("h3", null, row.name),
6335
+ (0, import_react5.createElement)("p", null, row.description || "\u9879\u76EE\u7EA6\u5B9A\u4E0E\u6267\u884C\u89C4\u5219"),
6336
+ (0, import_react5.createElement)("div", { className: "te-actions" }, kind === "skill" && onConfigureSkill ? (0, import_react5.createElement)(import_dsh_client_ui_primitives5.Button, { variant: "primary", size: "sm", onClick: () => onConfigureSkill({ source: levelOf(row), name: row.name }) }, "\u914D\u7F6E\u89C4\u5219") : null, (0, import_react5.createElement)(import_dsh_client_ui_primitives5.Button, { variant: "outline", size: "sm", onClick: () => {
6101
6337
  void edit(row, true);
6102
- } }, "\u67E5\u770B"), levelOf(row) !== "bundled" ? (0, import_react4.createElement)(import_dsh_client_ui_primitives4.Button, { variant: "ghost", size: "sm", onClick: () => {
6338
+ } }, "\u67E5\u770B"), levelOf(row) === "bundled" ? (0, import_react5.createElement)(import_dsh_client_ui_primitives5.Button, { variant: "ghost", size: "sm", disabled: busy, onClick: () => {
6339
+ void copyTemplate(row);
6340
+ } }, "\u4EE5\u6B64\u4E3A\u6A21\u677F\u65B0\u5EFA") : (0, import_react5.createElement)(import_dsh_client_ui_primitives5.Button, { variant: "ghost", size: "sm", onClick: () => {
6103
6341
  void edit(row);
6104
- } }, "\u7F16\u8F91") : null, levelOf(row) !== "bundled" ? (0, import_react4.createElement)("button", { className: "te-delete", onClick: () => {
6342
+ } }, "\u7F16\u8F91"), levelOf(row) !== "bundled" ? (0, import_react5.createElement)("button", { className: "te-delete", onClick: () => {
6105
6343
  setDeleting(row);
6106
6344
  setError("");
6107
6345
  } }, "\u5220\u9664") : null)
6108
6346
  ))),
6109
- kind === "skill" ? (0, import_react4.createElement)("button", { className: "te-link", onClick: () => {
6347
+ kind === "skill" ? (0, import_react5.createElement)("button", { className: "te-link", onClick: () => {
6110
6348
  setImporting(true);
6111
6349
  setManual(true);
6112
6350
  setError("");
6113
6351
  } }, "\u9AD8\u7EA7\uFF1A\u4ECE Harness \u4E3B\u673A\u8DEF\u5F84\u5B89\u88C5") : null,
6114
- importing ? (0, import_react4.createElement)(
6352
+ importing ? (0, import_react5.createElement)(
6115
6353
  ResourceModal,
6116
- { title: `\u5B89\u88C5${noun}`, description: "\u5148\u68C0\u67E5\u5185\u5BB9\u548C\u5B89\u88C5\u4F4D\u7F6E\uFF0C\u786E\u8BA4\u540E\u624D\u4F1A\u5199\u5165\u3002", onClose: close, footer: (0, import_react4.createElement)("div", { className: "te-actions" }, (0, import_react4.createElement)(import_dsh_client_ui_primitives4.Button, { variant: "ghost", disabled: busy, onClick: close }, "\u53D6\u6D88"), (0, import_react4.createElement)(import_dsh_client_ui_primitives4.Button, { variant: "primary", disabled: busy || !preview || preview.conflict, onClick: () => {
6354
+ { title: `\u5B89\u88C5${noun}`, description: "\u5148\u68C0\u67E5\u5185\u5BB9\u548C\u5B89\u88C5\u4F4D\u7F6E\uFF0C\u786E\u8BA4\u540E\u624D\u4F1A\u5199\u5165\u3002", onClose: close, footer: (0, import_react5.createElement)("div", { className: "te-actions" }, (0, import_react5.createElement)(import_dsh_client_ui_primitives5.Button, { variant: "ghost", disabled: busy, onClick: close }, "\u53D6\u6D88"), (0, import_react5.createElement)(import_dsh_client_ui_primitives5.Button, { variant: "primary", disabled: busy || !preview || preview.conflict, onClick: () => {
6117
6355
  void install();
6118
6356
  } }, busy ? "\u5904\u7406\u4E2D\u2026" : "\u786E\u8BA4\u5B89\u88C5")) },
6119
6357
  targets(),
6120
- (0, import_react4.createElement)("div", { className: "te-actions" }, (0, import_react4.createElement)(import_dsh_client_ui_primitives4.Button, { variant: "outline", disabled: busy, onClick: choose }, "\u91CD\u65B0\u9009\u62E9"), kind === "skill" ? (0, import_react4.createElement)(import_dsh_client_ui_primitives4.Button, { variant: "ghost", disabled: busy, onClick: () => setManual(!manual) }, manual ? "\u6536\u8D77\u9AD8\u7EA7\u65B9\u5F0F" : "\u4E3B\u673A\u8DEF\u5F84") : null),
6121
- manual ? (0, import_react4.createElement)("div", { className: "te-advanced" }, (0, import_react4.createElement)("p", null, "\u6B64\u8DEF\u5F84\u4F4D\u4E8E Harness \u4E3B\u673A\uFF1B\u6D4F\u89C8\u5668\u9009\u62E9\u5668\u8BFB\u53D6\u7684\u662F\u4F60\u5F53\u524D\u7535\u8111\u3002"), (0, import_react4.createElement)("div", { className: "te-toolbar" }, (0, import_react4.createElement)("input", { className: "te-input", "aria-label": "\u4E3B\u673A\u6280\u80FD\u76EE\u5F55", value: sourceDir, onChange: (e) => {
6358
+ (0, import_react5.createElement)("div", { className: "te-actions" }, (0, import_react5.createElement)(import_dsh_client_ui_primitives5.Button, { variant: "outline", disabled: busy, onClick: choose }, "\u91CD\u65B0\u9009\u62E9"), kind === "skill" ? (0, import_react5.createElement)(import_dsh_client_ui_primitives5.Button, { variant: "ghost", disabled: busy, onClick: () => setManual(!manual) }, manual ? "\u6536\u8D77\u9AD8\u7EA7\u65B9\u5F0F" : "\u4E3B\u673A\u8DEF\u5F84") : null),
6359
+ manual ? (0, import_react5.createElement)("div", { className: "te-advanced" }, (0, import_react5.createElement)("p", null, "\u6B64\u8DEF\u5F84\u4F4D\u4E8E Harness \u4E3B\u673A\uFF1B\u6D4F\u89C8\u5668\u9009\u62E9\u5668\u8BFB\u53D6\u7684\u662F\u4F60\u5F53\u524D\u7535\u8111\u3002"), (0, import_react5.createElement)("div", { className: "te-toolbar" }, (0, import_react5.createElement)("input", { className: "te-input", "aria-label": "\u4E3B\u673A\u6280\u80FD\u76EE\u5F55", value: sourceDir, onChange: (e) => {
6122
6360
  setSourceDir(e.target.value);
6123
6361
  setRequest(null);
6124
- } }), (0, import_react4.createElement)(import_dsh_client_ui_primitives4.Button, { variant: "outline", onClick: () => {
6362
+ } }), (0, import_react5.createElement)(import_dsh_client_ui_primitives5.Button, { variant: "outline", onClick: () => {
6125
6363
  void browse(sourceDir);
6126
- } }, "\u6D4F\u89C8"), (0, import_react4.createElement)(import_dsh_client_ui_primitives4.Button, { variant: "outline", disabled: busy || !sourceDir.trim(), onClick: () => setRequest({ kind, level, path: workspace, files: [], sourceDir }) }, "\u9884\u89C8\u76EE\u5F55")), (0, import_react4.createElement)("div", { className: "te-dir-list" }, browsePath ? (0, import_react4.createElement)("button", { onClick: () => {
6364
+ } }, "\u6D4F\u89C8"), (0, import_react5.createElement)(import_dsh_client_ui_primitives5.Button, { variant: "outline", disabled: busy || !sourceDir.trim(), onClick: () => setRequest({ kind, level, path: workspace, files: [], sourceDir }) }, "\u9884\u89C8\u76EE\u5F55")), (0, import_react5.createElement)("div", { className: "te-dir-list" }, browsePath ? (0, import_react5.createElement)("button", { onClick: () => {
6127
6365
  void browse(browsePath.replace(/[\\/][^\\/]+[\\/]?$/u, "") || "/");
6128
- } }, "\u2191 \u4E0A\u7EA7\u76EE\u5F55") : null, ...dirs.map((d) => (0, import_react4.createElement)("button", { key: d.name, onClick: () => {
6366
+ } }, "\u2191 \u4E0A\u7EA7\u76EE\u5F55") : null, ...dirs.map((d) => (0, import_react5.createElement)("button", { key: d.name, onClick: () => {
6129
6367
  setRequest(null);
6130
6368
  void browse(browsePath.replace(/[\\/]+$/u, "") + "/" + d.name);
6131
6369
  } }, d.name + (d.hasSkill ? " \xB7 SKILL.md" : ""))))) : null,
6132
- busy ? (0, import_react4.createElement)("p", { role: "status" }, "\u6B63\u5728\u6821\u9A8C\u6587\u4EF6\uFF0C\u8BF7\u7A0D\u5019\u2026") : null,
6370
+ busy ? (0, import_react5.createElement)("p", { role: "status" }, "\u6B63\u5728\u6821\u9A8C\u6587\u4EF6\uFF0C\u8BF7\u7A0D\u5019\u2026") : null,
6133
6371
  status(),
6134
- preview ? (0, import_react4.createElement)("div", { className: "te-preview" }, (0, import_react4.createElement)("h3", null, preview.name), (0, import_react4.createElement)("p", null, preview.description), (0, import_react4.createElement)("div", { className: "te-actions" }, (0, import_react4.createElement)("span", { className: "te-badge" }, `${preview.files} \u4E2A\u6587\u4EF6`), (0, import_react4.createElement)("span", { className: "te-badge" }, sizeText(preview.bytes))), (0, import_react4.createElement)("code", { className: "te-path" }, preview.target), preview.conflict ? (0, import_react4.createElement)("div", { className: "te-alert", role: "alert" }, "\u5DF2\u6709\u540C\u540D\u8D44\u6E90\u3002\u8BF7\u53D6\u6D88\u5E76\u68C0\u67E5\u73B0\u6709\u5185\u5BB9\uFF0C\u5B89\u88C5\u4E0D\u4F1A\u8986\u76D6\u5B83\u3002") : null, (0, import_react4.createElement)("div", { className: "te-markdown" }, (0, import_react4.createElement)(import_dsh_client_ui_primitives4.MarkdownText, { text: preview.content, labels }))) : null
6372
+ preview ? (0, import_react5.createElement)("div", { className: "te-preview" }, (0, import_react5.createElement)("h3", null, preview.name), (0, import_react5.createElement)("p", null, preview.description), (0, import_react5.createElement)("div", { className: "te-actions" }, (0, import_react5.createElement)("span", { className: "te-badge" }, `${preview.files} \u4E2A\u6587\u4EF6`), (0, import_react5.createElement)("span", { className: "te-badge" }, sizeText(preview.bytes))), (0, import_react5.createElement)("code", { className: "te-path" }, preview.target), preview.conflict ? (0, import_react5.createElement)("div", { className: "te-alert", role: "alert" }, "\u5DF2\u6709\u540C\u540D\u8D44\u6E90\u3002\u8BF7\u53D6\u6D88\u5E76\u68C0\u67E5\u73B0\u6709\u5185\u5BB9\uFF0C\u5B89\u88C5\u4E0D\u4F1A\u8986\u76D6\u5B83\u3002") : null, (0, import_react5.createElement)("div", { className: "te-markdown" }, (0, import_react5.createElement)(import_dsh_client_ui_primitives5.MarkdownText, { text: preview.content, labels }))) : null
6135
6373
  ) : null,
6136
- editing ? (0, import_react4.createElement)(
6374
+ editing ? (0, import_react5.createElement)(
6137
6375
  ResourceModal,
6138
- { title: editing === "new" ? `\u65B0\u5EFA${noun}` : `${viewing ? "\u67E5\u770B" : "\u7F16\u8F91"}${noun} \xB7 ${name}`, onClose: close, footer: (0, import_react4.createElement)("div", { className: "te-actions" }, (0, import_react4.createElement)(import_dsh_client_ui_primitives4.Button, { variant: "ghost", disabled: busy, onClick: close }, "\u5173\u95ED"), !readonly ? (0, import_react4.createElement)(import_dsh_client_ui_primitives4.Button, { variant: "outline", disabled: busy, onClick: () => setViewing(!viewing) }, viewing ? "\u7F16\u8F91\u5185\u5BB9" : "\u9884\u89C8") : null, !readonly ? (0, import_react4.createElement)(import_dsh_client_ui_primitives4.Button, { variant: "primary", disabled: busy || !name.trim() || !body2.trim() || kind === "skill" && !description.trim(), onClick: () => {
6376
+ { title: editing === "new" ? `\u65B0\u5EFA${noun}` : `${viewing ? "\u67E5\u770B" : "\u7F16\u8F91"}${noun} \xB7 ${name}`, onClose: close, footer: (0, import_react5.createElement)("div", { className: "te-actions" }, (0, import_react5.createElement)(import_dsh_client_ui_primitives5.Button, { variant: "ghost", disabled: busy, onClick: close }, "\u5173\u95ED"), readonly ? (0, import_react5.createElement)(import_dsh_client_ui_primitives5.Button, { variant: "outline", disabled: busy, onClick: () => {
6377
+ void copyTemplate(editing);
6378
+ } }, "\u4EE5\u6B64\u4E3A\u6A21\u677F\u65B0\u5EFA") : null, !readonly ? (0, import_react5.createElement)(import_dsh_client_ui_primitives5.Button, { variant: "outline", disabled: busy, onClick: () => setViewing(!viewing) }, viewing ? "\u7F16\u8F91\u5185\u5BB9" : "\u9884\u89C8") : null, !readonly ? (0, import_react5.createElement)(import_dsh_client_ui_primitives5.Button, { variant: "primary", disabled: busy || !name.trim() || !body2.trim() || kind === "skill" && !description.trim(), onClick: () => {
6139
6379
  void save2();
6140
6380
  } }, busy ? "\u5904\u7406\u4E2D\u2026" : "\u4FDD\u5B58") : null) },
6141
- !readonly ? targets() : (0, import_react4.createElement)("p", { className: "te-badge" }, "\u5185\u7F6E\u8D44\u6E90 \xB7 \u53EA\u8BFB"),
6381
+ !readonly ? targets() : (0, import_react5.createElement)("p", { className: "te-badge" }, "\u5185\u7F6E\u6837\u672C \xB7 \u53EA\u8BFB"),
6382
+ templateSource ? (0, import_react5.createElement)("p", null, `\u4EE5\u300C${templateSource.name}\u300D\u4E3A\u6A21\u677F\u590D\u5236\u6B63\u6587\u3002\u65B0\u8D44\u6E90\u7684\u5B8C\u6210\u51ED\u8BC1\u3001\u89C4\u5219\u548C\u9636\u6BB5\u7ED1\u5B9A\u9700\u5355\u72EC\u914D\u7F6E\uFF0C\u4FDD\u5B58\u672C\u8EAB\u4E0D\u4F1A\u542F\u7528\u5B83\u3002`) : null,
6142
6383
  status(),
6143
- viewing ? (0, import_react4.createElement)("div", { className: "te-markdown" }, (0, import_react4.createElement)(import_dsh_client_ui_primitives4.MarkdownText, { text: body2, labels })) : (0, import_react4.createElement)("div", { className: "te-form" }, (0, import_react4.createElement)("label", null, "\u540D\u79F0", (0, import_react4.createElement)("input", { className: "te-input", value: name, disabled: editing !== "new" || busy, onChange: (e) => setName(e.target.value), placeholder: "\u5C0F\u5199\u5B57\u6BCD\u3001\u6570\u5B57\u548C\u8FDE\u5B57\u7B26" })), kind === "skill" ? (0, import_react4.createElement)("label", null, "\u63CF\u8FF0", (0, import_react4.createElement)("input", { className: "te-input", value: description, disabled: busy, onChange: (e) => setDescription(e.target.value) })) : null, kind === "skill" ? (0, import_react4.createElement)("label", null, "\u4F7F\u7528\u65F6\u673A\uFF08\u53EF\u9009\uFF09", (0, import_react4.createElement)("input", { className: "te-input", value: whenToUse, disabled: busy, onChange: (e) => setWhenToUse(e.target.value) })) : null, (0, import_react4.createElement)("label", null, "Markdown \u6B63\u6587", (0, import_react4.createElement)("textarea", { className: "te-input te-editor", value: body2, disabled: busy, onChange: (e) => setBody(e.target.value) })))
6384
+ viewing ? (0, import_react5.createElement)("div", { className: "te-markdown" }, (0, import_react5.createElement)(import_dsh_client_ui_primitives5.MarkdownText, { text: body2, labels })) : (0, import_react5.createElement)("div", { className: "te-form" }, (0, import_react5.createElement)("label", null, "\u540D\u79F0", (0, import_react5.createElement)("input", { className: "te-input", value: name, disabled: editing !== "new" || busy, onChange: (e) => setName(e.target.value), placeholder: "\u5C0F\u5199\u5B57\u6BCD\u3001\u6570\u5B57\u548C\u8FDE\u5B57\u7B26" })), kind === "skill" ? (0, import_react5.createElement)("label", null, "\u63CF\u8FF0", (0, import_react5.createElement)("input", { className: "te-input", value: description, disabled: busy, onChange: (e) => setDescription(e.target.value) })) : null, kind === "skill" ? (0, import_react5.createElement)("label", null, "\u4F7F\u7528\u65F6\u673A\uFF08\u53EF\u9009\uFF09", (0, import_react5.createElement)("input", { className: "te-input", value: whenToUse, disabled: busy, onChange: (e) => setWhenToUse(e.target.value) })) : null, (0, import_react5.createElement)("label", null, "Markdown \u6B63\u6587", (0, import_react5.createElement)("textarea", { className: "te-input te-editor", value: body2, disabled: busy, onChange: (e) => setBody(e.target.value) })))
6144
6385
  ) : null,
6145
- deleting ? (0, import_react4.createElement)(ResourceModal, { title: `\u5220\u9664${noun}\u300C${deleting.name}\u300D\uFF1F`, description: levelOf(deleting) === "user" ? "\u8FD9\u662F\u4E2A\u4EBA\u5168\u5C40\u8D44\u6E90\uFF0C\u5220\u9664\u4F1A\u5F71\u54CD\u6B64\u4E3B\u673A\u4E0A\u7684\u6240\u6709\u9879\u76EE\u3002" : "\u5220\u9664\u5C06\u5F71\u54CD\u5F53\u524D\u9879\u76EE\u3002", onClose: close, footer: (0, import_react4.createElement)("div", { className: "te-actions" }, (0, import_react4.createElement)(import_dsh_client_ui_primitives4.Button, { variant: "outline", disabled: busy, onClick: close }, "\u4FDD\u7559"), (0, import_react4.createElement)("button", { className: "te-danger-button", disabled: busy, onClick: () => {
6386
+ deleting ? (0, import_react5.createElement)(ResourceModal, { title: `\u5220\u9664${noun}\u300C${deleting.name}\u300D\uFF1F`, description: levelOf(deleting) === "user" ? "\u8FD9\u662F\u4E2A\u4EBA\u5168\u5C40\u8D44\u6E90\uFF0C\u5220\u9664\u4F1A\u5F71\u54CD\u6B64\u4E3B\u673A\u4E0A\u7684\u6240\u6709\u9879\u76EE\u3002" : "\u5220\u9664\u5C06\u5F71\u54CD\u5F53\u524D\u9879\u76EE\u3002", onClose: close, footer: (0, import_react5.createElement)("div", { className: "te-actions" }, (0, import_react5.createElement)(import_dsh_client_ui_primitives5.Button, { variant: "outline", disabled: busy, onClick: close }, "\u4FDD\u7559"), (0, import_react5.createElement)("button", { className: "te-danger-button", disabled: busy, onClick: () => {
6146
6387
  void remove();
6147
- } }, busy ? "\u5220\u9664\u4E2D\u2026" : "\u786E\u8BA4\u6C38\u4E45\u5220\u9664")) }, (0, import_react4.createElement)("code", { className: "te-path" }, `${roots?.[levelOf(deleting) === "user" ? "user" : "project"] ?? "\u8D44\u6E90\u76EE\u5F55"}/${deleting.name}${kind === "rule" ? ".md" : ""}`), (0, import_react4.createElement)("p", null, "\u6B64\u64CD\u4F5C\u4E0D\u4F1A\u8FDB\u5165\u56DE\u6536\u7AD9\uFF0C\u8BF7\u786E\u8BA4\u5DF2\u6709\u5907\u4EFD\u3002"), status()) : null
6388
+ } }, busy ? "\u5220\u9664\u4E2D\u2026" : "\u786E\u8BA4\u6C38\u4E45\u5220\u9664")) }, (0, import_react5.createElement)("code", { className: "te-path" }, `${roots?.[levelOf(deleting) === "user" ? "user" : "project"] ?? "\u8D44\u6E90\u76EE\u5F55"}/${deleting.name}${kind === "rule" ? ".md" : ""}`), (0, import_react5.createElement)("p", null, "\u6B64\u64CD\u4F5C\u4E0D\u4F1A\u8FDB\u5165\u56DE\u6536\u7AD9\uFF0C\u8BF7\u786E\u8BA4\u5DF2\u6709\u5907\u4EFD\u3002"), status()) : null
6148
6389
  );
6149
6390
  }
6150
6391
 
6151
6392
  // src/client/SkillManager.tsx
6152
- function SkillManager(props) {
6153
- return (0, import_react5.createElement)(ResourceManager, { ...props, key: props.workspace, kind: "skill" });
6393
+ var import_jsx_runtime3 = require("react/jsx-runtime");
6394
+ function SkillManager({ workspace, remote }) {
6395
+ const [config, setConfig] = (0, import_react6.useState)(null);
6396
+ const [rules, setRules] = (0, import_react6.useState)([]);
6397
+ const [selected, setSelected] = (0, import_react6.useState)(null);
6398
+ const [message, setMessage] = (0, import_react6.useState)("");
6399
+ (0, import_react6.useEffect)(() => {
6400
+ let active = true;
6401
+ void Promise.all([remote.read(workspace), remote.listRules(workspace)]).then(([saved, availableRules]) => {
6402
+ if (!active) return;
6403
+ if (!saved.ok || !saved.value.ok || !availableRules.ok) {
6404
+ setMessage("\u8BFB\u53D6\u6280\u80FD\u89C4\u5219\u914D\u7F6E\u5931\u8D25\uFF0C\u8BF7\u91CD\u65B0\u6253\u5F00\u6280\u80FD\u9875\u3002");
6405
+ return;
6406
+ }
6407
+ const effective = saved.value.config;
6408
+ setConfig(compactProjectConfig({
6409
+ flow: saved.value.flow,
6410
+ stage_bindings: effective.stage_bindings,
6411
+ skill_profiles: effective.skill_profiles,
6412
+ commit: effective.commit,
6413
+ artifacts: effective.artifacts,
6414
+ review_depth: effective.review_depth,
6415
+ commit_required: effective.commit_required
6416
+ }));
6417
+ setRules(availableRules.value.rules);
6418
+ }).catch(() => {
6419
+ if (active) setMessage("\u8BFB\u53D6\u6280\u80FD\u89C4\u5219\u914D\u7F6E\u5931\u8D25\uFF0C\u8BF7\u91CD\u65B0\u6253\u5F00\u6280\u80FD\u9875\u3002");
6420
+ });
6421
+ return () => {
6422
+ active = false;
6423
+ };
6424
+ }, [remote, workspace]);
6425
+ const saveProfile = async (profile) => {
6426
+ if (!config || !selected) throw new Error("\u914D\u7F6E\u5C1A\u672A\u52A0\u8F7D\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002");
6427
+ const key = formatResourceRef(selected);
6428
+ const next = { ...config, skill_profiles: { ...config.skill_profiles, [key]: profile } };
6429
+ const result = await remote.write({ path: workspace, ...next });
6430
+ if (!result.ok || !result.value.ok) throw new Error(result.ok ? result.value.problems.join("\uFF1B") : "\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002");
6431
+ setConfig(next);
6432
+ setMessage(`\u5DF2\u4FDD\u5B58 ${selected.name} \u7684\u89C4\u5219\u914D\u7F6E\u3002`);
6433
+ setSelected(null);
6434
+ };
6435
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { children: [
6436
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ResourceManager, { workspace, remote, kind: "skill", onConfigureSkill: config ? (ref) => {
6437
+ setMessage("");
6438
+ setSelected(ref);
6439
+ } : void 0 }),
6440
+ selected === null && message ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { role: "status", className: "te-success", children: message }) : null,
6441
+ selected !== null ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
6442
+ SkillRuleDialog,
6443
+ {
6444
+ skill: selected,
6445
+ profile: config?.skill_profiles?.[formatResourceRef(selected)],
6446
+ rules,
6447
+ onSave: saveProfile,
6448
+ onClose: () => setSelected(null)
6449
+ },
6450
+ formatResourceRef(selected)
6451
+ ) : null
6452
+ ] });
6154
6453
  }
6155
6454
 
6156
6455
  // src/client/RuleManager.tsx
6157
- var import_react6 = require("react");
6456
+ var import_react7 = require("react");
6158
6457
  function RuleManager(props) {
6159
- return (0, import_react6.createElement)(ResourceManager, { ...props, key: props.workspace, kind: "rule" });
6458
+ return (0, import_react7.createElement)(ResourceManager, { ...props, key: props.workspace, kind: "rule" });
6160
6459
  }
6161
6460
 
6162
6461
  // src/client/TaskLedger.tsx
6163
- var import_react7 = require("react");
6164
- var import_dsh_client_ui_primitives5 = require("@deepseek-ai/dsh-client-ui-primitives");
6462
+ var import_react8 = require("react");
6463
+ var import_dsh_client_ui_primitives6 = require("@deepseek-ai/dsh-client-ui-primitives");
6165
6464
  var card2 = {
6166
6465
  display: "flex",
6167
6466
  flexDirection: "column",
@@ -6199,10 +6498,10 @@ var badge = {
6199
6498
  color: "var(--dsw-alias-label-secondary)"
6200
6499
  };
6201
6500
  function verdictDot(outcome) {
6202
- return (0, import_react7.createElement)(import_dsh_client_ui_primitives5.StateDot, { state: outcome === "pass" ? "done" : "error" });
6501
+ return (0, import_react8.createElement)(import_dsh_client_ui_primitives6.StateDot, { state: outcome === "pass" ? "done" : "error" });
6203
6502
  }
6204
6503
  function itemStatusDot(status) {
6205
- return (0, import_react7.createElement)(import_dsh_client_ui_primitives5.StateDot, { state: status === "done" ? "done" : "ongoing" });
6504
+ return (0, import_react8.createElement)(import_dsh_client_ui_primitives6.StateDot, { state: status === "done" ? "done" : "ongoing" });
6206
6505
  }
6207
6506
  function timeText(at) {
6208
6507
  return at.slice(0, 19).replace("T", " ");
@@ -6210,48 +6509,48 @@ function timeText(at) {
6210
6509
  function itemAudit(item) {
6211
6510
  const lines = [];
6212
6511
  if (item.dispatch !== void 0) {
6213
- lines.push((0, import_react7.createElement)(
6512
+ lines.push((0, import_react8.createElement)(
6214
6513
  "div",
6215
6514
  { key: "dispatch", style: metaLine },
6216
- (0, import_react7.createElement)("span", { style: badge }, "\u5DF2\u6D3E\u53D1"),
6217
- (0, import_react7.createElement)("span", null, item.dispatch.description === "" ? "\uFF08\u65E0\u63CF\u8FF0\uFF09" : item.dispatch.description),
6218
- (0, import_react7.createElement)("span", { style: badge }, timeText(item.dispatch.at))
6515
+ (0, import_react8.createElement)("span", { style: badge }, "\u5DF2\u6D3E\u53D1"),
6516
+ (0, import_react8.createElement)("span", null, item.dispatch.description === "" ? "\uFF08\u65E0\u63CF\u8FF0\uFF09" : item.dispatch.description),
6517
+ (0, import_react8.createElement)("span", { style: badge }, timeText(item.dispatch.at))
6219
6518
  ));
6220
6519
  }
6221
6520
  if (item.review !== void 0) {
6222
6521
  const spec = item.review.spec;
6223
6522
  const quality = item.review.quality;
6224
- lines.push((0, import_react7.createElement)(
6523
+ lines.push((0, import_react8.createElement)(
6225
6524
  "div",
6226
6525
  { key: "review", style: metaLine },
6227
6526
  verdictDot(spec.outcome),
6228
- (0, import_react7.createElement)("span", null, `\u89C4\u683C\u7B26\u5408 ${spec.outcome === "pass" ? "\u901A\u8FC7" : "\u4E0D\u901A\u8FC7"}`),
6229
- (0, import_react7.createElement)("span", null, "\xB7"),
6527
+ (0, import_react8.createElement)("span", null, `\u89C4\u683C\u7B26\u5408 ${spec.outcome === "pass" ? "\u901A\u8FC7" : "\u4E0D\u901A\u8FC7"}`),
6528
+ (0, import_react8.createElement)("span", null, "\xB7"),
6230
6529
  verdictDot(quality.outcome),
6231
- (0, import_react7.createElement)("span", null, `\u4EE3\u7801\u8D28\u91CF ${quality.outcome === "pass" ? "\u901A\u8FC7" : "\u4E0D\u901A\u8FC7"}`)
6530
+ (0, import_react8.createElement)("span", null, `\u4EE3\u7801\u8D28\u91CF ${quality.outcome === "pass" ? "\u901A\u8FC7" : "\u4E0D\u901A\u8FC7"}`)
6232
6531
  ));
6233
6532
  const failNotes = [spec, quality].flatMap((stage) => stage.outcome === "fail" ? stage.notes ?? [] : []);
6234
6533
  if (failNotes.length > 0) {
6235
- lines.push((0, import_react7.createElement)(
6534
+ lines.push((0, import_react8.createElement)(
6236
6535
  "div",
6237
6536
  { key: "notes", style: metaLine },
6238
- ...failNotes.map((note) => (0, import_react7.createElement)("span", { key: note, style: badge }, note))
6537
+ ...failNotes.map((note) => (0, import_react8.createElement)("span", { key: note, style: badge }, note))
6239
6538
  ));
6240
6539
  }
6241
6540
  }
6242
6541
  if (lines.length === 0) {
6243
- lines.push((0, import_react7.createElement)("div", { key: "none", style: metaLine }, (0, import_react7.createElement)("span", { style: badge }, "\u672A\u6D3E\u53D1 / \u672A\u5BA1\u67E5")));
6542
+ lines.push((0, import_react8.createElement)("div", { key: "none", style: metaLine }, (0, import_react8.createElement)("span", { style: badge }, "\u672A\u6D3E\u53D1 / \u672A\u5BA1\u67E5")));
6244
6543
  }
6245
- return (0, import_react7.createElement)("div", { style: { display: "flex", flexDirection: "column", gap: 4 } }, ...lines);
6544
+ return (0, import_react8.createElement)("div", { style: { display: "flex", flexDirection: "column", gap: 4 } }, ...lines);
6246
6545
  }
6247
6546
  function TaskLedger({ workspace, remote }) {
6248
- const [tasks, setTasks] = (0, import_react7.useState)([]);
6249
- const [error, setError] = (0, import_react7.useState)("");
6250
- const [loading, setLoading] = (0, import_react7.useState)(true);
6251
- const [query, setQuery] = (0, import_react7.useState)("");
6252
- const [risk, setRisk] = (0, import_react7.useState)("all");
6253
- const [stage, setStage] = (0, import_react7.useState)("all");
6254
- const refresh = (0, import_react7.useCallback)(() => {
6547
+ const [tasks, setTasks] = (0, import_react8.useState)([]);
6548
+ const [error, setError] = (0, import_react8.useState)("");
6549
+ const [loading, setLoading] = (0, import_react8.useState)(true);
6550
+ const [query, setQuery] = (0, import_react8.useState)("");
6551
+ const [risk, setRisk] = (0, import_react8.useState)("all");
6552
+ const [stage, setStage] = (0, import_react8.useState)("all");
6553
+ const refresh = (0, import_react8.useCallback)(() => {
6255
6554
  if (workspace === "") return;
6256
6555
  setError("");
6257
6556
  setLoading(true);
@@ -6264,57 +6563,57 @@ function TaskLedger({ workspace, remote }) {
6264
6563
  setError("\u8BFB\u53D6\u53F0\u8D26\u5931\u8D25\uFF1A" + describeError(reason));
6265
6564
  });
6266
6565
  }, [remote, workspace]);
6267
- (0, import_react7.useEffect)(() => {
6566
+ (0, import_react8.useEffect)(() => {
6268
6567
  refresh();
6269
6568
  }, [refresh]);
6270
6569
  const visible = tasks.filter((task) => `${task.task_id} ${task.title} ${task.branch}`.toLowerCase().includes(query.toLowerCase()) && (risk === "all" || task.risk_level === risk) && (stage === "all" || task.stage === stage));
6271
- return (0, import_react7.createElement)(
6570
+ return (0, import_react8.createElement)(
6272
6571
  "div",
6273
6572
  { style: styles.section },
6274
- (0, import_react7.createElement)(
6573
+ (0, import_react8.createElement)(
6275
6574
  "div",
6276
6575
  { className: "te-toolbar" },
6277
- (0, import_react7.createElement)("input", { className: "te-input", placeholder: "\u641C\u7D22\u4EFB\u52A1\u3001\u6807\u9898\u6216\u5206\u652F", value: query, onChange: (e) => setQuery(e.target.value) }),
6278
- (0, import_react7.createElement)("select", { className: "te-input", "aria-label": "\u98CE\u9669\u7B5B\u9009", value: risk, onChange: (e) => setRisk(e.target.value) }, (0, import_react7.createElement)("option", { value: "all" }, "\u5168\u90E8\u98CE\u9669"), (0, import_react7.createElement)("option", { value: "standard" }, "\u6807\u51C6"), (0, import_react7.createElement)("option", { value: "high_risk" }, "\u9AD8\u98CE\u9669")),
6279
- (0, import_react7.createElement)("select", { className: "te-input", "aria-label": "\u9636\u6BB5\u7B5B\u9009", value: stage, onChange: (e) => setStage(e.target.value) }, (0, import_react7.createElement)("option", { value: "all" }, "\u5168\u90E8\u9636\u6BB5"), ...Array.from(new Set(tasks.map((t) => t.stage))).map((value) => (0, import_react7.createElement)("option", { key: value, value }, value)))
6576
+ (0, import_react8.createElement)("input", { className: "te-input", placeholder: "\u641C\u7D22\u4EFB\u52A1\u3001\u6807\u9898\u6216\u5206\u652F", value: query, onChange: (e) => setQuery(e.target.value) }),
6577
+ (0, import_react8.createElement)("select", { className: "te-input", "aria-label": "\u98CE\u9669\u7B5B\u9009", value: risk, onChange: (e) => setRisk(e.target.value) }, (0, import_react8.createElement)("option", { value: "all" }, "\u5168\u90E8\u98CE\u9669"), (0, import_react8.createElement)("option", { value: "standard" }, "\u6807\u51C6"), (0, import_react8.createElement)("option", { value: "high_risk" }, "\u9AD8\u98CE\u9669")),
6578
+ (0, import_react8.createElement)("select", { className: "te-input", "aria-label": "\u9636\u6BB5\u7B5B\u9009", value: stage, onChange: (e) => setStage(e.target.value) }, (0, import_react8.createElement)("option", { value: "all" }, "\u5168\u90E8\u9636\u6BB5"), ...Array.from(new Set(tasks.map((t) => t.stage))).map((value) => (0, import_react8.createElement)("option", { key: value, value }, value)))
6280
6579
  ),
6281
- (0, import_react7.createElement)(
6580
+ (0, import_react8.createElement)(
6282
6581
  "div",
6283
6582
  { style: headerRow },
6284
- (0, import_react7.createElement)("span", { style: styles.bindingLabel }, "\u4EFB\u52A1\u53F0\u8D26"),
6285
- (0, import_react7.createElement)("span", { style: styles.sourceBadge }, "\u53EA\u8BFB \xB7 \u6765\u81EA .dsh/task-*.json"),
6286
- (0, import_react7.createElement)(import_dsh_client_ui_primitives5.Button, { variant: "outline", size: "sm", disabled: loading, onClick: refresh }, loading ? "\u8BFB\u53D6\u4E2D\u2026" : "\u5237\u65B0")
6583
+ (0, import_react8.createElement)("span", { style: styles.bindingLabel }, "\u4EFB\u52A1\u53F0\u8D26"),
6584
+ (0, import_react8.createElement)("span", { style: styles.sourceBadge }, "\u53EA\u8BFB \xB7 \u6765\u81EA .dsh/task-*.json"),
6585
+ (0, import_react8.createElement)(import_dsh_client_ui_primitives6.Button, { variant: "outline", size: "sm", disabled: loading, onClick: refresh }, loading ? "\u8BFB\u53D6\u4E2D\u2026" : "\u5237\u65B0")
6287
6586
  ),
6288
- loading ? (0, import_react7.createElement)("p", { role: "status" }, "\u6B63\u5728\u8BFB\u53D6\u4EFB\u52A1\u2026") : error !== "" ? (0, import_react7.createElement)("p", { style: styles.status }, error) : tasks.length === 0 ? (0, import_react7.createElement)("p", { style: styles.muted }, "\u5F53\u524D\u5DE5\u4F5C\u533A\u8FD8\u6CA1\u6709\u4EFB\u52A1\uFF1A\u5F00\u5DE5\u540E\uFF08dev_task create\uFF09\u4F1A\u5728\u8FD9\u91CC\u5217\u51FA\u6D3E\u53D1\u4E0E\u5BA1\u67E5\u7559\u75D5\u3002") : visible.length === 0 ? (0, import_react7.createElement)("div", { className: "te-empty" }, "\u6CA1\u6709\u5339\u914D\u7684\u4EFB\u52A1\uFF0C\u8BF7\u8C03\u6574\u7B5B\u9009\u3002") : (0, import_react7.createElement)(
6587
+ loading ? (0, import_react8.createElement)("p", { role: "status" }, "\u6B63\u5728\u8BFB\u53D6\u4EFB\u52A1\u2026") : error !== "" ? (0, import_react8.createElement)("p", { style: styles.status }, error) : tasks.length === 0 ? (0, import_react8.createElement)("p", { style: styles.muted }, "\u5F53\u524D\u5DE5\u4F5C\u533A\u8FD8\u6CA1\u6709\u4EFB\u52A1\uFF1A\u5F00\u5DE5\u540E\uFF08dev_task create\uFF09\u4F1A\u5728\u8FD9\u91CC\u5217\u51FA\u6D3E\u53D1\u4E0E\u5BA1\u67E5\u7559\u75D5\u3002") : visible.length === 0 ? (0, import_react8.createElement)("div", { className: "te-empty" }, "\u6CA1\u6709\u5339\u914D\u7684\u4EFB\u52A1\uFF0C\u8BF7\u8C03\u6574\u7B5B\u9009\u3002") : (0, import_react8.createElement)(
6289
6588
  "div",
6290
6589
  { style: { display: "flex", flexDirection: "column", gap: 12 } },
6291
- ...visible.map((task) => (0, import_react7.createElement)(
6590
+ ...visible.map((task) => (0, import_react8.createElement)(
6292
6591
  "div",
6293
6592
  { key: task.task_id, style: card2 },
6294
- (0, import_react7.createElement)(
6593
+ (0, import_react8.createElement)(
6295
6594
  "div",
6296
6595
  { style: headerRow },
6297
- (0, import_react7.createElement)("span", { style: { fontSize: 14, fontWeight: 600, color: "var(--dsw-alias-label-primary)" } }, task.task_id),
6298
- (0, import_react7.createElement)("span", { style: { fontSize: 13, color: "var(--dsw-alias-label-primary)" } }, task.title),
6299
- (0, import_react7.createElement)("span", { style: badge }, task.stage),
6300
- (0, import_react7.createElement)("span", { style: badge }, task.branch),
6301
- (0, import_react7.createElement)("span", { className: "te-badge", style: task.risk_level === "high_risk" ? { color: "var(--dsw-alias-state-error-primary)" } : {} }, task.risk_level === "high_risk" ? "\u9AD8\u98CE\u9669" : "\u6807\u51C6"),
6302
- (0, import_react7.createElement)("span", { className: "te-badge" }, task.verification_passed ? "\u9A8C\u8BC1\u901A\u8FC7" : "\u5F85\u9A8C\u8BC1"),
6303
- (0, import_react7.createElement)("span", { className: "te-badge" }, `\u5BA1\u6838\uFF1A${task.review_outcome ?? "pending"}`),
6304
- task.updated_at ? (0, import_react7.createElement)("span", { style: metaLine }, "\u66F4\u65B0\u4E8E " + timeText(task.updated_at)) : null
6596
+ (0, import_react8.createElement)("span", { style: { fontSize: 14, fontWeight: 600, color: "var(--dsw-alias-label-primary)" } }, task.task_id),
6597
+ (0, import_react8.createElement)("span", { style: { fontSize: 13, color: "var(--dsw-alias-label-primary)" } }, task.title),
6598
+ (0, import_react8.createElement)("span", { style: badge }, task.stage),
6599
+ (0, import_react8.createElement)("span", { style: badge }, task.branch),
6600
+ (0, import_react8.createElement)("span", { className: "te-badge", style: task.risk_level === "high_risk" ? { color: "var(--dsw-alias-state-error-primary)" } : {} }, task.risk_level === "high_risk" ? "\u9AD8\u98CE\u9669" : "\u6807\u51C6"),
6601
+ (0, import_react8.createElement)("span", { className: "te-badge" }, task.verification_passed ? "\u9A8C\u8BC1\u901A\u8FC7" : "\u5F85\u9A8C\u8BC1"),
6602
+ (0, import_react8.createElement)("span", { className: "te-badge" }, `\u5BA1\u6838\uFF1A${task.review_outcome ?? "pending"}`),
6603
+ task.updated_at ? (0, import_react8.createElement)("span", { style: metaLine }, "\u66F4\u65B0\u4E8E " + timeText(task.updated_at)) : null
6305
6604
  ),
6306
- (0, import_react7.createElement)(
6605
+ (0, import_react8.createElement)(
6307
6606
  "div",
6308
6607
  { style: { display: "flex", flexDirection: "column" } },
6309
- ...task.items.map((item) => (0, import_react7.createElement)(
6608
+ ...task.items.map((item) => (0, import_react8.createElement)(
6310
6609
  "div",
6311
6610
  { key: item.id, style: itemRow },
6312
- (0, import_react7.createElement)(
6611
+ (0, import_react8.createElement)(
6313
6612
  "div",
6314
6613
  { style: headerRow },
6315
6614
  itemStatusDot(item.status),
6316
- (0, import_react7.createElement)("span", { style: { fontSize: 13, color: "var(--dsw-alias-label-primary)" } }, item.id),
6317
- (0, import_react7.createElement)("span", { style: { fontSize: 12, color: "var(--dsw-alias-label-secondary)" } }, item.title)
6615
+ (0, import_react8.createElement)("span", { style: { fontSize: 13, color: "var(--dsw-alias-label-primary)" } }, item.id),
6616
+ (0, import_react8.createElement)("span", { style: { fontSize: 12, color: "var(--dsw-alias-label-secondary)" } }, item.title)
6318
6617
  ),
6319
6618
  itemAudit(item)
6320
6619
  ))
@@ -6355,7 +6654,7 @@ var tabbar = {
6355
6654
  var body = {
6356
6655
  flex: 1,
6357
6656
  overflowY: "auto",
6358
- padding: "24px clamp(12px, 3vw, 32px)"
6657
+ padding: "16px clamp(12px, 2vw, 28px)"
6359
6658
  };
6360
6659
  var selectStyle = {
6361
6660
  marginLeft: "auto",
@@ -6388,29 +6687,29 @@ var TABS = [
6388
6687
  function Workbench({ useStore, actions, useWorkspaces, remote }) {
6389
6688
  const open = useStore((s) => s.open);
6390
6689
  const workspaces = useWorkspaces((s) => s.items);
6391
- const [tab, setTab] = (0, import_react8.useState)("init");
6392
- const [workspace, setWorkspace] = (0, import_react8.useState)("");
6690
+ const [tab, setTab] = (0, import_react9.useState)("init");
6691
+ const [workspace, setWorkspace] = (0, import_react9.useState)("");
6393
6692
  if (!open) return null;
6394
6693
  const current = workspaces.some((w) => w.path === workspace) ? workspace : workspaces[0]?.path ?? "";
6395
- return (0, import_react8.createElement)(
6694
+ return (0, import_react9.createElement)(
6396
6695
  "div",
6397
6696
  { style: overlay, className: "te-workbench" },
6398
- (0, import_react8.createElement)("style", null, workbenchTheme),
6399
- (0, import_react8.createElement)(
6697
+ (0, import_react9.createElement)("style", null, workbenchTheme),
6698
+ (0, import_react9.createElement)(
6400
6699
  "div",
6401
6700
  { style: header },
6402
- (0, import_react8.createElement)(
6701
+ (0, import_react9.createElement)(
6403
6702
  "div",
6404
6703
  { style: headerBrand },
6405
- (0, import_react8.createElement)(import_dsh_client_ui_primitives6.IconSettingsOutline16, { size: 18 }),
6406
- (0, import_react8.createElement)(
6704
+ (0, import_react9.createElement)(import_dsh_client_ui_primitives7.IconSettingsOutline16, { size: 18 }),
6705
+ (0, import_react9.createElement)(
6407
6706
  "div",
6408
6707
  { style: headerText },
6409
- (0, import_react8.createElement)("span", { style: headerTitle }, "\u5DE5\u7A0B\u6D41\u7A0B"),
6410
- (0, import_react8.createElement)("p", { style: headerSub }, "\u5DE5\u7A0B\u5316\u4EA4\u4ED8\u5DE5\u4F5C\u53F0 \xB7 \u9700\u6C42\u8BC4\u5BA1 \u2192 \u8BBE\u8BA1 \u2192 \u5F00\u53D1 \u2192 \u4EA4\u4ED8 \u2192 \u4EE3\u7801\u5BA1\u6838")
6708
+ (0, import_react9.createElement)("span", { style: headerTitle }, "\u5DE5\u7A0B\u6D41\u7A0B"),
6709
+ (0, import_react9.createElement)("p", { style: headerSub }, "\u5DE5\u7A0B\u5316\u4EA4\u4ED8\u5DE5\u4F5C\u53F0 \xB7 \u9700\u6C42\u8BC4\u5BA1 \u2192 \u8BBE\u8BA1 \u2192 \u5F00\u53D1 \u2192 \u4EA4\u4ED8 \u2192 \u4EE3\u7801\u5BA1\u6838")
6411
6710
  )
6412
6711
  ),
6413
- (0, import_react8.createElement)(
6712
+ (0, import_react9.createElement)(
6414
6713
  "button",
6415
6714
  {
6416
6715
  type: "button",
@@ -6426,44 +6725,44 @@ function Workbench({ useStore, actions, useWorkspaces, remote }) {
6426
6725
  event.currentTarget.style.background = "transparent";
6427
6726
  }
6428
6727
  },
6429
- (0, import_react8.createElement)(import_dsh_client_ui_primitives6.IconCloseOutline16, { size: 16 })
6728
+ (0, import_react9.createElement)(import_dsh_client_ui_primitives7.IconCloseOutline16, { size: 16 })
6430
6729
  )
6431
6730
  ),
6432
- (0, import_react8.createElement)(
6731
+ (0, import_react9.createElement)(
6433
6732
  "div",
6434
6733
  { style: tabbar },
6435
- ...TABS.map((t) => (0, import_react8.createElement)(import_dsh_client_ui_primitives6.Pill, { key: t.id, active: tab === t.id, onClick: () => {
6734
+ ...TABS.map((t) => (0, import_react9.createElement)(import_dsh_client_ui_primitives7.Pill, { key: t.id, active: tab === t.id, onClick: () => {
6436
6735
  setTab(t.id);
6437
6736
  } }, t.label)),
6438
- workspaces.length > 0 ? (0, import_react8.createElement)("select", {
6737
+ workspaces.length > 0 ? (0, import_react9.createElement)("select", {
6439
6738
  style: selectStyle,
6440
6739
  "aria-label": "\u5F53\u524D\u5DE5\u4F5C\u533A",
6441
6740
  value: current,
6442
6741
  onChange: (ev) => {
6443
6742
  setWorkspace(ev.target.value);
6444
6743
  }
6445
- }, ...workspaces.map((w) => (0, import_react8.createElement)("option", { key: w.path, value: w.path }, w.title || w.path))) : null
6744
+ }, ...workspaces.map((w) => (0, import_react9.createElement)("option", { key: w.path, value: w.path }, w.title || w.path))) : null
6446
6745
  ),
6447
- (0, import_react8.createElement)(
6746
+ (0, import_react9.createElement)(
6448
6747
  "div",
6449
6748
  { style: body },
6450
- (0, import_react8.createElement)(
6749
+ (0, import_react9.createElement)(
6451
6750
  "div",
6452
6751
  { className: "te-content", key: current },
6453
- (0, import_react8.createElement)("p", { style: { ...styles.hint, marginBottom: 20 }, title: current }, "\u5DE5\u4F5C\u533A \xB7 " + current),
6454
- current === "" ? (0, import_react8.createElement)("p", { style: styles.muted }, "\u5F53\u524D\u6CA1\u6709\u5DE5\u4F5C\u533A\uFF1A\u8BF7\u5148\u5728\u4FA7\u680F\u521B\u5EFA\u4E00\u4E2A\u5DE5\u4F5C\u533A\uFF0C\u518D\u56DE\u6765\u914D\u7F6E\u6D41\u7A0B\u3002") : tab === "init" ? (0, import_react8.createElement)(InitPanel, { workspace: current, remote }) : tab === "flow" ? (0, import_react8.createElement)(TaskEngineSection, { workspace: current, remote }) : tab === "tasks" ? (0, import_react8.createElement)(TaskLedger, { workspace: current, remote }) : tab === "skills" ? (0, import_react8.createElement)(SkillManager, { workspace: current, remote }) : (0, import_react8.createElement)(RuleManager, { workspace: current, remote })
6752
+ (0, import_react9.createElement)("p", { style: { ...styles.hint, marginBottom: 10 }, title: current }, "\u5DE5\u4F5C\u533A \xB7 " + current),
6753
+ current === "" ? (0, import_react9.createElement)("p", { style: styles.muted }, "\u5F53\u524D\u6CA1\u6709\u5DE5\u4F5C\u533A\uFF1A\u8BF7\u5148\u5728\u4FA7\u680F\u521B\u5EFA\u4E00\u4E2A\u5DE5\u4F5C\u533A\uFF0C\u518D\u56DE\u6765\u914D\u7F6E\u6D41\u7A0B\u3002") : tab === "init" ? (0, import_react9.createElement)(InitPanel, { workspace: current, remote }) : tab === "flow" ? (0, import_react9.createElement)(TaskEngineSection, { workspace: current, remote }) : tab === "tasks" ? (0, import_react9.createElement)(TaskLedger, { workspace: current, remote }) : tab === "skills" ? (0, import_react9.createElement)(SkillManager, { workspace: current, remote }) : (0, import_react9.createElement)(RuleManager, { workspace: current, remote })
6455
6754
  )
6456
6755
  )
6457
6756
  );
6458
6757
  }
6459
6758
 
6460
6759
  // src/client/TriggerButton.tsx
6461
- var import_react9 = require("react");
6462
- var import_dsh_client_ui_primitives7 = require("@deepseek-ai/dsh-client-ui-primitives");
6760
+ var import_react10 = require("react");
6761
+ var import_dsh_client_ui_primitives8 = require("@deepseek-ai/dsh-client-ui-primitives");
6463
6762
  var hover = "var(--dsw-alias-bg-layer-2)";
6464
6763
  var label = "var(--dsw-alias-label-primary)";
6465
6764
  function TriggerButton({ wide, actions }) {
6466
- return (0, import_react9.createElement)(
6765
+ return (0, import_react10.createElement)(
6467
6766
  "button",
6468
6767
  {
6469
6768
  type: "button",
@@ -6503,8 +6802,8 @@ function TriggerButton({ wide, actions }) {
6503
6802
  transition: "background 120ms ease"
6504
6803
  }
6505
6804
  },
6506
- (0, import_react9.createElement)(import_dsh_client_ui_primitives7.IconSettingsOutline16, { size: wide ? 16 : 18 }),
6507
- wide ? (0, import_react9.createElement)("span", { style: { fontSize: 14, lineHeight: "22px" } }, "\u5DE5\u7A0B\u6D41\u7A0B") : null
6805
+ (0, import_react10.createElement)(import_dsh_client_ui_primitives8.IconSettingsOutline16, { size: wide ? 16 : 18 }),
6806
+ wide ? (0, import_react10.createElement)("span", { style: { fontSize: 14, lineHeight: "22px" } }, "\u5DE5\u7A0B\u6D41\u7A0B") : null
6508
6807
  );
6509
6808
  }
6510
6809