@godv61/dsh-task-engine 0.22.7 → 0.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/client.js CHANGED
@@ -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)";
@@ -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: [
@@ -5115,13 +5217,23 @@ function BindingEditor({ stages, stageBindings, setStageBindings, skills, rules
5115
5217
  ] });
5116
5218
  }
5117
5219
  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;
5220
+ try {
5221
+ const result = await remote.write({ path: workspace, flow, stage_bindings: stageBindings });
5222
+ if (!result.ok) {
5223
+ setSavedAt("\u4FDD\u5B58\u5931\u8D25\uFF1A" + describeError(result.error));
5224
+ return false;
5225
+ }
5226
+ if (!result.value.ok) {
5227
+ setSavedAt("\u4FDD\u5B58\u5931\u8D25\uFF1A" + result.value.problems.join("\uFF1B"));
5228
+ return false;
5229
+ }
5230
+ setSource(result.value.source);
5231
+ setSavedAt("\u5DF2\u4FDD\u5B58");
5232
+ return true;
5233
+ } catch (error) {
5234
+ setSavedAt("\u4FDD\u5B58\u5931\u8D25\uFF1A" + describeError(error));
5235
+ return false;
5122
5236
  }
5123
- setSource(result.value.source);
5124
- setSavedAt(result.value.ok ? "\u5DF2\u4FDD\u5B58" : "");
5125
5237
  }
5126
5238
 
5127
5239
  // src/client/InitPanel.tsx
@@ -5310,6 +5422,9 @@ function InitPanel({ workspace, remote }) {
5310
5422
  }
5311
5423
 
5312
5424
  // src/client/SkillManager.tsx
5425
+ var import_react5 = require("react");
5426
+
5427
+ // src/client/ResourceManager.tsx
5313
5428
  var import_react4 = require("react");
5314
5429
  var import_dsh_client_ui_primitives4 = require("@deepseek-ai/dsh-client-ui-primitives");
5315
5430
 
@@ -5398,23 +5513,49 @@ var footerStyle = {
5398
5513
  flex: "none"
5399
5514
  };
