@godv61/dsh-task-engine 0.5.1 → 0.5.3

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
@@ -168,8 +168,8 @@ var util;
168
168
  return util2.objectValues(filtered);
169
169
  };
170
170
  util2.objectValues = (obj) => {
171
- return util2.objectKeys(obj).map(function(e2) {
172
- return obj[e2];
171
+ return util2.objectKeys(obj).map(function(e) {
172
+ return obj[e];
173
173
  });
174
174
  };
175
175
  util2.objectKeys = typeof Object.keys === "function" ? (obj) => Object.keys(obj) : (object) => {
@@ -3337,13 +3337,13 @@ var ZodFunction = class _ZodFunction extends ZodType {
3337
3337
  const me = this;
3338
3338
  return OK(async function(...args) {
3339
3339
  const error = new ZodError([]);
3340
- const parsedArgs = await me._def.args.parseAsync(args, params).catch((e2) => {
3341
- error.addIssue(makeArgsIssue(args, e2));
3340
+ const parsedArgs = await me._def.args.parseAsync(args, params).catch((e) => {
3341
+ error.addIssue(makeArgsIssue(args, e));
3342
3342
  throw error;
3343
3343
  });
3344
3344
  const result = await Reflect.apply(fn, this, parsedArgs);
3345
- const parsedReturns = await me._def.returns._def.type.parseAsync(result, params).catch((e2) => {
3346
- error.addIssue(makeReturnsIssue(result, e2));
3345
+ const parsedReturns = await me._def.returns._def.type.parseAsync(result, params).catch((e) => {
3346
+ error.addIssue(makeReturnsIssue(result, e));
3347
3347
  throw error;
3348
3348
  });
3349
3349
  return parsedReturns;
@@ -4146,8 +4146,9 @@ var TYPERT_REMOTE = {
4146
4146
  };
4147
4147
  var remote_default = TYPERT_REMOTE;
4148
4148
 
4149
- // src/client/TaskEngineSection.ts
4150
- var import_react = require("react");
4149
+ // src/client/TaskEngineSection.tsx
4150
+ var import_react2 = require("react");
4151
+ var import_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
4151
4152
 
4152
4153
  // src/engine.ts
4153
4154
  var GUARD_NAMES = [
@@ -4223,23 +4224,389 @@ function validateWorkflow(config) {
4223
4224
  return problems;
4224
4225
  }
4225
4226
 
4226
- // src/client/TaskEngineSection.ts
4227
- var e = import_react.createElement;
4227
+ // src/client/FlowDiagram.tsx
4228
+ var import_react = require("react");
4229
+ var nodeW = 108;
4230
+ var nodeH = 40;
4231
+ var stepX = nodeW + 56;
4232
+ var margin = 40;
4233
+ var nodeTop = 92;
4234
+ var nodeCenterY = nodeTop + nodeH / 2;
4235
+ var textTertiary = "var(--dsw-alias-label-tertiary)";
4236
+ var textSecondary = "var(--dsw-alias-label-secondary)";
4237
+ var border = "var(--dsw-alias-border-l2)";
4238
+ var surface = "var(--dsw-alias-bg-layer-2)";
4239
+ var brand = "var(--dsw-alias-state-business-primary)";
4240
+ var danger = "var(--dsw-alias-state-error-primary)";
4241
+ function edgeList(config) {
4242
+ return config.transitions.map((t) => {
4243
+ const label = (t.requires ?? []).length > 0 ? (t.requires ?? []).join(" \xB7 ") : null;
4244
+ const orphaned = !config.stages.includes(t.from) || !config.stages.includes(t.to);
4245
+ return { from: t.from, to: t.to, label, orphaned };
4246
+ });
4247
+ }
4248
+ function nodeX(index, stageCount) {
4249
+ return index < 0 ? margin + stageCount * stepX + nodeW : margin + index * stepX;
4250
+ }
4251
+ function FlowDiagram({ config, onAddTransition, onRemoveTransition }) {
4252
+ const [dragFrom, setDragFrom] = (0, import_react.useState)(null);
4253
+ const [dragPos, setDragPos] = (0, import_react.useState)(null);
4254
+ const svgRef = (0, import_react.useRef)(null);
4255
+ const stages = config.stages;
4256
+ const edges = edgeList(config);
4257
+ const stageCount = stages.length;
4258
+ const indexOf = (s) => {
4259
+ const i = stages.indexOf(s);
4260
+ return i < 0 ? -1 : i;
4261
+ };
4262
+ const width = Math.max(margin * 2 + stageCount * stepX, 360);
4263
+ const height = 210;
4264
+ const toSvg = (e) => {
4265
+ const rect = svgRef.current.getBoundingClientRect();
4266
+ return { x: e.clientX - rect.left, y: e.clientY - rect.top };
4267
+ };
4268
+ const startDrag = (stage, e) => {
4269
+ setDragFrom(stage);
4270
+ setDragPos(toSvg(e));
4271
+ };
4272
+ const dropOn = (stage) => {
4273
+ if (dragFrom !== null && dragFrom !== stage) onAddTransition(dragFrom, stage);
4274
+ setDragFrom(null);
4275
+ setDragPos(null);
4276
+ };
4277
+ const cancelDrag = () => {
4278
+ setDragFrom(null);
4279
+ setDragPos(null);
4280
+ };
4281
+ const forwardPath = (from, to) => {
4282
+ const x1 = nodeX(from, stageCount) + nodeW;
4283
+ const x2 = nodeX(to, stageCount);
4284
+ if (to === from + 1) return `M ${x1} ${nodeCenterY} L ${x2} ${nodeCenterY}`;
4285
+ const cx = (x1 + x2) / 2;
4286
+ const cy = nodeCenterY + (to - from) * 20;
4287
+ return `M ${x1} ${nodeCenterY} Q ${cx} ${cy} ${x2} ${nodeCenterY}`;
4288
+ };
4289
+ const returnPath = (from, to) => {
4290
+ const x1 = nodeX(from, stageCount) + nodeW / 2;
4291
+ const x2 = nodeX(to, stageCount) + nodeW / 2;
4292
+ const y1 = nodeTop;
4293
+ const lift = 26 + Math.abs(from - to) * 6;
4294
+ if (from === to) {
4295
+ const cx2 = x1 + nodeW / 2 + 8;
4296
+ return `M ${x1 + nodeW / 2} ${y1} Q ${cx2} ${y1 - lift} ${x1 + nodeW / 2 + 18} ${y1}`;
4297
+ }
4298
+ const cx = (x1 + x2) / 2;
4299
+ return `M ${x1} ${y1} Q ${cx} ${y1 - lift} ${x2} ${y1}`;
4300
+ };
4301
+ const forwardLabelY = (from, to) => to === from + 1 ? nodeCenterY - 8 : nodeCenterY + (to - from) * 20 + 16;
4302
+ const returnLabelY = (from, to) => nodeTop - 30 - Math.abs(from - to) * 6;
4303
+ const dragLine = dragFrom !== null && dragPos !== null ? (() => {
4304
+ const from = indexOf(dragFrom);
4305
+ const cx = from < 0 ? nodeX(-1, stageCount) + nodeW / 2 : nodeX(from, stageCount) + nodeW / 2;
4306
+ const cy = nodeTop;
4307
+ return (0, import_react.createElement)("line", {
4308
+ x1: cx,
4309
+ y1: cy,
4310
+ x2: dragPos.x,
4311
+ y2: dragPos.y,
4312
+ stroke: brand,
4313
+ strokeWidth: 1.5,
4314
+ strokeDasharray: "5 3",
4315
+ pointerEvents: "none"
4316
+ });
4317
+ })() : null;
4318
+ return (0, import_react.createElement)(
4319
+ "svg",
4320
+ {
4321
+ ref: svgRef,
4322
+ width,
4323
+ height,
4324
+ viewBox: `0 0 ${width} ${height}`,
4325
+ style: { display: "block", minWidth: "100%", fontFamily: "inherit" },
4326
+ role: "img",
4327
+ "aria-label": "\u5DE5\u7A0B\u9636\u6BB5\u6D41\u8F6C\u56FE\uFF08\u53EF\u62D6\u62FD\u8FDE\u7EBF\u3001\u70B9\u51FB\u7BAD\u5934\u5220\u9664\uFF09",
4328
+ onMouseMove: dragFrom === null ? void 0 : (e) => {
4329
+ setDragPos(toSvg(e));
4330
+ },
4331
+ onMouseUp: cancelDrag,
4332
+ onMouseLeave: cancelDrag
4333
+ },
4334
+ (0, import_react.createElement)(
4335
+ "defs",
4336
+ null,
4337
+ (0, import_react.createElement)("marker", {
4338
+ id: "flow-arrow",
4339
+ viewBox: "0 0 10 10",
4340
+ refX: 8,
4341
+ refY: 5,
4342
+ markerWidth: 7,
4343
+ markerHeight: 7,
4344
+ orient: "auto"
4345
+ }, (0, import_react.createElement)("path", { d: "M 0 0 L 10 5 L 0 10 z", fill: "context-stroke" }))
4346
+ ),
4347
+ ...edges.map((edge, i) => {
4348
+ const from = indexOf(edge.from);
4349
+ const to = indexOf(edge.to);
4350
+ const stroke = edge.orphaned ? danger : textTertiary;
4351
+ const d = from < to ? forwardPath(from, to) : returnPath(from, to < 0 ? from : to);
4352
+ const labelY = from < to ? forwardLabelY(from, to) : returnLabelY(from, to < 0 ? from : to);
4353
+ const labelX = from < to ? (nodeX(from, stageCount) + nodeW + nodeX(to, stageCount)) / 2 : (nodeX(from, stageCount) + nodeX(to < 0 ? from : to, stageCount) + nodeW) / 2;
4354
+ const common = {
4355
+ key: `edge-${i}`,
4356
+ d,
4357
+ fill: "none",
4358
+ stroke,
4359
+ strokeWidth: 1.5,
4360
+ markerEnd: "url(#flow-arrow)",
4361
+ style: { cursor: "pointer" },
4362
+ onClick: () => {
4363
+ onRemoveTransition(i);
4364
+ },
4365
+ ...edge.orphaned ? { strokeDasharray: "4 3" } : {}
4366
+ };
4367
+ const label = edge.label === null ? null : (0, import_react.createElement)("text", {
4368
+ x: labelX,
4369
+ y: labelY,
4370
+ textAnchor: "middle",
4371
+ fontSize: 11,
4372
+ fill: edge.orphaned ? danger : textSecondary
4373
+ }, edge.label);
4374
+ return (0, import_react.createElement)(
4375
+ "g",
4376
+ { key: `edgeg-${i}` },
4377
+ (0, import_react.createElement)(
4378
+ "path",
4379
+ {
4380
+ ...common,
4381
+ strokeWidth: 6,
4382
+ stroke: "transparent",
4383
+ fill: "none",
4384
+ markerEnd: void 0,
4385
+ strokeDasharray: void 0
4386
+ }
4387
+ ),
4388
+ (0, import_react.createElement)("path", common),
4389
+ label
4390
+ );
4391
+ }),
4392
+ ...stages.map((stage, i) => {
4393
+ const x = nodeX(i, stageCount);
4394
+ const isStart = stage === config.start_stage;
4395
+ return (0, import_react.createElement)(
4396
+ "g",
4397
+ {
4398
+ key: stage,
4399
+ style: { cursor: dragFrom === null ? "crosshair" : "pointer" },
4400
+ onMouseDown: (e) => {
4401
+ startDrag(stage, e);
4402
+ },
4403
+ onMouseUp: () => {
4404
+ dropOn(stage);
4405
+ }
4406
+ },
4407
+ (0, import_react.createElement)("rect", {
4408
+ x,
4409
+ y: nodeTop,
4410
+ width: nodeW,
4411
+ height: nodeH,
4412
+ rx: 20,
4413
+ ry: 20,
4414
+ fill: surface,
4415
+ stroke: isStart ? brand : border,
4416
+ strokeWidth: isStart ? 2 : 1.5
4417
+ }),
4418
+ (0, import_react.createElement)("text", {
4419
+ x: x + nodeW / 2,
4420
+ y: nodeCenterY,
4421
+ textAnchor: "middle",
4422
+ alignmentBaseline: "middle",
4423
+ fontSize: 12,
4424
+ fill: "var(--dsw-alias-label-primary)",
4425
+ fontWeight: isStart ? 600 : 400
4426
+ }, stage),
4427
+ (0, import_react.createElement)("title", null, `${stage}${stage === config.start_stage ? "\uFF08\u8D77\u59CB\uFF09" : ""} \u2014 \u62D6\u5230\u53E6\u4E00\u9636\u6BB5\u65B0\u5EFA\u6D41\u8F6C`)
4428
+ );
4429
+ }),
4430
+ dragLine
4431
+ );
4432
+ }
4433
+
4434
+ // src/client/templates.ts
4435
+ var STANDARD = {
4436
+ stages: ["\u9700\u6C42\u8BC4\u5BA1", "\u8BBE\u8BA1", "\u5F00\u53D1", "\u4EA4\u4ED8", "\u4EE3\u7801\u5BA1\u6838", "\u5B8C\u6210"],
4437
+ start_stage: "\u9700\u6C42\u8BC4\u5BA1",
4438
+ transitions: [
4439
+ { from: "\u9700\u6C42\u8BC4\u5BA1", to: "\u8BBE\u8BA1", requires: ["requirement_confirmation", "artifacts_present"] },
4440
+ { from: "\u8BBE\u8BA1", to: "\u5F00\u53D1", requires: ["solution_confirmation", "artifacts_present"] },
4441
+ { from: "\u5F00\u53D1", to: "\u4EA4\u4ED8", requires: ["todos_done"] },
4442
+ { from: "\u4EA4\u4ED8", to: "\u4EE3\u7801\u5BA1\u6838", requires: ["verified"] },
4443
+ { from: "\u4EE3\u7801\u5BA1\u6838", to: "\u5B8C\u6210", requires: ["review_passed", "artifacts_present"] }
4444
+ ],
4445
+ artifacts: [
4446
+ { stage: "\u9700\u6C42\u8BC4\u5BA1", id: "requirement", name: "\u9700\u6C42\u8BF4\u660E", fields: ["scope", "acceptance_criteria"] },
4447
+ { stage: "\u8BBE\u8BA1", id: "design", name: "\u8BBE\u8BA1\u6587\u6863", fields: ["approach", "risks", "impact"] },
4448
+ { stage: "\u4EE3\u7801\u5BA1\u6838", id: "review", name: "\u8BC4\u5BA1\u8BB0\u5F55", fields: ["conclusion", "issues"] }
4449
+ ],
4450
+ commit: {
4451
+ policy: "task",
4452
+ message_pattern: "^\u3010(\\S+)\u3011\u3010(?:TASK|T\\d+)\u3011.+",
4453
+ message_hint: "\u3010<module>\u3011\u3010TASK/T1\u3011\u8BF4\u660E \u2014\u2014 \u5199\u7ED3\u679C\uFF0C\u4E0D\u5199\u7A7A\u6CDB\u52A8\u4F5C",
4454
+ checkpoints: ["\u4EA4\u4ED8"],
4455
+ file_scope: true
4456
+ },
4457
+ high_risk_requires_verification: true
4458
+ };
4459
+ var AGILE = {
4460
+ stages: ["\u9700\u6C42", "\u5F00\u53D1", "\u4EA4\u4ED8", "\u5BA1\u67E5"],
4461
+ start_stage: "\u9700\u6C42",
4462
+ transitions: [
4463
+ { from: "\u9700\u6C42", to: "\u5F00\u53D1", requires: ["requirement_confirmation"] },
4464
+ { from: "\u5F00\u53D1", to: "\u4EA4\u4ED8", requires: ["todos_done"] },
4465
+ { from: "\u4EA4\u4ED8", to: "\u5BA1\u67E5", requires: [] }
4466
+ ],
4467
+ artifacts: [
4468
+ { stage: "\u9700\u6C42", id: "requirement", name: "\u9700\u6C42\u8BF4\u660E", fields: ["scope"] }
4469
+ ],
4470
+ commit: {
4471
+ policy: "item",
4472
+ message_pattern: "^\u3010(\\S+)\u3011\u3010T\\d+\u3011.+",
4473
+ message_hint: "\u3010<module>\u3011\u3010T1\u3011\u8BF4\u660E",
4474
+ checkpoints: ["\u4EA4\u4ED8"],
4475
+ file_scope: true
4476
+ },
4477
+ high_risk_requires_verification: false
4478
+ };
4479
+ var MINIMAL = {
4480
+ stages: ["\u5F00\u53D1", "\u4EA4\u4ED8"],
4481
+ start_stage: "\u5F00\u53D1",
4482
+ transitions: [
4483
+ { from: "\u5F00\u53D1", to: "\u4EA4\u4ED8", requires: ["todos_done"] }
4484
+ ],
4485
+ artifacts: [],
4486
+ commit: {
4487
+ policy: "task",
4488
+ message_pattern: "",
4489
+ message_hint: "\u65E0\u683C\u5F0F\u8981\u6C42",
4490
+ checkpoints: ["\u4EA4\u4ED8"],
4491
+ file_scope: false
4492
+ },
4493
+ high_risk_requires_verification: false
4494
+ };
4495
+ var WORKFLOW_TEMPLATES = [
4496
+ { id: "standard", label: "\u6807\u51C6\u7814\u53D1", description: "\u9700\u6C42\u8BC4\u5BA1 \u2192 \u8BBE\u8BA1 \u2192 \u5F00\u53D1 \u2192 \u4EA4\u4ED8 \u2192 \u4EE3\u7801\u5BA1\u6838\uFF0C\u542B\u4EA7\u7269\u95E8 + \u786E\u8BA4\u95E8", config: STANDARD },
4497
+ { id: "agile", label: "\u654F\u6377\u8F7B\u91CF", description: "\u9700\u6C42 \u2192 \u5F00\u53D1 \u2192 \u4EA4\u4ED8 \u2192 \u5BA1\u67E5\uFF0C\u56DB\u9636\u6BB5\u3001\u5C11\u4EA7\u7269", config: AGILE },
4498
+ { id: "minimal", label: "\u7EAF\u4EE3\u7801", description: "\u5F00\u53D1 \u2192 \u4EA4\u4ED8\uFF0C\u4E24\u9636\u6BB5\uFF0C\u53EA\u7559\u63D0\u4EA4\u95E8\u7981", config: MINIMAL }
4499
+ ];
4500
+
4501
+ // src/client/styles.ts
4502
+ var text = "var(--dsw-alias-label-primary)";
4503
+ var textSecondary2 = "var(--dsw-alias-label-secondary)";
4504
+ var textTertiary2 = "var(--dsw-alias-label-tertiary)";
4505
+ var border2 = "var(--dsw-alias-border-l2)";
4506
+ var surface2 = "var(--dsw-alias-bg-layer-2)";
4507
+ var danger2 = "var(--dsw-alias-state-error-primary)";
4508
+ var success = "var(--dsw-alias-state-success-primary)";
4509
+ var warn = "var(--dsw-alias-state-warn-primary)";
4510
+ var styles = {
4511
+ wrap: { display: "flex", flexDirection: "column", gap: 16, padding: 20, maxWidth: 900 },
4512
+ head: { display: "flex", flexDirection: "column", gap: 4 },
4513
+ title: { margin: 0, color: text },
4514
+ muted: { margin: 0, color: textSecondary2, fontSize: 13, lineHeight: 1.5 },
4515
+ sourceRow: { display: "flex", alignItems: "center", gap: 8 },
4516
+ sourceText: { color: textTertiary2, fontSize: 13 },
4517
+ workspaceRow: { display: "flex", alignItems: "center", gap: 8 },
4518
+ workspaceLabel: { color: textSecondary2, fontSize: 13 },
4519
+ flowCard: { border: `1px solid ${border2}`, borderRadius: 10, background: surface2, padding: 12, overflowX: "auto" },
4520
+ section: { display: "flex", flexDirection: "column", gap: 12 },
4521
+ cardBody: { padding: "4px 0 8px", display: "flex", flexDirection: "column", gap: 12 },
4522
+ row: { display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" },
4523
+ field: { display: "flex", flexDirection: "column", gap: 4, flex: "1 1 220px", minWidth: 180 },
4524
+ fieldLabel: { color: textSecondary2, fontSize: 13 },
4525
+ hint: { color: textTertiary2, fontSize: 12, margin: 0, lineHeight: 1.4 },
4526
+ chips: { display: "flex", flexWrap: "wrap", gap: 6, alignItems: "center" },
4527
+ cardRow: {
4528
+ display: "flex",
4529
+ alignItems: "center",
4530
+ gap: 8,
4531
+ flexWrap: "wrap",
4532
+ border: `1px solid ${border2}`,
4533
+ borderRadius: 8,
4534
+ padding: "8px 10px"
4535
+ },
4536
+ inline: { display: "inline-flex", alignItems: "center", gap: 6, marginRight: 8 },
4537
+ problems: {
4538
+ display: "flex",
4539
+ flexDirection: "column",
4540
+ gap: 8,
4541
+ border: `1px solid ${danger2}`,
4542
+ borderRadius: 8,
4543
+ padding: "10px 12px"
4544
+ },
4545
+ problemsTitle: { color: danger2, fontSize: 13, fontWeight: 600, display: "flex", alignItems: "center", gap: 8 },
4546
+ problemsList: { margin: 0, paddingLeft: 20, color: text, fontSize: 13, display: "flex", flexDirection: "column", gap: 4 },
4547
+ noticeBox: {
4548
+ border: `1px solid ${warn}`,
4549
+ borderRadius: 8,
4550
+ padding: "10px 12px",
4551
+ display: "flex",
4552
+ flexDirection: "column",
4553
+ gap: 8
4554
+ },
4555
+ noticeTitle: { color: warn, fontSize: 13, fontWeight: 600, display: "flex", alignItems: "center", gap: 8 },
4556
+ okText: { color: success, fontSize: 13, display: "flex", alignItems: "center", gap: 6 },
4557
+ status: { color: textTertiary2, fontSize: 13, display: "flex", alignItems: "center", gap: 6 },
4558
+ actions: { display: "flex", alignItems: "center", gap: 12, marginTop: 4 }
4559
+ };
4560
+
4561
+ // src/client/TaskEngineSection.tsx
4562
+ var import_jsx_runtime = require("react/jsx-runtime");
4563
+ var text2 = "var(--dsw-alias-label-primary)";
4564
+ var textTertiary3 = "var(--dsw-alias-label-tertiary)";
4565
+ var control = {
4566
+ background: "var(--dsw-alias-bg-layer-1)",
4567
+ border: `1px solid ${border2}`,
4568
+ borderRadius: 8,
4569
+ padding: "5px 8px",
4570
+ color: text2,
4571
+ fontSize: 13,
4572
+ minWidth: 0
4573
+ };
4574
+ var cardV = {
4575
+ display: "flex",
4576
+ flexDirection: "column",
4577
+ gap: 8,
4578
+ border: `1px solid ${border2}`,
4579
+ borderRadius: 8,
4580
+ padding: "10px 12px"
4581
+ };
4582
+ var GUARD_OPTIONS = [
4583
+ { value: "requirement_confirmation", label: "\u9700\u6C42\u786E\u8BA4" },
4584
+ { value: "solution_confirmation", label: "\u65B9\u6848\u786E\u8BA4" },
4585
+ { value: "todos_done", label: "\u5F85\u529E\u5B8C\u6210" },
4586
+ { value: "verified", label: "\u5DF2\u9A8C\u8BC1" },
4587
+ { value: "review_passed", label: "\u8BC4\u5BA1\u901A\u8FC7" },
4588
+ { value: "artifacts_present", label: "\u4EA7\u7269\u9F50\u5168" }
4589
+ ];
4590
+ var POLICY_OPTIONS = [
4591
+ { value: "task", label: "task", hint: "\u68C0\u67E5\u70B9\u4E00\u6B21\u63D0\u4EA4" },
4592
+ { value: "item", label: "item", hint: "\u9010\u9879\u63D0\u4EA4 + \u6536\u5C3E TASK" },
4593
+ { value: "manual", label: "manual", hint: "\u4EBA\u5DE5\u6307\u793A" }
4594
+ ];
4228
4595
  function TaskEngineSection(props) {
4229
4596
  const { remote, useWorkspaces } = props;
4230
4597
  const workspaces = useWorkspaces((state) => state.items);
4231
- const [workspace, setWorkspace] = (0, import_react.useState)("");
4232
- const [config, setConfig] = (0, import_react.useState)(null);
4233
- const [source, setSource] = (0, import_react.useState)("default");
4234
- const [savedAt, setSavedAt] = (0, import_react.useState)("");
4235
- const [loadError, setLoadError] = (0, import_react.useState)("");
4236
- const [loadedProblems, setLoadedProblems] = (0, import_react.useState)([]);
4237
- (0, import_react.useEffect)(() => {
4598
+ const [workspace, setWorkspace] = (0, import_react2.useState)("");
4599
+ const [config, setConfig] = (0, import_react2.useState)(null);
4600
+ const [source, setSource] = (0, import_react2.useState)("default");
4601
+ const [savedAt, setSavedAt] = (0, import_react2.useState)("");
4602
+ const [loadError, setLoadError] = (0, import_react2.useState)("");
4603
+ const [loadedProblems, setLoadedProblems] = (0, import_react2.useState)([]);
4604
+ (0, import_react2.useEffect)(() => {
4238
4605
  if (workspaces.length > 0 && workspace === "") {
4239
4606
  setWorkspace(workspaces[0].path);
4240
4607
  }
4241
4608
  }, [workspaces, workspace]);
4242
- (0, import_react.useEffect)(() => {
4609
+ (0, import_react2.useEffect)(() => {
4243
4610
  if (workspace === "") return;
4244
4611
  let alive = true;
4245
4612
  setLoadError("");
@@ -4260,221 +4627,406 @@ function TaskEngineSection(props) {
4260
4627
  alive = false;
4261
4628
  };
4262
4629
  }, [remote, workspace]);
4263
- const problems = (0, import_react.useMemo)(() => config === null ? [] : validateWorkflow(config), [config]);
4630
+ const problems = (0, import_react2.useMemo)(() => config === null ? [] : validateWorkflow(config), [config]);
4264
4631
  const notice = problems.length === 0 && loadedProblems.length > 0 ? loadedProblems : [];
4632
+ const addTransition = (from, to) => {
4633
+ if (config === null || from === "" || to === "") return;
4634
+ update(config, setConfig, (c) => ({
4635
+ ...c,
4636
+ transitions: [...c.transitions, { from, to }]
4637
+ }));
4638
+ };
4639
+ const removeTransition = (index) => {
4640
+ if (config === null) return;
4641
+ update(config, setConfig, (c) => ({ ...c, transitions: c.transitions.filter((_, j) => j !== index) }));
4642
+ };
4265
4643
  if (workspaces.length === 0) {
4266
- return e(
4267
- "div",
4268
- { style: styles.wrap },
4269
- e("h2", { style: styles.title }, "\u5DE5\u7A0B\u6D41\u7A0B\u914D\u7F6E"),
4270
- e("p", { style: styles.problems }, "\u5F53\u524D\u6CA1\u6709\u4EFB\u4F55\u5DE5\u4F5C\u533A\uFF1A\u8BF7\u5148\u5728\u4FA7\u680F\u521B\u5EFA\u4E00\u4E2A\u5DE5\u4F5C\u533A\u3002")
4271
- );
4644
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.wrap, children: [
4645
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { style: styles.title, children: "\u5DE5\u7A0B\u6D41\u7A0B\u914D\u7F6E" }),
4646
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: styles.muted, children: "\u5F53\u524D\u6CA1\u6709\u4EFB\u4F55\u5DE5\u4F5C\u533A\uFF1A\u8BF7\u5148\u5728\u4FA7\u680F\u521B\u5EFA\u4E00\u4E2A\u5DE5\u4F5C\u533A\u3002" })
4647
+ ] });
4272
4648
  }
4273
4649
  if (loadError !== "") {
4274
- return e(
4275
- "div",
4276
- { style: styles.wrap },
4277
- e("h2", { style: styles.title }, "\u5DE5\u7A0B\u6D41\u7A0B\u914D\u7F6E"),
4278
- e("p", { style: styles.problems }, loadError)
4279
- );
4650
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.wrap, children: [
4651
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { style: styles.title, children: "\u5DE5\u7A0B\u6D41\u7A0B\u914D\u7F6E" }),
4652
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.problems, children: [
4653
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { style: styles.problemsTitle, children: [
4654
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.StateDot, { state: "error" }),
4655
+ "\u8BFB\u53D6\u5931\u8D25"
4656
+ ] }),
4657
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: styles.muted, children: loadError })
4658
+ ] })
4659
+ ] });
4280
4660
  }
4281
4661
  if (config === null) {
4282
- return e(
4283
- "div",
4284
- { style: styles.wrap },
4285
- e("h2", { style: styles.title }, "\u5DE5\u7A0B\u6D41\u7A0B\u914D\u7F6E"),
4286
- e("p", null, "\u52A0\u8F7D\u4E2D\u2026")
4287
- );
4288
- }
4289
- return e(
4290
- "div",
4291
- { style: styles.wrap },
4292
- e("h2", { style: styles.title }, "\u5DE5\u7A0B\u6D41\u7A0B\u914D\u7F6E"),
4293
- e("p", { style: styles.muted }, "\u8FD9\u4EFD\u914D\u7F6E\u540C\u65F6\u9A71\u52A8 dev_task \u7684\u786C\u95E8\u7981\uFF1B\u6709\u95EE\u9898\u7684\u914D\u7F6E\u4E0D\u4F1A\u88AB\u4FDD\u5B58\u3002"),
4294
- workspacePicker(workspaces, workspace, setWorkspace),
4295
- e("h3", null, "\u9636\u6BB5"),
4296
- stageEditor(config, setConfig),
4297
- e("h3", null, "\u6D41\u8F6C\uFF08\u9636\u6BB5 \u2192 \u9636\u6BB5\uFF0C\u53EF\u5E26\u5B88\u536B\uFF09"),
4298
- transitionEditor(config, setConfig),
4299
- e("h3", null, "\u4EA7\u7269\uFF08\u6BCF\u4E2A\u9636\u6BB5\u8981\u586B\u7684\u5B57\u6BB5\uFF09"),
4300
- artifactEditor(config, setConfig),
4301
- e("h3", null, "\u63D0\u4EA4\u89C4\u5219"),
4302
- commitEditor(config, setConfig),
4303
- e(
4304
- "label",
4305
- { style: styles.row },
4306
- e("input", {
4307
- type: "checkbox",
4308
- checked: config.high_risk_requires_verification,
4309
- onChange: (ev) => update(config, setConfig, (c) => ({ ...c, high_risk_requires_verification: ev.target.checked }))
4310
- }),
4311
- "\u9AD8\u98CE\u9669\u4EFB\u52A1\u5FC5\u987B\u9644\u9A8C\u8BC1\u8BC1\u636E\u624D\u80FD\u8FC7 verified \u5B88\u536B"
4312
- ),
4313
- problems.length > 0 ? e(
4314
- "div",
4315
- { style: styles.problems },
4316
- e("strong", null, `\u6709 ${problems.length} \u4E2A\u95EE\u9898\uFF08\u4FDD\u5B58\u4F1A\u88AB\u62D2\u7EDD\uFF09\uFF1A`),
4317
- e("ul", null, ...problems.map((p) => e("li", { key: p }, p)))
4318
- ) : notice.length > 0 ? e(
4319
- "div",
4320
- { style: styles.problems },
4321
- e("strong", null, "\u539F .dsh/eng.json \u65E0\u6CD5\u89E3\u6790\uFF1A"),
4322
- e("ul", null, ...notice.map((p) => e("li", { key: p }, p))),
4323
- e("p", { style: styles.muted }, "\u5F53\u524D\u663E\u793A\u5185\u7F6E\u9ED8\u8BA4\u914D\u7F6E\uFF1B\u70B9\u51FB\u4FDD\u5B58\u4F1A\u8986\u76D6\u539F\u6587\u4EF6\u3002")
4324
- ) : e("p", { style: styles.ok }, source === "default" ? "\u5F53\u524D\u4F7F\u7528\u5185\u7F6E\u9ED8\u8BA4\u914D\u7F6E\u3002" : "\u914D\u7F6E\u6709\u6548\u3002"),
4325
- e(
4326
- "div",
4327
- { style: styles.actions },
4328
- e("button", { onClick: () => save(props, config, workspace, setSavedAt, setSource, setLoadedProblems), disabled: problems.length > 0 }, "\u4FDD\u5B58\u5230 .dsh/eng.json"),
4329
- savedAt !== "" ? e("span", { style: styles.ok }, savedAt) : null
4330
- )
4331
- );
4662
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.wrap, children: [
4663
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { style: styles.title, children: "\u5DE5\u7A0B\u6D41\u7A0B\u914D\u7F6E" }),
4664
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: styles.muted, children: "\u52A0\u8F7D\u4E2D\u2026" })
4665
+ ] });
4666
+ }
4667
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.wrap, children: [
4668
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.head, children: [
4669
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { style: styles.title, children: "\u5DE5\u7A0B\u6D41\u7A0B\u914D\u7F6E" }),
4670
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: styles.muted, children: "\u8FD9\u4EFD\u914D\u7F6E\u540C\u65F6\u9A71\u52A8 dev_task \u7684\u786C\u95E8\u7981\uFF1B\u6709\u95EE\u9898\u7684\u914D\u7F6E\u4E0D\u4F1A\u88AB\u4FDD\u5B58\u3002" })
4671
+ ] }),
4672
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.sourceRow, children: [
4673
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.StateDot, { state: source === "project" ? "done" : source === "invalid" ? "warning" : "ongoing" }),
4674
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: styles.sourceText, children: sourceText(source) })
4675
+ ] }),
4676
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.workspaceRow, children: [
4677
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: styles.workspaceLabel, children: "\u5DE5\u4F5C\u533A" }),
4678
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
4679
+ "select",
4680
+ {
4681
+ style: control,
4682
+ value: workspace,
4683
+ onChange: (ev) => {
4684
+ setWorkspace(ev.target.value);
4685
+ },
4686
+ children: workspaces.map((w) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: w.path, children: w.title || w.path }, w.path))
4687
+ }
4688
+ )
4689
+ ] }),
4690
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TemplatePicker, { config, setConfig }),
4691
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: styles.flowCard, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FlowDiagram, { config, onAddTransition: addTransition, onRemoveTransition: removeTransition }) }),
4692
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SectionCard, { icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.IconSettingsOutline16, { size: 16 }), title: "\u9636\u6BB5", hint: "\u6D41\u7A0B\u7531\u8FD9\u4E9B\u9636\u6BB5\u6309\u987A\u5E8F\u7EC4\u6210\u3002\u70B9\u4E00\u4E2A\u6807\u7B7E\u53EF\u5220\u9664\u5B83\uFF08\u8D77\u59CB\u9636\u6BB5\u9664\u5916\uFF09\uFF1B\u7528\u4E2D\u6587\u540D\u66F4\u6613\u61C2\uFF0C\u4F8B\u5982\u300C\u9700\u6C42\u8BC4\u5BA1\u300D\u300C\u5F00\u53D1\u300D\u3002", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StageEditor, { config, setConfig }) }),
4693
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SectionCard, { icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.IconBranchOutline16, { size: 16 }), title: "\u6D41\u8F6C\uFF08\u9636\u6BB5 \u2192 \u9636\u6BB5\uFF0C\u53EF\u5E26\u5B88\u536B\uFF09", hint: "\u6BCF\u6761\u6D41\u8F6C = \u4ECE\u300C\u4E0A\u4E00\u6B65\u300D\u5230\u300C\u4E0B\u4E00\u6B65\u300D\u5141\u8BB8\u8D70\u7684\u8DEF\uFF1B\u53EF\u9644\u52A0\u5B88\u536B\uFF0C\u6EE1\u8DB3\u5B88\u536B\u624D\u653E\u884C\u3002\u4E5F\u53EF\u5728\u6D41\u7A0B\u56FE\u91CC\u76F4\u63A5\u8FDE\u7EBF/\u70B9\u7BAD\u5934\u5220\u9664\u3002", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TransitionEditor, { config, setConfig }) }),
4694
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SectionCard, { icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.IconCheckOutline16, { size: 16 }), title: "\u4EA7\u7269\uFF08\u6BCF\u4E2A\u9636\u6BB5\u8981\u586B\u7684\u5B57\u6BB5\uFF09", hint: "\u7ED9\u67D0\u9636\u6BB5\u58F0\u660E\u8981\u4EA4\u7684\u4EA7\u7269\u548C\u5FC5\u586B\u5B57\u6BB5\uFF1B\u914D\u5408\u6D41\u8F6C\u91CC\u7684\u300C\u4EA7\u7269\u9F50\u5168\u300D\u5B88\u536B\uFF0C\u5B57\u6BB5\u6CA1\u586B\u5168\u5C31\u8FC7\u4E0D\u53BB\u3002", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ArtifactEditor, { config, setConfig }) }),
4695
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SectionCard, { icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.IconEditOutline16, { size: 16 }), title: "\u63D0\u4EA4\u89C4\u5219", hint: "\u63D0\u4EA4\u7B56\u7565\u3001\u6D88\u606F\u683C\u5F0F\u3001\u63D0\u4EA4\u68C0\u67E5\u70B9\u3001\u6587\u4EF6\u8303\u56F4\uFF0C\u4EE5\u53CA\u9AD8\u98CE\u9669\u662F\u5426\u5FC5\u987B\u9644\u9A8C\u8BC1\u8BC1\u636E\u3002", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CommitEditor, { config, setConfig }) }),
4696
+ problems.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.problems, children: [
4697
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { style: styles.problemsTitle, children: [
4698
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.StateDot, { state: "error" }),
4699
+ "\u6709 ",
4700
+ problems.length,
4701
+ " \u4E2A\u95EE\u9898\uFF08\u4FDD\u5B58\u4F1A\u88AB\u62D2\u7EDD\uFF09"
4702
+ ] }),
4703
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { style: styles.problemsList, children: problems.map((p) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", { children: p }, p)) })
4704
+ ] }) : notice.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.noticeBox, children: [
4705
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { style: styles.noticeTitle, children: [
4706
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.StateDot, { state: "warning" }),
4707
+ "\u539F .dsh/eng.json \u65E0\u6CD5\u89E3\u6790"
4708
+ ] }),
4709
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { style: styles.problemsList, children: notice.map((p) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", { children: p }, p)) }),
4710
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: styles.muted, children: "\u5F53\u524D\u663E\u793A\u5185\u7F6E\u9ED8\u8BA4\u914D\u7F6E\uFF1B\u70B9\u51FB\u4FDD\u5B58\u4F1A\u8986\u76D6\u539F\u6587\u4EF6\u3002" })
4711
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { style: styles.okText, children: [
4712
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.StateDot, { state: "done" }),
4713
+ source === "default" ? "\u5F53\u524D\u4F7F\u7528\u5185\u7F6E\u9ED8\u8BA4\u914D\u7F6E" : "\u914D\u7F6E\u6709\u6548"
4714
+ ] }),
4715
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.actions, children: [
4716
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
4717
+ import_dsh_client_ui_primitives.Button,
4718
+ {
4719
+ variant: "primary",
4720
+ size: "md",
4721
+ icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.IconCheckOutline16, { size: 16 }),
4722
+ disabled: problems.length > 0,
4723
+ onClick: () => {
4724
+ void save(remote, config, workspace, setSavedAt, setSource, setLoadedProblems);
4725
+ },
4726
+ children: "\u4FDD\u5B58\u5230 .dsh/eng.json"
4727
+ }
4728
+ ),
4729
+ savedAt !== "" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { style: styles.okText, children: [
4730
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.StateDot, { state: savedAt.startsWith("\u5DF2") ? "done" : "error" }),
4731
+ savedAt
4732
+ ] }) : null
4733
+ ] })
4734
+ ] });
4332
4735
  }
