@godv61/dsh-task-engine 0.29.3 → 0.30.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.
Files changed (85) hide show
  1. package/.adaptive-test.mjs +380 -185
  2. package/.codex-project-test.mjs +18 -18
  3. package/.evidence-test.mjs +14 -1
  4. package/.hook-test.mjs +19 -19
  5. package/.resource-test.mjs +17 -0
  6. package/.roundtrip-test.mjs +8 -3
  7. package/.sonar-credential-test.mjs +38 -0
  8. package/.sonarlint-local-test.mjs +71 -0
  9. package/.workflow-test.mjs +56 -9
  10. package/README.md +35 -112
  11. package/docs/development.md +45 -53
  12. package/docs/manual.html +140 -84
  13. package/hooks/commit-msg +19 -1
  14. package/lib/adaptive.js +1 -1
  15. package/lib/adaptive.js.map +1 -1
  16. package/lib/client.js +297 -9
  17. package/lib/client.js.map +1 -1
  18. package/lib/controller.d.ts +44 -0
  19. package/lib/controller.js +73 -0
  20. package/lib/controller.js.map +1 -1
  21. package/lib/dev-task.d.ts +2 -0
  22. package/lib/dev-task.js +342 -42
  23. package/lib/dev-task.js.map +1 -1
  24. package/lib/engine.d.ts +5 -1
  25. package/lib/engine.js +6 -0
  26. package/lib/engine.js.map +1 -1
  27. package/lib/hook.js +3 -3
  28. package/lib/hook.js.map +1 -1
  29. package/lib/project-init.d.ts +4 -0
  30. package/lib/project-init.js +21 -2
  31. package/lib/project-init.js.map +1 -1
  32. package/lib/skill-audit.js +9 -1
  33. package/lib/skill-audit.js.map +1 -1
  34. package/lib/sonar-credential.d.ts +17 -0
  35. package/lib/sonar-credential.js +17 -0
  36. package/lib/sonar-credential.js.map +1 -0
  37. package/lib/sonar-report.d.ts +4 -0
  38. package/lib/sonar-report.js +53 -0
  39. package/lib/sonar-report.js.map +1 -0
  40. package/lib/sonar.d.ts +35 -2
  41. package/lib/sonar.js +63 -4
  42. package/lib/sonar.js.map +1 -1
  43. package/lib/sonarlint-local.d.ts +17 -0
  44. package/lib/sonarlint-local.js +317 -0
  45. package/lib/sonarlint-local.js.map +1 -0
  46. package/lib/verification-tests.d.ts +10 -0
  47. package/lib/verification-tests.js +15 -0
  48. package/lib/verification-tests.js.map +1 -0
  49. package/package.json +6 -4
  50. package/preset/enable.mjs +2 -2
  51. package/preset/persona.md +4 -4
  52. package/scripts/verify-dsh-compat.mjs +14 -14
  53. package/scripts/verify-package.mjs +10 -8
  54. package/skills/architecture-design/SKILL.md +11 -11
  55. package/skills/code-development/SKILL.md +11 -11
  56. package/skills/code-review/SKILL.md +12 -10
  57. package/skills/eng-delivery/SKILL.md +10 -7
  58. package/skills/requirements-analysis/SKILL.md +11 -11
  59. package/skills/task-orchestration/SKILL.md +11 -11
  60. package/skills/test-validation/SKILL.md +11 -9
  61. package/docs/BRIEF-FOR-REVIEW.md +0 -163
  62. package/docs/CHANGELOG.md +0 -407
  63. package/docs/README.md +0 -42
  64. package/docs/adaptive-workflows.md +0 -76
  65. package/docs/assets/workflow-banner.svg +0 -29
  66. package/docs/configuration.md +0 -80
  67. package/docs/faq.md +0 -59
  68. package/docs/getting-started.md +0 -55
  69. package/docs/listing/godv61__dsh-task-engine.yml +0 -6
  70. package/docs/listing/submission.md +0 -84
  71. package/docs/manual-legacy.html +0 -380
  72. package/docs/releases/0.23.0.md +0 -32
  73. package/docs/releases/0.23.1.md +0 -58
  74. package/docs/releases/0.23.2.md +0 -21
  75. package/docs/resource-install.md +0 -64
  76. package/docs/roadmap.md +0 -33
  77. package/docs/testing/0.23.0//346/265/213/350/257/225/346/211/247/350/241/214/350/256/260/345/275/225.md +0 -189
  78. package/docs/testing/0.23.0//346/265/213/350/257/225/346/212/245/345/221/212.md +0 -42
  79. package/docs/testing/0.23.1//346/265/213/350/257/225/346/212/245/345/221/212.md +0 -34
  80. package/docs/testing/0.23.1//350/207/252/345/212/250/345/214/226/346/265/213/350/257/225/346/230/216/347/273/206.md +0 -41
  81. package/docs/testing/0.23.2/R02/344/270/232/345/212/241/346/265/213/350/257/225/346/230/216/347/273/206.md +0 -56
  82. package/docs/testing/0.23.2/R03/344/270/232/345/212/241/346/265/213/350/257/225/346/230/216/347/273/206.md +0 -38
  83. package/docs/testing/0.23.2//346/265/213/350/257/225/346/212/245/345/221/212.md +0 -65
  84. package/docs/testing/0.23.2//350/207/252/345/212/250/345/214/226/346/265/213/350/257/225/346/230/216/347/273/206.md +0 -43
  85. package/docs/workflow-regression.md +0 -36