5400
5515
  function ResourceModal({ title, description, onClose, footer, children }) {
5516
+ const dialog = (0, import_react3.useRef)(null);
5517
+ const closer = (0, import_react3.useRef)(onClose);
5518
+ closer.current = onClose;
5401
5519
  (0, import_react3.useEffect)(() => {
5520
+ const previous = document.activeElement;
5521
+ dialog.current?.focus();
5402
5522
  const onKey = (e) => {
5403
- if (e.key === "Escape") onClose();
5523
+ if (!dialog.current?.contains(document.activeElement)) return;
5524
+ if (e.key === "Escape") {
5525
+ e.preventDefault();
5526
+ e.stopPropagation();
5527
+ closer.current();
5528
+ return;
5529
+ }
5530
+ if (e.key !== "Tab") return;
5531
+ 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);
5532
+ const first = nodes[0], last = nodes[nodes.length - 1];
5533
+ if (!first || !last) {
5534
+ e.preventDefault();
5535
+ return;
5536
+ }
5537
+ if (e.shiftKey && (document.activeElement === first || document.activeElement === dialog.current)) {
5538
+ e.preventDefault();
5539
+ last.focus();
5540
+ } else if (!e.shiftKey && (document.activeElement === last || document.activeElement === dialog.current)) {
5541
+ e.preventDefault();
5542
+ first.focus();
5543
+ }
5404
5544
  };
5405
5545
  document.addEventListener("keydown", onKey);
5406
5546
  return () => {
5407
5547
  document.removeEventListener("keydown", onKey);
5548
+ if (previous?.isConnected) previous.focus();
5408
5549
  };
5409
- }, [onClose]);
5550
+ }, []);
5410
5551
  return (0, import_react_dom.createPortal)(
5411
5552
  (0, import_react3.createElement)(
5412
5553
  "div",
5413
- { style: rootStyle, role: "presentation" },
5554
+ { style: rootStyle, className: "te-modal", role: "presentation" },
5414
5555
  (0, import_react3.createElement)("div", { style: maskStyle, "aria-hidden": true, onClick: onClose }),
5415
5556
  (0, import_react3.createElement)(
5416
5557
  "div",
5417
- { style: dialogStyle, role: "dialog", "aria-modal": true, "aria-label": title },
5558
+ { style: dialogStyle, ref: dialog, tabIndex: -1, role: "dialog", "aria-modal": true, "aria-label": title },
5418
5559
  (0, import_react3.createElement)(
5419
5560
  "div",
5420
5561
  { style: headerStyle },
@@ -5434,815 +5575,333 @@ function ResourceModal({ title, description, onClose, footer, children }) {
5434
5575
  );
5435
5576
  }
5436
5577
 
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)([]);
5578
+ // src/client/ResourceManager.tsx
5579
+ var labels = { code: { copyLabel: "\u590D\u5236", copiedLabel: "\u5DF2\u590D\u5236" }, footnotes: "\u811A\u6CE8" };
5580
+ var levelOf = (row) => row.source === "bundled" ? "bundled" : row.source.startsWith("user") ? "user" : "project";
5581
+ var sourceText2 = (source) => source === "bundled" ? "\u5185\u7F6E" : source.startsWith("user") ? "\u4E2A\u4EBA" : "\u9879\u76EE";
5582
+ var sizeText = (bytes) => bytes < 1024 ? `${bytes} B` : bytes < 1024 * 1024 ? `${(bytes / 1024).toFixed(1)} KB` : `${(bytes / 1024 / 1024).toFixed(1)} MB`;
5583
+ var fail = (r) => describeError(r.error ?? "\u64CD\u4F5C\u5931\u8D25");
5584
+ function ResourceManager({ workspace, remote, kind }) {
5585
+ const noun = kind === "skill" ? "\u6280\u80FD" : "\u89C4\u5219";
5586
+ const [rows, setRows] = (0, import_react4.useState)([]);
5587
+ const [query, setQuery] = (0, import_react4.useState)("");
5588
+ const [filter, setFilter] = (0, import_react4.useState)("all");
5589
+ const [notice, setNotice] = (0, import_react4.useState)("");
5590
+ const [error, setError] = (0, import_react4.useState)("");
5591
+ const [loading, setLoading] = (0, import_react4.useState)(true);
5592
+ const [revision, refresh] = (0, import_react4.useState)(0);
5593
+ const [busy, setBusy] = (0, import_react4.useState)(false);
5594
+ const [roots, setRoots] = (0, import_react4.useState)(null);
5595
+ const [importing, setImporting] = (0, import_react4.useState)(false);
5596
+ const [request, setRequest] = (0, import_react4.useState)(null);
5597
+ const [preview, setPreview] = (0, import_react4.useState)(null);
5498
5598
  const [level, setLevel] = (0, import_react4.useState)("project");
5599
+ const [manual, setManual] = (0, import_react4.useState)(false);
5600
+ const [sourceDir, setSourceDir] = (0, import_react4.useState)("");
5601
+ const [dirs, setDirs] = (0, import_react4.useState)([]);
5602
+ const [browsePath, setBrowsePath] = (0, import_react4.useState)("");
5499
5603
  const [editing, setEditing] = (0, import_react4.useState)(null);
5500
- const [creating, setCreating] = (0, import_react4.useState)(false);
5501
5604
  const [viewing, setViewing] = (0, import_react4.useState)(false);
5502
- const [confirming, setConfirming] = (0, import_react4.useState)(null);
5503
5605
  const [name, setName] = (0, import_react4.useState)("");
5504
5606
  const [description, setDescription] = (0, import_react4.useState)("");
5505
5607
  const [whenToUse, setWhenToUse] = (0, import_react4.useState)("");
5506
5608
  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([]);
5609
+ const [deleting, setDeleting] = (0, import_react4.useState)(null);
5610
+ const input = (0, import_react4.useRef)(null);
5611
+ const fileEpoch = (0, import_react4.useRef)(0);
5612
+ const browseEpoch = (0, import_react4.useRef)(0);
5613
+ const readonly = editing !== null && editing !== "new" && levelOf(editing) === "bundled";
5614
+ (0, import_react4.useEffect)(() => {
5615
+ let active = true;
5616
+ setLoading(true);
5617
+ setRows([]);
5618
+ setError("");
5619
+ const run = async () => {
5620
+ try {
5621
+ const r = kind === "skill" ? await remote.listSkills(workspace) : await remote.listRules(workspace);
5622
+ if (!active) return;
5623
+ if (!r.ok) throw new Error(fail(r));
5624
+ setRows("skills" in r.value ? r.value.skills : r.value.rules);
5625
+ } catch (e) {
5626
+ if (active) setError("\u52A0\u8F7D\u5931\u8D25\uFF1A" + describeError(e));
5627
+ } finally {
5628
+ if (active) setLoading(false);
5551
5629
  }
5630
+ };
5631
+ void run();
5632
+ void remote.resourceRoots({ kind, path: workspace }).then((r) => {
5633
+ if (active && r.ok) setRoots(r.value);
5552
5634
  }, () => {
5553
- setBrowseChildEntries([]);
5554
5635
  });
5636
+ return () => {
5637
+ active = false;
5638
+ fileEpoch.current++;
5639
+ };
5640
+ }, [workspace, remote, kind, revision]);
5641
+ (0, import_react4.useEffect)(() => {
5642
+ let active = true;
5643
+ setPreview(null);
5644
+ if (!request) return;
5645
+ setBusy(true);
5646
+ setError("");
5647
+ void remote.previewResource({ ...request, level, path: workspace }).then((r) => {
5648
+ if (!active) return;
5649
+ if (!r.ok) setError(fail(r));
5650
+ else if (!r.value.ok) setError(r.value.error ?? "\u9884\u89C8\u5931\u8D25");
5651
+ else setPreview(r.value);
5652
+ }, (e) => {
5653
+ if (active) setError(describeError(e));
5654
+ }).finally(() => {
5655
+ if (active) setBusy(false);
5656
+ });
5657
+ return () => {
5658
+ active = false;
5659
+ };
5660
+ }, [request, level, workspace, remote]);
5661
+ const close = () => {
5662
+ if (busy) return;
5663
+ fileEpoch.current++;
5664
+ setImporting(false);
5665
+ setEditing(null);
5666
+ setDeleting(null);
5667
+ setRequest(null);
5668
+ setError("");
5555
5669
  };
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);
5670
+ const choose = () => {
5671
+ setError("");
5672
+ if (input.current) {
5673
+ input.current.value = "";
5674
+ input.current.click();
5675
+ }
5573
5676
  };
5574
- const openBrowse = () => {
5575
- setBrowsing(true);
5576
- setBrowseError("");
5577
- loadLevel("");
5677
+ const selected = async (files) => {
5678
+ if (!files.length) return;
5679
+ const epoch = ++fileEpoch.current;
5680
+ setImporting(true);
5681
+ setManual(false);
5682
+ setRequest(null);
5683
+ setPreview(null);
5684
+ setBusy(true);
5685
+ setError("");
5686
+ setNotice("");
5687
+ try {
5688
+ files = files.filter((f) => !(f.webkitRelativePath || f.name).split("/").some((p) => ["node_modules", ".git", "__pycache__", ".venv", "venv", ".cache", ".DS_Store"].includes(p)));
5689
+ 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");
5690
+ const entries = [];
5691
+ for (const file of files) {
5692
+ const data = new Uint8Array(await file.arrayBuffer());
5693
+ let binary = "";
5694
+ for (let i = 0; i < data.length; i += 32768) binary += String.fromCharCode(...data.subarray(i, i + 32768));
5695
+ entries.push({ path: file.webkitRelativePath || file.name, base64: btoa(binary) });
5696
+ }
5697
+ if (epoch === fileEpoch.current) setRequest({ kind, level, path: workspace, files: entries });
5698
+ } catch (e) {
5699
+ if (epoch === fileEpoch.current) setError(describeError(e));
5700
+ } finally {
5701
+ if (epoch === fileEpoch.current) setBusy(false);
5702
+ }
5578
5703
  };
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));
5704
+ const install = async () => {
5705
+ if (!request || !preview || preview.conflict || busy) return;
5706
+ setBusy(true);
5707
+ setError("");
5708
+ try {
5709
+ const r = await remote.importResource({ ...request, level, path: workspace, expectedHash: preview.hash });
5710
+ if (!r.ok) throw new Error(fail(r));
5711
+ if (!r.value.ok) throw new Error(r.value.error ?? "\u5B89\u88C5\u5931\u8D25");
5712
+ setNotice(`\u5DF2\u5B89\u88C5${noun}\u300C${r.value.name}\u300D \xB7 ${r.value.target}`);
5713
+ setImporting(false);
5714
+ setRequest(null);
5715
+ refresh((n) => n + 1);
5716
+ } catch (e) {
5717
+ setError(describeError(e));
5718
+ } finally {
5719
+ setBusy(false);
5720
+ }
5583
5721
  };
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("");
5722
+ const browse = async (path) => {
5723
+ const epoch = ++browseEpoch.current;
5724
+ setError("");
5725
+ try {
5726
+ const r = await remote.listDirs({ path });
5727
+ if (epoch !== browseEpoch.current) return;
5728
+ if (!r.ok) throw new Error(fail(r));
5729
+ if (!r.value.ok) throw new Error(r.value.error ?? "\u76EE\u5F55\u8BFB\u53D6\u5931\u8D25");
5730
+ setBrowsePath(r.value.path);
5731
+ setSourceDir(r.value.path);
5732
+ setDirs(r.value.entries);
5733
+ } catch (e) {
5734
+ if (epoch === browseEpoch.current) setError(describeError(e));
5735
+ }
5604
5736
  };
5605
- const startCreate = () => {
5606
- setEditing(null);
5607
- setCreating(true);
5608
- setViewing(false);
5609
- setInstalling(false);
5610
- setLevel("project");
5611
- setName("");
5737
+ const edit = async (row, view = false) => {
5738
+ setEditing(row);
5739
+ setViewing(view);
5740
+ setName(row === "new" ? "" : row.name);
5612
5741
  setDescription("");
5613
5742
  setWhenToUse("");
5614
5743
  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"));
5744
+ setError("");
5745
+ if (row === "new") {
5746
+ setLevel("project");
5639
5747
  return;
5640
5748
  }
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);
5749
+ const lvl = levelOf(row);
5663
5750
  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;
5751
+ setBusy(true);
5752
+ try {
5753
+ const r = kind === "skill" ? await remote.readSkill({ name: row.name, level: lvl, path: workspace }) : await remote.readRule({ name: row.name, level: lvl, path: workspace });
5754
+ if (!r.ok) throw new Error(fail(r));
5755
+ if (!r.value.ok) throw new Error(r.value.error ?? "\u8BFB\u53D6\u5931\u8D25");
5756
+ setBody(r.value.content);
5757
+ if (kind === "skill") {
5758
+ const skill = r.value;
5759
+ setDescription(skill.description);
5760
+ setWhenToUse(skill.whenToUse);
5761
+ }
5762
+ } catch (e) {
5763
+ setError(describeError(e));
5764
+ } finally {
5765
+ setBusy(false);
5686
5766
  }
5687
- if (!result.value.ok) {
5688
- setMsg("\u4FDD\u5B58\u5931\u8D25\uFF1A" + (result.value.error ?? "\u672A\u77E5\u9519\u8BEF"));
5689
- return;
5767
+ };
5768
+ const save2 = async () => {
5769
+ if (busy) return;
5770
+ setBusy(true);
5771
+ setError("");
5772
+ try {
5773
+ 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");
5774
+ const r = kind === "skill" ? await remote.writeSkill({ name, description, whenToUse, content: body2, level, path: workspace }) : await remote.writeRule({ name, content: body2, level, path: workspace });
5775
+ if (!r.ok) throw new Error(fail(r));
5776
+ if (!r.value.ok) throw new Error(r.value.error ?? "\u4FDD\u5B58\u5931\u8D25");
5777
+ setNotice(`\u5DF2\u4FDD\u5B58${noun} \xB7 ${r.value.path}`);
5778
+ setEditing(null);
5779
+ refresh((n) => n + 1);
5780
+ } catch (e) {
5781
+ setError(describeError(e));
5782
+ } finally {
5783
+ setBusy(false);
5690
5784
  }
5691
- setMsg(`\u5DF2\u4FDD\u5B58 skill\u300C${result.value.name}\u300D`);
5692
- setEditing(null);
5693
- setCreating(false);
5694
- refresh();
5695
5785
  };
5696
- const remove = async (sk) => {
5697
- setMsg("");
5698
- const lvl = levelOf(sk.source);
5786
+ const remove = async () => {
5787
+ if (!deleting || busy) return;
5788
+ const lvl = levelOf(deleting);
5699
5789
  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;
5790
+ setBusy(true);
5791
+ setError("");
5792
+ try {
5793
+ const r = kind === "skill" ? await remote.deleteSkill({ name: deleting.name, level: lvl, path: workspace }) : await remote.deleteRule({ name: deleting.name, level: lvl, path: workspace });
5794
+ if (!r.ok) throw new Error(fail(r));
5795
+ if (!r.value.ok) throw new Error(r.value.error ?? "\u5220\u9664\u5931\u8D25");
5796
+ setNotice(`\u5DF2\u5220\u9664${noun}\u300C${deleting.name}\u300D`);
5797
+ setDeleting(null);
5798
+ refresh((n) => n + 1);
5799
+ } catch (e) {
5800
+ setError(describeError(e));
5801
+ } finally {
5802
+ setBusy(false);
5710
5803
  }
5711
- setMsg(`\u5DF2\u5220\u9664 skill\u300C${result.value.name}\u300D`);
5712
- if (editing === sk.name) setEditing(null);
5713
- setConfirming(null);
5714
- refresh();
5715
5804
  };
5716
- const formOpen = editing !== null || creating || installing;
5717
- const renderRow = (sk) => (0, import_react4.createElement)(
5805
+ const status = () => error ? (0, import_react4.createElement)("div", { className: "te-alert", role: "alert" }, error) : null;
5806
+ const targets = () => (0, import_react4.createElement)(
5718
5807
  "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
- )
5808
+ { className: "te-targets" },
5809
+ ...["project", "user"].map((lvl) => (0, import_react4.createElement)(
5810
+ "button",
5811
+ { type: "button", key: lvl, className: `te-target ${level === lvl ? "selected" : ""}`, "aria-pressed": level === lvl, disabled: busy || editing !== null && editing !== "new", onClick: () => {
5812
+ setPreview(null);
5813
+ setLevel(lvl);
5814
+ } },
5815
+ (0, import_react4.createElement)("strong", null, lvl === "project" ? "\u9879\u76EE\u5171\u4EAB" : "\u4E2A\u4EBA\u5168\u5C40"),
5816
+ (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")
5817
+ )),
5818
+ (0, import_react4.createElement)("code", { className: "te-path" }, roots?.[level] ?? (level === "project" ? `${workspace}/.dsh/${kind}s` : `DSH_HOME/${kind}s`))
5748
5819
  );
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)(
5820
+ const visible = rows.filter((r) => `${r.name} ${r.description ?? ""}`.toLowerCase().includes(query.toLowerCase()) && (filter === "all" || levelOf(r) === filter));
5821
+ return (0, import_react4.createElement)(
5822
+ "section",
5823
+ { className: "te-resource" },
5824
+ (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) => {
5825
+ void selected(Array.from(e.target.files ?? []));
5826
+ } }),
5827
+ (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: () => {
5828
+ void edit("new");
5829
+ } }, `\u65B0\u5EFA${noun}`), (0, import_react4.createElement)(import_dsh_client_ui_primitives4.Button, { variant: "primary", onClick: choose }, `\u5B89\u88C5${noun}`))),
5830
+ (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")),
5831
+ notice ? (0, import_react4.createElement)("div", { className: "te-success", role: "status" }, notice) : null,
5832
+ !importing && !editing && !deleting ? status() : null,
5833
+ 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)(
5834
+ "article",
5835
+ { className: "te-resource-card", key: row.source + "/" + row.name },
5836
+ (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))),
5837
+ (0, import_react4.createElement)("h3", null, row.name),
5838
+ (0, import_react4.createElement)("p", null, row.description || "\u9879\u76EE\u7EA6\u5B9A\u4E0E\u6267\u884C\u89C4\u5219"),
5839
+ (0, import_react4.createElement)("div", { className: "te-actions" }, (0, import_react4.createElement)(import_dsh_client_ui_primitives4.Button, { variant: "outline", size: "sm", onClick: () => {
5840
+ void edit(row, true);
5841
+ } }, "\u67E5\u770B"), levelOf(row) !== "bundled" ? (0, import_react4.createElement)(import_dsh_client_ui_primitives4.Button, { variant: "ghost", size: "sm", onClick: () => {
5842
+ void edit(row);
5843
+ } }, "\u7F16\u8F91") : null, levelOf(row) !== "bundled" ? (0, import_react4.createElement)("button", { className: "te-delete", onClick: () => {
5844
+ setDeleting(row);
5845
+ setError("");
5846
+ } }, "\u5220\u9664") : null)
5847
+ ))),
5848
+ kind === "skill" ? (0, import_react4.createElement)("button", { className: "te-link", onClick: () => {
5849
+ setImporting(true);
5850
+ setManual(true);
5851
+ setError("");
5852
+ } }, "\u9AD8\u7EA7\uFF1A\u4ECE Harness \u4E3B\u673A\u8DEF\u5F84\u5B89\u88C5") : null,
5853
+ importing ? (0, import_react4.createElement)(
5763
5854
  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, "")))
