patchwarden 1.1.0 → 1.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (258) hide show
  1. package/README.en.md +83 -8
  2. package/README.md +78 -10
  3. package/dist/assessments/agentAssessor.d.ts +1 -1
  4. package/dist/assessments/agentAssessor.js +3 -3
  5. package/dist/assessments/assessmentStore.d.ts +1 -1
  6. package/dist/assessments/assessmentStore.js +2 -2
  7. package/dist/assessments/confirmCli.js +5 -4
  8. package/dist/config.d.ts +7 -0
  9. package/dist/config.js +34 -0
  10. package/dist/control/middleware/auth.d.ts +10 -0
  11. package/dist/control/middleware/auth.js +8 -0
  12. package/dist/control/middleware/static.d.ts +3 -0
  13. package/dist/control/middleware/static.js +65 -0
  14. package/dist/control/routes/audit.d.ts +15 -0
  15. package/dist/control/routes/audit.js +277 -0
  16. package/dist/control/routes/evidence.d.ts +4 -0
  17. package/dist/control/routes/evidence.js +96 -0
  18. package/dist/control/routes/lineage.d.ts +3 -0
  19. package/dist/control/routes/lineage.js +71 -0
  20. package/dist/control/routes/policy.d.ts +3 -0
  21. package/dist/control/routes/policy.js +81 -0
  22. package/dist/control/routes/process.d.ts +5 -0
  23. package/dist/control/routes/process.js +200 -0
  24. package/dist/control/routes/sessions.d.ts +22 -0
  25. package/dist/control/routes/sessions.js +224 -0
  26. package/dist/control/routes/status.d.ts +6 -0
  27. package/dist/control/routes/status.js +250 -0
  28. package/dist/control/routes/taskActions.d.ts +21 -0
  29. package/dist/control/routes/taskActions.js +233 -0
  30. package/dist/control/routes/tasks.d.ts +20 -0
  31. package/dist/control/routes/tasks.js +310 -0
  32. package/dist/control/routes/workspace.d.ts +15 -0
  33. package/dist/control/routes/workspace.js +193 -0
  34. package/dist/control/runtime.d.ts +91 -0
  35. package/dist/control/runtime.js +392 -0
  36. package/dist/control/server.d.ts +13 -0
  37. package/dist/control/server.js +479 -0
  38. package/dist/control/shared.d.ts +35 -0
  39. package/dist/control/shared.js +288 -0
  40. package/dist/controlCenter.d.ts +6 -0
  41. package/dist/controlCenter.js +7 -2001
  42. package/dist/direct/directGuards.js +30 -8
  43. package/dist/direct/directSessionStore.d.ts +2 -0
  44. package/dist/direct/directVerification.js +7 -0
  45. package/dist/doctor.d.ts +18 -1
  46. package/dist/doctor.js +579 -348
  47. package/dist/goal/goalReport.d.ts +54 -0
  48. package/dist/goal/goalReport.js +204 -0
  49. package/dist/goal/goalStatus.d.ts +6 -0
  50. package/dist/goal/specKitImport.d.ts +63 -0
  51. package/dist/goal/specKitImport.js +220 -0
  52. package/dist/goal/subgoalSync.js +2 -1
  53. package/dist/httpServer.js +15 -12
  54. package/dist/index.js +7 -4
  55. package/dist/logging.d.ts +7 -1
  56. package/dist/logging.js +8 -0
  57. package/dist/policy/projectPolicy.d.ts +55 -0
  58. package/dist/policy/projectPolicy.js +286 -0
  59. package/dist/runner/changeCapture.d.ts +3 -3
  60. package/dist/runner/changeCapture.js +63 -39
  61. package/dist/runner/cli.js +7 -6
  62. package/dist/runner/postTaskCleanup.js +26 -2
  63. package/dist/runner/runTask.js +245 -221
  64. package/dist/runner/simpleProcess.js +4 -4
  65. package/dist/runner/watch.js +17 -14
  66. package/dist/security/contentRedaction.d.ts +6 -0
  67. package/dist/security/contentRedaction.js +22 -0
  68. package/dist/smoke-test.js +261 -255
  69. package/dist/test/unit/apply-patch.test.d.ts +1 -0
  70. package/dist/test/unit/apply-patch.test.js +225 -0
  71. package/dist/test/unit/create-task.test.d.ts +1 -0
  72. package/dist/test/unit/create-task.test.js +197 -0
  73. package/dist/test/unit/direct-guards.test.js +124 -9
  74. package/dist/test/unit/evidence-pack.test.d.ts +1 -0
  75. package/dist/test/unit/evidence-pack.test.js +224 -0
  76. package/dist/test/unit/get-task-status.test.d.ts +1 -0
  77. package/dist/test/unit/get-task-status.test.js +174 -0
  78. package/dist/test/unit/get-task-summary.test.d.ts +1 -0
  79. package/dist/test/unit/get-task-summary.test.js +146 -0
  80. package/dist/test/unit/goal-report.test.d.ts +1 -0
  81. package/dist/test/unit/goal-report.test.js +159 -0
  82. package/dist/test/unit/goal-subgoal-task.test.js +6 -6
  83. package/dist/test/unit/goal-tools-registry.test.js +6 -4
  84. package/dist/test/unit/path-guard.test.js +24 -0
  85. package/dist/test/unit/project-policy-release-mode.test.d.ts +1 -0
  86. package/dist/test/unit/project-policy-release-mode.test.js +125 -0
  87. package/dist/test/unit/run-task-loop.test.d.ts +1 -0
  88. package/dist/test/unit/run-task-loop.test.js +380 -0
  89. package/dist/test/unit/schema-drift-check.test.js +10 -9
  90. package/dist/test/unit/spec-kit-import.test.d.ts +1 -0
  91. package/dist/test/unit/spec-kit-import.test.js +341 -0
  92. package/dist/test/unit/wait-for-task.test.d.ts +1 -0
  93. package/dist/test/unit/wait-for-task.test.js +144 -0
  94. package/dist/tools/auditTask.d.ts +8 -63
  95. package/dist/tools/auditTask.js +12 -8
  96. package/dist/tools/createDirectSession.d.ts +1 -1
  97. package/dist/tools/createDirectSession.js +2 -2
  98. package/dist/tools/createTask.d.ts +2 -2
  99. package/dist/tools/createTask.js +4 -4
  100. package/dist/tools/dispatch/coreDispatch.d.ts +9 -0
  101. package/dist/tools/dispatch/coreDispatch.js +282 -0
  102. package/dist/tools/dispatch/diagnosticDispatch.d.ts +14 -0
  103. package/dist/tools/dispatch/diagnosticDispatch.js +78 -0
  104. package/dist/tools/dispatch/directDispatch.d.ts +8 -0
  105. package/dist/tools/dispatch/directDispatch.js +115 -0
  106. package/dist/tools/dispatch/goalDispatch.d.ts +8 -0
  107. package/dist/tools/dispatch/goalDispatch.js +91 -0
  108. package/dist/tools/dispatch/releaseDispatch.d.ts +8 -0
  109. package/dist/tools/dispatch/releaseDispatch.js +45 -0
  110. package/dist/tools/dispatch/types.d.ts +23 -0
  111. package/dist/tools/dispatch/types.js +15 -0
  112. package/dist/tools/evidencePack.d.ts +45 -0
  113. package/dist/tools/evidencePack.js +375 -0
  114. package/dist/tools/finalizeDirectSession.d.ts +1 -1
  115. package/dist/tools/finalizeDirectSession.js +3 -3
  116. package/dist/tools/goalSubgoalTask.d.ts +1 -1
  117. package/dist/tools/goalSubgoalTask.js +2 -2
  118. package/dist/tools/healthCheck.js +3 -3
  119. package/dist/tools/recommendAgentForTask.d.ts +19 -0
  120. package/dist/tools/recommendAgentForTask.js +56 -0
  121. package/dist/tools/registry.d.ts +3 -3
  122. package/dist/tools/registry.js +333 -402
  123. package/dist/tools/releaseMode.d.ts +50 -0
  124. package/dist/tools/releaseMode.js +370 -0
  125. package/dist/tools/retryTask.d.ts +2 -2
  126. package/dist/tools/retryTask.js +2 -2
  127. package/dist/tools/runDirectVerificationBundle.d.ts +26 -0
  128. package/dist/tools/runDirectVerificationBundle.js +64 -0
  129. package/dist/tools/runTaskLoop.d.ts +57 -0
  130. package/dist/tools/runTaskLoop.js +417 -0
  131. package/dist/tools/runVerification.d.ts +4 -0
  132. package/dist/tools/runVerification.js +4 -0
  133. package/dist/tools/safeViews.d.ts +8 -2
  134. package/dist/tools/safeViews.js +4 -2
  135. package/dist/tools/taskLineage.d.ts +91 -0
  136. package/dist/tools/taskLineage.js +175 -0
  137. package/dist/tools/toolCatalog.d.ts +2 -2
  138. package/dist/tools/toolCatalog.js +6 -0
  139. package/dist/tools/toolRegistry.js +132 -0
  140. package/dist/version.d.ts +2 -2
  141. package/dist/version.js +2 -2
  142. package/docs/CODE_WIKI.md +983 -0
  143. package/docs/agentseal-integration.md +150 -0
  144. package/docs/architecture.md +63 -0
  145. package/docs/assets/patchwarden-oss-demo.gif +0 -0
  146. package/docs/chatgpt-usage.md +31 -0
  147. package/docs/control-center/README.md +9 -0
  148. package/docs/dashboard-overview.md +86 -0
  149. package/docs/demo.md +8 -0
  150. package/docs/direct-session-workflow.md +98 -0
  151. package/docs/evidence-pack-schema.md +215 -0
  152. package/docs/execution-plan-2026-07-09.md +315 -0
  153. package/docs/lineage-evidence-pack-workflow.md +127 -0
  154. package/docs/mcp-inspector-testing.md +200 -0
  155. package/docs/open-source-application.md +162 -0
  156. package/docs/opencode-worker.md +151 -0
  157. package/docs/openhands-worker.md +181 -0
  158. package/docs/release-evidence.md +72 -0
  159. package/docs/roadmap-execution-and-acceptance.md +365 -0
  160. package/docs/spec-kit-integration.md +131 -0
  161. package/docs/task-safe-review-workflow.md +98 -0
  162. package/docs/threat-model.md +79 -0
  163. package/docs/user-feedback.md +40 -0
  164. package/docs/why-patchwarden.md +110 -0
  165. package/package.json +3 -3
  166. package/scripts/checks/control-center-smoke.js +443 -0
  167. package/scripts/checks/control-smoke.js +2 -2
  168. package/scripts/checks/lifecycle-smoke.js +29 -23
  169. package/scripts/checks/mcp-manifest-check.js +12 -0
  170. package/scripts/checks/mcp-smoke.js +33 -7
  171. package/scripts/checks/watcher-supervisor-smoke.js +1 -1
  172. package/scripts/generate-demo-gif.py +320 -0
  173. package/src/assessments/agentAssessor.ts +3 -3
  174. package/src/assessments/assessmentStore.ts +2 -2
  175. package/src/assessments/confirmCli.ts +5 -4
  176. package/src/config.ts +37 -0
  177. package/src/control/middleware/auth.ts +17 -0
  178. package/src/control/middleware/static.ts +71 -0
  179. package/src/control/routes/audit.ts +321 -0
  180. package/src/control/routes/evidence.ts +107 -0
  181. package/src/control/routes/lineage.ts +92 -0
  182. package/src/control/routes/policy.ts +81 -0
  183. package/src/control/routes/process.ts +204 -0
  184. package/src/control/routes/sessions.ts +251 -0
  185. package/src/control/routes/status.ts +325 -0
  186. package/src/control/routes/taskActions.ts +248 -0
  187. package/src/control/routes/tasks.ts +323 -0
  188. package/src/control/routes/workspace.ts +203 -0
  189. package/src/control/runtime.ts +472 -0
  190. package/src/control/server.ts +471 -0
  191. package/src/control/shared.ts +294 -0
  192. package/src/controlCenter.ts +7 -2150
  193. package/src/direct/directGuards.ts +28 -7
  194. package/src/direct/directSessionStore.ts +2 -0
  195. package/src/direct/directVerification.ts +7 -0
  196. package/src/doctor.ts +741 -481
  197. package/src/goal/goalReport.ts +271 -0
  198. package/src/goal/goalStatus.ts +6 -0
  199. package/src/goal/specKitImport.ts +355 -0
  200. package/src/goal/subgoalSync.ts +4 -2
  201. package/src/httpServer.ts +17 -14
  202. package/src/index.ts +7 -4
  203. package/src/logging.ts +10 -1
  204. package/src/policy/projectPolicy.ts +344 -0
  205. package/src/runner/changeCapture.ts +70 -42
  206. package/src/runner/cli.ts +7 -6
  207. package/src/runner/postTaskCleanup.ts +26 -2
  208. package/src/runner/runTask.ts +325 -223
  209. package/src/runner/simpleProcess.ts +4 -4
  210. package/src/runner/watch.ts +17 -14
  211. package/src/security/contentRedaction.ts +29 -0
  212. package/src/smoke-test.ts +254 -252
  213. package/src/test/unit/apply-patch.test.ts +293 -0
  214. package/src/test/unit/create-task.test.ts +255 -0
  215. package/src/test/unit/direct-guards.test.ts +178 -8
  216. package/src/test/unit/evidence-pack.test.ts +251 -0
  217. package/src/test/unit/get-task-status.test.ts +203 -0
  218. package/src/test/unit/get-task-summary.test.ts +173 -0
  219. package/src/test/unit/goal-report.test.ts +189 -0
  220. package/src/test/unit/goal-subgoal-task.test.ts +6 -6
  221. package/src/test/unit/goal-tools-registry.test.ts +7 -5
  222. package/src/test/unit/path-guard.test.ts +30 -0
  223. package/src/test/unit/project-policy-release-mode.test.ts +156 -0
  224. package/src/test/unit/run-task-loop.test.ts +425 -0
  225. package/src/test/unit/schema-drift-check.test.ts +11 -9
  226. package/src/test/unit/spec-kit-import.test.ts +429 -0
  227. package/src/test/unit/wait-for-task.test.ts +176 -0
  228. package/src/tools/auditTask.ts +99 -59
  229. package/src/tools/createDirectSession.ts +3 -3
  230. package/src/tools/createTask.ts +7 -7
  231. package/src/tools/dispatch/coreDispatch.ts +374 -0
  232. package/src/tools/dispatch/diagnosticDispatch.ts +101 -0
  233. package/src/tools/dispatch/directDispatch.ts +167 -0
  234. package/src/tools/dispatch/goalDispatch.ts +127 -0
  235. package/src/tools/dispatch/releaseDispatch.ts +65 -0
  236. package/src/tools/dispatch/types.ts +24 -0
  237. package/src/tools/evidencePack.ts +490 -0
  238. package/src/tools/finalizeDirectSession.ts +4 -4
  239. package/src/tools/goalSubgoalTask.ts +2 -2
  240. package/src/tools/healthCheck.ts +3 -3
  241. package/src/tools/listWorkspace.ts +71 -71
  242. package/src/tools/recommendAgentForTask.ts +79 -0
  243. package/src/tools/registry.ts +352 -509
  244. package/src/tools/releaseMode.ts +450 -0
  245. package/src/tools/retryTask.ts +2 -2
  246. package/src/tools/runDirectVerificationBundle.ts +98 -0
  247. package/src/tools/runTaskLoop.ts +526 -0
  248. package/src/tools/runVerification.ts +8 -0
  249. package/src/tools/safeViews.ts +4 -2
  250. package/src/tools/taskLineage.ts +300 -0
  251. package/src/tools/toolCatalog.ts +6 -0
  252. package/src/tools/toolRegistry.ts +132 -0
  253. package/src/version.ts +2 -2
  254. package/ui/pages/audit.html +192 -3
  255. package/ui/pages/dashboard.html +1070 -14
  256. package/ui/pages/direct-sessions.html +505 -53
  257. package/ui/pages/task-detail.html +456 -438
  258. package/ui/pages/tasks.html +598 -61