package/lib/client.js CHANGED
@@ -4248,6 +4248,35 @@ var taskLedgerViewSchema = external_exports.object({
4248
4248
  updated_at: external_exports.string().optional(),
4249
4249
  verification_passed: external_exports.boolean().optional(),
4250
4250
  review_outcome: external_exports.string().optional(),
4251
+ sonar: external_exports.object({
4252
+ source: external_exports.string(),
4253
+ audit: external_exports.object({
4254
+ gate: external_exports.string(),
4255
+ review_gate: external_exports.string().optional(),
4256
+ checked_at: external_exports.string(),
4257
+ target: external_exports.string(),
4258
+ blocking_count: external_exports.number(),
4259
+ unresolved_count: external_exports.number().optional(),
4260
+ uncovered_files: external_exports.array(external_exports.string()),
4261
+ dispositions: external_exports.array(external_exports.object({
4262
+ issue_key: external_exports.string(),
4263
+ kind: external_exports.string(),
4264
+ reason: external_exports.string(),
4265
+ evidence: external_exports.array(external_exports.string()),
4266
+ approved_at: external_exports.string()
4267
+ })).optional(),
4268
+ report_path: external_exports.string().optional(),
4269
+ scanned_files: external_exports.array(external_exports.string()).optional(),
4270
+ findings: external_exports.array(external_exports.object({
4271
+ key: external_exports.string(),
4272
+ rule: external_exports.string(),
4273
+ message: external_exports.string(),
4274
+ severity: external_exports.string(),
4275
+ file: external_exports.string(),
4276
+ line: external_exports.number().optional()
4277
+ }))
4278
+ }).optional()
4279
+ }).optional(),
4251
4280
  task_id: external_exports.string(),
4252
4281
  title: external_exports.string(),
4253
4282
  stage: external_exports.string(),
@@ -4298,7 +4327,11 @@ var adaptiveConfigSchema = external_exports.object({
4298
4327
  host_url: external_exports.string().optional(),
4299
4328
  project_key: external_exports.string().optional(),
4300
4329
  mode: external_exports.enum(["branch", "pull-request"]).optional(),
4301
- token_env: external_exports.string().optional()
4330
+ token_env: external_exports.string().optional(),
4331
+ source: external_exports.enum(["ci", "local", "ide-local"]).optional(),
4332
+ reference_branch: external_exports.string().optional(),
4333
+ scan_command: external_exports.string().optional(),
4334
+ include_paths: external_exports.array(external_exports.string()).optional()
4302
4335
  }).optional()
4303
4336
  });