5855
+ { 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: () => {
5856
+ void install();
5857
+ } }, busy ? "\u5904\u7406\u4E2D\u2026" : "\u786E\u8BA4\u5B89\u88C5")) },
5858
+ targets(),
5859
+ (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),
5860
+ 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) => {
5861
+ setSourceDir(e.target.value);
5862
+ setRequest(null);
5863
+ } }), (0, import_react4.createElement)(import_dsh_client_ui_primitives4.Button, { variant: "outline", onClick: () => {
5864
+ void browse(sourceDir);
5865
+ } }, "\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: () => {
5866
+ void browse(browsePath.replace(/[\\/][^\\/]+[\\/]?$/u, "") || "/");
5867
+ } }, "\u2191 \u4E0A\u7EA7\u76EE\u5F55") : null, ...dirs.map((d) => (0, import_react4.createElement)("button", { key: d.name, onClick: () => {
5868
+ setRequest(null);
5869
+ void browse(browsePath.replace(/[\\/]+$/u, "") + "/" + d.name);
5870
+ } }, d.name + (d.hasSkill ? " \xB7 SKILL.md" : ""))))) : null,
5871
+ busy ? (0, import_react4.createElement)("p", { role: "status" }, "\u6B63\u5728\u6821\u9A8C\u6587\u4EF6\uFF0C\u8BF7\u7A0D\u5019\u2026") : null,
5872
+ status(),
5873
+ 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
5874
  ) : 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