4333
- function workspacePicker(workspaces, workspace, setWorkspace) {
4334
- if (workspaces.length === 0) return e("p", { style: styles.problems }, "\u5F53\u524D\u6CA1\u6709\u4EFB\u4F55\u5DE5\u4F5C\u533A\uFF1A\u8BF7\u5148\u5728\u4FA7\u680F\u521B\u5EFA\u4E00\u4E2A\u5DE5\u4F5C\u533A\u3002");
4335
- return e(
4336
- "label",
4337
- { style: styles.row },
4338
- "\u5DE5\u4F5C\u533A ",
4339
- e(
4340
- "select",
4341
- { value: workspace, onChange: (ev) => setWorkspace(ev.target.value) },
4342
- ...workspaces.map((w) => e("option", { key: w.path, value: w.path }, w.title || w.path))
4343
- )
4344
- );
4736
+ function sourceText(source) {
4737
+ switch (source) {
4738
+ case "project":
4739
+ return "\u9879\u76EE\u914D\u7F6E\uFF08.dsh/eng.json\uFF09";
4740
+ case "invalid":
4741
+ return "\u539F\u6587\u4EF6\u65E0\u6CD5\u89E3\u6790\uFF0C\u663E\u793A\u5185\u7F6E\u9ED8\u8BA4\u914D\u7F6E";
4742
+ default:
4743
+ return "\u5185\u7F6E\u9ED8\u8BA4\u914D\u7F6E\uFF08\u5DE5\u4F5C\u533A\u5C1A\u65E0 .dsh/eng.json\uFF09";
4744
+ }
4345
4745
  }
4346
- function stageEditor(config, setConfig) {
4347
- const stageText = () => config.stages.join("\n");
4348
- return e(
4349
- "div",
4350
- null,
4351
- e("textarea", {
4352
- style: styles.textarea,
4353
- rows: 4,
4354
- value: stageText(),
4355
- onChange: (ev) => update(config, setConfig, (c) => ({
4746
+ function SectionCard({ icon, title, hint, children }) {
4747
+ const [open, setOpen] = (0, import_react2.useState)(true);
4748
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: styles.section, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
4749
+ import_dsh_client_ui_primitives.DisclosureRow,
4750
+ {
4751
+ icon,
4752
+ title,
4753
+ open,
4754
+ expandable: true,
4755
+ onToggle: () => {
4756
+ setOpen(!open);
4757
+ },
4758
+ keepContentWhenOpen: true,
4759
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.cardBody, children: [
4760
+ hint !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: styles.muted, children: hint }) : null,
4761
+ children
4762
+ ] })
4763
+ }
4764
+ ) });
4765
+ }
4766
+ function TemplatePicker({ config, setConfig }) {
4767
+ const apply2 = (id) => {
4768
+ const template = WORKFLOW_TEMPLATES.find((t) => t.id === id);
4769
+ if (template === void 0) return;
4770
+ setConfig(cloneConfig(template.config));
4771
+ };
4772
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.field, children: [
4773
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: styles.fieldLabel, children: "\u6D41\u7A0B\u6A21\u677F\uFF08\u70B9\u4E00\u4E0B\u6574\u4F53\u5957\u7528\uFF0C\u4F1A\u8986\u76D6\u5F53\u524D\u7F16\u8F91\uFF09" }),
4774
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: styles.chips, children: WORKFLOW_TEMPLATES.map((t) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Pill, { active: config.stages.join(",") === t.config.stages.join(","), onClick: () => {
4775
+ apply2(t.id);
4776
+ }, title: t.description, children: t.label }, t.id)) }),
4777
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: styles.hint, children: "\u4E0D\u786E\u5B9A\u600E\u4E48\u914D\u5C31\u4ECE\u300C\u6807\u51C6\u7814\u53D1\u300D\u8D77\u6B65\uFF0C\u5957\u7528\u540E\u518D\u5FAE\u8C03\uFF1B\u4E5F\u53EF\u4EE5\u5148\u5957\u6A21\u677F\uFF0C\u518D\u7528\u4E0B\u9762\u7684\u5361\u7247\u6539\u3002" })
4778
+ ] });
4779
+ }
4780
+ function cloneConfig(config) {
4781
+ return JSON.parse(JSON.stringify(config));
4782
+ }
4783
+ function StageEditor({ config, setConfig }) {
4784
+ const [draft, setDraft] = (0, import_react2.useState)("");
4785
+ const addStage = () => {
4786
+ const name = draft.trim();
4787
+ if (name === "" || config.stages.includes(name)) return;
4788
+ update(config, setConfig, (c) => ({ ...c, stages: [...c.stages, name] }));
4789
+ setDraft("");
4790
+ };
4791
+ const removeStage = (stage) => {
4792
+ update(config, setConfig, (c) => {
4793
+ const stages = c.stages.filter((s) => s !== stage);
4794
+ return {
4356
4795
  ...c,
4357
- stages: ev.target.value.split("\n").map((s) => s.trim()).filter((s) => s.length > 0)
4358
- }))
4359
- }),
4360
- e(
4361
- "label",
4362
- { style: styles.row },
4363
- "\u8D77\u59CB\u9636\u6BB5 ",
4364
- e(
4796
+ stages,
4797
+ start_stage: c.start_stage === stage ? stages[0] ?? "" : c.start_stage
4798
+ };
4799
+ });
4800
+ };
4801
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.section, children: [
4802
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: styles.chips, children: config.stages.map((stage) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
4803
+ import_dsh_client_ui_primitives.Pill,
4804
+ {
4805
+ active: stage === config.start_stage,
4806
+ onClick: stage === config.start_stage ? void 0 : () => {
4807
+ removeStage(stage);
4808
+ },
4809
+ title: stage === config.start_stage ? "\u8D77\u59CB\u9636\u6BB5" : `\u70B9\u51FB\u5220\u9664 ${stage}`,
4810
+ children: stage
4811
+ },
4812
+ stage
4813
+ )) }),
4814
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.row, children: [
4815
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
4816
+ "input",
4817
+ {
4818
+ style: { ...control, flex: "1 1 180px" },
4819
+ placeholder: "\u65B0\u9636\u6BB5\u540D",
4820
+ value: draft,
4821
+ onChange: (ev) => {
4822
+ setDraft(ev.target.value);
4823
+ },
4824
+ onKeyDown: (ev) => {
4825
+ if (ev.key === "Enter") addStage();
4826
+ }
4827
+ }
4828
+ ),
4829
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Button, { variant: "outline", size: "sm", icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.IconPlusOutline16, { size: 14 }), disabled: draft.trim() === "", onClick: addStage, children: "\u6DFB\u52A0\u9636\u6BB5" })
4830
+ ] }),
4831
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.row, children: [
4832
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: styles.fieldLabel, children: "\u8D77\u59CB\u9636\u6BB5" }),
4833
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
4365
4834
  "select",