4304
4337
  var adaptiveViewSchema = external_exports.object({
@@ -4310,6 +4343,8 @@ var adaptiveViewSchema = external_exports.object({
4310
4343
  grades: external_exports.array(external_exports.object({ id: external_exports.string(), label: external_exports.string(), guidance: external_exports.string(), stages: external_exports.array(external_exports.string()) }))
4311
4344
  });
4312
4345
  var adaptiveWriteRequestSchema = external_exports.object({ path: external_exports.string(), config: adaptiveConfigSchema, expected_hash: external_exports.string() });
4346
+ var sonarTokenInfoSchema = external_exports.object({ configured: external_exports.boolean(), source: external_exports.string().optional(), writable: external_exports.boolean() });
4347
+ var sonarTokenWriteSchema = external_exports.object({ path: external_exports.string(), token: external_exports.string().min(1) });
4313
4348
  var projectSkillProfileRequestSchema = external_exports.object({ path: external_exports.string(), name: external_exports.string() });
4314
4349
  var projectSkillProfileWriteRequestSchema = projectSkillProfileRequestSchema.extend({
4315
4350
  profile: skillProfileSchema,
@@ -4348,6 +4383,48 @@ var TYPERT_REMOTE = {
4348
4383
  }],
4349
4384
  result: { mode: "strict", typeSymbol: `${PACKAGE}/types#AdaptiveConfigView`, create: () => adaptiveViewSchema, schema: adaptiveViewSchema }
4350
4385
  },
4386
+ {
4387
+ id: `${PACKAGE}#task-engine/describeSonarToken`,
4388
+ service: "taskEngineController",
4389
+ namespace: "task-engine",
4390
+ method: "describeSonarToken",
4391
+ invocation: { kind: "direct" },
4392
+ parameters: [{
4393
+ name: "path",
4394
+ wire: "path",
4395
+ source: "json",
4396
+ codec: { mode: "strict", typeSymbol: "string", create: () => external_exports.string(), schema: external_exports.string() }
4397
+ }],
4398
+ result: { mode: "strict", typeSymbol: `${PACKAGE}/types#SonarTokenInfo`, create: () => sonarTokenInfoSchema, schema: sonarTokenInfoSchema }
4399
+ },
4400
+ {
4401
+ id: `${PACKAGE}#task-engine/setSonarToken`,
4402
+ service: "taskEngineController",
4403
+ namespace: "task-engine",
4404
+ method: "setSonarToken",
4405
+ invocation: { kind: "direct" },
4406
+ parameters: [{
4407
+ name: "request",
4408
+ wire: "request",
4409
+ source: "json",
4410
+ codec: { mode: "strict", typeSymbol: `${PACKAGE}/types#SonarTokenWrite`, create: () => sonarTokenWriteSchema, schema: sonarTokenWriteSchema }
4411
+ }],
4412
+ result: { mode: "strict", typeSymbol: `${PACKAGE}/types#SonarTokenInfo`, create: () => sonarTokenInfoSchema, schema: sonarTokenInfoSchema }
4413
+ },
4414
+ {
4415
+ id: `${PACKAGE}#task-engine/unsetSonarToken`,
4416
+ service: "taskEngineController",
4417
+ namespace: "task-engine",
4418
+ method: "unsetSonarToken",
4419
+ invocation: { kind: "direct" },
4420
+ parameters: [{
4421
+ name: "path",
4422
+ wire: "path",
4423
+ source: "json",
4424
+ codec: { mode: "strict", typeSymbol: "string", create: () => external_exports.string(), schema: external_exports.string() }
4425
+ }],
4426
+ result: { mode: "strict", typeSymbol: `${PACKAGE}/types#SonarTokenInfo`, create: () => sonarTokenInfoSchema, schema: sonarTokenInfoSchema }
4427
+ },
4351
4428
  {
4352
4429
  id: `${PACKAGE}#task-engine/readProjectSkillProfile`,
4353
4430
  service: "taskEngineController",
@@ -5258,9 +5335,18 @@ function AdaptivePanel({ workspace, remote, onOpenInit }) {
5258
5335
  const [saving, setSaving] = (0, import_react3.useState)(false);
5259
5336
  const [dirty, setDirty] = (0, import_react3.useState)(false);
5260
5337
  const [message, setMessage] = (0, import_react3.useState)("");
5338
+ const [sonarToken, setSonarToken] = (0, import_react3.useState)("");
5339
+ const [tokenInfo, setTokenInfo] = (0, import_react3.useState)(null);
5340
+ const [tokenBusy, setTokenBusy] = (0, import_react3.useState)(false);
5261
5341
  const refresh = (0, import_react3.useCallback)(() => {
5262
5342
  setLoading(true);
5263
5343
  setMessage("");
5344
+ setSonarToken("");
5345
+ setTokenInfo(null);
5346
+ void remote.describeSonarToken(workspace).then((result) => {
5347
+ if (result.ok) setTokenInfo(result.value);
5348
+ }, () => {
5349
+ });
5264
5350
  void Promise.all([remote.readAdaptive(workspace), remote.listSkills(workspace), remote.listRules(workspace)]).then(([config, catalog, ruleCatalog]) => {
5265
5351
  setLoading(false);
5266
5352
  if (!config.ok) {
@@ -5397,6 +5483,39 @@ function AdaptivePanel({ workspace, remote, onOpenInit }) {
5397
5483
  setMessage("\u4FDD\u5B58\u5931\u8D25\uFF1A" + describeError(error));
5398
5484
  });
5399
5485
  };
5486
+ const saveToken = () => {
5487
+ if (!sonarToken.trim()) return;
5488
+ setTokenBusy(true);
5489
+ void remote.setSonarToken({ path: workspace, token: sonarToken }).then((result) => {
5490
+ setTokenBusy(false);
5491
+ if (!result.ok) {
5492
+ setMessage("\u4FDD\u5B58 SonarQube Token \u5931\u8D25\uFF1A" + describeError(result.error));
5493
+ return;
5494
+ }
5495
+ setSonarToken("");
5496
+ setTokenInfo(result.value);
5497
+ setMessage("\u5F53\u524D\u9879\u76EE\u7684 SonarQube Token \u5DF2\u4FDD\u5B58\u5230\u672C\u673A DSH \u51ED\u636E\u5B58\u50A8\uFF0C\u53EF\u7ACB\u5373\u4F7F\u7528\u3002");
5498
+ }, (error) => {
5499
+ setTokenBusy(false);
5500
+ setMessage("\u4FDD\u5B58 SonarQube Token \u5931\u8D25\uFF1A" + describeError(error));
5501
+ });
5502
+ };
5503
+ const clearToken = () => {
5504
+ setTokenBusy(true);
5505
+ void remote.unsetSonarToken(workspace).then((result) => {
5506
+ setTokenBusy(false);
5507
+ if (!result.ok) {
5508
+ setMessage("\u79FB\u9664 SonarQube Token \u5931\u8D25\uFF1A" + describeError(result.error));
5509
+ return;
5510
+ }
5511
+ setSonarToken("");
5512
+ setTokenInfo(result.value);
5513
+ setMessage("\u5DF2\u79FB\u9664\u5F53\u524D\u9879\u76EE\u4FDD\u5B58\u5728\u672C\u673A\u7684 SonarQube Token\u3002");
5514
+ }, (error) => {
5515
+ setTokenBusy(false);
5516
+ setMessage("\u79FB\u9664 SonarQube Token \u5931\u8D25\uFF1A" + describeError(error));
5517
+ });
5518
+ };
5400
5519
  const candidates = [...new Set(skills.map((skill) => skill.name))].filter((name) => name !== "eng-delivery" && !(name in META_STAGES)).sort();
5401
5520
  const sonar = draft.sonar ?? {};
5402
5521
  return (0, import_react3.createElement)(
@@ -5484,14 +5603,34 @@ function AdaptivePanel({ workspace, remote, onOpenInit }) {
5484
5603
  "\u542F\u7528\uFF08\u4EC5\u4EE3\u7801\u5BA1\u6838\u9636\u6BB5\uFF09"
5485
5604
  )
5486
5605
  ),
5487
- (0, import_react3.createElement)("span", { style: label }, "\u590D\u7528 CI \u626B\u63CF\u7684 ceTaskId\uFF1B\u8D28\u91CF\u95E8\u7981\u6216\u65B0\u4EE3\u7801\u4E2D\u9AD8\u7B49\u7EA7\u95EE\u9898\u672A\u901A\u8FC7\u65F6\u963B\u6B62\u5BA1\u6838\u3002Token \u4EC5\u4ECE\u670D\u52A1\u8FDB\u7A0B\u73AF\u5883\u53D8\u91CF\u8BFB\u53D6\uFF0C\u4E0D\u5199\u5165\u4ED3\u5E93\u3002"),
5606
+ (0, import_react3.createElement)("span", { style: label }, "\u53EF\u590D\u7528 CI \u626B\u63CF\uFF0C\u6216\u5728\u672C\u673A\u6309\u670D\u52A1\u7AEF\u89C4\u5219\u5BA1\u6838\u65B0\u4EE3\u7801\u3002Token \u6309\u5F53\u524D\u9879\u76EE\u4FDD\u5B58\u5728\u672C\u673A DSH \u51ED\u636E\u5B58\u50A8\uFF0C\u4E0D\u5199\u5165\u4EE3\u7801\u4ED3\u5E93\uFF1B\u4ECD\u517C\u5BB9\u5DF2\u6709\u7684\u73AF\u5883\u53D8\u91CF\u3002"),
5488
5607
  sonar.enabled === true ? (0, import_react3.createElement)(
5489
5608
  "div",
5490
5609
  { style: grid },
5610
+ (0, import_react3.createElement)(
5611
+ "label",
5612
+ { style: { display: "flex", flexDirection: "column", gap: 4 } },
5613
+ (0, import_react3.createElement)("span", { style: label }, "\u626B\u63CF\u6765\u6E90"),
5614
+ (0, import_react3.createElement)(
5615
+ "select",
5616
+ {
5617
+ style: input,
5618
+ value: sonar.source ?? "ci",
5619
+ onChange: (event) => updateSonar({
5620
+ source: event.target.value,
5621
+ ...event.target.value !== "ci" ? { mode: "branch" } : {},
5622
+ ...event.target.value !== "ide-local" ? { include_paths: [] } : {}
5623
+ })
5624
+ },
5625
+ (0, import_react3.createElement)("option", { value: "ci" }, "CI \u5DF2\u6709\u7ED3\u679C"),
5626
+ (0, import_react3.createElement)("option", { value: "ide-local" }, "\u672C\u5730\u89C4\u5219\u5BA1\u6838\uFF08\u65E0\u9700\u63D0\u4EA4\u6216\u63A8\u9001\uFF09"),
5627
+ (0, import_react3.createElement)("option", { value: "local" }, "\u672C\u673A\u626B\u63CF\u5E76\u4E0A\u4F20\uFF08\u9700 Developer Edition\uFF09")
5628
+ )
5629
+ ),
5491
5630
  ...[
5492
5631
  ["host_url", "\u670D\u52A1\u5730\u5740", "https://sonar.example"],
5493
5632
  ["project_key", "\u9879\u76EE Key", "my-project"],
5494
- ["token_env", "Token \u73AF\u5883\u53D8\u91CF\u540D", "SONAR_TOKEN"]
5633
+ ["token_env", "Token \u73AF\u5883\u53D8\u91CF\u540D\uFF08\u53EF\u9009\u540E\u5907\uFF09", "SONAR_TOKEN"]
5495
5634
  ].map(([key, title, placeholder]) => (0, import_react3.createElement)(
5496
5635
  "label",
5497
5636
  { key, style: { display: "flex", flexDirection: "column", gap: 4 } },
@@ -5512,11 +5651,86 @@ function AdaptivePanel({ workspace, remote, onOpenInit }) {
5512
5651
  {
5513
5652
  style: input,
5514
5653
  value: sonar.mode ?? "branch",
5654
+ disabled: sonar.source === "local" || sonar.source === "ide-local",
5515
5655
  onChange: (event) => updateSonar({ mode: event.target.value })
5516
5656
  },
5517
5657
  (0, import_react3.createElement)("option", { value: "branch" }, "\u5206\u652F"),
5518
5658
  (0, import_react3.createElement)("option", { value: "pull-request" }, "\u5408\u5E76\u8BF7\u6C42")
5519
5659
  )
5660
+ ),
5661
+ sonar.source === "local" || sonar.source === "ide-local" ? (0, import_react3.createElement)(
5662
+ "label",
5663
+ { style: { display: "flex", flexDirection: "column", gap: 4 } },
5664
+ (0, import_react3.createElement)("span", { style: label }, sonar.source === "local" ? "\u65B0\u4EE3\u7801\u53C2\u8003\u5206\u652F\uFF08\u987B\u5DF2\u6709 Sonar \u5206\u6790\uFF09" : "\u65B0\u4EE3\u7801\u53C2\u8003\u5206\u652F\uFF08\u672C\u673A Git \u5206\u652F\uFF09"),
5665
+ (0, import_react3.createElement)("input", {
5666
+ style: input,
5667
+ value: sonar.reference_branch ?? "",
5668
+ placeholder: "\u4F8B\u5982 qdm_sit",
5669
+ onChange: (event) => updateSonar({ reference_branch: event.target.value })
5670
+ })
5671
+ ) : null,
5672
+ sonar.source === "local" ? (0, import_react3.createElement)(
5673
+ "label",
5674
+ { style: { display: "flex", flexDirection: "column", gap: 4 } },
5675
+ (0, import_react3.createElement)("span", { style: label }, "\u672C\u673A\u626B\u63CF\u547D\u4EE4\uFF08\u53EF\u9009\uFF1B\u4E0D\u586B\u5219\u81EA\u52A8\u9009\u62E9 Maven / sonar-scanner\uFF09"),
5676
+ (0, import_react3.createElement)("input", {
5677
+ style: input,
5678
+ value: sonar.scan_command ?? "",
5679
+ placeholder: "mvn org.sonarsource.scanner.maven:sonar-maven-plugin:5.5.0.6356:sonar",
5680
+ onChange: (event) => updateSonar({ scan_command: event.target.value })
5681
+ })
5682
+ ) : null,
5683
+ sonar.source === "local" ? (0, import_react3.createElement)(
5684
+ "span",
5685
+ { style: label },
5686
+ "\u672C\u673A\u5206\u652F\u626B\u63CF\u9700\u8981 SonarQube Developer Edition \u6216\u66F4\u9AD8\u7248\u672C\u3001\u5DF2\u6709\u5206\u6790\u7684\u53C2\u8003\u5206\u652F\u53CA\u672C\u673A\u626B\u63CF\u5668/JDK\uFF1BCommunity Build \u4F1A\u5728\u4E0A\u4F20\u524D\u62D2\u7EDD\u3002"
5687
+ ) : null,
5688
+ sonar.source === "ide-local" ? (0, import_react3.createElement)(
5689
+ "label",
5690
+ { style: { display: "flex", flexDirection: "column", gap: 4 } },
5691
+ (0, import_react3.createElement)("span", { style: label }, "\u672C\u5730\u5BA1\u6838\u8303\u56F4\uFF08\u6BCF\u884C\u4E00\u4E2A\u9879\u76EE\u76F8\u5BF9\u76EE\u5F55\u6216\u6587\u4EF6\uFF1B\u7559\u7A7A\u4E3A\u4EFB\u52A1\u5168\u90E8\u4EE3\u7801\uFF09"),
5692
+ (0, import_react3.createElement)("textarea", {
5693
+ style: { ...input, minHeight: 76 },
5694
+ value: (sonar.include_paths ?? []).join("\n"),
5695
+ placeholder: "\u4F8B\u5982 fp-bussiness\nfp-ruoyi\nfp-ruoyi-spring-boot\npom.xml",
5696
+ onChange: (event) => updateSonar({
5697
+ include_paths: event.target.value.split(/\r?\n|,/u).map((path) => path.trim()).filter(Boolean)
5698
+ })
5699
+ })
5700
+ ) : null,
5701
+ sonar.source === "ide-local" ? (0, import_react3.createElement)(
5702
+ "span",
5703
+ { style: label },
5704
+ "\u672C\u5730\u89C4\u5219\u5BA1\u6838\u4ECE SonarQube \u540C\u6B65\u9879\u76EE\u89C4\u5219\uFF0C\u6309\u4E0A\u65B9\u8303\u56F4\u7B5B\u9009\u4EFB\u52A1\u65B0\u589E\u4EE3\u7801\uFF0C\u4E0D\u4E0A\u4F20\u7ED3\u679C\u3002\u626B\u63CF\u8303\u56F4\u7531 CI \u6784\u5EFA\u4E0E\u9879\u76EE\u914D\u7F6E\u51B3\u5B9A\uFF0CQuality Profile \u672C\u8EAB\u4E0D\u51B3\u5B9A\u626B\u63CF\u54EA\u4E9B\u76EE\u5F55\u3002\u5176\u4ED6\u8BED\u8A00\u4EC5\u5728\u8BE5\u9879\u76EE\u5B58\u5728\u751F\u6548\u89C4\u5219\u800C\u672C\u5730\u65E0\u6CD5\u5206\u6790\u65F6\u5217\u4E3A\u672A\u8986\u76D6\u3002\u9700\u5B89\u88C5 SonarLint \u540E\u53F0\u7EC4\u4EF6\u5E76\u914D\u7F6E DSH_SONARLINT_JAVA\u3001DSH_SONARLINT_LIB\u3001DSH_SONARLINT_PLUGINS\u3002"
5705
+ ) : null,
5706
+ (0, import_react3.createElement)(
5707
+ "div",
5708
+ { style: { display: "flex", flexDirection: "column", gap: 5 } },
5709
+ (0, import_react3.createElement)("span", { style: label }, `\u5F53\u524D\u9879\u76EE Token\uFF1A${tokenInfo === null ? "\u72B6\u6001\u4E0D\u53EF\u7528" : tokenInfo.configured ? "\u5DF2\u914D\u7F6E" : "\u672A\u914D\u7F6E"}`),
5710
+ (0, import_react3.createElement)("input", {
5711
+ type: "password",
5712
+ autoComplete: "new-password",
5713
+ style: input,
5714
+ value: sonarToken,
5715
+ placeholder: "\u8F93\u5165\u7528\u6237\u4EE4\u724C\uFF08\u4FDD\u5B58\u540E\u4E0D\u56DE\u663E\uFF09",
5716
+ onChange: (event) => setSonarToken(event.target.value)
5717
+ }),
5718
+ (0, import_react3.createElement)(
5719
+ "div",
5720
+ { style: row },
5721
+ (0, import_react3.createElement)(import_dsh_client_ui_primitives2.Button, {
5722
+ variant: "outline",
5723
+ size: "sm",
5724
+ disabled: tokenBusy || !sonarToken.trim() || tokenInfo?.writable === false,
5725
+ onClick: saveToken
5726
+ }, tokenBusy ? "\u5904\u7406\u4E2D\u2026" : "\u4FDD\u5B58 Token"),
5727
+ tokenInfo?.configured ? (0, import_react3.createElement)(import_dsh_client_ui_primitives2.Button, {
5728
+ variant: "outline",
5729
+ size: "sm",
5730
+ disabled: tokenBusy || tokenInfo.writable === false,
5731
+ onClick: clearToken
5732
+ }, "\u79FB\u9664 Token") : null
5733
+ )
5520
5734
  )
5521
5735
  ) : null
5522
5736
  ),
@@ -5559,7 +5773,7 @@ var card2 = {
5559
5773
  borderRadius: 8,
5560
5774
  padding: "12px 14px"
5561
5775
  };
5562
- var projectInitPrompt = (workspace) => `\u8BF7\u5728\u5F53\u524D\u9879\u76EE\u6839\u5DE5\u4F5C\u533A ${workspace} \u4F7F\u7528\u5DE5\u7A0B\u5316\u5F00\u53D1\u5F15\u64CE\u521D\u59CB\u5316\u9879\u76EE Skill \u548C Rule\u3002\u5148\u8C03\u7528 dev_task init_project\uFF08phase=inspect\uFF09\uFF0C\u7ED3\u5408\u4EE3\u8868\u6027\u6E90\u7801\u3001\u6784\u5EFA\u6587\u4EF6\u3001\u6D4B\u8BD5\u548C\u5DF2\u6709\u89C4\u8303\u6838\u5B9E\u626B\u63CF\u7ED3\u679C\u3002\u6309\u9879\u76EE\u5B9E\u9645\u60C5\u51B5\u62DF\u5B9A\u9879\u76EE\u7ED3\u6784\u5730\u56FE\u3001\u6280\u672F\u6808\u3001\u7F16\u7801\u65B9\u6CD5\u7B49 Skill \u548C\u5FC5\u8981\u7684 Rule\uFF0C\u5E76\u6807\u660E\u9002\u7528\u7684\u5143\u6280\u80FD\u3002\u8C03\u7528 phase=propose \u5C55\u793A\u62DF\u521B\u5EFA\u7684\u6587\u4EF6\u3001\u5185\u5BB9\u548C\u6302\u8F7D\u5173\u7CFB\uFF1B\u7B49\u6211\u5BA1\u9605\u786E\u8BA4\u540E\u518D\u8C03\u7528 phase=apply\u3002\u4E0D\u8981\u8986\u76D6\u540C\u540D\u8D44\u6E90\uFF0C\u4E5F\u4E0D\u8981\u628A\u5076\u53D1\u4EE3\u7801\u5199\u6CD5\u5F53\u6210\u56E2\u961F\u89C4\u8303\u3002`;
5776
+ var projectInitPrompt = (workspace) => `\u8BF7\u5728\u5F53\u524D\u9879\u76EE\u6839\u5DE5\u4F5C\u533A ${workspace} \u4F7F\u7528\u5DE5\u7A0B\u5316\u5F00\u53D1\u5F15\u64CE\u521D\u59CB\u5316\u9879\u76EE Skill \u548C Rule\u3002\u5148\u8C03\u7528 dev_task init_project\uFF08phase=inspect\uFF09\uFF0C\u7ED3\u5408\u4EE3\u8868\u6027\u6E90\u7801\u3001\u6784\u5EFA\u6587\u4EF6\u3001\u6D4B\u8BD5\u548C\u5DF2\u6709\u89C4\u8303\u6838\u5B9E\u626B\u63CF\u7ED3\u679C\u3002\u6309\u9879\u76EE\u5B9E\u9645\u60C5\u51B5\u62DF\u5B9A\u9879\u76EE\u7ED3\u6784\u5730\u56FE\u3001\u6280\u672F\u6808\u3001\u7F16\u7801\u65B9\u6CD5\u7B49 Skill \u548C\u5FC5\u8981\u7684 Rule\uFF0C\u5E76\u6807\u660E\u9002\u7528\u7684\u5143\u6280\u80FD\u3002\u9879\u76EE\u5730\u56FE\u5FC5\u987B\u603B\u7ED3\u6574\u4E2A\u4ED3\u5E93\u7684\u6A21\u5757\u804C\u8D23\u3001\u4F9D\u8D56\u548C\u901A\u7528\u4EE3\u7801\u5165\u53E3\uFF0C\u80FD\u591F\u4F9B\u4E0D\u540C\u9700\u6C42\u590D\u7528\uFF1B\u4E0D\u8981\u628A\u5F53\u524D\u4F1A\u8BDD\u7684\u9700\u6C42\u3001\u4E13\u5C5E\u8C03\u7528\u94FE\u6216\u5B9E\u73B0\u65B9\u6848\u5199\u6210\u9879\u76EE\u5730\u56FE\uFF0C\u76F8\u5173\u5185\u5BB9\u5E94\u8FDB\u5165\u8BE5\u4EFB\u52A1\u4EA7\u7269\u6216\u5355\u72EC\u7684\u9886\u57DF Skill\u3002\u8C03\u7528 phase=propose \u5C55\u793A\u62DF\u521B\u5EFA\u7684\u6587\u4EF6\u3001\u5185\u5BB9\u548C\u6302\u8F7D\u5173\u7CFB\uFF1B\u7B49\u6211\u5BA1\u9605\u786E\u8BA4\u540E\u518D\u8C03\u7528 phase=apply\u3002\u4E0D\u8981\u8986\u76D6\u540C\u540D\u8D44\u6E90\uFF0C\u4E5F\u4E0D\u8981\u628A\u5076\u53D1\u4EE3\u7801\u5199\u6CD5\u5F53\u6210\u56E2\u961F\u89C4\u8303\u3002`;
5563
5777
  function InitPanel({ workspace, remote }) {
5564
5778
  const [view, setView] = (0, import_react4.useState)(null);
5565
5779
  const [generating, setGenerating] = (0, import_react4.useState)(false);
@@ -5642,7 +5856,12 @@ function InitPanel({ workspace, remote }) {
5642
5856
  (0, import_react4.createElement)(
5643
5857
  "p",
5644
5858
  { style: styles.muted },
5645
- "\u626B\u63CF\u4EE3\u7801\u5E93\u5E76\u62DF\u5B9A\u9879\u76EE\u5730\u56FE\u3001\u6280\u672F\u6808\u3001\u7F16\u7801 Skill \u548C Rule\u3002\u5148\u9884\u89C8\u751F\u6210\u5185\u5BB9\uFF0C\u786E\u8BA4\u540E\u624D\u5199\u5165\u9879\u76EE\uFF1B\u5DF2\u6709\u540C\u540D\u8D44\u6E90\u4E0D\u4F1A\u88AB\u8986\u76D6\u3002"
5859
+ "\u626B\u63CF\u53EA\u8FD4\u56DE\u9879\u76EE\u8BC1\u636E\u4E0E\u5EFA\u8BAE\u540D\u79F0\uFF1B\u4F1A\u8BDD\u6A21\u578B\u636E\u6B64\u62DF\u5B9A\u8986\u76D6\u6574\u4E2A\u4ED3\u5E93\u7684\u9879\u76EE\u5730\u56FE\u3001\u6280\u672F\u6808\u3001\u7F16\u7801 Skill \u548C Rule\u3002\u5F53\u524D\u9700\u6C42\u7684\u4E13\u5C5E\u4FE1\u606F\u5E94\u5199\u5165\u4EFB\u52A1\u4EA7\u7269\u3002\u5148\u9884\u89C8\u751F\u6210\u5185\u5BB9\uFF0C\u786E\u8BA4\u540E\u624D\u5199\u5165\u9879\u76EE\uFF1B\u5DF2\u6709\u540C\u540D\u8D44\u6E90\u4E0D\u4F1A\u88AB\u8986\u76D6\u3002"
5860
+ ),
5861
+ (0, import_react4.createElement)(
5862
+ "p",
5863
+ { style: styles.muted },
5864
+ "\u56E2\u961F\u5171\u4EAB\u65F6\uFF0C\u8BF7\u5C06\u751F\u6210\u7684 .dsh/skills\u3001.dsh/rules \u548C .dsh/meta.json \u7EB3\u5165 Git\uFF1B\u5BA1\u6838\u62A5\u544A\u53EF\u4FDD\u7559\u5728\u672C\u5730\u3002"
5646
5865
  ),
5647
5866
  (0, import_react4.createElement)(
5648
5867
  "p",
@@ -6489,7 +6708,7 @@ function itemAudit(item) {
6489
6708
  lines.push((0, import_react8.createElement)(
6490
6709
  "div",
6491
6710
  { key: "dispatch", style: metaLine },
6492
- (0, import_react8.createElement)("span", { style: badge }, "\u5DF2\u6D3E\u53D1"),
6711
+ (0, import_react8.createElement)("span", { style: badge }, "\u5DF2\u5F00\u59CB"),
6493
6712
  (0, import_react8.createElement)("span", null, item.dispatch.description === "" ? "\uFF08\u65E0\u63CF\u8FF0\uFF09" : item.dispatch.description),
6494
6713
  (0, import_react8.createElement)("span", { style: badge }, timeText(item.dispatch.at))
6495
6714
  ));
@@ -6516,10 +6735,72 @@ function itemAudit(item) {
6516
6735
  }
6517
6736
  }
6518
6737
  if (lines.length === 0) {
6519
- lines.push((0, import_react8.createElement)("div", { key: "none", style: metaLine }, (0, import_react8.createElement)("span", { style: badge }, "\u672A\u6D3E\u53D1 / \u672A\u5BA1\u67E5")));
6738
+ const status = item.status === "done" ? "\u5DF2\u6807\u8BB0\u5B8C\u6210\uFF0C\u7F3A\u5C11\u5B9E\u65BD\u9879\u5BA1\u67E5\u8BB0\u5F55" : item.status === "doing" ? "\u5B9E\u65BD\u4E2D\uFF0C\u5F85\u5BA1\u67E5" : "\u5F85\u5F00\u59CB";
6739
+ lines.push((0, import_react8.createElement)("div", { key: "none", style: metaLine }, (0, import_react8.createElement)("span", { style: badge }, status)));
6520
6740
  }
6521
6741
  return (0, import_react8.createElement)("div", { style: { display: "flex", flexDirection: "column", gap: 4 } }, ...lines);
6522
6742
  }
6743
+ function sonarAudit(task) {
6744
+ if (!task.sonar) return null;
6745
+ const audit = task.sonar.audit;
6746
+ if (!audit) return (0, import_react8.createElement)("div", { style: metaLine }, "SonarQube \u5DF2\u542F\u7528\uFF0C\u5C1A\u672A\u8FD0\u884C\u4EE3\u7801\u5BA1\u6838\u3002");
6747
+ const source = { "ide-local": "\u672C\u5730\u89C4\u5219\u5BA1\u6838", local: "\u672C\u673A\u4E0A\u4F20\u626B\u63CF", ci: "CI \u626B\u63CF" }[task.sonar.source] ?? task.sonar.source;
6748
+ const reviewGate = audit.review_gate ?? audit.gate;
6749
+ const outcome = reviewGate === "OK" ? "\u901A\u8FC7" : "\u672A\u901A\u8FC7";
6750
+ const unresolved = audit.unresolved_count ?? audit.blocking_count;
6751
+ return (0, import_react8.createElement)(
6752
+ "details",
6753
+ { style: { borderTop: "1px solid var(--dsw-alias-border-l2)", paddingTop: 8 } },
6754
+ (0, import_react8.createElement)(
6755
+ "summary",
6756
+ { style: { cursor: "pointer", fontSize: 13 } },
6757
+ `\u6700\u8FD1\u4E00\u6B21 SonarQube \u5BA1\u6838\uFF1A${outcome} \xB7 \u672A\u89E3\u51B3 ${unresolved} \u6761 \xB7 \u539F\u59CB\u547D\u4E2D ${audit.blocking_count} \u6761 \xB7 ${timeText(audit.checked_at)}`
6758
+ ),
6759
+ (0, import_react8.createElement)(
6760
+ "p",
6761
+ { style: metaLine },
6762
+ `\u6765\u6E90\uFF1A${source}\uFF1B\u5206\u6790\u76EE\u6807\uFF1A${audit.target}\uFF1B\u539F\u59CB\u7ED3\u679C\uFF1A${audit.gate}\u3002\u8FD9\u662F\u8BE5\u6B21\u5BA1\u6838\u8BB0\u5F55\uFF1B\u4EE3\u7801\u6216\u89C4\u5219\u53D8\u66F4\u540E\u9700\u91CD\u65B0\u6D4B\u8BD5\u5E76\u5BA1\u6838\u3002`
6763
+ ),
6764
+ audit.report_path ? (0, import_react8.createElement)("p", { style: metaLine }, `\u5BA1\u6838\u6587\u4EF6\uFF1A${audit.report_path}`) : null,
6765
+ audit.scanned_files?.length ? (0, import_react8.createElement)(
6766
+ "details",
6767
+ null,
6768
+ (0, import_react8.createElement)("summary", { style: { cursor: "pointer", fontSize: 12 } }, `\u672C\u6B21\u5206\u6790\u6587\u4EF6\uFF08${audit.scanned_files.length}\uFF09`),
6769
+ ...audit.scanned_files.map((file) => (0, import_react8.createElement)("div", { key: file, style: metaLine }, file))
6770
+ ) : null,
6771
+ ...audit.uncovered_files.map((file) => (0, import_react8.createElement)(
6772
+ "div",
6773
+ { key: `uncovered-${file}`, style: metaLine },
6774
+ `\u672A\u8986\u76D6\uFF1A${file}`
6775
+ )),
6776
+ ...(audit.dispositions ?? []).map((entry) => (0, import_react8.createElement)(
6777
+ "div",
6778
+ { key: `disposition-${entry.issue_key}`, style: metaLine },
6779
+ `\u4EBA\u5DE5\u786E\u8BA4\u8BEF\u62A5\uFF1A${entry.issue_key} \xB7 ${entry.reason} \xB7 ${entry.approved_at}`
6780
+ )),
6781
+ audit.findings.length === 0 ? (0, import_react8.createElement)("p", { style: metaLine }, "\u6CA1\u6709\u65B0\u589E\u4EE3\u7801\u95EE\u9898\u3002") : (0, import_react8.createElement)(
6782
+ "div",
6783
+ { style: { display: "flex", flexDirection: "column", gap: 6 } },
6784
+ ...audit.findings.map((finding) => (0, import_react8.createElement)(
6785
+ "div",
6786
+ { key: finding.key, style: {
6787
+ ...itemRow,
6788
+ padding: "6px 0",
6789
+ fontSize: 12,
6790
+ overflowWrap: "anywhere"
6791
+ } },
6792
+ (0, import_react8.createElement)(
6793
+ "div",
6794
+ { style: headerRow },
6795
+ (0, import_react8.createElement)("strong", null, finding.severity),
6796
+ (0, import_react8.createElement)("code", null, finding.rule),
6797
+ (0, import_react8.createElement)("span", null, `${finding.file}${finding.line === void 0 ? "" : `:${finding.line}`}`)
6798
+ ),
6799
+ (0, import_react8.createElement)("span", null, finding.message)
6800
+ ))
6801
+ )
6802
+ );
6803
+ }
6523
6804
  function TaskLedger({ workspace, remote }) {
6524
6805
  const [tasks, setTasks] = (0, import_react8.useState)([]);
6525
6806
  const [error, setError] = (0, import_react8.useState)("");
@@ -6531,13 +6812,19 @@ function TaskLedger({ workspace, remote }) {
6531
6812
  if (workspace === "") return;
6532
6813
  setError("");
6533
6814
  setLoading(true);
6534
- void remote.readTasks(workspace).then((result) => {
6815
+ let timer;
6816
+ const timeout = new Promise((_, reject) => {
6817
+ timer = setTimeout(() => reject(new Error("\u8BFB\u53D6\u8D85\u65F6\uFF0C\u8BF7\u5237\u65B0\u9875\u9762\u6216\u91CD\u65B0\u767B\u5F55\u540E\u91CD\u8BD5")), 15e3);
6818
+ });
6819
+ void Promise.race([remote.readTasks(workspace), timeout]).then((result) => {
6535
6820
  setLoading(false);
6536
6821
  if (result.ok) setTasks(result.value.tasks);
6537
6822
  else setError("\u8BFB\u53D6\u53F0\u8D26\u5931\u8D25\uFF1A" + describeError(result.error));
6538
6823
  }, (reason) => {
6539
6824
  setLoading(false);
6540
6825
  setError("\u8BFB\u53D6\u53F0\u8D26\u5931\u8D25\uFF1A" + describeError(reason));
6826
+ }).finally(() => {
6827
+ if (timer !== void 0) clearTimeout(timer);
6541
6828
  });
6542
6829
  }, [remote, workspace]);
6543
6830
  (0, import_react8.useEffect)(() => {
@@ -6561,7 +6848,7 @@ function TaskLedger({ workspace, remote }) {
6561
6848
  (0, import_react8.createElement)("span", { style: styles.sourceBadge }, "\u53EA\u8BFB \xB7 \u6765\u81EA .dsh/task-*.json"),
6562
6849
  (0, import_react8.createElement)(import_dsh_client_ui_primitives5.Button, { variant: "outline", size: "sm", disabled: loading, onClick: refresh }, loading ? "\u8BFB\u53D6\u4E2D\u2026" : "\u5237\u65B0")
6563
6850
  ),
6564
- loading ? (0, import_react8.createElement)("p", { role: "status" }, "\u6B63\u5728\u8BFB\u53D6\u4EFB\u52A1\u2026") : error !== "" ? (0, import_react8.createElement)("p", { style: styles.status }, error) : tasks.length === 0 ? (0, import_react8.createElement)("p", { style: styles.muted }, "\u5F53\u524D\u5DE5\u4F5C\u533A\u8FD8\u6CA1\u6709\u4EFB\u52A1\uFF1A\u5F00\u5DE5\u540E\uFF08dev_task create\uFF09\u4F1A\u5728\u8FD9\u91CC\u5217\u51FA\u6D3E\u53D1\u4E0E\u5BA1\u67E5\u7559\u75D5\u3002") : visible.length === 0 ? (0, import_react8.createElement)("div", { className: "te-empty" }, "\u6CA1\u6709\u5339\u914D\u7684\u4EFB\u52A1\uFF0C\u8BF7\u8C03\u6574\u7B5B\u9009\u3002") : (0, import_react8.createElement)(
6851
+ loading ? (0, import_react8.createElement)("p", { role: "status" }, "\u6B63\u5728\u8BFB\u53D6\u4EFB\u52A1\u2026") : error !== "" ? (0, import_react8.createElement)("p", { style: styles.status }, error) : tasks.length === 0 ? (0, import_react8.createElement)("p", { style: styles.muted }, "\u5F53\u524D\u5DE5\u4F5C\u533A\u8FD8\u6CA1\u6709\u4EFB\u52A1\uFF1A\u5F00\u5DE5\u540E\uFF08dev_task create\uFF09\u4F1A\u5728\u8FD9\u91CC\u5217\u51FA\u5B9E\u65BD\u4E0E\u5BA1\u67E5\u8BB0\u5F55\u3002") : visible.length === 0 ? (0, import_react8.createElement)("div", { className: "te-empty" }, "\u6CA1\u6709\u5339\u914D\u7684\u4EFB\u52A1\uFF0C\u8BF7\u8C03\u6574\u7B5B\u9009\u3002") : (0, import_react8.createElement)(
6565
6852
  "div",
6566
6853
  { style: { display: "flex", flexDirection: "column", gap: 12 } },
6567
6854
  ...visible.map((task) => (0, import_react8.createElement)(
@@ -6580,6 +6867,7 @@ function TaskLedger({ workspace, remote }) {
6580
6867
  (0, import_react8.createElement)("span", { className: "te-badge" }, `\u5BA1\u6838\uFF1A${task.review_outcome ?? "pending"}`),
6581
6868
  task.updated_at ? (0, import_react8.createElement)("span", { style: metaLine }, "\u66F4\u65B0\u4E8E " + timeText(task.updated_at)) : null
6582
6869
  ),
6870
+ sonarAudit(task),
6583
6871
  (0, import_react8.createElement)(
6584
6872
  "div",
6585
6873
  { style: { display: "flex", flexDirection: "column" } },