@godv61/dsh-task-engine 0.22.7 → 0.23.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 (68) hide show
  1. package/.p0-test.mjs +739 -748
  2. package/.resource-test.mjs +133 -0
  3. package/.workflow-test.mjs +234 -0
  4. package/LICENSE +21 -0
  5. package/README.md +110 -207
  6. package/cordis.patch.yml +10 -10
  7. package/defaults/eng.json +10 -10
  8. package/docs/CHANGELOG.md +185 -0
  9. package/docs/README.md +27 -0
  10. package/docs/assets/workflow-banner.svg +29 -0
  11. package/docs/configuration.md +49 -0
  12. package/docs/development.md +53 -0
  13. package/docs/faq.md +43 -0
  14. package/docs/getting-started.md +51 -0
  15. package/docs/listing/godv61__dsh-task-engine.yml +6 -0
  16. package/docs/listing/submission.md +9 -0
  17. package/docs/manual.html +391 -382
  18. package/docs/release-0.23.0.md +32 -0
  19. package/docs/release-0.23.1.md +58 -0
  20. package/docs/resource-install.md +62 -0
  21. package/docs/roadmap.md +33 -0
  22. package/docs/testing/0.23.0//346/265/213/350/257/225/346/211/247/350/241/214/350/256/260/345/275/225.md +189 -0
  23. package/docs/testing/0.23.0//346/265/213/350/257/225/346/212/245/345/221/212.md +42 -0
  24. package/docs/testing/0.23.1//346/265/213/350/257/225/346/212/245/345/221/212.md +34 -0
  25. package/docs/testing/0.23.1//350/207/252/345/212/250/345/214/226/346/265/213/350/257/225/346/230/216/347/273/206.md +41 -0
  26. package/docs/workflow-regression.md +36 -0
  27. package/hooks/commit-msg +4 -4
  28. package/lib/client.js +555 -868
  29. package/lib/client.js.map +4 -4
  30. package/lib/controller.d.ts +19 -0
  31. package/lib/controller.js +86 -137
  32. package/lib/controller.js.map +1 -1
  33. package/lib/dev-task.js +190 -37
  34. package/lib/dev-task.js.map +1 -1
  35. package/lib/engine.d.ts +19 -1
  36. package/lib/engine.js +5 -0
  37. package/lib/engine.js.map +1 -1
  38. package/lib/resource-import.d.ts +21 -0
  39. package/lib/resource-import.js +210 -0
  40. package/lib/resource-import.js.map +1 -0
  41. package/lib/resource-types.d.ts +25 -0
  42. package/lib/resource-types.js +2 -0
  43. package/lib/resource-types.js.map +1 -0
  44. package/lib/shipped-skills.js +2 -1
  45. package/lib/shipped-skills.js.map +1 -1
  46. package/lib/skill-audit.d.ts +16 -0
  47. package/lib/skill-audit.js +60 -0
  48. package/lib/skill-audit.js.map +1 -0
  49. package/lib/workflows.js +4 -4
  50. package/lib/workflows.js.map +1 -1
  51. package/lib/workspace-access.d.ts +6 -0
  52. package/lib/workspace-access.js +13 -0
  53. package/lib/workspace-access.js.map +1 -0
  54. package/package.json +95 -85
  55. package/preset/agent.cordis.yml +21 -21
  56. package/preset/enable.mjs +87 -87
  57. package/preset/persona.md +4 -4
  58. package/preset/preset.yml +1 -1
  59. package/rules/coding-conventions.md +6 -6
  60. package/rules/commit-conventions.md +5 -5
  61. package/rules/security-redlines.md +5 -5
  62. package/skills/code-commit/SKILL.md +13 -13
  63. package/skills/code-implement/SKILL.md +23 -22
  64. package/skills/code-review/SKILL.md +13 -13
  65. package/skills/code-verify/SKILL.md +16 -11
  66. package/skills/eng-delivery/SKILL.md +38 -34
  67. package/skills/requirement-analysis/SKILL.md +15 -15
  68. package/skills/solution-design/SKILL.md +18 -15
package/lib/client.js CHANGED
@@ -28,7 +28,7 @@ __export(index_exports, {
28
28
  });
29
29
  module.exports = __toCommonJS(index_exports);
30
30
 
31
- // node_modules/zod/v3/external.js
31
+ // D:/dsharness/my-dsh/dsh-task-engine/node_modules/zod/v3/external.js
32
32
  var external_exports = {};