@@ -293,6 +293,55 @@ html.dark {
293
293
  </div>
294
294
  </section>
295
295
 
296
+ <!-- ===== 1b. Warnings Aggregation ===== -->
297
+ <section class="rounded-lg overflow-hidden mb-6" style="background-color: var(--pw-bg-surface); border: 1px solid var(--pw-border); border-left: 3px solid var(--pw-state-warning);">
298
+ <div class="flex items-center justify-between px-5 py-4" style="border-bottom: 1px solid var(--pw-border-subtle);">
299
+ <div class="flex items-center gap-2 flex-wrap">
300
+ <i data-lucide="alert-triangle" class="w-4 h-4 shrink-0" style="color: var(--pw-state-warning);"></i>
301
+ <h2 class="text-sm font-semibold" style="color: var(--pw-text-primary);" data-zh="警告聚合" data-en="Warnings Aggregation">警告聚合</h2>
302
+ <span id="warnings-count" class="text-xs px-2 py-0.5 rounded-md whitespace-nowrap" style="font-family: var(--pw-font-mono); color: var(--pw-text-tertiary); background-color: var(--pw-bg-hover);">—</span>
303
+ </div>
304
+ </div>
305
+
306
+ <!-- Warnings Loading State -->
307
+ <div id="warningsLoadingState" class="py-10 text-center">
308
+ <svg class="pw-spin inline-block mb-2" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="var(--pw-text-tertiary)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
309
+ <line x1="12" y1="2" x2="12" y2="6"/>
310
+ <line x1="12" y1="18" x2="12" y2="22"/>
311
+ <line x1="4.93" y1="4.93" x2="7.76" y2="7.76"/>
312
+ <line x1="16.24" y1="16.24" x2="19.07" y2="19.07"/>
313
+ <line x1="2" y1="12" x2="6" y2="12"/>
314
+ <line x1="18" y1="12" x2="22" y2="12"/>
315
+ <line x1="4.93" y1="19.07" x2="7.76" y2="16.24"/>
316
+ <line x1="16.24" y1="7.76" x2="19.07" y2="4.93"/>
317
+ </svg>
318
+ <p class="text-xs" style="color: var(--pw-text-tertiary);" data-zh="加载警告中..." data-en="Loading warnings...">加载警告中...</p>
319
+ </div>
320
+
321
+ <!-- Warnings Error State -->
322
+ <div id="warningsErrorState" class="hidden py-10 text-center">
323
+ <svg class="inline-block mb-2" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="var(--pw-state-error)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
324
+ <circle cx="12" cy="12" r="10"/>
325
+ <line x1="12" y1="8" x2="12" y2="12"/>
326
+ <line x1="12" y1="16" x2="12.01" y2="16"/>
327
+ </svg>
328
+ <p class="text-xs font-medium" style="color: var(--pw-state-error);" data-zh="警告加载失败" data-en="Warnings Load Failed">警告加载失败</p>
329
+ <p id="warningsErrorMessage" class="text-xs mt-2 px-6 break-words" style="color: var(--pw-text-tertiary); font-family: var(--pw-font-mono);"></p>
330
+ </div>
331
+
332
+ <!-- Warnings Empty State -->
333
+ <div id="warningsEmptyState" class="hidden py-10 text-center">
334
+ <svg class="inline-block mb-2" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="var(--pw-state-success)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
335
+ <path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/>
336
+ <polyline points="22 4 12 14.01 9 11.01"/>
337
+ </svg>
338
+ <p class="text-xs" style="color: var(--pw-text-tertiary);" data-zh="暂无警告" data-en="No Warnings">暂无警告</p>
339
+ </div>
340
+
341
+ <!-- Warnings Cards Container -->
342
+ <div id="warningsBody" class="hidden px-5 py-4 space-y-3"></div>
343
+ </section>
344
+
296
345
  <!-- ===== 2. Audit Log Table ===== -->
297
346
  <section class="rounded-lg overflow-hidden mb-6" style="background-color: var(--pw-bg-surface); border: 1px solid var(--pw-border); border-left: 3px solid var(--pw-accent);">
298
347
 
@@ -438,8 +487,10 @@ html.dark {
438
487
  'use strict';
439
488
 
440
489
  var API_URL = '/api/audit';
490
+ var WARNINGS_URL = '/api/warnings';
441
491
 
442
492
  var allAudits = [];
493
+ var allWarnings = [];
443
494
  var selectedTaskId = null;
444
495
 
445
496
  // ---- DOM helpers ----
@@ -724,16 +775,154 @@ html.dark {
724
775
  });
725
776
  }