4366
- { value: config.start_stage, onChange: (ev) => update(config, setConfig, (c) => ({ ...c, start_stage: ev.target.value })) },
4367
- ...config.stages.map((s) => e("option", { key: s, value: s }, s))
4835
+ {
4836
+ style: control,
4837
+ value: config.start_stage,
4838
+ onChange: (ev) => {
4839
+ update(config, setConfig, (c) => ({ ...c, start_stage: ev.target.value }));
4840
+ },
4841
+ children: config.stages.map((s) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: s, children: s }, s))
4842
+ }
4368
4843
  )
4369
- )
4370
- );
4844
+ ] })
4845
+ ] });
4371
4846
  }
4372
- function transitionEditor(config, setConfig) {
4373
- const rows = config.transitions.map((t, i) => e(
4374
- "div",
4375
- { key: i, style: styles.card },
4376
- selectOf(config, t.from, (v) => update(config, setConfig, (c) => ({ ...c, transitions: c.transitions.map((x, j) => j === i ? { ...x, from: v } : x) }))),
4377
- " \u2192 ",
4378
- selectOf(config, t.to, (v) => update(config, setConfig, (c) => ({ ...c, transitions: c.transitions.map((x, j) => j === i ? { ...x, to: v } : x) }))),
4379
- e("input", {
4380
- style: styles.input,
4381
- placeholder: "\u5B88\u536B\uFF0C\u9017\u53F7\u5206\u9694\uFF08\u5982 todos_done, verified\uFF09",
4382
- value: (t.requires ?? []).join(", "),
4383
- onChange: (ev) => update(config, setConfig, (c) => ({ ...c, transitions: c.transitions.map((x, j) => j === i ? { ...x, requires: splitList(ev.target.value) } : x) }))
4384
- }),
4385
- e("button", { type: "button", onClick: () => update(config, setConfig, (c) => ({ ...c, transitions: c.transitions.filter((_, j) => j !== i) })) }, "\u5220\u9664")
4386
- ));
4387
- return e(
4388
- "div",
4389
- null,
4390
- ...rows,
4391
- e("button", { type: "button", onClick: () => update(config, setConfig, (c) => ({ ...c, transitions: [...c.transitions, { from: c.start_stage, to: c.start_stage }] })) }, "+ \u52A0\u4E00\u6761\u6D41\u8F6C")
4392
- );
4393
- }
4394
- function artifactEditor(config, setConfig) {
4395
- const rows = config.artifacts.map((a, i) => e(
4396
- "div",
4397
- { key: i, style: styles.card },
4398
- selectOf(config, a.stage, (v) => update(config, setConfig, (c) => ({ ...c, artifacts: c.artifacts.map((x, j) => j === i ? { ...x, stage: v } : x) }))),
4399
- e("input", { style: styles.input, placeholder: "id", value: a.id, onChange: (ev) => update(config, setConfig, (c) => ({ ...c, artifacts: c.artifacts.map((x, j) => j === i ? { ...x, id: ev.target.value } : x) })) }),
4400
- e("input", { style: styles.input, placeholder: "\u540D\u79F0", value: a.name, onChange: (ev) => update(config, setConfig, (c) => ({ ...c, artifacts: c.artifacts.map((x, j) => j === i ? { ...x, name: ev.target.value } : x) })) }),
4401
- e("input", { style: styles.input, placeholder: "\u5B57\u6BB5\uFF0C\u9017\u53F7\u5206\u9694", value: a.fields.join(", "), onChange: (ev) => update(config, setConfig, (c) => ({ ...c, artifacts: c.artifacts.map((x, j) => j === i ? { ...x, fields: splitList(ev.target.value) } : x) })) }),
4402
- e("button", { type: "button", onClick: () => update(config, setConfig, (c) => ({ ...c, artifacts: c.artifacts.filter((_, j) => j !== i) })) }, "\u5220\u9664")
4403
- ));
4404
- return e(
4405
- "div",
4406
- null,
4407
- ...rows,
4408
- e("button", { type: "button", onClick: () => update(config, setConfig, (c) => ({ ...c, artifacts: [...c.artifacts, { stage: c.start_stage, id: "", name: "", fields: [] }] })) }, "+ \u52A0\u4E00\u4E2A\u4EA7\u7269")
4409
- );
4847
+ function TransitionEditor({ config, setConfig }) {
4848
+ const setTransition = (i, patch) => {
4849
+ update(config, setConfig, (c) => ({
4850
+ ...c,
4851
+ transitions: c.transitions.map((t, j) => j === i ? { ...t, ...patch } : t)
4852
+ }));
4853
+ };
4854
+ const toggleGuard = (i, guard) => {
4855
+ const t = config.transitions[i];
4856
+ if (t === void 0) return;
4857
+ const current = t.requires ?? [];
4858
+ const next = current.includes(guard) ? current.filter((g) => g !== guard) : [...current, guard];
4859
+ setTransition(i, { requires: next });
4860
+ };
4861
+ const remove = (i) => {
4862
+ update(config, setConfig, (c) => ({ ...c, transitions: c.transitions.filter((_, j) => j !== i) }));
4863
+ };
4864
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.section, children: [
4865
+ config.transitions.map((t, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: cardV, children: [
4866
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.row, children: [
4867
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("select", { style: control, value: t.from, onChange: (ev) => {
4868
+ setTransition(i, { from: ev.target.value });
4869
+ }, children: config.stages.map((s) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: s, children: s }, s)) }),
4870
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { color: textTertiary3 }, children: "\u2192" }),
4871
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("select", { style: control, value: t.to, onChange: (ev) => {
4872
+ setTransition(i, { to: ev.target.value });
4873
+ }, children: config.stages.map((s) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: s, children: s }, s)) }),
4874
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Button, { variant: "ghost", size: "sm", icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.IconCloseOutline16, { size: 14 }), onClick: () => {
4875
+ remove(i);
4876
+ }, title: "\u5220\u9664\u8FD9\u6761\u6D41\u8F6C" })
4877
+ ] }),
4878
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: styles.chips, children: GUARD_OPTIONS.map((g) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
4879
+ import_dsh_client_ui_primitives.Pill,
4880
+ {
4881
+ active: (t.requires ?? []).includes(g.value),
4882
+ onClick: () => {
4883
+ toggleGuard(i, g.value);
4884
+ },
4885
+ title: `\u5B88\u536B ${g.value}`,
4886
+ children: g.label
4887
+ },
4888
+ g.value
4889
+ )) })
4890
+ ] }, i)),
4891
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
4892
+ import_dsh_client_ui_primitives.Button,
4893
+ {
4894
+ variant: "outline",
4895
+ size: "sm",
4896
+ icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.IconPlusOutline16, { size: 14 }),
4897
+ onClick: () => {
4898
+ update(config, setConfig, (c) => ({ ...c, transitions: [...c.transitions, { from: c.start_stage, to: c.start_stage }] }));
4899
+ },
4900
+ children: "\u52A0\u4E00\u6761\u6D41\u8F6C"
4901
+ }
4902
+ ) })
4903
+ ] });
4410
4904
  }