5875
+ editing ? (0, import_react4.createElement)(
5876
+ ResourceModal,
5877
+ { 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: () => {
5878
+ void save2();
5879
+ } }, busy ? "\u5904\u7406\u4E2D\u2026" : "\u4FDD\u5B58") : null) },
5880
+ !readonly ? targets() : (0, import_react4.createElement)("p", { className: "te-badge" }, "\u5185\u7F6E\u8D44\u6E90 \xB7 \u53EA\u8BFB"),
5881
+ status(),
5882
+ 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) })))
5883
+ ) : null,
5884
+ 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: () => {
5885
+ void remove();
5886
+ } }, 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
5887
  );
6012
5888
  }
6013
5889
 
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";
5890
+ // src/client/SkillManager.tsx
5891
+ function SkillManager(props) {
5892
+ return (0, import_react5.createElement)(ResourceManager, { ...props, key: props.workspace, kind: "skill" });
6038
5893
  }
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
- );
5894
+
5895
+ // src/client/RuleManager.tsx
5896
+ var import_react6 = require("react");
5897
+ function RuleManager(props) {
5898
+ return (0, import_react6.createElement)(ResourceManager, { ...props, key: props.workspace, kind: "rule" });
6240
5899
  }
6241
5900
 
6242
5901
  // 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 = {