726
777
 
778
+ // ---- Warnings aggregation ----
779
+ function showWarningsLoading() {
780
+ show($('warningsLoadingState'));
781
+ hide($('warningsErrorState'));
782
+ hide($('warningsEmptyState'));
783
+ hide($('warningsBody'));
784
+ }
785
+
786
+ function showWarningsError(msg) {
787
+ hide($('warningsLoadingState'));
788
+ show($('warningsErrorState'));
789
+ hide($('warningsEmptyState'));
790
+ hide($('warningsBody'));
791
+ var errEl = $('warningsErrorMessage');
792
+ if (errEl) errEl.textContent = msg || '未知错误';
793
+ }
794
+
795
+ function showWarningsEmpty() {
796
+ hide($('warningsLoadingState'));
797
+ hide($('warningsErrorState'));
798
+ show($('warningsEmptyState'));
799
+ hide($('warningsBody'));
800
+ }
801
+
802
+ function showWarningsBody() {
803
+ hide($('warningsLoadingState'));
804
+ hide($('warningsErrorState'));
805
+ hide($('warningsEmptyState'));
806
+ show($('warningsBody'));
807
+ }
808
+
809
+ // Map a warning type to a display label + icon + accent color.
810
+ function warningTypeMeta(type) {
811
+ var map = {
812
+ failed_verification: { label: 'Failed verification', color: 'var(--pw-state-error)' },
813
+ stale_task: { label: 'Stale task', color: 'var(--pw-state-warning)' },
814
+ manual_verification_required: { label: 'Manual verification required', color: 'var(--pw-state-warning)' },
815
+ unrecorded_command_execution: { label: 'Unrecorded command execution', color: 'var(--pw-state-info)' },
816
+ release_publish_claim: { label: 'Release/publish claim', color: 'var(--pw-state-error)' },
817
+ artifact_hygiene: { label: 'Artifact hygiene', color: 'var(--pw-state-info)' },
818
+ scope_changes: { label: 'Scope changes', color: 'var(--pw-state-info)' }
819
+ };
820
+ return map[type] || { label: type || 'Unknown', color: 'var(--pw-text-tertiary)' };
821
+ }
822
+
823
+ function severityBadge(severity) {
824
+ var v = String(severity || '').toLowerCase();
825
+ var bg, color;
826
+ if (v === 'error') {
827
+ bg = 'var(--pw-state-error-bg)';
828
+ color = 'var(--pw-state-error)';
829
+ } else if (v === 'warning') {
830
+ bg = 'var(--pw-state-warning-bg)';
831
+ color = 'var(--pw-state-warning)';
832
+ } else {
833
+ bg = 'var(--pw-state-info-bg)';
834
+ color = 'var(--pw-state-info)';
835
+ }
836
+ return '<span class="inline-flex items-center px-2 py-0.5 rounded-md text-xs font-medium whitespace-nowrap" style="background-color: ' + bg + '; color: ' + color + ';">' + escapeHtml(v || 'info') + '</span>';
837
+ }
838
+
839
+ function flagLabel(active, label, activeColor) {
840
+ if (!active) return '';
841
+ return '<span class="inline-flex items-center px-1.5 py-0.5 rounded text-xs whitespace-nowrap" style="background-color: ' + activeColor + '_bg; color: ' + activeColor + '; border-left: 2px solid ' + activeColor + ';">' + escapeHtml(label) + '</span>';
842
+ }
843
+
844
+ function renderWarnings() {
845
+ var countEl = $('warnings-count');
846
+ if (allWarnings.length === 0) {
847
+ if (countEl) countEl.textContent = '0';
848
+ showWarningsEmpty();
849
+ return;
850
+ }
851
+ if (countEl) countEl.textContent = String(allWarnings.length);
852
+ var html = '';
853
+ for (var i = 0; i < allWarnings.length; i++) {
854
+ var w = allWarnings[i];
855
+ var meta = warningTypeMeta(w.type);
856
+ var tasks = Array.isArray(w.affected_tasks) ? w.affected_tasks : [];
857
+ var taskLinksHtml = '';
858
+ for (var j = 0; j < tasks.length; j++) {
859
+ var tid = tasks[j];
860
+ var href = '/pages/task-detail.html?id=' + encodeURIComponent(tid);
861
+ taskLinksHtml += '<a href="' + href + '" class="inline-block hover:underline px-1.5 py-0.5 rounded text-xs" style="font-family: var(--pw-font-mono); color: var(--pw-text-accent); background-color: var(--pw-accent-subtle);" title="' + escapeAttr(tid) + '">' + escapeHtml(truncate(tid, 18)) + '</a>';
862
+ }
863
+ var flagsHtml = ''
864
+ + flagLabel(w.likely_false_positive === true, 'likely false positive', 'var(--pw-state-warning)')
865
+ + flagLabel(w.needs_fix === true, 'needs fix', 'var(--pw-state-error)')
866
+ + flagLabel(w.blocked === true, 'blocked', 'var(--pw-state-error)');
867
+ html += ''
868
+ + '<div class="rounded-md p-3" style="background-color: var(--pw-bg-hover); border-left: 3px solid ' + meta.color + ';">'
869
+ + '<div class="flex items-center gap-2 mb-2 flex-wrap">'
870
+ + '<span class="text-sm font-semibold truncate" style="color: var(--pw-text-primary);">' + escapeHtml(meta.label) + '</span>'
871
+ + severityBadge(w.severity)
872
+ + '<span class="text-xs whitespace-nowrap" style="color: var(--pw-text-tertiary); font-family: var(--pw-font-mono);">' + escapeHtml(String(w.affected_tasks_count || 0)) + ' task' + (w.affected_tasks_count === 1 ? '' : 's') + '</span>'
873
+ + (flagsHtml ? '<span class="flex items-center gap-1 flex-wrap">' + flagsHtml + '</span>' : '')
874
+ + '</div>'
875
+ + (w.recommended_action ? '<div class="text-xs mb-2" style="color: var(--pw-text-secondary);">' + escapeHtml(w.recommended_action) + '</div>' : '')
876
+ + (taskLinksHtml ? '<div class="flex flex-wrap gap-1.5">' + taskLinksHtml + '</div>' : '')
877
+ + '</div>';
878
+ }
879
+ $('warningsBody').innerHTML = html;
880
+ showWarningsBody();
881
+ }
882
+
883
+ function fetchWarnings() {
884
+ showWarningsLoading();
885
+ fetch(WARNINGS_URL, {
886
+ method: 'GET',
887
+ headers: { 'Accept': 'application/json' },
888
+ cache: 'no-store'
889
+ })
890
+ .then(function (res) {
891
+ if (!res.ok) {
892
+ return res.text().then(function (body) {
893
+ throw new Error('HTTP ' + res.status + (body ? (': ' + body.slice(0, 200)) : ''));
894
+ });
895
+ }
896
+ return res.json();
897
+ })
898
+ .then(function (data) {
899
+ allWarnings = (data && Array.isArray(data.warnings)) ? data.warnings : [];
900
+ renderWarnings();
901
+ })
902
+ .catch(function (err) {
903
+ var msg = (err && err.message) ? err.message : '未知错误';
904
+ if (err && err.name === 'TypeError' && /fetch/i.test(msg)) {
905
+ msg = '无法连接到 ' + WARNINGS_URL + '(请确认 PatchWarden 服务正在运行)';
906
+ }
907
+ showWarningsError(msg);
908
+ });
909
+ }
910
+
911
+ function refreshAll() {
912
+ fetchWarnings();
913
+ fetchAudits();
914
+ }
915
+
727
916
  // ---- Event wiring ----
728
- $('refreshBtn').addEventListener('click', fetchAudits);
917
+ $('refreshBtn').addEventListener('click', refreshAll);
729
918
 
730
919
  var retryBtn = $('retryBtn');
731
920
  if (retryBtn) {
732
- retryBtn.addEventListener('click', fetchAudits);
921
+ retryBtn.addEventListener('click', refreshAll);
733
922
  }
734
923
 
735
924
  // Initial load
736
- fetchAudits();
925
+ refreshAll();
737
926
  })();
738
927
  </script>
739
928