4411
- function commitEditor(config, setConfig) {
4412
- const c = config.commit;
4413
- return e(
4414
- "div",
4415
- null,
4416
- e(
4417
- "label",
4418
- { style: styles.row },
4419
- "\u63D0\u4EA4\u7B56\u7565 ",
4420
- e(
4421
- "select",
4422
- { value: c.policy, onChange: (ev) => update(config, setConfig, (cfg) => ({ ...cfg, commit: { ...cfg.commit, policy: ev.target.value } })) },
4423
- e("option", { value: "task" }, "task\uFF08\u68C0\u67E5\u70B9\u4E00\u6B21\u63D0\u4EA4\uFF09"),
4424
- e("option", { value: "item" }, "item\uFF08\u9010\u9879\u63D0\u4EA4 + \u6536\u5C3E TASK\uFF09"),
4425
- e("option", { value: "manual" }, "manual\uFF08\u4EBA\u5DE5\u6307\u793A\uFF09")
4905
+ function ArtifactEditor({ config, setConfig }) {
4906
+ const setArtifact = (i, patch) => {
4907
+ update(config, setConfig, (c) => ({
4908
+ ...c,
4909
+ artifacts: c.artifacts.map((a, j) => j === i ? { ...a, ...patch } : a)
4910
+ }));
4911
+ };
4912
+ const remove = (i) => {
4913
+ update(config, setConfig, (c) => ({ ...c, artifacts: c.artifacts.filter((_, j) => j !== i) }));
4914
+ };
4915
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.section, children: [
4916
+ config.artifacts.map((a, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: cardV, children: [
4917
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.row, children: [
4918
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("select", { style: control, value: a.stage, onChange: (ev) => {
4919
+ setArtifact(i, { stage: ev.target.value });
4920
+ }, children: config.stages.map((s) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: s, children: s }, s)) }),
4921
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { style: { ...control, flex: "1 1 120px" }, placeholder: "id", value: a.id, onChange: (ev) => {
4922
+ setArtifact(i, { id: ev.target.value });
4923
+ } }),
4924
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { style: { ...control, flex: "1 1 140px" }, placeholder: "\u540D\u79F0", value: a.name, onChange: (ev) => {
4925
+ setArtifact(i, { name: ev.target.value });
4926
+ } }),
4927
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Button, { variant: "ghost", size: "sm", icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.IconCloseOutline16, { size: 14 }), onClick: () => {
4928
+ remove(i);
4929
+ }, title: "\u5220\u9664\u8FD9\u4E2A\u4EA7\u7269" })
4930
+ ] }),
4931
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
4932
+ "input",
4933
+ {
4934
+ style: control,
4935
+ placeholder: "\u5B57\u6BB5\uFF0C\u9017\u53F7\u5206\u9694\uFF08\u5982 scope, acceptance_criteria\uFF09",
4936
+ value: a.fields.join(", "),
4937
+ onChange: (ev) => {
4938
+ setArtifact(i, { fields: splitList(ev.target.value) });
4939
+ }
4940
+ }
4426
4941
  )