33
33
  __export(external_exports, {
34
34
  BRAND: () => BRAND,
@@ -140,7 +140,7 @@ __export(external_exports, {
140
140
  void: () => voidType
141
141
  });
142
142
 
143
- // node_modules/zod/v3/helpers/util.js
143
+ // D:/dsharness/my-dsh/dsh-task-engine/node_modules/zod/v3/helpers/util.js
144
144
  var util;
145
145
  (function(util2) {
146
146
  util2.assertEqual = (_) => {
@@ -274,7 +274,7 @@ var getParsedType = (data) => {
274
274
  }
275
275
  };
276
276
 
277
- // node_modules/zod/v3/ZodError.js
277
+ // D:/dsharness/my-dsh/dsh-task-engine/node_modules/zod/v3/ZodError.js
278
278
  var ZodIssueCode = util.arrayToEnum([
279
279
  "invalid_type",
280
280
  "invalid_literal",
@@ -392,7 +392,7 @@ ZodError.create = (issues) => {
392
392
  return error;
393
393
  };
394
394
 
395
- // node_modules/zod/v3/locales/en.js
395
+ // D:/dsharness/my-dsh/dsh-task-engine/node_modules/zod/v3/locales/en.js
396
396
  var errorMap = (issue, _ctx) => {
397
397
  let message;
398
398
  switch (issue.code) {
@@ -495,7 +495,7 @@ var errorMap = (issue, _ctx) => {
495
495
  };
496
496
  var en_default = errorMap;
497
497
 
498
- // node_modules/zod/v3/errors.js
498
+ // D:/dsharness/my-dsh/dsh-task-engine/node_modules/zod/v3/errors.js
499
499
  var overrideErrorMap = en_default;
500
500
  function setErrorMap(map) {
501
501
  overrideErrorMap = map;
@@ -504,7 +504,7 @@ function getErrorMap() {
504
504
  return overrideErrorMap;
505
505
  }
506
506
 
507
- // node_modules/zod/v3/helpers/parseUtil.js
507
+ // D:/dsharness/my-dsh/dsh-task-engine/node_modules/zod/v3/helpers/parseUtil.js
508
508
  var makeIssue = (params) => {
509
509
  const { data, path, errorMaps, issueData } = params;
510
510
  const fullPath = [...path, ...issueData.path || []];
@@ -614,14 +614,14 @@ var isDirty = (x) => x.status === "dirty";
614
614
  var isValid = (x) => x.status === "valid";
615
615
  var isAsync = (x) => typeof Promise !== "undefined" && x instanceof Promise;
616
616
 
617
- // node_modules/zod/v3/helpers/errorUtil.js
617
+ // D:/dsharness/my-dsh/dsh-task-engine/node_modules/zod/v3/helpers/errorUtil.js
618
618
  var errorUtil;
619
619
  (function(errorUtil2) {
620
620
  errorUtil2.errToObj = (message) => typeof message === "string" ? { message } : message || {};
621
621
  errorUtil2.toString = (message) => typeof message === "string" ? message : message?.message;
622
622
  })(errorUtil || (errorUtil = {}));
623
623
 
624
- // node_modules/zod/v3/types.js
624
+ // D:/dsharness/my-dsh/dsh-task-engine/node_modules/zod/v3/types.js
625
625
  var ParseInputLazyPath = class {
626
626
  constructor(parent, value, path, key) {
627
627
  this._cachedPath = [];
@@ -4206,6 +4206,10 @@ var taskLedgerItemSchema = external_exports.object({
4206
4206
  });
4207
4207
  var taskLedgerViewSchema = external_exports.object({
4208
4208
  tasks: external_exports.array(external_exports.object({
4209
+ risk_level: external_exports.string().optional(),
4210
+ updated_at: external_exports.string().optional(),
4211
+ verification_passed: external_exports.boolean().optional(),
4212
+ review_outcome: external_exports.string().optional(),
4209
4213
  task_id: external_exports.string(),
4210
4214
  title: external_exports.string(),
4211
4215
  stage: external_exports.string(),
@@ -4238,10 +4242,37 @@ var initDraftSchema = external_exports.object({
4238
4242
  lines: external_exports.number(),
4239
4243
  error: external_exports.string().optional()
4240
4244
  });
4245
+ var resourceRequestSchema = external_exports.object({
4246
+ kind: external_exports.enum(["skill", "rule"]),
4247
+ level: external_exports.enum(["project", "user"]),
4248
+ path: external_exports.string(),
4249
+ files: external_exports.array(external_exports.object({ path: external_exports.string(), base64: external_exports.string() })).max(1e3),
4250
+ sourceDir: external_exports.string().optional(),
4251
+ expectedHash: external_exports.string().optional()
4252
+ });
4253
+ var resourcePreviewSchema = external_exports.object({ ok: external_exports.boolean(), name: external_exports.string(), description: external_exports.string(), content: external_exports.string(), target: external_exports.string(), files: external_exports.number(), bytes: external_exports.number(), hash: external_exports.string(), conflict: external_exports.boolean(), error: external_exports.string().optional() });
4241
4254
  var PACKAGE = "@godv61/dsh-task-engine";
4242
4255
  var TYPERT_REMOTE = {
4243
4256
  package: PACKAGE,
4244
4257
  descriptors: [
4258
+ ...["previewResource", "importResource"].map((method) => ({
4259
+ id: `${PACKAGE}#task-engine/${method}`,
4260
+ service: "taskEngineController",
4261
+ namespace: "task-engine",
4262
+ method,
4263
+ invocation: { kind: "direct" },
4264
+ parameters: [{ name: "request", wire: "request", source: "json", codec: { mode: "strict", typeSymbol: `${PACKAGE}/types#ResourceImportRequest`, schema: resourceRequestSchema } }],
4265
+ result: { mode: "strict", typeSymbol: `${PACKAGE}/types#ResourcePreview`, schema: resourcePreviewSchema }
4266
+ })),
4267
+ {
4268
+ id: `${PACKAGE}#task-engine/resourceRoots`,
4269
+ service: "taskEngineController",
4270
+ namespace: "task-engine",
4271
+ method: "resourceRoots",
4272
+ invocation: { kind: "direct" },
4273
+ parameters: [{ name: "request", wire: "request", source: "json", codec: { mode: "strict", typeSymbol: `${PACKAGE}/types#ResourceRootsRequest`, schema: external_exports.object({ kind: external_exports.enum(["skill", "rule"]), path: external_exports.string() }) } }],
4274
+ result: { mode: "strict", typeSymbol: `${PACKAGE}/types#ResourceRoots`, schema: external_exports.object({ project: external_exports.string(), user: external_exports.string() }) }
4275
+ },
4245
4276
  {
4246
4277
  id: `${PACKAGE}#task-engine/read`,
4247
4278
  service: "taskEngineController",
@@ -4503,8 +4534,59 @@ var TYPERT_REMOTE = {
4503
4534
  var remote_default = TYPERT_REMOTE;
4504
4535
 
4505
4536
  // src/client/Workbench.tsx
4506
- var import_react7 = require("react");
4507
- var import_dsh_client_ui_primitives7 = require("@deepseek-ai/dsh-client-ui-primitives");
4537
+ var import_react8 = require("react");
4538
+ var import_dsh_client_ui_primitives6 = require("@deepseek-ai/dsh-client-ui-primitives");
4539
+
4540
+ // src/client/workbench-theme.ts
4541
+ var workbenchTheme = `
4542
+ .te-workbench { color:var(--dsw-alias-label-primary); font-size:14px; }
4543
+ .te-workbench *,.te-modal * { box-sizing:border-box; }
4544
+ .te-workbench button,.te-modal button { font-family:inherit; }
4545
+ .te-workbench button:focus-visible,.te-modal button:focus-visible,.te-input:focus-visible { outline:2px solid var(--dsw-alias-state-business-primary); outline-offset:3px; }
4546
+ .te-workbench h2 { margin:0 0 6px; font-size:24px; letter-spacing:-.5px; }
4547
+ .te-workbench h3,.te-modal h3 { margin:0; font-size:16px; overflow-wrap:anywhere; }
4548
+ .te-workbench p,.te-modal p { color:var(--dsw-alias-label-secondary); line-height:1.65; }
4549
+ .te-content { max-width:1120px; margin:auto; width:100%; }
4550
+ .te-resource { display:flex; flex-direction:column; gap:20px; }
4551
+ .te-section-heading { display:flex; justify-content:space-between; align-items:center; gap:16px; flex-wrap:wrap; }
4552
+ .te-section-heading p { margin:0; }
4553
+ .te-actions { display:flex; align-items:center; flex-wrap:wrap; gap:10px; }
4554
+ .te-toolbar { display:flex; flex-wrap:wrap; align-items:center; gap:12px; }
4555
+ .te-toolbar>input { flex:1; min-width:180px; }
4556
+ .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; }
4557
+ .te-resource-grid { display:grid; grid-template-columns:repeat(auto-fill,minmax(min(100%,280px),1fr)); gap:16px; }
4558
+ .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; }
4559
+ .te-resource-card:hover { border-color:var(--dsw-alias-state-business-primary); }
4560
+ .te-resource-card p { margin:0; font-size:13px; flex:1; }
4561
+ .te-card-top { display:flex; justify-content:space-between; align-items:center; }
4562
+ .te-resource-icon { display:grid; place-items:center; width:36px; height:36px; border-radius:10px; background:var(--dsw-alias-bg-layer-2); color:var(--dsw-alias-state-business-primary); font-size:25px; }
4563
+ .te-badge { display:inline-flex; border-radius:20px; background:var(--dsw-alias-bg-layer-2); color:var(--dsw-alias-label-secondary); padding:4px 10px; font-size:12px; }
4564
+ .te-delete,.te-link { border:none; background:transparent; cursor:pointer; padding:8px; color:var(--dsw-alias-label-secondary); }
4565
+ .te-delete { margin-left:auto; }
4566
+ .te-delete:hover { color:var(--dsw-alias-state-error-primary); }
4567
+ .te-link { text-align:left; align-self:flex-start; text-decoration:underline; }
4568
+ .te-danger-button { border:0; border-radius:9px; padding:10px 16px; background:var(--dsw-alias-state-error-primary); color:white; cursor:pointer; }
4569
+ .te-danger-button:disabled { opacity:.5; cursor:wait; }
4570
+ .te-alert,.te-success { padding:12px 16px; border-radius:10px; border:1px solid currentColor; overflow-wrap:anywhere; font-size:13px; }
4571
+ .te-alert { color:var(--dsw-alias-state-error-primary); }
4572
+ .te-success { color:var(--dsw-alias-state-success-primary); }
4573
+ .te-empty { text-align:center; padding:56px 24px; border:1px dashed var(--dsw-alias-border-l2); border-radius:16px; color:var(--dsw-alias-label-secondary); }
4574
+ .te-targets { display:grid; grid-template-columns:1fr 1fr; gap:12px; margin:4px 0 16px; }
4575
+ .te-target { display:flex; flex-direction:column; align-items:flex-start; gap:6px; padding:16px; border-radius:12px; border:1px solid var(--dsw-alias-border-l2); background:var(--dsw-alias-bg-layer-1); color:var(--dsw-alias-label-primary); cursor:pointer; }
4576
+ .te-target small { color:var(--dsw-alias-label-secondary); text-align:left; }
4577
+ .te-target.selected { border-color:var(--dsw-alias-state-business-primary); box-shadow:0 0 0 1px var(--dsw-alias-state-business-primary); }
4578
+ .te-path { display:block; grid-column:1/-1; padding:10px 12px; font-size:12px; border-radius:8px; background:var(--dsw-alias-bg-layer-1); color:var(--dsw-alias-label-secondary); overflow-wrap:anywhere; white-space:pre-wrap; }
4579
+ .te-preview { display:flex; flex-direction:column; gap:12px; margin-top:16px; }
4580
+ .te-markdown { max-height:360px; overflow:auto; padding:16px; border:1px solid var(--dsw-alias-border-l2); border-radius:12px; }
4581
+ .te-advanced { margin-top:16px; padding:12px; border:1px dashed var(--dsw-alias-border-l2); border-radius:12px; }
4582
+ .te-dir-list { max-height:160px; overflow:auto; display:flex; flex-direction:column; gap:4px; }
4583
+ .te-dir-list button { text-align:left; border:0; background:transparent; color:var(--dsw-alias-label-primary); padding:8px; cursor:pointer; }
4584
+ .te-dir-list button:hover { background:var(--dsw-alias-bg-layer-1); }
4585
+ .te-form { display:flex; flex-direction:column; gap:16px; }
4586
+ .te-form label { display:flex; flex-direction:column; gap:8px; font-size:13px; }
4587
+ .te-editor { min-height:260px; resize:vertical; line-height:1.6; font-family:monospace; }
4588
+ @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;} }
4589
+ `;
4508
4590
 
4509
4591
  // src/client/styles.ts
4510
4592
  var text = "var(--dsw-alias-label-primary)";
@@ -4749,7 +4831,7 @@ var STANDARD = {
4749
4831
  policy: "task",
4750
4832
  message_pattern: "^\u3010(\\S+)\u3011\u3010(?:TASK|T\\d+)\u3011.+",
4751
4833
  message_hint: "\u3010<task_id>\u3011\u3010TASK/T1\u3011\u8BF4\u660E \u2014\u2014 \u7B2C\u4E00\u6BB5\u586B\u672C\u4EFB\u52A1 id\uFF08\u5982 GREET-001\uFF09\uFF0C\u5199\u7ED3\u679C\u4E0D\u5199\u7A7A\u6CDB\u52A8\u4F5C",
4752
- checkpoints: ["\u4EA4\u4ED8"],
4834
+ checkpoints: ["\u4EE3\u7801\u5BA1\u6838"],
4753
4835
  file_scope: true
4754
4836
  },
4755
4837
  high_risk_requires_verification: true,
@@ -4757,8 +4839,8 @@ var STANDARD = {
4757
4839
  "\u9700\u6C42\u8BC4\u5BA1": { skills: ["requirement-analysis"], rules: ["security-redlines"] },
4758
4840
  "\u8BBE\u8BA1": { skills: ["solution-design"] },
4759
4841
  "\u5F00\u53D1": { skills: ["code-implement"], rules: ["coding-conventions"] },
4760
- "\u4EA4\u4ED8": { skills: ["code-verify", "code-commit"], rules: ["coding-conventions", "commit-conventions"] },
4761
- "\u4EE3\u7801\u5BA1\u6838": { skills: ["code-review"], rules: ["security-redlines"] }
4842
+ "\u4EA4\u4ED8": { skills: ["code-verify"], rules: ["coding-conventions"] },
4843
+ "\u4EE3\u7801\u5BA1\u6838": { skills: ["code-review", "code-commit"], rules: ["security-redlines", "commit-conventions"] }
4762
4844
  }
4763
4845
  };
4764
4846
  var AGILE = {
@@ -4820,7 +4902,7 @@ function preset(id, version, label2, description, config) {
4820
4902
  return { id, version, label: label2, description, capabilities: deriveCapabilities(config), config };
4821
4903
  }
4822
4904
  var FLOW_PRESETS = {
4823
- standard: preset("standard", 1, "\u6807\u51C6\u7814\u53D1", "\u9700\u6C42\u8BC4\u5BA1 \u2192 \u8BBE\u8BA1 \u2192 \u5F00\u53D1 \u2192 \u4EA4\u4ED8 \u2192 \u4EE3\u7801\u5BA1\u6838\uFF0C\u542B\u4EA7\u7269\u95E8 + \u786E\u8BA4\u95E8", STANDARD),
4905
+ standard: preset("standard", 2, "\u6807\u51C6\u7814\u53D1", "\u9700\u6C42\u8BC4\u5BA1 \u2192 \u8BBE\u8BA1 \u2192 \u5F00\u53D1 \u2192 \u4EA4\u4ED8 \u2192 \u4EE3\u7801\u5BA1\u6838\uFF0C\u5BA1\u6838\u540E\u63D0\u4EA4", STANDARD),
4824
4906
  agile: preset("agile", 1, "\u654F\u6377\u8F7B\u91CF", "\u9700\u6C42 \u2192 \u5F00\u53D1 \u2192 \u4EA4\u4ED8 \u2192 \u5BA1\u67E5\uFF0C\u56DB\u9636\u6BB5\u3001\u5C11\u4EA7\u7269", AGILE),
4825
4907
  minimal: preset("minimal", 1, "\u7EAF\u4EE3\u7801", "\u5F00\u53D1 \u2192 \u4EA4\u4ED8\uFF0C\u4E24\u9636\u6BB5\uFF0C\u53EA\u7559\u63D0\u4EA4\u95E8\u7981", MINIMAL)
4826
4908
  };
@@ -4898,29 +4980,39 @@ function TaskEngineSection(props) {
4898
4980
  const [source, setSource] = (0, import_react.useState)("default");
4899
4981
  const [savedAt, setSavedAt] = (0, import_react.useState)("");
4900
4982
  const [loadError, setLoadError] = (0, import_react.useState)("");
4983
+ const [saving, setSaving] = (0, import_react.useState)(false);
4984
+ const [loading, setLoading] = (0, import_react.useState)(true);
4985
+ const [loadAttempt, setLoadAttempt] = (0, import_react.useState)(0);
4986
+ const [configProblems, setConfigProblems] = (0, import_react.useState)([]);
4901
4987
  const [skills, setSkills] = (0, import_react.useState)([]);
4902
4988
  const [rules, setRules] = (0, import_react.useState)([]);
4903
4989
  (0, import_react.useEffect)(() => {
4904
4990
  if (workspace === "") return;
4905
4991
  let alive = true;
4906
4992
  setLoadError("");
4993
+ setLoading(true);
4907
4994
  void remote.read(workspace).then((result) => {
4908
4995
  if (!alive) return;
4996
+ setLoading(false);
4909
4997
  if (result.ok) {
4910
4998
  setFlow(result.value.flow);
4911
4999
  setStageBindings(result.value.config.stage_bindings ?? {});
4912
5000
  setSource(result.value.source);
5001
+ setConfigProblems(result.value.problems);
4913
5002
  setSavedAt("");
4914
5003
  } else {
4915
5004
  setLoadError("\u8BFB\u53D6\u914D\u7F6E\u5931\u8D25\uFF1A" + describeError(result.error));
4916
5005
  }
4917
5006
  }, (error) => {
4918
- if (alive) setLoadError("\u8BFB\u53D6\u914D\u7F6E\u5931\u8D25\uFF1A" + describeError(error));
5007
+ if (alive) {
5008
+ setLoading(false);
5009
+ setLoadError("\u8BFB\u53D6\u914D\u7F6E\u5931\u8D25\uFF1A" + describeError(error));
5010
+ }
4919
5011
  });
4920
5012
  return () => {
4921
5013
  alive = false;
4922
5014
  };
4923
- }, [remote, workspace]);
5015
+ }, [remote, workspace, loadAttempt]);
4924
5016
  const refreshCatalogs = (0, import_react.useCallback)(() => {
4925
5017
  if (workspace === "") return;
4926
5018
  void remote.listSkills(workspace).then((result) => {
@@ -4952,11 +5044,18 @@ function TaskEngineSection(props) {
4952
5044
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.StateDot, { state: "error" }),
4953
5045
  "\u8BFB\u53D6\u5931\u8D25"
4954
5046
  ] }),
4955
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: styles.muted, children: loadError })
5047
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: styles.muted, children: loadError }),
5048
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Button, { onClick: () => setLoadAttempt((n) => n + 1), children: "\u91CD\u8BD5" })
4956
5049
  ] })
4957
5050
  ] });
4958
5051
  }
5052
+ if (loading) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { role: "status", children: "\u6B63\u5728\u8BFB\u53D6\u6D41\u7A0B\u914D\u7F6E\u2026" });
4959
5053
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.wrap, children: [
5054
+ configProblems.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { role: "alert", style: styles.problems, children: [
5055
+ "\u539F\u914D\u7F6E\u6709\u95EE\u9898\uFF1A",
5056
+ configProblems.join("\uFF1B"),
5057
+ "\u3002\u8BF7\u9009\u62E9\u6709\u6548\u9884\u8BBE\u5E76\u4FDD\u5B58\u4FEE\u590D\u3002"
5058
+ ] }),
4960
5059
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.head, children: [
4961
5060
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { style: styles.title, children: "\u5DE5\u7A0B\u6D41\u7A0B\u914D\u7F6E" }),
4962
5061
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: styles.muted, children: "\u9009\u4E00\u5957\u6D41\u7A0B\uFF0C\u518D\u7ED9\u6BCF\u4E2A\u8282\u70B9\u6302\u4E0A skill / rule\u3002\u9636\u6BB5\u6D41\u8F6C\u3001\u5B88\u536B\u3001\u63D0\u4EA4\u89C4\u5219\u90FD\u7531\u6D41\u7A0B\u9884\u8BBE\u56FA\u5316\uFF0C\u65E0\u9700\u624B\u5DE5\u914D\u7F6E\u3002" })
@@ -5012,11 +5111,14 @@ function TaskEngineSection(props) {
5012
5111
  variant: "primary",
5013
5112
  size: "md",
5014
5113
  icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.IconCheckOutline16, { size: 16 }),
5015
- disabled: problems.length > 0,
5114
+ disabled: problems.length > 0 || saving,
5016
5115
  onClick: () => {
5017
- void save(remote, flow, stageBindings, workspace, setSavedAt, setSource);
5116
+ setSaving(true);
5117
+ void save(remote, flow, stageBindings, workspace, setSavedAt, setSource).then((ok) => {
5118
+ if (ok) setConfigProblems([]);
5119
+ }).finally(() => setSaving(false));
5018
5120
  },
5019
- children: "\u4FDD\u5B58\u5230 .dsh/eng.json"
5121
+ children: saving ? "\u6B63\u5728\u4FDD\u5B58\u2026" : "\u4FDD\u5B58\u5230 .dsh/eng.json"
5020
5122
  }
5021
5123
  ),
5022
5124
  savedAt !== "" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { style: styles.okText, children: [
@@ -5077,6 +5179,7 @@ function BindingEditor({ stages, stageBindings, setStageBindings, skills, rules
5077
5179
  const boundSkills = stageBindings[currentStage]?.skills ?? [];
5078
5180
  const boundRules = stageBindings[currentStage]?.rules ?? [];
5079
5181
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.section, children: [
5182
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: styles.hint, children: "\u7ED1\u5B9A\u6309\u540D\u79F0\u751F\u6548\uFF1B\u540C\u540D\u8D44\u6E90\u53EF\u5728\u8D44\u6E90\u7BA1\u7406\u4E2D\u6309\u9879\u76EE\uFF0F\u4E2A\u4EBA\u5206\u522B\u67E5\u770B\u3002\u5B8C\u6210\u8282\u70B9\u7684\u6280\u80FD\u5FC5\u987B\u5728\u8FDB\u5165\u5B8C\u6210\u524D\u6267\u884C\uFF0C\u6D4B\u8BD5\u6280\u80FD\u5EFA\u8BAE\u653E\u5728\u4EA4\u4ED8\u8282\u70B9\u3002" }),
5080
5183
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.field, children: [
5081
5184
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: styles.fieldLabel, children: "\u9009\u62E9\u8282\u70B9\uFF08\u6539\u54EA\u4E2A\u8282\u70B9\u7684\u6302\u8F7D\uFF09" }),
5082
5185
  /* @__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: () => {
@@ -5086,7 +5189,7 @@ function BindingEditor({ stages, stageBindings, setStageBindings, skills, rules
5086
5189
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: cardV, children: [
5087
5190
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.bindingStage, children: [
5088
5191
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: styles.fieldLabel, children: "skill\uFF08\u8FD9\u4E2A\u8282\u70B9\u505A\u4EC0\u4E48\uFF09" }),
5089
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: styles.chips, children: skills.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: styles.sourceBadge, children: "\u6682\u65E0\u53EF\u7528 skill \u2014\u2014 \u5207\u5230\u4E0A\u65B9\u300C\u6280\u80FD\u300D\u6807\u7B7E\u9875\u65B0\u5EFA" }) : skills.map((sk) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_dsh_client_ui_primitives.Pill, { active: boundSkills.includes(sk.name), onClick: () => {
5192
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: styles.chips, children: skills.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: styles.sourceBadge, children: "\u6682\u65E0\u53EF\u7528 skill \u2014\u2014 \u5207\u5230\u4E0A\u65B9\u300C\u6280\u80FD\u300D\u6807\u7B7E\u9875\u65B0\u5EFA" }) : skills.filter((sk, index, all) => all.findIndex((other) => other.name === sk.name) === index).map((sk) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_dsh_client_ui_primitives.Pill, { active: boundSkills.includes(sk.name), onClick: () => {
5090
5193
  toggleSkill(sk.name);
5091
5194
  }, title: `${sk.description}\uFF08${sourceLabel(sk.source)}\uFF09`, children: [
5092
5195
  sk.name,
@@ -5099,7 +5202,7 @@ function BindingEditor({ stages, stageBindings, setStageBindings, skills, rules
5099
5202
  ] }),
5100
5203
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.bindingStage, children: [
5101
5204
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: styles.fieldLabel, children: "rule\uFF08\u8FD9\u4E2A\u8282\u70B9\u5B88\u4EC0\u4E48\uFF09" }),
5102
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: styles.chips, children: rules.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: styles.sourceBadge, children: "\u6682\u65E0\u53EF\u7528 rule \u2014\u2014 \u5207\u5230\u4E0A\u65B9\u300C\u89C4\u5219\u300D\u6807\u7B7E\u9875\u65B0\u5EFA" }) : rules.map((rule) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_dsh_client_ui_primitives.Pill, { active: boundRules.includes(rule.name), onClick: () => {
5205
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: styles.chips, children: rules.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: styles.sourceBadge, children: "\u6682\u65E0\u53EF\u7528 rule \u2014\u2014 \u5207\u5230\u4E0A\u65B9\u300C\u89C4\u5219\u300D\u6807\u7B7E\u9875\u65B0\u5EFA" }) : rules.filter((rule, index, all) => all.findIndex((other) => other.name === rule.name) === index).map((rule) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_dsh_client_ui_primitives.Pill, { active: boundRules.includes(rule.name), onClick: () => {
5103
5206
  toggleRule(rule.name);
5104
5207
  }, title: `\u6765\u6E90\uFF1A${sourceLabel(rule.source)}`, children: [
5105
5208
  rule.name,
@@ -5115,13 +5218,23 @@ function BindingEditor({ stages, stageBindings, setStageBindings, skills, rules
5115
5218
  ] });
5116
5219
  }
5117
5220
  async function save(remote, flow, stageBindings, workspace, setSavedAt, setSource) {
5118
- const result = await remote.write({ path: workspace, flow, stage_bindings: stageBindings });
5119
- if (!result.ok) {
5120
- setSavedAt("\u4FDD\u5B58\u5931\u8D25\uFF1A" + describeError(result.error));
5121
- return;
5221
+ try {
5222
+ const result = await remote.write({ path: workspace, flow, stage_bindings: stageBindings });
5223
+ if (!result.ok) {
5224
+ setSavedAt("\u4FDD\u5B58\u5931\u8D25\uFF1A" + describeError(result.error));
5225
+ return false;
5226
+ }
5227
+ if (!result.value.ok) {
5228
+ setSavedAt("\u4FDD\u5B58\u5931\u8D25\uFF1A" + result.value.problems.join("\uFF1B"));
5229
+ return false;
5230
+ }
5231
+ setSource(result.value.source);
5232
+ setSavedAt("\u5DF2\u4FDD\u5B58");
5233
+ return true;
5234
+ } catch (error) {
5235
+ setSavedAt("\u4FDD\u5B58\u5931\u8D25\uFF1A" + describeError(error));
5236
+ return false;
5122
5237
  }
5123
- setSource(result.value.source);
5124
- setSavedAt(result.value.ok ? "\u5DF2\u4FDD\u5B58" : "");
5125
5238
  }
5126
5239
 
5127
5240
  // src/client/InitPanel.tsx
@@ -5310,6 +5423,9 @@ function InitPanel({ workspace, remote }) {
5310
5423
  }
5311
5424
 
5312
5425
  // src/client/SkillManager.tsx
5426
+ var import_react5 = require("react");
5427
+
5428
+ // src/client/ResourceManager.tsx
5313
5429
  var import_react4 = require("react");
5314
5430
  var import_dsh_client_ui_primitives4 = require("@deepseek-ai/dsh-client-ui-primitives");
5315
5431
 
@@ -5398,23 +5514,49 @@ var footerStyle = {
5398
5514
  flex: "none"
5399
5515
  };
5400
5516
  function ResourceModal({ title, description, onClose, footer, children }) {
5517
+ const dialog = (0, import_react3.useRef)(null);
5518
+ const closer = (0, import_react3.useRef)(onClose);
5519
+ closer.current = onClose;
5401
5520
  (0, import_react3.useEffect)(() => {
5521
+ const previous = document.activeElement;
5522
+ dialog.current?.focus();
5402
5523
  const onKey = (e) => {
5403
- if (e.key === "Escape") onClose();
5524
+ if (!dialog.current?.contains(document.activeElement)) return;
5525
+ if (e.key === "Escape") {
5526
+ e.preventDefault();
5527
+ e.stopPropagation();
5528
+ closer.current();
5529
+ return;
5530
+ }
5531
+ if (e.key !== "Tab") return;
5532
+ 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);
5533
+ const first = nodes[0], last = nodes[nodes.length - 1];
5534
+ if (!first || !last) {
5535
+ e.preventDefault();
5536
+ return;
5537
+ }
5538
+ if (e.shiftKey && (document.activeElement === first || document.activeElement === dialog.current)) {
5539
+ e.preventDefault();
5540
+ last.focus();
5541
+ } else if (!e.shiftKey && (document.activeElement === last || document.activeElement === dialog.current)) {
5542
+ e.preventDefault();
5543
+ first.focus();
5544
+ }
5404
5545
  };
5405
5546
  document.addEventListener("keydown", onKey);
5406
5547
  return () => {
5407
5548
  document.removeEventListener("keydown", onKey);
5549
+ if (previous?.isConnected) previous.focus();
5408
5550
  };
5409
- }, [onClose]);
5551
+ }, []);
5410
5552
  return (0, import_react_dom.createPortal)(
5411
5553
  (0, import_react3.createElement)(
5412
5554
  "div",
5413
- { style: rootStyle, role: "presentation" },
5555
+ { style: rootStyle, className: "te-modal", role: "presentation" },
5414
5556
  (0, import_react3.createElement)("div", { style: maskStyle, "aria-hidden": true, onClick: onClose }),
5415
5557
  (0, import_react3.createElement)(
5416
5558
  "div",
5417
- { style: dialogStyle, role: "dialog", "aria-modal": true, "aria-label": title },
5559
+ { style: dialogStyle, ref: dialog, tabIndex: -1, role: "dialog", "aria-modal": true, "aria-label": title },
5418
5560
  (0, import_react3.createElement)(
5419
5561
  "div",
5420
5562
  { style: headerStyle },
@@ -5434,815 +5576,333 @@ function ResourceModal({ title, description, onClose, footer, children }) {
5434
5576
  );
5435
5577
  }
5436
5578
 
5437
- // src/client/SkillManager.tsx
5438
- var MD_LABELS2 = { code: { copyLabel: "\u590D\u5236", copiedLabel: "\u5DF2\u590D\u5236" }, footnotes: "\u811A\u6CE8" };
5439
- var control = {
5440
- background: "var(--dsw-alias-bg-layer-1)",
5441
- border: "1px solid var(--dsw-alias-border-l2)",
5442
- borderRadius: 8,
5443
- padding: "5px 8px",
5444
- color: "var(--dsw-alias-label-primary)",
5445
- fontSize: 13,
5446
- minWidth: 0
5447
- };
5448
- var card2 = {
5449
- display: "flex",
5450
- flexDirection: "column",
5451
- gap: 8,
5452
- border: "1px solid var(--dsw-alias-border-l2)",
5453
- borderRadius: 8,
5454
- padding: "10px 12px"
5455
- };
5456
- function levelOf(source) {
5457
- if (source === "bundled") return "bundled";
5458
- return source.startsWith("user") ? "user" : "project";
5459
- }
5460
- function joinPath(dir, name) {
5461
- if (dir === "") return name;
5462
- return dir.replace(/[\\/]+$/u, "") + "/" + name;
5463
- }
5464
- function breadcrumbSegments(path) {
5465
- const trimmed = path.replace(/[\\/]+$/u, "");
5466
- const sep = trimmed.includes("\\") ? "\\" : "/";
5467
- const parts = trimmed.split(/[\\/]+/u).filter((part) => part !== "");
5468
- const segments = [];
5469
- let acc = "";
5470
- for (const part of parts) {
5471
- if (acc === "") {
5472
- acc = /^[A-Za-z]:$/u.test(part) ? part + sep : sep + part;
5473
- segments.push({ label: part, path: acc });
5474
- } else {
5475
- acc = acc.replace(/[\\/]+$/u, "") + sep + part;
5476
- segments.push({ label: part, path: acc });
5477
- }
5478
- }
5479
- return segments;
5480
- }
5481
- function isRootLevel(path) {
5482
- if (path === "") return true;
5483
- return /^[A-Za-z]:[\\/]?$/u.test(path) || path === "/";
5484
- }
5485
- var paneStyle = {
5486
- flex: "1 1 0",
5487
- minWidth: 0,
5488
- overflowY: "auto",
5489
- display: "flex",
5490
- flexDirection: "column",
5491
- gap: 2,
5492
- border: "1px solid var(--dsw-alias-border-l2)",
5493
- borderRadius: 8,
5494
- padding: 4
5495
- };
5496
- function SkillManager({ workspace, remote }) {
5497
- const [skills, setSkills] = (0, import_react4.useState)([]);
5579
+ // src/client/ResourceManager.tsx
5580
+ var labels = { code: { copyLabel: "\u590D\u5236", copiedLabel: "\u5DF2\u590D\u5236" }, footnotes: "\u811A\u6CE8" };
5581
+ var levelOf = (row) => row.source === "bundled" ? "bundled" : row.source.startsWith("user") ? "user" : "project";
5582
+ var sourceText2 = (source) => source === "bundled" ? "\u5185\u7F6E" : source.startsWith("user") ? "\u4E2A\u4EBA" : "\u9879\u76EE";
5583
+ var sizeText = (bytes) => bytes < 1024 ? `${bytes} B` : bytes < 1024 * 1024 ? `${(bytes / 1024).toFixed(1)} KB` : `${(bytes / 1024 / 1024).toFixed(1)} MB`;
5584
+ var fail = (r) => describeError(r.error ?? "\u64CD\u4F5C\u5931\u8D25");
5585
+ function ResourceManager({ workspace, remote, kind }) {
5586
+ const noun = kind === "skill" ? "\u6280\u80FD" : "\u89C4\u5219";
5587
+ const [rows, setRows] = (0, import_react4.useState)([]);
5588
+ const [query, setQuery] = (0, import_react4.useState)("");
5589
+ const [filter, setFilter] = (0, import_react4.useState)("all");
5590
+ const [notice, setNotice] = (0, import_react4.useState)("");
5591
+ const [error, setError] = (0, import_react4.useState)("");
5592
+ const [loading, setLoading] = (0, import_react4.useState)(true);
5593
+ const [revision, refresh] = (0, import_react4.useState)(0);
5594
+ const [busy, setBusy] = (0, import_react4.useState)(false);
5595
+ const [roots, setRoots] = (0, import_react4.useState)(null);
5596
+ const [importing, setImporting] = (0, import_react4.useState)(false);
5597
+ const [request, setRequest] = (0, import_react4.useState)(null);
5598
+ const [preview, setPreview] = (0, import_react4.useState)(null);
5498
5599
  const [level, setLevel] = (0, import_react4.useState)("project");
5600
+ const [manual, setManual] = (0, import_react4.useState)(false);
5601
+ const [sourceDir, setSourceDir] = (0, import_react4.useState)("");
5602
+ const [dirs, setDirs] = (0, import_react4.useState)([]);
5603
+ const [browsePath, setBrowsePath] = (0, import_react4.useState)("");
5499
5604
  const [editing, setEditing] = (0, import_react4.useState)(null);
5500
- const [creating, setCreating] = (0, import_react4.useState)(false);
5501
5605
  const [viewing, setViewing] = (0, import_react4.useState)(false);
5502
- const [confirming, setConfirming] = (0, import_react4.useState)(null);
5503
5606
  const [name, setName] = (0, import_react4.useState)("");
5504
5607
  const [description, setDescription] = (0, import_react4.useState)("");
5505
5608
  const [whenToUse, setWhenToUse] = (0, import_react4.useState)("");
5506
5609
  const [body2, setBody] = (0, import_react4.useState)("");
5507
- const [msg, setMsg] = (0, import_react4.useState)("");
5508
- const [installing, setInstalling] = (0, import_react4.useState)(false);
5509
- const [installDir, setInstallDir] = (0, import_react4.useState)("");
5510
- const [installLevel, setInstallLevel] = (0, import_react4.useState)("project");
5511
- const [browsing, setBrowsing] = (0, import_react4.useState)(false);
5512
- const [browseCurrent, setBrowseCurrent] = (0, import_react4.useState)("");
5513
- const [browseEntries, setBrowseEntries] = (0, import_react4.useState)([]);
5514
- const [browseSelected, setBrowseSelected] = (0, import_react4.useState)(null);
5515
- const [browseChildEntries, setBrowseChildEntries] = (0, import_react4.useState)([]);
5516
- const [browseChildHasSkill, setBrowseChildHasSkill] = (0, import_react4.useState)(false);
5517
- const [browseRoots, setBrowseRoots] = (0, import_react4.useState)([]);
5518
- const [browseHasSkill, setBrowseHasSkill] = (0, import_react4.useState)(false);
5519
- const [browseDraft, setBrowseDraft] = (0, import_react4.useState)("");
5520
- const [browseError, setBrowseError] = (0, import_react4.useState)("");
5521
- const loadLevel = (path) => {
5522
- setBrowseError("");
5523
- setBrowseSelected(null);
5524
- setBrowseChildEntries([]);
5525
- setBrowseChildHasSkill(false);
5526
- void remote.listDirs({ path }).then((r) => {
5527
- if (r.ok && r.value.ok) {
5528
- setBrowseCurrent(r.value.path);
5529
- setBrowseDraft(r.value.path);
5530
- setBrowseEntries(r.value.entries);
5531
- setBrowseRoots(r.value.roots);
5532
- setBrowseHasSkill(r.value.currentHasSkill);
5533
- } else {
5534
- setBrowseEntries([]);
5535
- setBrowseError(describeError(r.ok ? r.value.error : r.error));
5536
- }
5537
- }, (error) => {
5538
- setBrowseEntries([]);
5539
- setBrowseError("\u76EE\u5F55\u8BFB\u53D6\u5931\u8D25\uFF1A" + describeError(error));
5540
- });
5541
- };
5542
- const loadChild = (path) => {
5543
- setBrowseChildEntries([]);
5544
- setBrowseChildHasSkill(false);
5545
- void remote.listDirs({ path }).then((r) => {
5546
- if (r.ok && r.value.ok) {
5547
- setBrowseChildEntries(r.value.entries);
5548
- setBrowseChildHasSkill(r.value.currentHasSkill);
5549
- } else {
5550
- setBrowseChildEntries([]);
5610
+ const [deleting, setDeleting] = (0, import_react4.useState)(null);
5611
+ const input = (0, import_react4.useRef)(null);
5612
+ const fileEpoch = (0, import_react4.useRef)(0);
5613
+ const browseEpoch = (0, import_react4.useRef)(0);
5614
+ const readonly = editing !== null && editing !== "new" && levelOf(editing) === "bundled";
5615
+ (0, import_react4.useEffect)(() => {
5616
+ let active = true;
5617
+ setLoading(true);
5618
+ setRows([]);
5619
+ setError("");
5620
+ const run = async () => {
5621
+ try {
5622
+ const r = kind === "skill" ? await remote.listSkills(workspace) : await remote.listRules(workspace);
5623
+ if (!active) return;
5624
+ if (!r.ok) throw new Error(fail(r));
5625
+ setRows("skills" in r.value ? r.value.skills : r.value.rules);
5626
+ } catch (e) {
5627
+ if (active) setError("\u52A0\u8F7D\u5931\u8D25\uFF1A" + describeError(e));
5628
+ } finally {
5629
+ if (active) setLoading(false);
5551
5630
  }
5631
+ };
5632
+ void run();
5633
+ void remote.resourceRoots({ kind, path: workspace }).then((r) => {
5634
+ if (active && r.ok) setRoots(r.value);
5552
5635
  }, () => {
5553
- setBrowseChildEntries([]);
5554
5636
  });
5637
+ return () => {
5638
+ active = false;
5639
+ fileEpoch.current++;
5640
+ };
5641
+ }, [workspace, remote, kind, revision]);
5642
+ (0, import_react4.useEffect)(() => {
5643
+ let active = true;
5644
+ setPreview(null);
5645
+ if (!request) return;
5646
+ setBusy(true);
5647
+ setError("");
5648
+ void remote.previewResource({ ...request, level, path: workspace }).then((r) => {
5649
+ if (!active) return;
5650
+ if (!r.ok) setError(fail(r));
5651
+ else if (!r.value.ok) setError(r.value.error ?? "\u9884\u89C8\u5931\u8D25");
5652
+ else setPreview(r.value);
5653
+ }, (e) => {
5654
+ if (active) setError(describeError(e));
5655
+ }).finally(() => {
5656
+ if (active) setBusy(false);
5657
+ });
5658
+ return () => {
5659
+ active = false;
5660
+ };
5661
+ }, [request, level, workspace, remote]);
5662
+ const close = () => {
5663
+ if (busy) return;
5664
+ fileEpoch.current++;
5665
+ setImporting(false);
5666
+ setEditing(null);
5667
+ setDeleting(null);
5668
+ setRequest(null);
5669
+ setError("");
5555
5670
  };
5556
- const selectRow = (entry) => {
5557
- const next = joinPath(browseCurrent, entry.name);
5558
- setBrowseSelected({ name: entry.name, path: next });
5559
- loadChild(next);
5560
- };
5561
- const selectChildRow = (entry) => {
5562
- if (browseSelected === null) return;
5563
- const base = browseSelected.path;
5564
- const baseEntries = browseChildEntries;
5565
- const baseHasSkill = browseChildHasSkill;
5566
- setBrowseCurrent(base);
5567
- setBrowseDraft(base);
5568
- setBrowseEntries(baseEntries);
5569
- setBrowseHasSkill(baseHasSkill);
5570
- const next = joinPath(base, entry.name);
5571
- setBrowseSelected({ name: entry.name, path: next });
5572
- loadChild(next);
5671
+ const choose = () => {
5672
+ setError("");
5673
+ if (input.current) {
5674
+ input.current.value = "";
5675
+ input.current.click();
5676
+ }
5573
5677
  };
5574
- const openBrowse = () => {
5575
- setBrowsing(true);
5576
- setBrowseError("");
5577
- loadLevel("");
5678
+ const selected = async (files) => {
5679
+ if (!files.length) return;
5680
+ const epoch = ++fileEpoch.current;
5681
+ setImporting(true);
5682
+ setManual(false);
5683
+ setRequest(null);
5684
+ setPreview(null);
5685
+ setBusy(true);
5686
+ setError("");
5687
+ setNotice("");
5688
+ try {
5689
+ files = files.filter((f) => !(f.webkitRelativePath || f.name).split("/").some((p) => ["node_modules", ".git", "__pycache__", ".venv", "venv", ".cache", ".DS_Store"].includes(p)));
5690
+ if (!files.length || files.length > 1e3 || files.reduce((n, f) => n + f.size, 0) > 100 * 1024 * 1024 || files.some((f) => f.size > 20 * 1024 * 1024)) throw new Error("\u8BF7\u9009\u62E9\u4E0D\u8D85\u8FC7 1000 \u4E2A\u6587\u4EF6 / 100 MB \u7684\u6280\u80FD\u5305\uFF0C\u5355\u6587\u4EF6\u4E0D\u8D85\u8FC7 20 MB");
5691
+ const entries = [];
5692
+ for (const file of files) {
5693
+ const data = new Uint8Array(await file.arrayBuffer());
5694
+ let binary = "";
5695
+ for (let i = 0; i < data.length; i += 32768) binary += String.fromCharCode(...data.subarray(i, i + 32768));
5696
+ entries.push({ path: file.webkitRelativePath || file.name, base64: btoa(binary) });
5697
+ }
5698
+ if (epoch === fileEpoch.current) setRequest({ kind, level, path: workspace, files: entries });
5699
+ } catch (e) {
5700
+ if (epoch === fileEpoch.current) setError(describeError(e));
5701
+ } finally {
5702
+ if (epoch === fileEpoch.current) setBusy(false);
5703
+ }
5578
5704
  };
5579
- const browseUp = () => {
5580
- const p = browseCurrent.replace(/[\\/]+$/u, "");
5581
- const idx = Math.max(p.lastIndexOf("/"), p.lastIndexOf("\\"));
5582
- loadLevel(idx <= 2 ? "" : p.slice(0, idx));
5705
+ const install = async () => {
5706
+ if (!request || !preview || preview.conflict || busy) return;
5707
+ setBusy(true);
5708
+ setError("");
5709
+ try {
5710
+ const r = await remote.importResource({ ...request, level, path: workspace, expectedHash: preview.hash });
5711
+ if (!r.ok) throw new Error(fail(r));
5712
+ if (!r.value.ok) throw new Error(r.value.error ?? "\u5B89\u88C5\u5931\u8D25");
5713
+ setNotice(`\u5DF2\u5B89\u88C5${noun}\u300C${r.value.name}\u300D \xB7 ${r.value.target}`);
5714
+ setImporting(false);
5715
+ setRequest(null);
5716
+ refresh((n) => n + 1);
5717
+ } catch (e) {
5718
+ setError(describeError(e));
5719
+ } finally {
5720
+ setBusy(false);
5721
+ }
5583
5722
  };
5584
- const pickedPath = browseSelected !== null ? browseSelected.path : browseCurrent;
5585
- const pickedHasSkill = browseSelected !== null ? browseChildHasSkill : browseHasSkill;
5586
- const refresh = (0, import_react4.useCallback)(() => {
5587
- void remote.listSkills(workspace).then((r) => {
5588
- if (r.ok) setSkills(r.value.skills);
5589
- }, () => {
5590
- });
5591
- }, [remote, workspace]);
5592
- (0, import_react4.useEffect)(() => {
5593
- refresh();
5594
- }, [refresh]);
5595
- const closeForm = () => {
5596
- setEditing(null);
5597
- setCreating(false);
5598
- setViewing(false);
5599
- setName("");
5600
- setDescription("");
5601
- setWhenToUse("");
5602
- setBody("");
5603
- setMsg("");
5723
+ const browse = async (path) => {
5724
+ const epoch = ++browseEpoch.current;
5725
+ setError("");
5726
+ try {
5727
+ const r = await remote.listDirs({ path });
5728
+ if (epoch !== browseEpoch.current) return;
5729
+ if (!r.ok) throw new Error(fail(r));
5730
+ if (!r.value.ok) throw new Error(r.value.error ?? "\u76EE\u5F55\u8BFB\u53D6\u5931\u8D25");
5731
+ setBrowsePath(r.value.path);
5732
+ setSourceDir(r.value.path);
5733
+ setDirs(r.value.entries);
5734
+ } catch (e) {
5735
+ if (epoch === browseEpoch.current) setError(describeError(e));
5736
+ }
5604
5737
  };
5605
- const startCreate = () => {
5606
- setEditing(null);
5607
- setCreating(true);
5608
- setViewing(false);
5609
- setInstalling(false);
5610
- setLevel("project");
5611
- setName("");
5738
+ const edit = async (row, view = false) => {
5739
+ setEditing(row);
5740
+ setViewing(view);
5741
+ setName(row === "new" ? "" : row.name);
5612
5742
  setDescription("");
5613
5743
  setWhenToUse("");
5614
5744
  setBody("");
5615
- setMsg("");
5616
- };
5617
- const startInstall = () => {
5618
- setEditing(null);
5619
- setCreating(false);
5620
- setViewing(false);
5621
- setInstalling(true);
5622
- setInstallDir("");
5623
- setInstallLevel("project");
5624
- setMsg("");
5625
- };
5626
- const submitInstall = async () => {
5627
- setMsg("");
5628
- const result = await remote.installSkill({
5629
- sourceDir: installDir,
5630
- level: installLevel,
5631
- path: installLevel === "project" ? workspace : void 0
5632
- });
5633
- if (!result.ok) {
5634
- setMsg("\u5B89\u88C5\u5931\u8D25\uFF1A" + describeError(result.error));
5635
- return;
5636
- }
5637
- if (!result.value.ok) {
5638
- setMsg("\u5B89\u88C5\u5931\u8D25\uFF1A" + (result.value.error ?? "\u672A\u77E5\u9519\u8BEF"));
5745
+ setError("");
5746
+ if (row === "new") {
5747
+ setLevel("project");
5639
5748
  return;
5640
5749
  }
5641
- setMsg(`\u5DF2\u5B89\u88C5 skill\u300C${result.value.name}\u300D\u2192 ${result.value.path}`);
5642
- setInstalling(false);
5643
- refresh();
5644
- };
5645
- const loadSkill = (skillName, lvl) => {
5646
- setMsg("");
5647
- void remote.readSkill({ name: skillName, level: lvl, path: workspace }).then((r) => {
5648
- if (r.ok && r.value.ok) {
5649
- setName(r.value.name);
5650
- setDescription(r.value.description);
5651
- setWhenToUse(r.value.whenToUse);
5652
- setBody(r.value.content);
5653
- } else {
5654
- setMsg("\u8BFB\u53D6\u5931\u8D25\uFF1A" + (r.ok ? r.value.error ?? "\u672A\u77E5\u9519\u8BEF" : describeError(r.error)));
5655
- }
5656
- });
5657
- };
5658
- const startEdit = (sk) => {
5659
- const lvl = levelOf(sk.source);
5660
- setEditing(sk.name);
5661
- setCreating(false);
5662
- setViewing(false);
5750
+ const lvl = levelOf(row);
5663
5751
  setLevel(lvl === "user" ? "user" : "project");
5664
- loadSkill(sk.name, lvl);
5665
- };
5666
- const startView = (sk) => {
5667
- setEditing(sk.name);
5668
- setCreating(false);
5669
- setViewing(true);
5670
- loadSkill(sk.name, "bundled");
5671
- };
5672
- const submit = async () => {
5673
- setMsg("");
5674
- const target = editing ?? name;
5675
- const result = await remote.writeSkill({
5676
- name: target,
5677
- description,
5678
- whenToUse: whenToUse.trim() === "" ? void 0 : whenToUse,
5679
- content: body2,
5680
- level,
5681
- path: level === "project" ? workspace : void 0
5682
- });
5683
- if (!result.ok) {
5684
- setMsg("\u4FDD\u5B58\u5931\u8D25\uFF1A" + describeError(result.error));
5685
- return;
5752
+ setBusy(true);
5753
+ try {
5754
+ const r = kind === "skill" ? await remote.readSkill({ name: row.name, level: lvl, path: workspace }) : await remote.readRule({ name: row.name, level: lvl, path: workspace });
5755
+ if (!r.ok) throw new Error(fail(r));
5756
+ if (!r.value.ok) throw new Error(r.value.error ?? "\u8BFB\u53D6\u5931\u8D25");
5757
+ setBody(r.value.content);
5758
+ if (kind === "skill") {
5759
+ const skill = r.value;
5760
+ setDescription(skill.description);
5761
+ setWhenToUse(skill.whenToUse);
5762
+ }
5763
+ } catch (e) {
5764
+ setError(describeError(e));
5765
+ } finally {
5766
+ setBusy(false);
5686
5767
  }
5687
- if (!result.value.ok) {
5688
- setMsg("\u4FDD\u5B58\u5931\u8D25\uFF1A" + (result.value.error ?? "\u672A\u77E5\u9519\u8BEF"));
5689
- return;
5768
+ };
5769
+ const save2 = async () => {
5770
+ if (busy) return;
5771
+ setBusy(true);
5772
+ setError("");
5773
+ try {
5774
+ if (editing === "new" && rows.some((r2) => r2.name === name && (levelOf(r2) === level || levelOf(r2) === "bundled"))) throw new Error("\u540C\u540D\u8D44\u6E90\u5DF2\u5B58\u5728\uFF0C\u8BF7\u6362\u540D\u6216\u7F16\u8F91\u73B0\u6709\u8D44\u6E90");
5775
+ const r = kind === "skill" ? await remote.writeSkill({ name, description, whenToUse, content: body2, level, path: workspace }) : await remote.writeRule({ name, content: body2, level, path: workspace });
5776
+ if (!r.ok) throw new Error(fail(r));
5777
+ if (!r.value.ok) throw new Error(r.value.error ?? "\u4FDD\u5B58\u5931\u8D25");
5778
+ setNotice(`\u5DF2\u4FDD\u5B58${noun} \xB7 ${r.value.path}`);
5779
+ setEditing(null);
5780
+ refresh((n) => n + 1);
5781
+ } catch (e) {
5782
+ setError(describeError(e));
5783
+ } finally {
5784
+ setBusy(false);
5690
5785
  }
5691
- setMsg(`\u5DF2\u4FDD\u5B58 skill\u300C${result.value.name}\u300D`);
5692
- setEditing(null);
5693
- setCreating(false);
5694
- refresh();
5695
5786
  };
5696
- const remove = async (sk) => {
5697
- setMsg("");
5698
- const lvl = levelOf(sk.source);
5787
+ const remove = async () => {
5788
+ if (!deleting || busy) return;
5789
+ const lvl = levelOf(deleting);
5699
5790
  if (lvl === "bundled") return;
5700
- const result = await remote.deleteSkill({ name: sk.name, level: lvl, path: workspace });
5701
- if (!result.ok) {
5702
- setMsg("\u5220\u9664\u5931\u8D25\uFF1A" + describeError(result.error));
5703
- setConfirming(null);
5704
- return;
5705
- }
5706
- if (!result.value.ok) {
5707
- setMsg("\u5220\u9664\u5931\u8D25\uFF1A" + (result.value.error ?? "\u672A\u77E5\u9519\u8BEF"));
5708
- setConfirming(null);
5709
- return;
5791
+ setBusy(true);
5792
+ setError("");
5793
+ try {
5794
+ const r = kind === "skill" ? await remote.deleteSkill({ name: deleting.name, level: lvl, path: workspace }) : await remote.deleteRule({ name: deleting.name, level: lvl, path: workspace });
5795
+ if (!r.ok) throw new Error(fail(r));
5796
+ if (!r.value.ok) throw new Error(r.value.error ?? "\u5220\u9664\u5931\u8D25");
5797
+ setNotice(`\u5DF2\u5220\u9664${noun}\u300C${deleting.name}\u300D`);
5798
+ setDeleting(null);
5799
+ refresh((n) => n + 1);
5800
+ } catch (e) {
5801
+ setError(describeError(e));
5802
+ } finally {
5803
+ setBusy(false);
5710
5804
  }
5711
- setMsg(`\u5DF2\u5220\u9664 skill\u300C${result.value.name}\u300D`);
5712
- if (editing === sk.name) setEditing(null);
5713
- setConfirming(null);
5714
- refresh();
5715
5805
  };
5716
- const formOpen = editing !== null || creating || installing;
5717
- const renderRow = (sk) => (0, import_react4.createElement)(
5806
+ const status = () => error ? (0, import_react4.createElement)("div", { className: "te-alert", role: "alert" }, error) : null;
5807
+ const targets = () => (0, import_react4.createElement)(
5718
5808
  "div",
5719
- {
5720
- key: sk.name,
5721
- style: { display: "flex", alignItems: "center", gap: 8, justifyContent: "space-between", padding: "6px 0", borderBottom: "1px solid var(--dsw-alias-border-l2)" }
5722
- },
5723
- (0, import_react4.createElement)(
5724
- "div",
5725
- { style: { display: "flex", flexDirection: "column", gap: 2, minWidth: 0 } },
5726
- (0, import_react4.createElement)(
5727
- "span",
5728
- { style: { fontSize: 13, color: "var(--dsw-alias-label-primary)" } },
5729
- sk.name,
5730
- sk.source !== "bundled" ? (0, import_react4.createElement)("span", { style: styles.sourceBadge }, `\uFF08${sourceLabel(sk.source)}\uFF09`) : null
5731
- ),
5732
- (0, import_react4.createElement)("span", { style: styles.sourceBadge }, sk.description)
5733
- ),
5734
- sk.source === "bundled" ? (0, import_react4.createElement)(import_dsh_client_ui_primitives4.Button, { variant: "outline", size: "sm", onClick: () => {
5735
- startView(sk);
5736
- } }, "\u67E5\u770B") : (0, import_react4.createElement)(
5737
- "div",
5738
- { style: { display: "flex", gap: 6 } },
5739
- (0, import_react4.createElement)(import_dsh_client_ui_primitives4.Button, { variant: "outline", size: "sm", onClick: () => {
5740
- startEdit(sk);
5741
- } }, "\u7F16\u8F91"),
5742
- confirming === sk.name ? (0, import_react4.createElement)(import_dsh_client_ui_primitives4.Button, { variant: "primary", size: "sm", onClick: () => {
5743
- void remove(sk);
5744
- } }, "\u786E\u8BA4\u5220\u9664") : (0, import_react4.createElement)(import_dsh_client_ui_primitives4.Button, { variant: "ghost", size: "sm", onClick: () => {
5745
- setConfirming(sk.name);
5746
- } }, "\u5220\u9664")
5747
- )
5809
+ { className: "te-targets" },
5810
+ ...["project", "user"].map((lvl) => (0, import_react4.createElement)(
5811
+ "button",
5812
+ { type: "button", key: lvl, className: `te-target ${level === lvl ? "selected" : ""}`, "aria-pressed": level === lvl, disabled: busy || editing !== null && editing !== "new", onClick: () => {
5813
+ setPreview(null);
5814
+ setLevel(lvl);
5815
+ } },
5816
+ (0, import_react4.createElement)("strong", null, lvl === "project" ? "\u9879\u76EE\u5171\u4EAB" : "\u4E2A\u4EBA\u5168\u5C40"),
5817
+ (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")
5818
+ )),
5819
+ (0, import_react4.createElement)("code", { className: "te-path" }, roots?.[level] ?? (level === "project" ? `${workspace}/.dsh/${kind}s` : `DSH_HOME/${kind}s`))
5748
5820
  );
5749
- const renderForm = () => {
5750
- if (viewing) {
5751
- return (0, import_react4.createElement)(
5752
- ResourceModal,
5753
- {
5754
- title: `\u67E5\u770B skill\u300C${editing ?? ""}\u300D`,
5755
- description: "\u5185\u7F6E \xB7 \u53EA\u8BFB" + (whenToUse !== "" && whenToUse !== void 0 ? ` \xB7 \u4F7F\u7528\u65F6\u673A\uFF1A${whenToUse}` : ""),
5756
- onClose: closeForm,
5757
- footer: (0, import_react4.createElement)(import_dsh_client_ui_primitives4.Button, { variant: "ghost", size: "sm", onClick: closeForm }, "\u5173\u95ED")
5758
- },
5759
- (0, import_react4.createElement)(import_dsh_client_ui_primitives4.MarkdownText, { text: body2, labels: MD_LABELS2 })
5760
- );
5761
- }
5762
- return (0, import_react4.createElement)(
5821
+ const visible = rows.filter((r) => `${r.name} ${r.description ?? ""}`.toLowerCase().includes(query.toLowerCase()) && (filter === "all" || levelOf(r) === filter));
5822
+ return (0, import_react4.createElement)(
5823
+ "section",
5824
+ { className: "te-resource" },
5825
+ (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) => {
5826
+ void selected(Array.from(e.target.files ?? []));
5827
+ } }),
5828
+ (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: () => {
5829
+ void edit("new");
5830
+ } }, `\u65B0\u5EFA${noun}`), (0, import_react4.createElement)(import_dsh_client_ui_primitives4.Button, { variant: "primary", onClick: choose }, `\u5B89\u88C5${noun}`))),
5831
+ (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")),
5832
+ notice ? (0, import_react4.createElement)("div", { className: "te-success", role: "status" }, notice) : null,
5833
+ !importing && !editing && !deleting ? status() : null,
5834
+ 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)(
5835
+ "article",
5836
+ { className: "te-resource-card", key: row.source + "/" + row.name },
5837
+ (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))),
5838
+ (0, import_react4.createElement)("h3", null, row.name),
5839
+ (0, import_react4.createElement)("p", null, row.description || "\u9879\u76EE\u7EA6\u5B9A\u4E0E\u6267\u884C\u89C4\u5219"),
5840
+ (0, import_react4.createElement)("div", { className: "te-actions" }, (0, import_react4.createElement)(import_dsh_client_ui_primitives4.Button, { variant: "outline", size: "sm", onClick: () => {
5841
+ void edit(row, true);
5842
+ } }, "\u67E5\u770B"), levelOf(row) !== "bundled" ? (0, import_react4.createElement)(import_dsh_client_ui_primitives4.Button, { variant: "ghost", size: "sm", onClick: () => {
5843
+ void edit(row);
5844
+ } }, "\u7F16\u8F91") : null, levelOf(row) !== "bundled" ? (0, import_react4.createElement)("button", { className: "te-delete", onClick: () => {
5845
+ setDeleting(row);
5846
+ setError("");
5847
+ } }, "\u5220\u9664") : null)
5848
+ ))),
5849
+ kind === "skill" ? (0, import_react4.createElement)("button", { className: "te-link", onClick: () => {
5850
+ setImporting(true);
5851
+ setManual(true);
5852
+ setError("");
5853
+ } }, "\u9AD8\u7EA7\uFF1A\u4ECE Harness \u4E3B\u673A\u8DEF\u5F84\u5B89\u88C5") : null,
5854
+ importing ? (0, import_react4.createElement)(
5763
5855
  ResourceModal,
5764
- {
5765
- title: editing === null ? "\u65B0\u5EFA skill" : `\u7F16\u8F91 skill\u300C${editing ?? ""}\u300D`,
5766
- onClose: closeForm,
5767
- footer: (0, import_react4.createElement)(
5768
- "div",
5769
- { style: styles.row },
5770
- (0, import_react4.createElement)(import_dsh_client_ui_primitives4.Button, {
5771
- variant: "primary",
5772
- size: "sm",
5773
- disabled: editing === null && name.trim() === "" || description.trim() === "" || body2.trim() === "",
5774
- onClick: () => {
5775
- void submit();
5776
- }
5777
- }, "\u4FDD\u5B58"),
5778
- (0, import_react4.createElement)(import_dsh_client_ui_primitives4.Button, { variant: "ghost", size: "sm", onClick: closeForm }, "\u53D6\u6D88")
5779
- )
5780
- },
5781
- (0, import_react4.createElement)(
5782
- "div",
5783
- { style: styles.chips },
5784
- (0, import_react4.createElement)(import_dsh_client_ui_primitives4.Pill, { active: level === "project", onClick: () => {
5785
- setLevel("project");
5786
- }, title: "\u5199\u5230\u5DE5\u4F5C\u533A .dsh/skills\uFF0C\u56E2\u961F\u5171\u4EAB" }, "\u9879\u76EE\u7EA7"),
5787
- (0, import_react4.createElement)(import_dsh_client_ui_primitives4.Pill, { active: level === "user", onClick: () => {
5788
- setLevel("user");
5789
- }, title: "\u5199\u5230 $DSH_HOME/skills\uFF0C\u4E2A\u4EBA\u6240\u6709\u9879\u76EE\u53EF\u7528" }, "\u7528\u6237\u7EA7")
5790
- ),
5791
- editing === null ? (0, import_react4.createElement)("input", { style: control, placeholder: "name\uFF08\u5982 my-skill\uFF0C\u53EA\u542B\u5C0F\u5199\u5B57\u6BCD\u6570\u5B57\u548C -\uFF09", value: name, onChange: (ev) => {
5792
- setName(ev.target.value);
5793
- } }) : (0, import_react4.createElement)("span", { style: styles.sourceBadge }, `name \u56FA\u5B9A\u4E3A ${name}\uFF08\u6539\u540D\u8BF7\u5220\u9664\u540E\u91CD\u5EFA\uFF09`),
5794
- (0, import_react4.createElement)("input", { style: control, placeholder: "description\uFF08\u4E00\u53E5\u8BDD\u8BF4\u660E\u5B83\u505A\u4EC0\u4E48\uFF09", value: description, onChange: (ev) => {
5795
- setDescription(ev.target.value);
5796
- } }),
5797
- (0, import_react4.createElement)("input", { style: control, placeholder: "whenToUse\uFF08\u53EF\u9009\uFF1A\u4EC0\u4E48\u60C5\u51B5\u8BE5\u7528\uFF09", value: whenToUse, onChange: (ev) => {
5798
- setWhenToUse(ev.target.value);
5799
- } }),
5800
- (0, import_react4.createElement)("textarea", { style: { ...styles.textarea, minHeight: 300 }, placeholder: "\u6B63\u6587\uFF08\u544A\u8BC9\u5927\u6A21\u578B\u8FD9\u4E2A\u9636\u6BB5\u600E\u4E48\u5E72\uFF09", value: body2, onChange: (ev) => {
5801
- setBody(ev.target.value);
5802
- } }),
5803
- msg !== "" ? (0, import_react4.createElement)("p", { style: styles.status }, msg) : null
5804
- );
5805
- };
5806
- const renderInstallForm = () => (0, import_react4.createElement)(
5807
- ResourceModal,
5808
- {
5809
- title: "\u5B89\u88C5\u73B0\u6709 skill\uFF08\u76EE\u5F55\u578B\uFF09",
5810
- description: "\u628A\u4E00\u4E2A\u672C\u673A\u5DF2\u6709\u7684 skill \u76EE\u5F55\uFF08\u542B SKILL.md\uFF0C\u53EF\u5E26 references / scripts \u7B49\u6587\u4EF6\uFF09\u5B89\u88C5\u5230\u9879\u76EE\u7EA7\u6216\u7528\u6237\u7EA7\u3002",
5811
- onClose: () => {
5812
- setInstalling(false);
5813
- setMsg("");
5814
- },
5815
- footer: (0, import_react4.createElement)(
5816
- "div",
5817
- { style: styles.row },
5818
- (0, import_react4.createElement)(import_dsh_client_ui_primitives4.Button, {
5819
- variant: "primary",
5820
- size: "sm",
5821
- disabled: installDir.trim() === "",
5822
- onClick: () => {
5823
- void submitInstall();
5824
- }
5825
- }, "\u5B89\u88C5"),
5826
- (0, import_react4.createElement)(import_dsh_client_ui_primitives4.Button, { variant: "ghost", size: "sm", onClick: () => {
5827
- setInstalling(false);
5828
- setMsg("");
5829
- } }, "\u53D6\u6D88")
5830
- )
5831
- },
5832
- (0, import_react4.createElement)(
5833
- "div",
5834
- { style: styles.chips },
5835
- (0, import_react4.createElement)(import_dsh_client_ui_primitives4.Pill, { active: installLevel === "project", onClick: () => {
5836
- setInstallLevel("project");
5837
- }, title: "\u88C5\u5230\u5DE5\u4F5C\u533A .dsh/skills\uFF0C\u56E2\u961F\u5171\u4EAB" }, "\u9879\u76EE\u7EA7"),
5838
- (0, import_react4.createElement)(import_dsh_client_ui_primitives4.Pill, { active: installLevel === "user", onClick: () => {
5839
- setInstallLevel("user");
5840
- }, title: "\u88C5\u5230 $DSH_HOME/skills\uFF0C\u4E2A\u4EBA\u6240\u6709\u9879\u76EE\u53EF\u7528" }, "\u7528\u6237\u7EA7")
5841
- ),
5842
- (0, import_react4.createElement)(
5843
- "div",
5844
- { style: styles.row },
5845
- (0, import_react4.createElement)("input", {
5846
- style: { ...control, flex: "1 1 220px", minWidth: 160 },
5847
- placeholder: "\u6E90\u76EE\u5F55\u7EDD\u5BF9\u8DEF\u5F84\uFF08\u672C\u673A skill \u76EE\u5F55\uFF0C\u9700\u542B SKILL.md\uFF09",
5848
- value: installDir,
5849
- onChange: (ev) => {
5850
- setInstallDir(ev.target.value);
5851
- }
5852
- }),
5853
- (0, import_react4.createElement)(import_dsh_client_ui_primitives4.Button, { variant: "outline", size: "sm", onClick: openBrowse }, "\u6D4F\u89C8\u2026")
5854
- ),
5855
- (0, import_react4.createElement)("p", { style: styles.hint }, "\u8981\u6C42\uFF1A\u76EE\u5F55\u5185\u6709 SKILL.md\uFF08frontmatter \u542B name + description\uFF09\u3002skill \u53EF\u4EE5\u662F\u5B8C\u6574\u5305\uFF08references / scripts / \u6A21\u677F\u7B49\u90FD\u4F1A\u4FDD\u7559\uFF09\uFF1B\u5B89\u88C5\u81EA\u52A8\u6392\u9664 node_modules / .git / __pycache__ \u7B49\u7F13\u5B58\u76EE\u5F55\uFF08\u4E0A\u9650 1000 \u6587\u4EF6 / 100 MB\uFF09\uFF0C\u540C\u540D\u5185\u7F6E\u6280\u80FD\u62D2\u7EDD\u8986\u76D6\uFF0C\u540C\u540D\u5DF2\u88C5\u6280\u80FD\u9700\u5148\u5220\u9664\u3002\u70B9\u300C\u6D4F\u89C8\u2026\u300D\u9009\u62E9\u76EE\u5F55\uFF0C\u6216\u76F4\u63A5\u8F93\u5165\u8DEF\u5F84\u3002"),
5856
- msg !== "" ? (0, import_react4.createElement)("p", { style: styles.status }, msg) : null
5857
- );
5858
- const renderDirRow = (entry, active, onClick) => (0, import_react4.createElement)(
5859
- "button",
5860
- {
5861
- key: entry.name,
5862
- type: "button",
5863
- onClick,
5864
- title: entry.name,
5865
- style: {
5866
- display: "flex",
5867
- alignItems: "center",
5868
- gap: 6,
5869
- width: "100%",
5870
- border: "none",
5871
- cursor: "pointer",
5872
- textAlign: "left",
5873
- padding: "5px 8px",
5874
- borderRadius: 6,
5875
- fontSize: 13,
5876
- background: active ? "var(--dsw-alias-bg-layer-2)" : "transparent",
5877
- color: "var(--dsw-alias-label-primary)",
5878
- fontWeight: active ? 600 : 400
5879
- }
5880
- },
5881
- (0, import_react4.createElement)("span", { style: { flex: "1 1 auto", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" } }, " " + entry.name),
5882
- entry.hasSkill ? (0, import_react4.createElement)("span", { style: { fontSize: 11, color: "var(--dsw-alias-state-success-primary)" } }, "SKILL.md") : null
5883
- );
5884
- const renderBrowseModal = () => (0, import_react4.createElement)(
5885
- ResourceModal,
5886
- {
5887
- title: "\u9009\u62E9 skill \u76EE\u5F55",
5888
- description: "\u76EE\u5F55\u5217\u8868\u7531\u4F60\u7684 DSH \u4E3B\u673A\u8BFB\u53D6\uFF1B\u5C55\u5F00\u5230\u542B SKILL.md \u7684\u76EE\u5F55\u540E\u70B9\u300C\u9009\u6B64\u76EE\u5F55\u300D\u3002",
5889
- onClose: () => {
5890
- setBrowsing(false);
5891
- },
5892
- footer: (0, import_react4.createElement)(
5893
- "div",
5894
- { style: styles.row },
5895
- (0, import_react4.createElement)("span", {
5896
- style: {
5897
- ...styles.sourceText,
5898
- flex: "1 1 auto",
5899
- color: pickedHasSkill ? "var(--dsw-alias-state-success-primary)" : "var(--dsw-alias-label-tertiary)"
5900
- }
5901
- }, pickedHasSkill ? "\u2713 \u5F53\u524D\u76EE\u5F55\u542B SKILL.md\uFF0C\u53EF\u76F4\u63A5\u5B89\u88C5" : "\u5F53\u524D\u76EE\u5F55\u4E0D\u542B SKILL.md\u2014\u2014\u8FDB\u5165\u542B SKILL.md \u7684\u5B50\u76EE\u5F55\u518D\u9009"),
5902
- (0, import_react4.createElement)(import_dsh_client_ui_primitives4.Button, {
5903
- variant: "primary",
5904
- size: "sm",
5905
- disabled: pickedPath.trim() === "",
5906
- onClick: () => {
5907
- setInstallDir(pickedPath);
5908
- setBrowsing(false);
5909
- }
5910
- }, "\u9009\u6B64\u76EE\u5F55"),
5911
- (0, import_react4.createElement)(import_dsh_client_ui_primitives4.Button, { variant: "ghost", size: "sm", onClick: () => {
5912
- setBrowsing(false);
5913
- } }, "\u53D6\u6D88")
5914
- )
5915
- },
5916
- (0, import_react4.createElement)(
5917
- "div",
5918
- { style: { ...styles.row, marginBottom: 6 } },
5919
- (0, import_react4.createElement)("input", {
5920
- style: { ...control, flex: "1 1 200px", minWidth: 140 },
5921
- placeholder: "\u8F93\u5165\u7EDD\u5BF9\u8DEF\u5F84\u540E\u56DE\u8F66\u524D\u5F80",
5922
- value: browseDraft,
5923
- onChange: (ev) => {
5924
- setBrowseDraft(ev.target.value);
5925
- },
5926
- onKeyDown: (ev) => {
5927
- if (ev.key === "Enter") loadLevel(browseDraft.trim());
5928
- }
5929
- }),
5930
- (0, import_react4.createElement)(import_dsh_client_ui_primitives4.Button, { variant: "ghost", size: "sm", onClick: () => {
5931
- loadLevel(browseDraft.trim());
5932
- } }, "\u524D\u5F80"),
5933
- (0, import_react4.createElement)(import_dsh_client_ui_primitives4.Button, { variant: "ghost", size: "sm", disabled: isRootLevel(browseCurrent), onClick: browseUp, title: "\u8FDB\u5165\u4E0A\u7EA7\u76EE\u5F55" }, "\u2191 \u4E0A\u7EA7")
5934
- ),
5935
- browseRoots.length > 1 ? (0, import_react4.createElement)(
5936
- "div",
5937
- { style: { ...styles.chips, marginBottom: 6 } },
5938
- ...browseRoots.map((root) => (0, import_react4.createElement)(import_dsh_client_ui_primitives4.Button, { key: root, variant: "ghost", size: "sm", onClick: () => {
5939
- loadLevel(root);
5940
- } }, root.replace(/[\\/]+$/u, "")))
5856
+ { 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: () => {
5857
+ void install();
5858
+ } }, busy ? "\u5904\u7406\u4E2D\u2026" : "\u786E\u8BA4\u5B89\u88C5")) },
5859
+ targets(),
5860
+ (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),
5861
+ 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) => {
5862
+ setSourceDir(e.target.value);
5863
+ setRequest(null);
5864
+ } }), (0, import_react4.createElement)(import_dsh_client_ui_primitives4.Button, { variant: "outline", onClick: () => {
5865
+ void browse(sourceDir);
5866
+ } }, "\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: () => {
5867
+ void browse(browsePath.replace(/[\\/][^\\/]+[\\/]?$/u, "") || "/");
5868
+ } }, "\u2191 \u4E0A\u7EA7\u76EE\u5F55") : null, ...dirs.map((d) => (0, import_react4.createElement)("button", { key: d.name, onClick: () => {
5869
+ setRequest(null);
5870
+ void browse(browsePath.replace(/[\\/]+$/u, "") + "/" + d.name);
5871
+ } }, d.name + (d.hasSkill ? " \xB7 SKILL.md" : ""))))) : null,
5872
+ busy ? (0, import_react4.createElement)("p", { role: "status" }, "\u6B63\u5728\u6821\u9A8C\u6587\u4EF6\uFF0C\u8BF7\u7A0D\u5019\u2026") : null,
5873
+ status(),
5874
+ 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
5941
5875
  ) : null,
5942
- // Breadcrumb: the current level with every ancestor clickable — the
5943
- // visible answer to "where am I / how do I go up".
5944
- (0, import_react4.createElement)(
5945
- "div",
5946
- { style: { display: "flex", alignItems: "center", flexWrap: "wrap", gap: 2, marginBottom: 6, minHeight: 22 } },
5947
- browseCurrent === "" ? (0, import_react4.createElement)("span", { style: styles.sourceText }, "\u4E3B\u76EE\u5F55") : (0, import_react4.createElement)(
5948
- "span",
5949
- { style: { display: "inline-flex", alignItems: "center", flexWrap: "wrap", gap: 2 } },
5950
- ...breadcrumbSegments(browseCurrent).map(
5951
- (seg) => (0, import_react4.createElement)("button", {
5952
- key: seg.path,
5953
- type: "button",
5954
- onClick: () => {
5955
- loadLevel(seg.path);
5956
- },
5957
- title: seg.path,
5958
- style: { border: "none", background: "transparent", cursor: "pointer", padding: "1px 3px", borderRadius: 4, fontSize: 12, color: "var(--dsw-alias-label-secondary)" }
5959
- }, seg.label + " \u203A")
5960
- )
5961
- )
5962
- ),
5963
- browseError !== "" ? (0, import_react4.createElement)("p", { style: { ...styles.status, color: "var(--dsw-alias-state-error-primary)" } }, browseError) : null,
5964
- (0, import_react4.createElement)(
5965
- "div",
5966
- { style: { display: "flex", gap: 8, height: 260 } },
5967
- (0, import_react4.createElement)(
5968
- "div",
5969
- { style: paneStyle },
5970
- browseEntries.length === 0 && browseError === "" ? (0, import_react4.createElement)("p", { style: styles.sourceText }, "\uFF08\u6B64\u76EE\u5F55\u4E0B\u6CA1\u6709\u5B50\u76EE\u5F55\uFF09") : null,
5971
- ...browseEntries.map((entry) => renderDirRow(entry, browseSelected?.name === entry.name, () => {
5972
- selectRow(entry);
5973
- }))
5974
- ),
5975
- browseSelected !== null ? (0, import_react4.createElement)(
5976
- "div",
5977
- { style: paneStyle },
5978
- browseChildEntries.length === 0 ? (0, import_react4.createElement)("p", { style: styles.sourceText }, "\uFF08\u6CA1\u6709\u5B50\u76EE\u5F55\uFF09") : null,
5979
- ...browseChildEntries.map((entry) => renderDirRow(entry, false, () => {
5980
- selectChildRow(entry);
5981
- }))
5982
- ) : null
5983
- )
5984
- );
5985
- return (0, import_react4.createElement)(
5986
- "div",
5987
- { style: styles.section },
5988
- (0, import_react4.createElement)(
5989
- "div",
5990
- { style: card2 },
5991
- (0, import_react4.createElement)(
5992
- "div",
5993
- { style: styles.bindingStage },
5994
- (0, import_react4.createElement)("span", { style: styles.bindingLabel }, "\u5DF2\u5B89\u88C5\u7684 skill"),
5995
- skills.length === 0 ? (0, import_react4.createElement)("p", { style: styles.muted }, "\u6682\u65E0 skill\uFF0C\u70B9\u4E0B\u65B9\u300C\u65B0\u5EFA skill\u300D\u521B\u5EFA\uFF0C\u6216\u300C\u5B89\u88C5 skill\u300D\u5BFC\u5165\u672C\u673A\u5DF2\u6709\u7684 skill \u76EE\u5F55\u3002") : (0, import_react4.createElement)(
5996
- "div",
5997
- { style: styles.section },
5998
- ...skills.map(renderRow)
5999
- )
6000
- ),
6001
- (0, import_react4.createElement)(
6002
- "div",
6003
- { style: styles.row },
6004
- (0, import_react4.createElement)(import_dsh_client_ui_primitives4.Button, { variant: "outline", size: "md", onClick: startCreate }, "\u65B0\u5EFA skill"),
6005
- (0, import_react4.createElement)(import_dsh_client_ui_primitives4.Button, { variant: "outline", size: "md", onClick: startInstall }, "\u5B89\u88C5 skill")
6006
- )
6007
- ),
6008
- installing ? renderInstallForm() : null,
6009
- browsing ? renderBrowseModal() : null,
6010
- formOpen && !installing ? renderForm() : null
5876
+ editing ? (0, import_react4.createElement)(
5877
+ ResourceModal,
5878
+ { 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: () => {
5879
+ void save2();
5880
+ } }, busy ? "\u5904\u7406\u4E2D\u2026" : "\u4FDD\u5B58") : null) },
5881
+ !readonly ? targets() : (0, import_react4.createElement)("p", { className: "te-badge" }, "\u5185\u7F6E\u8D44\u6E90 \xB7 \u53EA\u8BFB"),
5882
+ status(),
5883
+ 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) })))
5884
+ ) : null,
5885
+ 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: () => {
5886
+ void remove();
5887
+ } }, 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
6011
5888
  );
6012
5889
  }
6013
5890
 
6014
- // src/client/RuleManager.tsx
6015
- var import_react5 = require("react");
6016
- var import_dsh_client_ui_primitives5 = require("@deepseek-ai/dsh-client-ui-primitives");
6017
- var MD_LABELS3 = { code: { copyLabel: "\u590D\u5236", copiedLabel: "\u5DF2\u590D\u5236" }, footnotes: "\u811A\u6CE8" };
6018
- var control2 = {
6019
- background: "var(--dsw-alias-bg-layer-1)",
6020
- border: "1px solid var(--dsw-alias-border-l2)",
6021
- borderRadius: 8,
6022
- padding: "5px 8px",
6023
- color: "var(--dsw-alias-label-primary)",
6024
- fontSize: 13,
6025
- minWidth: 0
6026
- };
6027
- var card3 = {
6028
- display: "flex",
6029
- flexDirection: "column",
6030
- gap: 8,
6031
- border: "1px solid var(--dsw-alias-border-l2)",
6032
- borderRadius: 8,
6033
- padding: "10px 12px"
6034
- };
6035
- function levelOf2(source) {
6036
- if (source === "bundled") return "bundled";
6037
- return source.startsWith("user") ? "user" : "project";
5891
+ // src/client/SkillManager.tsx
5892
+ function SkillManager(props) {
5893
+ return (0, import_react5.createElement)(ResourceManager, { ...props, key: props.workspace, kind: "skill" });
6038
5894
  }
6039
- function RuleManager({ workspace, remote }) {
6040
- const [rules, setRules] = (0, import_react5.useState)([]);
6041
- const [level, setLevel] = (0, import_react5.useState)("project");
6042
- const [editing, setEditing] = (0, import_react5.useState)(null);
6043
- const [creating, setCreating] = (0, import_react5.useState)(false);
6044
- const [viewing, setViewing] = (0, import_react5.useState)(false);
6045
- const [confirming, setConfirming] = (0, import_react5.useState)(null);
6046
- const [name, setName] = (0, import_react5.useState)("");
6047
- const [body2, setBody] = (0, import_react5.useState)("");
6048
- const [msg, setMsg] = (0, import_react5.useState)("");
6049
- const refresh = (0, import_react5.useCallback)(() => {
6050
- void remote.listRules(workspace).then((r) => {
6051
- if (r.ok) setRules(r.value.rules);
6052
- }, () => {
6053
- });
6054
- }, [remote, workspace]);
6055
- (0, import_react5.useEffect)(() => {
6056
- refresh();
6057
- }, [refresh]);
6058
- const closeForm = () => {
6059
- setEditing(null);
6060
- setCreating(false);
6061
- setViewing(false);
6062
- setName("");
6063
- setBody("");
6064
- setMsg("");
6065
- };
6066
- const startCreate = () => {
6067
- setEditing(null);
6068
- setCreating(true);
6069
- setViewing(false);
6070
- setLevel("project");
6071
- setName("");
6072
- setBody("");
6073
- setMsg("");
6074
- };
6075
- const loadRule = (ruleName, lvl) => {
6076
- setMsg("");
6077
- void remote.readRule({ name: ruleName, level: lvl, path: workspace }).then((r) => {
6078
- if (r.ok && r.value.ok) {
6079
- setName(r.value.name);
6080
- setBody(r.value.content);
6081
- } else {
6082
- setMsg("\u8BFB\u53D6\u5931\u8D25\uFF1A" + (r.ok ? r.value.error ?? "\u672A\u77E5\u9519\u8BEF" : describeError(r.error)));
6083
- }
6084
- });
6085
- };
6086
- const startEdit = (rule) => {
6087
- const lvl = levelOf2(rule.source);
6088
- setEditing(rule.name);
6089
- setCreating(false);
6090
- setViewing(false);
6091
- setLevel(lvl === "user" ? "user" : "project");
6092
- loadRule(rule.name, lvl);
6093
- };
6094
- const startView = (rule) => {
6095
- setEditing(rule.name);
6096
- setCreating(false);
6097
- setViewing(true);
6098
- loadRule(rule.name, "bundled");
6099
- };
6100
- const submit = async () => {
6101
- setMsg("");
6102
- const result = await remote.writeRule({
6103
- name: editing ?? name,
6104
- content: body2,
6105
- level,
6106
- path: level === "project" ? workspace : void 0
6107
- });
6108
- if (!result.ok) {
6109
- setMsg("\u4FDD\u5B58\u5931\u8D25\uFF1A" + describeError(result.error));
6110
- return;
6111
- }
6112
- if (!result.value.ok) {
6113
- setMsg("\u4FDD\u5B58\u5931\u8D25\uFF1A" + (result.value.error ?? "\u672A\u77E5\u9519\u8BEF"));
6114
- return;
6115
- }
6116
- setMsg(`\u5DF2\u4FDD\u5B58 rule\u300C${result.value.name}\u300D`);
6117
- setEditing(null);
6118
- setCreating(false);
6119
- refresh();
6120
- };
6121
- const remove = async (rule) => {
6122
- setMsg("");
6123
- const lvl = levelOf2(rule.source);
6124
- if (lvl === "bundled") return;
6125
- const result = await remote.deleteRule({ name: rule.name, level: lvl, path: workspace });
6126
- if (!result.ok) {
6127
- setMsg("\u5220\u9664\u5931\u8D25\uFF1A" + describeError(result.error));
6128
- setConfirming(null);
6129
- return;
6130
- }
6131
- if (!result.value.ok) {
6132
- setMsg("\u5220\u9664\u5931\u8D25\uFF1A" + (result.value.error ?? "\u672A\u77E5\u9519\u8BEF"));
6133
- setConfirming(null);
6134
- return;
6135
- }
6136
- setMsg(`\u5DF2\u5220\u9664 rule\u300C${result.value.name}\u300D`);
6137
- if (editing === rule.name) setEditing(null);
6138
- setConfirming(null);
6139
- refresh();
6140
- };
6141
- const formOpen = editing !== null || creating;
6142
- const renderRow = (rule) => (0, import_react5.createElement)(
6143
- "div",
6144
- {
6145
- key: rule.name,
6146
- style: { display: "flex", alignItems: "center", gap: 8, justifyContent: "space-between", padding: "6px 0", borderBottom: "1px solid var(--dsw-alias-border-l2)" }
6147
- },
6148
- (0, import_react5.createElement)(
6149
- "span",
6150
- { style: { fontSize: 13, color: "var(--dsw-alias-label-primary)" } },
6151
- rule.name,
6152
- rule.source !== "bundled" ? (0, import_react5.createElement)("span", { style: styles.sourceBadge }, `\uFF08${sourceLabel(rule.source)}\uFF09`) : null
6153
- ),
6154
- rule.source === "bundled" ? (0, import_react5.createElement)(import_dsh_client_ui_primitives5.Button, { variant: "outline", size: "sm", onClick: () => {
6155
- startView(rule);
6156
- } }, "\u67E5\u770B") : (0, import_react5.createElement)(
6157
- "div",
6158
- { style: { display: "flex", gap: 6 } },
6159
- (0, import_react5.createElement)(import_dsh_client_ui_primitives5.Button, { variant: "outline", size: "sm", onClick: () => {
6160
- startEdit(rule);
6161
- } }, "\u7F16\u8F91"),
6162
- confirming === rule.name ? (0, import_react5.createElement)(import_dsh_client_ui_primitives5.Button, { variant: "primary", size: "sm", onClick: () => {
6163
- void remove(rule);
6164
- } }, "\u786E\u8BA4\u5220\u9664") : (0, import_react5.createElement)(import_dsh_client_ui_primitives5.Button, { variant: "ghost", size: "sm", onClick: () => {
6165
- setConfirming(rule.name);
6166
- } }, "\u5220\u9664")
6167
- )
6168
- );
6169
- const renderForm = () => {
6170
- if (viewing) {
6171
- return (0, import_react5.createElement)(
6172
- ResourceModal,
6173
- {
6174
- title: `\u67E5\u770B rule\u300C${editing ?? ""}\u300D`,
6175
- description: "\u5185\u7F6E \xB7 \u53EA\u8BFB",
6176
- onClose: closeForm,
6177
- footer: (0, import_react5.createElement)(import_dsh_client_ui_primitives5.Button, { variant: "ghost", size: "sm", onClick: closeForm }, "\u5173\u95ED")
6178
- },
6179
- (0, import_react5.createElement)(import_dsh_client_ui_primitives5.MarkdownText, { text: body2, labels: MD_LABELS3 })
6180
- );
6181
- }
6182
- return (0, import_react5.createElement)(
6183
- ResourceModal,
6184
- {
6185
- title: editing === null ? "\u65B0\u5EFA rule" : `\u7F16\u8F91 rule\u300C${editing ?? ""}\u300D`,
6186
- onClose: closeForm,
6187
- footer: (0, import_react5.createElement)(
6188
- "div",
6189
- { style: styles.row },
6190
- (0, import_react5.createElement)(import_dsh_client_ui_primitives5.Button, {
6191
- variant: "primary",
6192
- size: "sm",
6193
- disabled: editing === null && name.trim() === "" || body2.trim() === "",
6194
- onClick: () => {
6195
- void submit();
6196
- }
6197
- }, "\u4FDD\u5B58"),
6198
- (0, import_react5.createElement)(import_dsh_client_ui_primitives5.Button, { variant: "ghost", size: "sm", onClick: closeForm }, "\u53D6\u6D88")
6199
- )
6200
- },
6201
- (0, import_react5.createElement)(
6202
- "div",
6203
- { style: styles.chips },
6204
- (0, import_react5.createElement)(import_dsh_client_ui_primitives5.Pill, { active: level === "project", onClick: () => {
6205
- setLevel("project");
6206
- }, title: "\u5199\u5230\u5DE5\u4F5C\u533A .dsh/rules\uFF0C\u56E2\u961F\u5171\u4EAB" }, "\u9879\u76EE\u7EA7"),
6207
- (0, import_react5.createElement)(import_dsh_client_ui_primitives5.Pill, { active: level === "user", onClick: () => {
6208
- setLevel("user");
6209
- }, title: "\u5199\u5230 $DSH_HOME/rules\uFF0C\u4E2A\u4EBA\u6240\u6709\u9879\u76EE\u53EF\u7528" }, "\u7528\u6237\u7EA7")
6210
- ),
6211
- editing === null ? (0, import_react5.createElement)("input", { style: control2, placeholder: "name\uFF08\u5982 my-redlines\uFF0C\u53EA\u542B\u5C0F\u5199\u5B57\u6BCD\u6570\u5B57\u548C -\uFF09", value: name, onChange: (ev) => {
6212
- setName(ev.target.value);
6213
- } }) : (0, import_react5.createElement)("span", { style: styles.sourceBadge }, `name \u56FA\u5B9A\u4E3A ${name}\uFF08\u6539\u540D\u8BF7\u5220\u9664\u540E\u91CD\u5EFA\uFF09`),
6214
- (0, import_react5.createElement)("textarea", { style: { ...styles.textarea, minHeight: 260 }, placeholder: "\u6B63\u6587\uFF08\u8FD9\u6761\u89C4\u5219\u7EA6\u675F\u5927\u6A21\u578B\u9075\u5B88\u4EC0\u4E48\uFF09", value: body2, onChange: (ev) => {
6215
- setBody(ev.target.value);
6216
- } }),
6217
- msg !== "" ? (0, import_react5.createElement)("p", { style: styles.status }, msg) : null
6218
- );
6219
- };
6220
- return (0, import_react5.createElement)(
6221
- "div",
6222
- { style: styles.section },
6223
- (0, import_react5.createElement)(
6224
- "div",
6225
- { style: card3 },
6226
- (0, import_react5.createElement)(
6227
- "div",
6228
- { style: styles.bindingStage },
6229
- (0, import_react5.createElement)("span", { style: styles.bindingLabel }, "\u5DF2\u5B89\u88C5\u7684 rule"),
6230
- rules.length === 0 ? (0, import_react5.createElement)("p", { style: styles.muted }, "\u6682\u65E0 rule\uFF0C\u70B9\u4E0B\u65B9\u300C\u65B0\u5EFA rule\u300D\u521B\u5EFA\u4E00\u4E2A\u3002") : (0, import_react5.createElement)(
6231
- "div",
6232
- { style: styles.section },
6233
- ...rules.map(renderRow)
6234
- )
6235
- ),
6236
- (0, import_react5.createElement)(import_dsh_client_ui_primitives5.Button, { variant: "outline", size: "md", onClick: startCreate }, "\u65B0\u5EFA rule")
6237
- ),
6238
- formOpen ? renderForm() : null
6239
- );
5895
+
5896
+ // src/client/RuleManager.tsx
5897
+ var import_react6 = require("react");
5898
+ function RuleManager(props) {
5899
+ return (0, import_react6.createElement)(ResourceManager, { ...props, key: props.workspace, kind: "rule" });
6240
5900
  }
6241
5901
 
6242
5902
  // src/client/TaskLedger.tsx
6243
- var import_react6 = require("react");
6244
- var import_dsh_client_ui_primitives6 = require("@deepseek-ai/dsh-client-ui-primitives");
6245
- var card4 = {
5903
+ var import_react7 = require("react");
5904
+ var import_dsh_client_ui_primitives5 = require("@deepseek-ai/dsh-client-ui-primitives");
5905
+ var card2 = {
6246
5906
  display: "flex",
6247
5907
  flexDirection: "column",
6248
5908
  gap: 10,
@@ -6279,10 +5939,10 @@ var badge = {
6279
5939
  color: "var(--dsw-alias-label-secondary)"
6280
5940
  };
6281
5941
  function verdictDot(outcome) {
6282
- return (0, import_react6.createElement)(import_dsh_client_ui_primitives6.StateDot, { state: outcome === "pass" ? "done" : "error" });
5942
+ return (0, import_react7.createElement)(import_dsh_client_ui_primitives5.StateDot, { state: outcome === "pass" ? "done" : "error" });
6283
5943
  }
6284
5944
  function itemStatusDot(status) {
6285
- return (0, import_react6.createElement)(import_dsh_client_ui_primitives6.StateDot, { state: status === "done" ? "done" : "ongoing" });
5945
+ return (0, import_react7.createElement)(import_dsh_client_ui_primitives5.StateDot, { state: status === "done" ? "done" : "ongoing" });
6286
5946
  }
6287
5947
  function timeText(at) {
6288
5948
  return at.slice(0, 19).replace("T", " ");
@@ -6290,92 +5950,111 @@ function timeText(at) {
6290
5950
  function itemAudit(item) {
6291
5951
  const lines = [];
6292
5952
  if (item.dispatch !== void 0) {
6293
- lines.push((0, import_react6.createElement)(
5953
+ lines.push((0, import_react7.createElement)(
6294
5954
  "div",
6295
5955
  { key: "dispatch", style: metaLine },
6296
- (0, import_react6.createElement)("span", { style: badge }, "\u5DF2\u6D3E\u53D1"),
6297
- (0, import_react6.createElement)("span", null, item.dispatch.description === "" ? "\uFF08\u65E0\u63CF\u8FF0\uFF09" : item.dispatch.description),
6298
- (0, import_react6.createElement)("span", { style: badge }, timeText(item.dispatch.at))
5956
+ (0, import_react7.createElement)("span", { style: badge }, "\u5DF2\u6D3E\u53D1"),
5957
+ (0, import_react7.createElement)("span", null, item.dispatch.description === "" ? "\uFF08\u65E0\u63CF\u8FF0\uFF09" : item.dispatch.description),
5958
+ (0, import_react7.createElement)("span", { style: badge }, timeText(item.dispatch.at))
6299
5959
  ));
6300
5960
  }
6301
5961
  if (item.review !== void 0) {
6302
5962
  const spec = item.review.spec;
6303
5963
  const quality = item.review.quality;
6304
- lines.push((0, import_react6.createElement)(
5964
+ lines.push((0, import_react7.createElement)(
6305
5965
  "div",
6306
5966
  { key: "review", style: metaLine },
6307
5967
  verdictDot(spec.outcome),
6308
- (0, import_react6.createElement)("span", null, `\u89C4\u683C\u7B26\u5408 ${spec.outcome === "pass" ? "\u901A\u8FC7" : "\u4E0D\u901A\u8FC7"}`),
6309
- (0, import_react6.createElement)("span", null, "\xB7"),
5968
+ (0, import_react7.createElement)("span", null, `\u89C4\u683C\u7B26\u5408 ${spec.outcome === "pass" ? "\u901A\u8FC7" : "\u4E0D\u901A\u8FC7"}`),
5969
+ (0, import_react7.createElement)("span", null, "\xB7"),
6310
5970
  verdictDot(quality.outcome),
6311
- (0, import_react6.createElement)("span", null, `\u4EE3\u7801\u8D28\u91CF ${quality.outcome === "pass" ? "\u901A\u8FC7" : "\u4E0D\u901A\u8FC7"}`)
5971
+ (0, import_react7.createElement)("span", null, `\u4EE3\u7801\u8D28\u91CF ${quality.outcome === "pass" ? "\u901A\u8FC7" : "\u4E0D\u901A\u8FC7"}`)
6312
5972
  ));
6313
5973
  const failNotes = [spec, quality].flatMap((stage) => stage.outcome === "fail" ? stage.notes ?? [] : []);
6314
5974
  if (failNotes.length > 0) {
6315
- lines.push((0, import_react6.createElement)(
5975
+ lines.push((0, import_react7.createElement)(
6316
5976
  "div",
6317
5977
  { key: "notes", style: metaLine },
6318
- ...failNotes.map((note) => (0, import_react6.createElement)("span", { key: note, style: badge }, note))
5978
+ ...failNotes.map((note) => (0, import_react7.createElement)("span", { key: note, style: badge }, note))
6319
5979
  ));
6320
5980
  }
6321
5981
  }
6322
5982
  if (lines.length === 0) {
6323
- lines.push((0, import_react6.createElement)("div", { key: "none", style: metaLine }, (0, import_react6.createElement)("span", { style: badge }, "\u672A\u6D3E\u53D1 / \u672A\u5BA1\u67E5")));
5983
+ lines.push((0, import_react7.createElement)("div", { key: "none", style: metaLine }, (0, import_react7.createElement)("span", { style: badge }, "\u672A\u6D3E\u53D1 / \u672A\u5BA1\u67E5")));
6324
5984
  }
6325
- return (0, import_react6.createElement)("div", { style: { display: "flex", flexDirection: "column", gap: 4 } }, ...lines);
5985
+ return (0, import_react7.createElement)("div", { style: { display: "flex", flexDirection: "column", gap: 4 } }, ...lines);
6326
5986
  }
6327
5987
  function TaskLedger({ workspace, remote }) {
6328
- const [tasks, setTasks] = (0, import_react6.useState)([]);
6329
- const [error, setError] = (0, import_react6.useState)("");
6330
- const refresh = (0, import_react6.useCallback)(() => {
5988
+ const [tasks, setTasks] = (0, import_react7.useState)([]);
5989
+ const [error, setError] = (0, import_react7.useState)("");
5990
+ const [loading, setLoading] = (0, import_react7.useState)(true);
5991
+ const [query, setQuery] = (0, import_react7.useState)("");
5992
+ const [risk, setRisk] = (0, import_react7.useState)("all");
5993
+ const [stage, setStage] = (0, import_react7.useState)("all");
5994
+ const refresh = (0, import_react7.useCallback)(() => {
6331
5995
  if (workspace === "") return;
6332
5996
  setError("");
5997
+ setLoading(true);
6333
5998
  void remote.readTasks(workspace).then((result) => {
5999
+ setLoading(false);
6334
6000
  if (result.ok) setTasks(result.value.tasks);
6335
6001
  else setError("\u8BFB\u53D6\u53F0\u8D26\u5931\u8D25\uFF1A" + describeError(result.error));
6336
6002
  }, (reason) => {
6003
+ setLoading(false);
6337
6004
  setError("\u8BFB\u53D6\u53F0\u8D26\u5931\u8D25\uFF1A" + describeError(reason));
6338
6005
  });
6339
6006
  }, [remote, workspace]);
6340
- (0, import_react6.useEffect)(() => {
6007
+ (0, import_react7.useEffect)(() => {
6341
6008
  refresh();
6342
6009
  }, [refresh]);
6343
- return (0, import_react6.createElement)(
6010
+ 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));
6011
+ return (0, import_react7.createElement)(
6344
6012
  "div",
6345
6013
  { style: styles.section },
6346
- (0, import_react6.createElement)(
6014
+ (0, import_react7.createElement)(
6015
+ "div",
6016
+ { className: "te-toolbar" },
6017
+ (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) }),
6018
+ (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")),
6019
+ (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)))
6020
+ ),
6021
+ (0, import_react7.createElement)(
6347
6022
  "div",
6348
6023
  { style: headerRow },
6349
- (0, import_react6.createElement)("span", { style: styles.bindingLabel }, "\u4EFB\u52A1\u53F0\u8D26"),
6350
- (0, import_react6.createElement)("span", { style: styles.sourceBadge }, "\u53EA\u8BFB \xB7 \u6765\u81EA .dsh/task-*.json"),
6351
- (0, import_react6.createElement)(import_dsh_client_ui_primitives6.Button, { variant: "outline", size: "sm", onClick: refresh }, "\u5237\u65B0")
6024
+ (0, import_react7.createElement)("span", { style: styles.bindingLabel }, "\u4EFB\u52A1\u53F0\u8D26"),
6025
+ (0, import_react7.createElement)("span", { style: styles.sourceBadge }, "\u53EA\u8BFB \xB7 \u6765\u81EA .dsh/task-*.json"),
6026
+ (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")
6352
6027
  ),
6353
- error !== "" ? (0, import_react6.createElement)("p", { style: styles.status }, error) : tasks.length === 0 ? (0, import_react6.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") : (0, import_react6.createElement)(
6028
+ 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)(
6354
6029
  "div",
6355
6030
  { style: { display: "flex", flexDirection: "column", gap: 12 } },
6356
- ...tasks.map((task) => (0, import_react6.createElement)(
6031
+ ...visible.map((task) => (0, import_react7.createElement)(
6357
6032
  "div",
6358
- { key: task.task_id, style: card4 },
6359
- (0, import_react6.createElement)(
6033
+ { key: task.task_id, style: card2 },
6034
+ (0, import_react7.createElement)(
6360
6035
  "div",
6361
6036
  { style: headerRow },
6362
- (0, import_react6.createElement)("span", { style: { fontSize: 14, fontWeight: 600, color: "var(--dsw-alias-label-primary)" } }, task.task_id),
6363
- (0, import_react6.createElement)("span", { style: { fontSize: 13, color: "var(--dsw-alias-label-primary)" } }, task.title),
6364
- (0, import_react6.createElement)("span", { style: badge }, task.stage),
6365
- (0, import_react6.createElement)("span", { style: badge }, task.branch)
6037
+ (0, import_react7.createElement)("span", { style: { fontSize: 14, fontWeight: 600, color: "var(--dsw-alias-label-primary)" } }, task.task_id),
6038
+ (0, import_react7.createElement)("span", { style: { fontSize: 13, color: "var(--dsw-alias-label-primary)" } }, task.title),
6039
+ (0, import_react7.createElement)("span", { style: badge }, task.stage),
6040
+ (0, import_react7.createElement)("span", { style: badge }, task.branch),
6041
+ (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"),
6042
+ (0, import_react7.createElement)("span", { className: "te-badge" }, task.verification_passed ? "\u9A8C\u8BC1\u901A\u8FC7" : "\u5F85\u9A8C\u8BC1"),
6043
+ (0, import_react7.createElement)("span", { className: "te-badge" }, `\u5BA1\u6838\uFF1A${task.review_outcome ?? "pending"}`),
6044
+ task.updated_at ? (0, import_react7.createElement)("span", { style: metaLine }, "\u66F4\u65B0\u4E8E " + timeText(task.updated_at)) : null
6366
6045
  ),
6367
- (0, import_react6.createElement)(
6046
+ (0, import_react7.createElement)(
6368
6047
  "div",
6369
6048
  { style: { display: "flex", flexDirection: "column" } },
6370
- ...task.items.map((item) => (0, import_react6.createElement)(
6049
+ ...task.items.map((item) => (0, import_react7.createElement)(
6371
6050
  "div",
6372
6051
  { key: item.id, style: itemRow },
6373
- (0, import_react6.createElement)(
6052
+ (0, import_react7.createElement)(
6374
6053
  "div",
6375
6054
  { style: headerRow },
6376
6055
  itemStatusDot(item.status),
6377
- (0, import_react6.createElement)("span", { style: { fontSize: 13, color: "var(--dsw-alias-label-primary)" } }, item.id),
6378
- (0, import_react6.createElement)("span", { style: { fontSize: 12, color: "var(--dsw-alias-label-secondary)" } }, item.title)
6056
+ (0, import_react7.createElement)("span", { style: { fontSize: 13, color: "var(--dsw-alias-label-primary)" } }, item.id),
6057
+ (0, import_react7.createElement)("span", { style: { fontSize: 12, color: "var(--dsw-alias-label-secondary)" } }, item.title)
6379
6058
  ),
6380
6059
  itemAudit(item)
6381
6060
  ))
@@ -6398,24 +6077,25 @@ var header = {
6398
6077
  display: "flex",
6399
6078
  alignItems: "center",
6400
6079
  justifyContent: "space-between",
6401
- padding: "12px 20px",
6080
+ padding: "20px 28px",
6402
6081
  borderBottom: "1px solid var(--dsw-alias-border-l2)"
6403
6082
  };
6404
6083
  var headerBrand = { display: "flex", alignItems: "center", gap: 10, minWidth: 0 };
6405
6084
  var headerText = { display: "flex", flexDirection: "column", gap: 1, minWidth: 0 };
6406
- var headerTitle = { fontSize: 15, fontWeight: 600, color: "var(--dsw-alias-label-primary)" };
6085
+ var headerTitle = { fontSize: 20, fontWeight: 650, color: "var(--dsw-alias-label-primary)" };
6407
6086
  var headerSub = { fontSize: 12, color: "var(--dsw-alias-label-tertiary)", margin: 0 };
6408
6087
  var tabbar = {
6409
6088
  display: "flex",
6410
6089
  alignItems: "center",
6411
6090
  gap: 8,
6412
- padding: "10px 20px",
6091
+ padding: "12px 28px",
6092
+ flexWrap: "wrap",
6413
6093
  borderBottom: "1px solid var(--dsw-alias-border-l2)"
6414
6094
  };
6415
6095
  var body = {
6416
6096
  flex: 1,
6417
6097
  overflowY: "auto",
6418
- padding: 20
6098
+ padding: "24px clamp(12px, 3vw, 32px)"
6419
6099
  };
6420
6100
  var selectStyle = {
6421
6101
  marginLeft: "auto",
@@ -6442,34 +6122,35 @@ var TABS = [
6442
6122
  { id: "init", label: "\u9879\u76EE\u521D\u59CB\u5316" },
6443
6123
  { id: "flow", label: "\u6D41\u7A0B\u914D\u7F6E" },
6444
6124
  { id: "tasks", label: "\u4EFB\u52A1\u53F0\u8D26" },
6445
- { id: "skills", label: "\u6280\u80FD skill" },
6446
- { id: "rules", label: "\u89C4\u5219 rule" }
6125
+ { id: "skills", label: "\u6280\u80FD" },
6126
+ { id: "rules", label: "\u89C4\u5219" }
6447
6127
  ];
6448
6128
  function Workbench({ useStore, actions, useWorkspaces, remote }) {
6449
6129
  const open = useStore((s) => s.open);
6450
6130
  const workspaces = useWorkspaces((s) => s.items);
6451
- const [tab, setTab] = (0, import_react7.useState)("init");
6452
- const [workspace, setWorkspace] = (0, import_react7.useState)("");
6131
+ const [tab, setTab] = (0, import_react8.useState)("init");
6132
+ const [workspace, setWorkspace] = (0, import_react8.useState)("");
6453
6133
  if (!open) return null;
6454
6134
  const current = workspaces.some((w) => w.path === workspace) ? workspace : workspaces[0]?.path ?? "";
6455
- return (0, import_react7.createElement)(
6135
+ return (0, import_react8.createElement)(
6456
6136
  "div",
6457
- { style: overlay },
6458
- (0, import_react7.createElement)(
6137
+ { style: overlay, className: "te-workbench" },
6138
+ (0, import_react8.createElement)("style", null, workbenchTheme),
6139
+ (0, import_react8.createElement)(
6459
6140
  "div",
6460
6141
  { style: header },
6461
- (0, import_react7.createElement)(
6142
+ (0, import_react8.createElement)(
6462
6143
  "div",
6463
6144
  { style: headerBrand },
6464
- (0, import_react7.createElement)(import_dsh_client_ui_primitives7.IconSettingsOutline16, { size: 18 }),
6465
- (0, import_react7.createElement)(
6145
+ (0, import_react8.createElement)(import_dsh_client_ui_primitives6.IconSettingsOutline16, { size: 18 }),
6146
+ (0, import_react8.createElement)(
6466
6147
  "div",
6467
6148
  { style: headerText },
6468
- (0, import_react7.createElement)("span", { style: headerTitle }, "\u5DE5\u7A0B\u6D41\u7A0B"),
6469
- (0, import_react7.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")
6149
+ (0, import_react8.createElement)("span", { style: headerTitle }, "\u5DE5\u7A0B\u6D41\u7A0B"),
6150
+ (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")
6470
6151
  )
6471
6152
  ),
6472
- (0, import_react7.createElement)(
6153
+ (0, import_react8.createElement)(
6473
6154
  "button",
6474
6155
  {
6475
6156
  type: "button",
@@ -6485,38 +6166,44 @@ function Workbench({ useStore, actions, useWorkspaces, remote }) {
6485
6166
  event.currentTarget.style.background = "transparent";
6486
6167
  }
6487
6168
  },
6488
- (0, import_react7.createElement)(import_dsh_client_ui_primitives7.IconCloseOutline16, { size: 16 })
6169
+ (0, import_react8.createElement)(import_dsh_client_ui_primitives6.IconCloseOutline16, { size: 16 })
6489
6170
  )
6490
6171
  ),
6491
- (0, import_react7.createElement)(
6172
+ (0, import_react8.createElement)(
6492
6173
  "div",
6493
6174
  { style: tabbar },
6494
- ...TABS.map((t) => (0, import_react7.createElement)(import_dsh_client_ui_primitives7.Pill, { key: t.id, active: tab === t.id, onClick: () => {
6175
+ ...TABS.map((t) => (0, import_react8.createElement)(import_dsh_client_ui_primitives6.Pill, { key: t.id, active: tab === t.id, onClick: () => {
6495
6176
  setTab(t.id);
6496
6177
  } }, t.label)),
6497
- workspaces.length > 0 ? (0, import_react7.createElement)("select", {
6178
+ workspaces.length > 0 ? (0, import_react8.createElement)("select", {
6498
6179
  style: selectStyle,
6180
+ "aria-label": "\u5F53\u524D\u5DE5\u4F5C\u533A",
6499
6181
  value: current,
6500
6182
  onChange: (ev) => {
6501
6183
  setWorkspace(ev.target.value);
6502
6184
  }
6503
- }, ...workspaces.map((w) => (0, import_react7.createElement)("option", { key: w.path, value: w.path }, w.title || w.path))) : null
6185
+ }, ...workspaces.map((w) => (0, import_react8.createElement)("option", { key: w.path, value: w.path }, w.title || w.path))) : null
6504
6186
  ),
6505
- (0, import_react7.createElement)(
6187
+ (0, import_react8.createElement)(
6506
6188
  "div",
6507
6189
  { style: body },
6508
- current === "" ? (0, import_react7.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_react7.createElement)(InitPanel, { workspace: current, remote }) : tab === "flow" ? (0, import_react7.createElement)(TaskEngineSection, { workspace: current, remote }) : tab === "tasks" ? (0, import_react7.createElement)(TaskLedger, { workspace: current, remote }) : tab === "skills" ? (0, import_react7.createElement)(SkillManager, { workspace: current, remote }) : (0, import_react7.createElement)(RuleManager, { workspace: current, remote })
6190
+ (0, import_react8.createElement)(
6191
+ "div",
6192
+ { className: "te-content", key: current },
6193
+ (0, import_react8.createElement)("p", { style: { ...styles.hint, marginBottom: 20 }, title: current }, "\u5DE5\u4F5C\u533A \xB7 " + current),
6194
+ 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 })
6195
+ )
6509
6196
  )
6510
6197
  );
6511
6198
  }
6512
6199
 
6513
6200
  // src/client/TriggerButton.tsx
6514
- var import_react8 = require("react");
6515
- var import_dsh_client_ui_primitives8 = require("@deepseek-ai/dsh-client-ui-primitives");
6201
+ var import_react9 = require("react");
6202
+ var import_dsh_client_ui_primitives7 = require("@deepseek-ai/dsh-client-ui-primitives");
6516
6203
  var hover = "var(--dsw-alias-bg-layer-2)";
6517
6204
  var label = "var(--dsw-alias-label-primary)";
6518
6205
  function TriggerButton({ wide, actions }) {
6519
- return (0, import_react8.createElement)(
6206
+ return (0, import_react9.createElement)(
6520
6207
  "button",
6521
6208
  {
6522
6209
  type: "button",
@@ -6556,8 +6243,8 @@ function TriggerButton({ wide, actions }) {
6556
6243
  transition: "background 120ms ease"
6557
6244
  }
6558
6245
  },
6559
- (0, import_react8.createElement)(import_dsh_client_ui_primitives8.IconSettingsOutline16, { size: wide ? 16 : 18 }),
6560
- wide ? (0, import_react8.createElement)("span", { style: { fontSize: 14, lineHeight: "22px" } }, "\u5DE5\u7A0B\u6D41\u7A0B") : null
6246
+ (0, import_react9.createElement)(import_dsh_client_ui_primitives7.IconSettingsOutline16, { size: wide ? 16 : 18 }),
6247
+ wide ? (0, import_react9.createElement)("span", { style: { fontSize: 14, lineHeight: "22px" } }, "\u5DE5\u7A0B\u6D41\u7A0B") : null
6561
6248
  );
6562
6249
  }
6563
6250