5902
+ var import_react7 = require("react");
5903
+ var import_dsh_client_ui_primitives5 = require("@deepseek-ai/dsh-client-ui-primitives");
5904
+ var card2 = {
6246
5905
  display: "flex",
6247
5906
  flexDirection: "column",
6248
5907
  gap: 10,
@@ -6279,10 +5938,10 @@ var badge = {
6279
5938
  color: "var(--dsw-alias-label-secondary)"
6280
5939
  };
6281
5940
  function verdictDot(outcome) {
6282
- return (0, import_react6.createElement)(import_dsh_client_ui_primitives6.StateDot, { state: outcome === "pass" ? "done" : "error" });
5941
+ return (0, import_react7.createElement)(import_dsh_client_ui_primitives5.StateDot, { state: outcome === "pass" ? "done" : "error" });
6283
5942
  }
6284
5943
  function itemStatusDot(status) {
6285
- return (0, import_react6.createElement)(import_dsh_client_ui_primitives6.StateDot, { state: status === "done" ? "done" : "ongoing" });
5944
+ return (0, import_react7.createElement)(import_dsh_client_ui_primitives5.StateDot, { state: status === "done" ? "done" : "ongoing" });
6286
5945
  }
6287
5946
  function timeText(at) {
6288
5947
  return at.slice(0, 19).replace("T", " ");
@@ -6290,92 +5949,111 @@ function timeText(at) {
6290
5949
  function itemAudit(item) {
6291
5950
  const lines = [];
6292
5951
  if (item.dispatch !== void 0) {
6293
- lines.push((0, import_react6.createElement)(
5952
+ lines.push((0, import_react7.createElement)(
6294
5953
  "div",
6295
5954
  { 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))
5955
+ (0, import_react7.createElement)("span", { style: badge }, "\u5DF2\u6D3E\u53D1"),
5956
+ (0, import_react7.createElement)("span", null, item.dispatch.description === "" ? "\uFF08\u65E0\u63CF\u8FF0\uFF09" : item.dispatch.description),
5957
+ (0, import_react7.createElement)("span", { style: badge }, timeText(item.dispatch.at))
6299
5958
  ));
6300
5959
  }
6301
5960
  if (item.review !== void 0) {
6302
5961
  const spec = item.review.spec;
6303
5962
  const quality = item.review.quality;
6304
- lines.push((0, import_react6.createElement)(
5963
+ lines.push((0, import_react7.createElement)(
6305
5964
  "div",
6306
5965
  { key: "review", style: metaLine },
6307
5966
  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"),
5967
+ (0, import_react7.createElement)("span", null, `\u89C4\u683C\u7B26\u5408 ${spec.outcome === "pass" ? "\u901A\u8FC7" : "\u4E0D\u901A\u8FC7"}`),
5968
+ (0, import_react7.createElement)("span", null, "\xB7"),
6310
5969
  verdictDot(quality.outcome),
6311
- (0, import_react6.createElement)("span", null, `\u4EE3\u7801\u8D28\u91CF ${quality.outcome === "pass" ? "\u901A\u8FC7" : "\u4E0D\u901A\u8FC7"}`)
5970
+ (0, import_react7.createElement)("span", null, `\u4EE3\u7801\u8D28\u91CF ${quality.outcome === "pass" ? "\u901A\u8FC7" : "\u4E0D\u901A\u8FC7"}`)
6312
5971
  ));
6313
5972
  const failNotes = [spec, quality].flatMap((stage) => stage.outcome === "fail" ? stage.notes ?? [] : []);
6314
5973
  if (failNotes.length > 0) {
6315
- lines.push((0, import_react6.createElement)(
5974
+ lines.push((0, import_react7.createElement)(
6316
5975
  "div",
6317
5976
  { key: "notes", style: metaLine },
6318
- ...failNotes.map((note) => (0, import_react6.createElement)("span", { key: note, style: badge }, note))
5977
+ ...failNotes.map((note) => (0, import_react7.createElement)("span", { key: note, style: badge }, note))
6319
5978
  ));
6320
5979
  }
6321
5980
  }
6322
5981
  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")));
5982
+ 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
5983
  }
6325
- return (0, import_react6.createElement)("div", { style: { display: "flex", flexDirection: "column", gap: 4 } }, ...lines);
5984
+ return (0, import_react7.createElement)("div", { style: { display: "flex", flexDirection: "column", gap: 4 } }, ...lines);
6326
5985
  }
6327
5986
  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)(() => {
5987
+ const [tasks, setTasks] = (0, import_react7.useState)([]);
5988
+ const [error, setError] = (0, import_react7.useState)("");
5989
+ const [loading, setLoading] = (0, import_react7.useState)(true);
5990
+ const [query, setQuery] = (0, import_react7.useState)("");
5991
+ const [risk, setRisk] = (0, import_react7.useState)("all");
5992
+ const [stage, setStage] = (0, import_react7.useState)("all");
5993
+ const refresh = (0, import_react7.useCallback)(() => {
6331
5994
  if (workspace === "") return;
6332
5995
  setError("");
5996
+ setLoading(true);
6333
5997
  void remote.readTasks(workspace).then((result) => {
5998
+ setLoading(false);
6334
5999
  if (result.ok) setTasks(result.value.tasks);
6335
6000
  else setError("\u8BFB\u53D6\u53F0\u8D26\u5931\u8D25\uFF1A" + describeError(result.error));
6336
6001
  }, (reason) => {
6002
+ setLoading(false);
6337
6003
  setError("\u8BFB\u53D6\u53F0\u8D26\u5931\u8D25\uFF1A" + describeError(reason));
6338
6004
  });
6339
6005
  }, [remote, workspace]);
6340
- (0, import_react6.useEffect)(() => {
6006
+ (0, import_react7.useEffect)(() => {
6341
6007
  refresh();
6342
6008
  }, [refresh]);
6343
- return (0, import_react6.createElement)(
6009
+ 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));
6010
+ return (0, import_react7.createElement)(
6344
6011
  "div",
6345
6012
  { style: styles.section },
6346
- (0, import_react6.createElement)(
6013
+ (0, import_react7.createElement)(
6014
+ "div",
6015
+ { className: "te-toolbar" },
6016
+ (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) }),
6017
+ (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")),
6018
+ (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)))
6019
+ ),
6020
+ (0, import_react7.createElement)(
6347
6021
  "div",
6348
6022
  { 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")
6023
+ (0, import_react7.createElement)("span", { style: styles.bindingLabel }, "\u4EFB\u52A1\u53F0\u8D26"),
6024
+ (0, import_react7.createElement)("span", { style: styles.sourceBadge }, "\u53EA\u8BFB \xB7 \u6765\u81EA .dsh/task-*.json"),
6025
+ (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
6026
  ),
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)(
6027
+ 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
6028
  "div",
6355
6029
  { style: { display: "flex", flexDirection: "column", gap: 12 } },
6356
- ...tasks.map((task) => (0, import_react6.createElement)(
6030
+ ...visible.map((task) => (0, import_react7.createElement)(
6357
6031
  "div",
6358
- { key: task.task_id, style: card4 },
6359
- (0, import_react6.createElement)(
6032
+ { key: task.task_id, style: card2 },
6033
+ (0, import_react7.createElement)(
6360
6034
  "div",
6361
6035
  { 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)
6036
+ (0, import_react7.createElement)("span", { style: { fontSize: 14, fontWeight: 600, color: "var(--dsw-alias-label-primary)" } }, task.task_id),
6037
+ (0, import_react7.createElement)("span", { style: { fontSize: 13, color: "var(--dsw-alias-label-primary)" } }, task.title),
6038
+ (0, import_react7.createElement)("span", { style: badge }, task.stage),
6039
+ (0, import_react7.createElement)("span", { style: badge }, task.branch),
6040
+ (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"),
6041
+ (0, import_react7.createElement)("span", { className: "te-badge" }, task.verification_passed ? "\u9A8C\u8BC1\u901A\u8FC7" : "\u5F85\u9A8C\u8BC1"),
6042
+ (0, import_react7.createElement)("span", { className: "te-badge" }, `\u5BA1\u6838\uFF1A${task.review_outcome ?? "pending"}`),
6043
+ task.updated_at ? (0, import_react7.createElement)("span", { style: metaLine }, "\u66F4\u65B0\u4E8E " + timeText(task.updated_at)) : null
6366
6044
  ),
6367
- (0, import_react6.createElement)(
6045
+ (0, import_react7.createElement)(
6368
6046
  "div",
6369
6047
  { style: { display: "flex", flexDirection: "column" } },
6370
- ...task.items.map((item) => (0, import_react6.createElement)(
6048
+ ...task.items.map((item) => (0, import_react7.createElement)(
6371
6049
  "div",
6372
6050
  { key: item.id, style: itemRow },
6373
- (0, import_react6.createElement)(
6051
+ (0, import_react7.createElement)(
6374
6052
  "div",
6375
6053
  { style: headerRow },
6376
6054
  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)
6055
+ (0, import_react7.createElement)("span", { style: { fontSize: 13, color: "var(--dsw-alias-label-primary)" } }, item.id),
6056
+ (0, import_react7.createElement)("span", { style: { fontSize: 12, color: "var(--dsw-alias-label-secondary)" } }, item.title)
6379
6057
  ),
6380
6058
  itemAudit(item)
6381
6059
  ))
@@ -6398,24 +6076,25 @@ var header = {
6398
6076
  display: "flex",
6399
6077
  alignItems: "center",
6400
6078
  justifyContent: "space-between",
6401
- padding: "12px 20px",
6079
+ padding: "20px 28px",
6402
6080
  borderBottom: "1px solid var(--dsw-alias-border-l2)"
6403
6081
  };
6404
6082
  var headerBrand = { display: "flex", alignItems: "center", gap: 10, minWidth: 0 };
6405
6083
  var headerText = { display: "flex", flexDirection: "column", gap: 1, minWidth: 0 };
6406
- var headerTitle = { fontSize: 15, fontWeight: 600, color: "var(--dsw-alias-label-primary)" };
6084
+ var headerTitle = { fontSize: 20, fontWeight: 650, color: "var(--dsw-alias-label-primary)" };
6407
6085
  var headerSub = { fontSize: 12, color: "var(--dsw-alias-label-tertiary)", margin: 0 };
6408
6086
  var tabbar = {
6409
6087
  display: "flex",
6410
6088
  alignItems: "center",
6411
6089
  gap: 8,
6412
- padding: "10px 20px",
6090
+ padding: "12px 28px",
6091
+ flexWrap: "wrap",
6413
6092
  borderBottom: "1px solid var(--dsw-alias-border-l2)"
6414
6093
  };
6415
6094
  var body = {
6416
6095
  flex: 1,
6417
6096
  overflowY: "auto",
6418
- padding: 20
6097
+ padding: "24px clamp(12px, 3vw, 32px)"
6419
6098
  };
6420
6099
  var selectStyle = {
6421
6100
  marginLeft: "auto",
@@ -6442,34 +6121,35 @@ var TABS = [
6442
6121
  { id: "init", label: "\u9879\u76EE\u521D\u59CB\u5316" },
6443
6122
  { id: "flow", label: "\u6D41\u7A0B\u914D\u7F6E" },
6444
6123
  { id: "tasks", label: "\u4EFB\u52A1\u53F0\u8D26" },
6445
- { id: "skills", label: "\u6280\u80FD skill" },
6446
- { id: "rules", label: "\u89C4\u5219 rule" }
6124
+ { id: "skills", label: "\u6280\u80FD" },
6125
+ { id: "rules", label: "\u89C4\u5219" }
6447
6126
  ];
6448
6127
  function Workbench({ useStore, actions, useWorkspaces, remote }) {
6449
6128
  const open = useStore((s) => s.open);
6450
6129
  const workspaces = useWorkspaces((s) => s.items);
6451
- const [tab, setTab] = (0, import_react7.useState)("init");
6452
- const [workspace, setWorkspace] = (0, import_react7.useState)("");
6130
+ const [tab, setTab] = (0, import_react8.useState)("init");
6131
+ const [workspace, setWorkspace] = (0, import_react8.useState)("");
6453
6132
  if (!open) return null;
6454
6133
  const current = workspaces.some((w) => w.path === workspace) ? workspace : workspaces[0]?.path ?? "";
6455
- return (0, import_react7.createElement)(
6134
+ return (0, import_react8.createElement)(
6456
6135
  "div",
6457
- { style: overlay },
6458
- (0, import_react7.createElement)(
6136
+ { style: overlay, className: "te-workbench" },
6137
+ (0, import_react8.createElement)("style", null, workbenchTheme),
6138
+ (0, import_react8.createElement)(
6459
6139
  "div",
6460
6140
  { style: header },
6461
- (0, import_react7.createElement)(
6141
+ (0, import_react8.createElement)(
6462
6142
  "div",
6463
6143
  { style: headerBrand },
6464
- (0, import_react7.createElement)(import_dsh_client_ui_primitives7.IconSettingsOutline16, { size: 18 }),
6465
- (0, import_react7.createElement)(
6144
+ (0, import_react8.createElement)(import_dsh_client_ui_primitives6.IconSettingsOutline16, { size: 18 }),
6145
+ (0, import_react8.createElement)(
6466
6146
  "div",
6467
6147
  { 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")
6148
+ (0, import_react8.createElement)("span", { style: headerTitle }, "\u5DE5\u7A0B\u6D41\u7A0B"),
6149
+ (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
6150
  )
6471
6151
  ),
6472
- (0, import_react7.createElement)(
6152
+ (0, import_react8.createElement)(
6473
6153
  "button",
6474
6154
  {
6475
6155
  type: "button",
@@ -6485,38 +6165,44 @@ function Workbench({ useStore, actions, useWorkspaces, remote }) {
6485
6165
  event.currentTarget.style.background = "transparent";
6486
6166
  }
6487
6167
  },
6488
- (0, import_react7.createElement)(import_dsh_client_ui_primitives7.IconCloseOutline16, { size: 16 })
6168
+ (0, import_react8.createElement)(import_dsh_client_ui_primitives6.IconCloseOutline16, { size: 16 })
6489
6169
  )
6490
6170
  ),
6491
- (0, import_react7.createElement)(
6171
+ (0, import_react8.createElement)(
6492
6172
  "div",
6493
6173
  { style: tabbar },
6494
- ...TABS.map((t) => (0, import_react7.createElement)(import_dsh_client_ui_primitives7.Pill, { key: t.id, active: tab === t.id, onClick: () => {
6174
+ ...TABS.map((t) => (0, import_react8.createElement)(import_dsh_client_ui_primitives6.Pill, { key: t.id, active: tab === t.id, onClick: () => {
6495
6175
  setTab(t.id);
6496
6176
  } }, t.label)),
6497
- workspaces.length > 0 ? (0, import_react7.createElement)("select", {
6177
+ workspaces.length > 0 ? (0, import_react8.createElement)("select", {
6498
6178
  style: selectStyle,
6179
+ "aria-label": "\u5F53\u524D\u5DE5\u4F5C\u533A",
6499
6180
  value: current,
6500
6181
  onChange: (ev) => {
6501
6182
  setWorkspace(ev.target.value);
6502
6183
  }
6503
- }, ...workspaces.map((w) => (0, import_react7.createElement)("option", { key: w.path, value: w.path }, w.title || w.path))) : null
6184
+ }, ...workspaces.map((w) => (0, import_react8.createElement)("option", { key: w.path, value: w.path }, w.title || w.path))) : null
6504
6185
  ),
6505
- (0, import_react7.createElement)(
6186
+ (0, import_react8.createElement)(
6506
6187
  "div",
6507
6188
  { 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 })
6189
+ (0, import_react8.createElement)(
6190
+ "div",
6191
+ { className: "te-content", key: current },
6192
+ (0, import_react8.createElement)("p", { style: { ...styles.hint, marginBottom: 20 }, title: current }, "\u5DE5\u4F5C\u533A \xB7 " + current),
6193
+ 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 })
6194
+ )
6509
6195
  )
6510
6196
  );
6511
6197
  }
6512
6198
 
6513
6199
  // src/client/TriggerButton.tsx
6514
- var import_react8 = require("react");
6515
- var import_dsh_client_ui_primitives8 = require("@deepseek-ai/dsh-client-ui-primitives");
6200
+ var import_react9 = require("react");
6201
+ var import_dsh_client_ui_primitives7 = require("@deepseek-ai/dsh-client-ui-primitives");
6516
6202
  var hover = "var(--dsw-alias-bg-layer-2)";
6517
6203
  var label = "var(--dsw-alias-label-primary)";
6518
6204
  function TriggerButton({ wide, actions }) {
6519
- return (0, import_react8.createElement)(
6205
+ return (0, import_react9.createElement)(
6520
6206
  "button",
6521
6207
  {
6522
6208
  type: "button",
@@ -6556,8 +6242,8 @@ function TriggerButton({ wide, actions }) {
6556
6242
  transition: "background 120ms ease"
6557
6243
  }
6558
6244
  },
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
6245
+ (0, import_react9.createElement)(import_dsh_client_ui_primitives7.IconSettingsOutline16, { size: wide ? 16 : 18 }),
6246
+ wide ? (0, import_react9.createElement)("span", { style: { fontSize: 14, lineHeight: "22px" } }, "\u5DE5\u7A0B\u6D41\u7A0B") : null
6561
6247
  );
6562
6248
  }
6563
6249