4427
- ),
4428
- e(
4429
- "label",
4430
- { style: styles.row },
4431
- "\u6D88\u606F\u683C\u5F0F\uFF08\u6B63\u5219\uFF09",
4432
- e("input", { style: styles.input, value: c.message_pattern, onChange: (ev) => update(config, setConfig, (cfg) => ({ ...cfg, commit: { ...cfg.commit, message_pattern: ev.target.value } })) })
4433
- ),
4434
- e(
4435
- "label",
4436
- { style: styles.row },
4437
- "\u683C\u5F0F\u8BF4\u660E",
4438
- e("input", { style: styles.input, value: c.message_hint, onChange: (ev) => update(config, setConfig, (cfg) => ({ ...cfg, commit: { ...cfg.commit, message_hint: ev.target.value } })) })
4439
- ),
4440
- e(
4441
- "div",
4442
- { style: styles.row },
4443
- "\u63D0\u4EA4\u68C0\u67E5\u70B9\uFF1A",
4444
- ...config.stages.map((s) => e(
4445
- "label",
4446
- { key: s, style: styles.inline },
4447
- e("input", {
4448
- type: "checkbox",
4449
- checked: c.checkpoints.includes(s),
4450
- onChange: (ev) => update(config, setConfig, (cfg) => ({
4451
- ...cfg,
4452
- commit: { ...cfg.commit, checkpoints: toggle(cfg.commit.checkpoints, s, ev.target.checked) }
4453
- }))
4454
- }),
4455
- s
4456
- ))
4457
- ),
4458
- e(
4459
- "label",
4460
- { style: styles.row },
4461
- e("input", { type: "checkbox", checked: c.file_scope, onChange: (ev) => update(config, setConfig, (cfg) => ({ ...cfg, commit: { ...cfg.commit, file_scope: ev.target.checked } })) }),
4462
- "\u6587\u4EF6\u8303\u56F4\u5F00\u5173\uFF08\u63D0\u4EA4\u53EA\u5141\u8BB8\u4EFB\u52A1\u91CC\u58F0\u660E\u7684\u6587\u4EF6\uFF09"
4463
- )
4464
- );
4942
+ ] }, i)),
4943
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
4944
+ import_dsh_client_ui_primitives.Button,
4945
+ {
4946
+ variant: "outline",
4947
+ size: "sm",
4948
+ icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.IconPlusOutline16, { size: 14 }),
4949
+ onClick: () => {
4950
+ update(config, setConfig, (c) => ({ ...c, artifacts: [...c.artifacts, { stage: c.start_stage, id: "", name: "", fields: [] }] }));
4951
+ },
4952
+ children: "\u52A0\u4E00\u4E2A\u4EA7\u7269"
4953
+ }
4954
+ ) })
4955
+ ] });
4465
4956
  }
4466
- function selectOf(config, value, onChange) {
4467
- return e(
4468
- "select",
4469
- { style: styles.select, value, onChange: (ev) => onChange(ev.target.value) },
4470
- ...config.stages.map((s) => e("option", { key: s, value: s }, s))
4471
- );
4957
+ function CommitEditor({ config, setConfig }) {
4958
+ const commit = config.commit;
4959
+ const setCommit = (patch) => {
4960
+ update(config, setConfig, (c) => ({ ...c, commit: { ...c.commit, ...patch } }));
4961
+ };
4962
+ const toggleCheckpoint = (stage) => {
4963
+ const current = commit.checkpoints;
4964
+ const next = current.includes(stage) ? current.filter((s) => s !== stage) : [...current, stage];
4965
+ setCommit({ checkpoints: next });
4966
+ };
4967
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.section, children: [
4968
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.field, children: [
4969
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: styles.fieldLabel, children: "\u63D0\u4EA4\u7B56\u7565" }),
4970
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: styles.chips, children: POLICY_OPTIONS.map((p) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Pill, { active: commit.policy === p.value, onClick: () => {
4971
+ setCommit({ policy: p.value });
4972
+ }, title: p.hint, children: p.label }, p.value)) }),
4973
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: styles.hint, children: POLICY_OPTIONS.find((p) => p.value === commit.policy)?.hint })
4974
+ ] }),
4975
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.row, children: [
4976
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { style: styles.field, children: [
4977
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: styles.fieldLabel, children: "\u63D0\u4EA4\u6D88\u606F\u683C\u5F0F\uFF08\u6B63\u5219\uFF0C\u7559\u7A7A\u5219\u4E0D\u6821\u9A8C\uFF09" }),
4978
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { style: control, value: commit.message_pattern, onChange: (ev) => {
4979
+ setCommit({ message_pattern: ev.target.value });
4980
+ } })
4981
+ ] }),
4982
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { style: styles.field, children: [
4983
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: styles.fieldLabel, children: "\u683C\u5F0F\u8BF4\u660E" }),
4984
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { style: control, value: commit.message_hint, onChange: (ev) => {
4985
+ setCommit({ message_hint: ev.target.value });
4986
+ } })
4987
+ ] })
4988
+ ] }),
4989
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.field, children: [
4990
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: styles.fieldLabel, children: "\u63D0\u4EA4\u68C0\u67E5\u70B9\uFF08\u5230\u8FBE\u8FD9\u4E9B\u9636\u6BB5\u524D\u9700\u63D0\u4EA4\uFF09" }),
4991
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: styles.chips, children: config.stages.map((s) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Pill, { active: commit.checkpoints.includes(s), onClick: () => {
4992
+ toggleCheckpoint(s);
4993
+ }, title: `\u68C0\u67E5\u70B9 ${s}`, children: s }, s)) })
4994
+ ] }),
4995
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.field, children: [
4996
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.inline, children: [
4997
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
4998
+ "input",
4999
+ {
5000
+ type: "checkbox",
5001
+ checked: commit.file_scope,
5002
+ onChange: (ev) => {
5003
+ setCommit({ file_scope: ev.target.checked });
5004
+ }
5005
+ }
5006
+ ),
5007
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: styles.fieldLabel, children: "\u6587\u4EF6\u8303\u56F4\u5F00\u5173\uFF08\u63D0\u4EA4\u53EA\u5141\u8BB8\u4EFB\u52A1\u91CC\u58F0\u660E\u7684\u6587\u4EF6\uFF09" })
5008
+ ] }),
5009
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.inline, children: [
5010
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
5011
+ "input",
5012
+ {
5013
+ type: "checkbox",
5014
+ checked: config.high_risk_requires_verification,
5015
+ onChange: (ev) => {
5016
+ update(config, setConfig, (c) => ({ ...c, high_risk_requires_verification: ev.target.checked }));
5017
+ }
5018
+ }
5019
+ ),
5020
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: styles.fieldLabel, children: "\u9AD8\u98CE\u9669\u4EFB\u52A1\u5FC5\u987B\u9644\u9A8C\u8BC1\u8BC1\u636E\u624D\u80FD\u8FC7 verified \u5B88\u536B" })
5021
+ ] })
5022
+ ] })
5023
+ ] });
4472
5024
  }
4473
5025
  function update(config, setConfig, fn) {
4474
5026
  setConfig(fn(config));
4475
5027
  }
4476
- async function save(props, config, workspace, setSavedAt, setSource, setLoadedProblems) {
4477
- const result = await props.remote.write({ path: workspace, config });
5028
+ async function save(remote, config, workspace, setSavedAt, setSource, setLoadedProblems) {
5029
+ const result = await remote.write({ path: workspace, config });
4478
5030
  if (!result.ok) {
4479
5031
  setSavedAt("\u4FDD\u5B58\u5931\u8D25\uFF1A" + describeError(result.error));
4480
5032
  return;
@@ -4483,31 +5035,14 @@ async function save(props, config, workspace, setSavedAt, setSource, setLoadedPr
4483
5035
  setLoadedProblems(result.value.source === "invalid" ? result.value.problems : []);
4484
5036
  setSavedAt(result.value.ok ? "\u5DF2\u4FDD\u5B58" : "");
4485
5037
  }
4486
- function splitList(text) {
4487
- return text.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
4488
- }
4489
- function toggle(list, value, on) {
4490
- return on ? list.includes(value) ? list : [...list, value] : list.filter((v) => v !== value);
5038
+ function splitList(textInput) {
5039
+ return textInput.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
4491
5040
  }
4492
5041
  function describeError(error) {
4493
5042
  if (error instanceof Error) return error.message;
4494
5043
  if (typeof error === "string") return error;
4495
5044
  return "\u672A\u77E5\u9519\u8BEF";
4496
5045
  }
4497
- var styles = {
4498
- wrap: { padding: "16px", maxWidth: "760px", display: "flex", flexDirection: "column", gap: "8px" },
4499
- title: { margin: "0 0 4px" },
4500
- muted: { margin: "0 0 8px", opacity: "0.7" },
4501
- row: { display: "flex", alignItems: "center", gap: "8px", flexWrap: "wrap" },
4502
- inline: { display: "inline-flex", alignItems: "center", gap: "4px", marginRight: "12px" },
4503
- card: { display: "flex", alignItems: "center", gap: "8px", flexWrap: "wrap", padding: "4px 0" },
4504
- input: { flex: "1 1 220px", minWidth: "140px" },
4505
- select: { minWidth: "90px" },
4506
- textarea: { width: "100%", fontFamily: "monospace" },
4507
- problems: { color: "#c62828", background: "#fdecea", padding: "8px 12px", borderRadius: "4px" },
4508
- ok: { color: "#2e7d32" },
4509
- actions: { display: "flex", alignItems: "center", gap: "12px", marginTop: "8px" }
4510
- };
4511
5046
 
4512
5047
  // src/client/index.ts
4513
5048
  var inject = ["remote", "slots"];