patchwarden 1.5.1 → 1.6.2

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 (591) hide show
  1. package/PatchWarden.cmd +32 -2
  2. package/README.en.md +158 -26
  3. package/README.md +124 -24
  4. package/dist/assessments/agentAssessor.js +21 -12
  5. package/dist/assessments/assessmentDiagnostics.d.ts +29 -0
  6. package/dist/assessments/assessmentDiagnostics.js +132 -0
  7. package/dist/assessments/assessmentStore.d.ts +39 -0
  8. package/dist/assessments/assessmentStore.js +207 -45
  9. package/dist/assessments/securitySnapshot.d.ts +50 -0
  10. package/dist/assessments/securitySnapshot.js +158 -0
  11. package/dist/config.d.ts +15 -0
  12. package/dist/config.js +66 -13
  13. package/dist/control/fileManager.d.ts +2 -0
  14. package/dist/control/fileManager.js +39 -0
  15. package/dist/control/middleware/auth.d.ts +6 -0
  16. package/dist/control/middleware/auth.js +14 -5
  17. package/dist/control/middleware/static.js +16 -3
  18. package/dist/control/routeTable.d.ts +24 -0
  19. package/dist/control/routeTable.js +263 -0
  20. package/dist/control/routes/audit.js +17 -7
  21. package/dist/control/routes/evidence.js +1 -1
  22. package/dist/control/routes/lineage.js +1 -1
  23. package/dist/control/routes/process.d.ts +7 -0
  24. package/dist/control/routes/process.js +329 -42
  25. package/dist/control/routes/sessions.d.ts +9 -1
  26. package/dist/control/routes/sessions.js +84 -21
  27. package/dist/control/routes/status.d.ts +60 -1
  28. package/dist/control/routes/status.js +94 -15
  29. package/dist/control/routes/taskActions.js +24 -60
  30. package/dist/control/routes/tasks.d.ts +4 -0
  31. package/dist/control/routes/tasks.js +61 -62
  32. package/dist/control/routes/workspace.js +50 -23
  33. package/dist/control/runtime.d.ts +3 -2
  34. package/dist/control/runtime.js +65 -40
  35. package/dist/control/server.js +37 -365
  36. package/dist/control/shared.d.ts +25 -1
  37. package/dist/control/shared.js +64 -11
  38. package/dist/diagnostics/allowedTestCommandSafety.d.ts +1 -0
  39. package/dist/diagnostics/allowedTestCommandSafety.js +11 -0
  40. package/dist/direct/directAudit.js +234 -225
  41. package/dist/direct/directGuards.d.ts +2 -1
  42. package/dist/direct/directGuards.js +42 -29
  43. package/dist/direct/directPatch.d.ts +6 -1
  44. package/dist/direct/directPatch.js +55 -8
  45. package/dist/direct/directSessionStore.d.ts +16 -6
  46. package/dist/direct/directSessionStore.js +128 -35
  47. package/dist/direct/directVerification.js +8 -16
  48. package/dist/doctor.js +65 -57
  49. package/dist/goal/acceptanceEngine.d.ts +1 -1
  50. package/dist/goal/goalProgress.js +75 -69
  51. package/dist/goal/goalReport.js +5 -12
  52. package/dist/goal/goalStatus.d.ts +2 -0
  53. package/dist/goal/goalStatus.js +10 -3
  54. package/dist/goal/goalStore.d.ts +9 -2
  55. package/dist/goal/goalStore.js +152 -45
  56. package/dist/goal/handoffExport.js +6 -6
  57. package/dist/goal/specKitImport.js +97 -96
  58. package/dist/goal/subgoalSync.js +11 -9
  59. package/dist/goal/worktreeManager.d.ts +2 -0
  60. package/dist/goal/worktreeManager.js +209 -136
  61. package/dist/httpServer.js +111 -32
  62. package/dist/logging.js +5 -3
  63. package/dist/policy/projectPolicy.js +5 -2
  64. package/dist/release/releaseGate.d.ts +1 -1
  65. package/dist/release/releaseGate.js +78 -25
  66. package/dist/runner/agentInvocation.d.ts +14 -0
  67. package/dist/runner/agentInvocation.js +96 -4
  68. package/dist/runner/changeCapture.d.ts +13 -5
  69. package/dist/runner/changeCapture.js +243 -61
  70. package/dist/runner/postTaskCleanup.js +48 -19
  71. package/dist/runner/processSecurity.d.ts +56 -0
  72. package/dist/runner/processSecurity.js +373 -0
  73. package/dist/runner/runTask.d.ts +2 -1
  74. package/dist/runner/runTask.js +162 -93
  75. package/dist/runner/simpleProcess.d.ts +3 -0
  76. package/dist/runner/simpleProcess.js +50 -36
  77. package/dist/{taskProgress.d.ts → runner/taskProgress.d.ts} +1 -1
  78. package/dist/{taskProgress.js → runner/taskProgress.js} +2 -2
  79. package/dist/{taskRuntime.d.ts → runner/taskRuntime.d.ts} +3 -1
  80. package/dist/{taskRuntime.js → runner/taskRuntime.js} +3 -2
  81. package/dist/runner/taskStatusStore.d.ts +11 -0
  82. package/dist/runner/taskStatusStore.js +35 -0
  83. package/dist/runner/watch.d.ts +14 -1
  84. package/dist/runner/watch.js +320 -49
  85. package/dist/security/contentRedaction.js +2 -2
  86. package/dist/security/discoveryTokenStore.d.ts +3 -2
  87. package/dist/security/discoveryTokenStore.js +17 -2
  88. package/dist/security/loopbackHost.d.ts +2 -0
  89. package/dist/security/loopbackHost.js +16 -0
  90. package/dist/security/pathGuard.js +32 -17
  91. package/dist/security/planGuard.js +2 -1
  92. package/dist/security/runtimeGuard.js +9 -6
  93. package/dist/security/secretComparison.d.ts +3 -0
  94. package/dist/security/secretComparison.js +11 -0
  95. package/dist/security/sensitiveGuard.d.ts +5 -0
  96. package/dist/security/sensitiveGuard.js +27 -8
  97. package/dist/security/toolInvocationGuard.d.ts +2 -2
  98. package/dist/security/toolInvocationGuard.js +1 -1
  99. package/dist/security/workspaceRootGuard.d.ts +8 -0
  100. package/dist/security/workspaceRootGuard.js +47 -0
  101. package/dist/smoke-test.js +27 -26
  102. package/dist/tools/catalog/index.d.ts +4 -0
  103. package/dist/tools/catalog/index.js +4 -0
  104. package/dist/tools/{toolCatalog.js → catalog/toolCatalog.js} +3 -12
  105. package/dist/tools/{toolRegistry.d.ts → catalog/toolRegistry.d.ts} +3 -3
  106. package/dist/tools/{toolRegistry.js → catalog/toolRegistry.js} +6 -15
  107. package/dist/tools/definitions/toolDefs.d.ts +18 -0
  108. package/dist/tools/definitions/toolDefs.js +1177 -0
  109. package/dist/tools/{auditSession.d.ts → diagnostics/auditSession.d.ts} +1 -1
  110. package/dist/tools/{auditSession.js → diagnostics/auditSession.js} +2 -2
  111. package/dist/tools/{auditTask.d.ts → diagnostics/auditTask.d.ts} +2 -1
  112. package/dist/tools/{auditTask.js → diagnostics/auditTask.js} +134 -36
  113. package/dist/tools/{healthCheck.d.ts → diagnostics/healthCheck.d.ts} +18 -6
  114. package/dist/tools/{healthCheck.js → diagnostics/healthCheck.js} +36 -8
  115. package/dist/tools/diagnostics/index.d.ts +6 -0
  116. package/dist/tools/diagnostics/index.js +6 -0
  117. package/dist/tools/{safeStatus.d.ts → diagnostics/safeStatus.d.ts} +3 -3
  118. package/dist/tools/{safeStatus.js → diagnostics/safeStatus.js} +6 -6
  119. package/dist/tools/{safeViews.d.ts → diagnostics/safeViews.d.ts} +12 -8
  120. package/dist/tools/{safeViews.js → diagnostics/safeViews.js} +23 -13
  121. package/dist/tools/{schemaDriftCheck.d.ts → diagnostics/schemaDriftCheck.d.ts} +1 -1
  122. package/dist/tools/{schemaDriftCheck.js → diagnostics/schemaDriftCheck.js} +2 -2
  123. package/dist/tools/{createDirectSession.js → direct/createDirectSession.js} +6 -6
  124. package/dist/tools/{finalizeDirectSession.d.ts → direct/finalizeDirectSession.d.ts} +1 -1
  125. package/dist/tools/direct/finalizeDirectSession.js +86 -0
  126. package/dist/tools/direct/index.d.ts +3 -0
  127. package/dist/tools/direct/index.js +3 -0
  128. package/dist/tools/{runDirectVerificationBundle.js → direct/runDirectVerificationBundle.js} +2 -2
  129. package/dist/tools/{discoverTools.d.ts → discovery/discoverTools.d.ts} +2 -2
  130. package/dist/tools/{discoverTools.js → discovery/discoverTools.js} +5 -5
  131. package/dist/tools/{explainTool.d.ts → discovery/explainTool.d.ts} +2 -2
  132. package/dist/tools/{explainTool.js → discovery/explainTool.js} +2 -2
  133. package/dist/tools/discovery/index.d.ts +3 -0
  134. package/dist/tools/discovery/index.js +3 -0
  135. package/dist/tools/{invokeDiscoveredTool.d.ts → discovery/invokeDiscoveredTool.d.ts} +2 -2
  136. package/dist/tools/{invokeDiscoveredTool.js → discovery/invokeDiscoveredTool.js} +5 -5
  137. package/dist/tools/dispatch/coreDispatch.js +32 -31
  138. package/dist/tools/dispatch/diagnosticDispatch.d.ts +3 -5
  139. package/dist/tools/dispatch/diagnosticDispatch.js +70 -68
  140. package/dist/tools/dispatch/directDispatch.js +11 -10
  141. package/dist/tools/dispatch/goalDispatch.js +5 -4
  142. package/dist/tools/dispatch/releaseDispatch.js +3 -2
  143. package/dist/tools/dispatch/validation.d.ts +7 -0
  144. package/dist/tools/dispatch/validation.js +71 -0
  145. package/dist/tools/{getPlan.js → goals/getPlan.js} +4 -4
  146. package/dist/tools/{goalSubgoalTask.d.ts → goals/goalSubgoalTask.d.ts} +1 -1
  147. package/dist/tools/goals/goalSubgoalTask.js +118 -0
  148. package/dist/tools/goals/index.d.ts +3 -0
  149. package/dist/tools/goals/index.js +3 -0
  150. package/dist/tools/{savePlan.js → goals/savePlan.js} +28 -8
  151. package/dist/tools/registry.d.ts +7 -11
  152. package/dist/tools/registry.js +17 -1178
  153. package/dist/tools/{checkReleaseGate.d.ts → release/checkReleaseGate.d.ts} +1 -1
  154. package/dist/tools/{checkReleaseGate.js → release/checkReleaseGate.js} +3 -3
  155. package/dist/tools/release/index.d.ts +2 -0
  156. package/dist/tools/release/index.js +2 -0
  157. package/dist/tools/{releaseMode.d.ts → release/releaseMode.d.ts} +2 -2
  158. package/dist/tools/{releaseMode.js → release/releaseMode.js} +46 -26
  159. package/dist/tools/tasks/cancelTask.d.ts +11 -0
  160. package/dist/tools/tasks/cancelTask.js +86 -0
  161. package/dist/tools/{createTask.d.ts → tasks/createTask.d.ts} +12 -4
  162. package/dist/tools/{createTask.js → tasks/createTask.js} +110 -34
  163. package/dist/tools/{diagnoseTask.d.ts → tasks/diagnoseTask.d.ts} +1 -1
  164. package/dist/tools/{diagnoseTask.js → tasks/diagnoseTask.js} +12 -16
  165. package/dist/tools/{evidencePack.js → tasks/evidencePack.js} +34 -22
  166. package/dist/tools/{getTaskFile.js → tasks/getTaskFile.js} +4 -4
  167. package/dist/tools/{getTaskStatus.d.ts → tasks/getTaskStatus.d.ts} +6 -1
  168. package/dist/tools/{getTaskStatus.js → tasks/getTaskStatus.js} +11 -6
  169. package/dist/tools/{getTaskStdoutTail.js → tasks/getTaskStdoutTail.js} +13 -11
  170. package/dist/tools/{getTaskSummary.js → tasks/getTaskSummary.js} +35 -36
  171. package/dist/tools/tasks/index.d.ts +18 -0
  172. package/dist/tools/tasks/index.js +18 -0
  173. package/dist/tools/tasks/killTask.d.ts +1 -0
  174. package/dist/tools/{listTasks.d.ts → tasks/listTasks.d.ts} +1 -1
  175. package/dist/tools/{listTasks.js → tasks/listTasks.js} +5 -4
  176. package/dist/tools/{reconcileTasks.d.ts → tasks/reconcileTasks.d.ts} +3 -2
  177. package/dist/tools/tasks/reconcileTasks.js +496 -0
  178. package/dist/tools/tasks/retryTask.js +60 -0
  179. package/dist/tools/{runTaskLoop.d.ts → tasks/runTaskLoop.d.ts} +6 -6
  180. package/dist/tools/{runTaskLoop.js → tasks/runTaskLoop.js} +63 -41
  181. package/dist/tools/tasks/runVerification.js +38 -0
  182. package/dist/tools/{taskLineage.js → tasks/taskLineage.js} +8 -7
  183. package/dist/tools/{taskOutputs.d.ts → tasks/taskOutputs.d.ts} +2 -2
  184. package/dist/tools/{taskOutputs.js → tasks/taskOutputs.js} +17 -16
  185. package/dist/tools/tasks/taskStates.d.ts +6 -0
  186. package/dist/tools/tasks/taskStates.js +52 -0
  187. package/dist/tools/{waitForTask.js → tasks/waitForTask.js} +3 -11
  188. package/dist/tools/{androidDoctor.js → workspace/androidDoctor.js} +16 -10
  189. package/dist/tools/{applyPatch.d.ts → workspace/applyPatch.d.ts} +1 -1
  190. package/dist/tools/workspace/applyPatch.js +53 -0
  191. package/dist/tools/{discardWorktree.js → workspace/discardWorktree.js} +3 -3
  192. package/dist/tools/workspace/index.d.ts +10 -0
  193. package/dist/tools/workspace/index.js +10 -0
  194. package/dist/tools/workspace/listAgents.d.ts +23 -0
  195. package/dist/tools/workspace/listAgents.js +56 -0
  196. package/dist/tools/{listWorkspace.js → workspace/listWorkspace.js} +3 -3
  197. package/dist/tools/{mergeWorktree.js → workspace/mergeWorktree.js} +3 -3
  198. package/dist/tools/{readWorkspaceFile.js → workspace/readWorkspaceFile.js} +8 -8
  199. package/dist/tools/{recommendAgentForTask.js → workspace/recommendAgentForTask.js} +3 -3
  200. package/dist/tools/{searchWorkspace.js → workspace/searchWorkspace.js} +5 -5
  201. package/dist/tools/{syncFile.d.ts → workspace/syncFile.d.ts} +1 -1
  202. package/dist/tools/workspace/syncFile.js +134 -0
  203. package/dist/utils/atomicFile.d.ts +7 -0
  204. package/dist/utils/atomicFile.js +67 -0
  205. package/dist/utils/boundedFile.d.ts +8 -0
  206. package/dist/utils/boundedFile.js +93 -0
  207. package/dist/utils/lockedJsonFile.d.ts +15 -0
  208. package/dist/utils/lockedJsonFile.js +224 -0
  209. package/dist/utils/platform.d.ts +11 -0
  210. package/dist/utils/platform.js +26 -0
  211. package/dist/utils/stableJson.d.ts +2 -0
  212. package/dist/utils/stableJson.js +12 -0
  213. package/dist/version.d.ts +3 -2
  214. package/dist/version.js +3 -2
  215. package/dist/watcherStatus.d.ts +2 -2
  216. package/dist/watcherStatus.js +18 -0
  217. package/docs/CODE_WIKI.md +808 -143
  218. package/docs/architecture.md +15 -55
  219. package/docs/assets/patchwarden-desktop-onboarding.png +0 -0
  220. package/docs/control-center/README.md +4 -4
  221. package/docs/dashboard-overview.md +4 -4
  222. package/docs/desktop-app.md +175 -0
  223. package/docs/evidence-pack-schema.md +3 -3
  224. package/docs/open-source-application.md +16 -11
  225. package/docs/release-checklist.md +1 -1
  226. package/docs/release-evidence.md +35 -39
  227. package/docs/task-safe-review-workflow.md +5 -5
  228. package/docs/threat-model.md +19 -1
  229. package/examples/config.example.json +4 -2
  230. package/package.json +27 -10
  231. package/scripts/README.md +15 -6
  232. package/scripts/build.js +11 -0
  233. package/scripts/checks/brand-check.js +3 -0
  234. package/scripts/checks/build-output-check.js +37 -0
  235. package/scripts/checks/control-center-smoke.js +102 -10
  236. package/scripts/checks/control-smoke.js +19 -8
  237. package/scripts/checks/http-mcp-smoke.js +82 -4
  238. package/scripts/checks/lifecycle-smoke.js +15 -12
  239. package/scripts/checks/mcp-manifest-check.js +1 -1
  240. package/scripts/checks/mcp-smoke.js +58 -4
  241. package/scripts/checks/package-manifest-check.js +20 -7
  242. package/scripts/checks/unit-tests.js +3 -5
  243. package/scripts/checks/watcher-supervisor-smoke.js +38 -1
  244. package/scripts/control/get-patchwarden-health.ps1 +1 -1
  245. package/scripts/control/manage-patchwarden.ps1 +69 -4
  246. package/scripts/control/provision-patchwarden-tunnel.ps1 +127 -0
  247. package/scripts/control/run-background-supervisor.ps1 +41 -0
  248. package/scripts/control/start-patchwarden-tunnel.ps1 +191 -33
  249. package/scripts/e2e/demo-runtime.mjs +153 -0
  250. package/{PatchWarden-Control-Tray.cmd → scripts/launchers/PatchWarden-Control-Tray.cmd} +3 -3
  251. package/scripts/launchers/PatchWarden-Control.cmd +6 -0
  252. package/{PatchWarden-Desktop.cmd → scripts/launchers/PatchWarden-Desktop.cmd} +2 -2
  253. package/scripts/launchers/Restart-PatchWarden-Control.cmd +6 -0
  254. package/{Stop-PatchWarden.cmd → scripts/launchers/Stop-PatchWarden.cmd} +2 -2
  255. package/scripts/lib/clean-generated-output.js +11 -0
  256. package/scripts/lib/file-discovery.js +12 -0
  257. package/scripts/release/desktop-preflight.js +211 -0
  258. package/scripts/release/pack-clean.js +59 -14
  259. package/src/assessments/agentAssessor.ts +26 -12
  260. package/src/assessments/assessmentDiagnostics.ts +172 -0
  261. package/src/assessments/assessmentStore.ts +288 -51
  262. package/src/assessments/securitySnapshot.ts +231 -0
  263. package/src/config.ts +70 -13
  264. package/src/control/fileManager.ts +40 -0
  265. package/src/control/middleware/auth.ts +22 -4
  266. package/src/control/middleware/static.ts +16 -3
  267. package/src/control/routeTable.ts +301 -0
  268. package/src/control/routes/audit.ts +14 -6
  269. package/src/control/routes/evidence.ts +1 -1
  270. package/src/control/routes/lineage.ts +1 -1
  271. package/src/control/routes/process.ts +341 -40
  272. package/src/control/routes/sessions.ts +88 -25
  273. package/src/control/routes/status.ts +134 -17
  274. package/src/control/routes/taskActions.ts +24 -58
  275. package/src/control/routes/tasks.ts +66 -58
  276. package/src/control/routes/workspace.ts +56 -25
  277. package/src/control/runtime.ts +71 -43
  278. package/src/control/server.ts +37 -342
  279. package/src/control/shared.ts +77 -11
  280. package/src/diagnostics/allowedTestCommandSafety.ts +12 -0
  281. package/src/direct/directAudit.ts +17 -9
  282. package/src/direct/directGuards.ts +72 -44
  283. package/src/direct/directPatch.ts +95 -8
  284. package/src/direct/directSessionStore.ts +213 -55
  285. package/src/direct/directVerification.ts +9 -23
  286. package/src/doctor.ts +76 -64
  287. package/src/goal/acceptanceEngine.ts +1 -1
  288. package/src/goal/goalProgress.ts +17 -13
  289. package/src/goal/goalReport.ts +5 -13
  290. package/src/goal/goalStatus.ts +19 -3
  291. package/src/goal/goalStore.ts +241 -54
  292. package/src/goal/handoffExport.ts +6 -6
  293. package/src/goal/specKitImport.ts +12 -12
  294. package/src/goal/subgoalSync.ts +11 -8
  295. package/src/goal/worktreeManager.ts +139 -22
  296. package/src/httpServer.ts +113 -30
  297. package/src/logging.ts +10 -3
  298. package/src/policy/projectPolicy.ts +5 -2
  299. package/src/release/releaseGate.ts +74 -27
  300. package/src/runner/agentInvocation.ts +126 -4
  301. package/src/runner/changeCapture.ts +291 -57
  302. package/src/runner/postTaskCleanup.ts +41 -17
  303. package/src/runner/processSecurity.ts +433 -0
  304. package/src/runner/runTask.ts +197 -97
  305. package/src/runner/simpleProcess.ts +66 -31
  306. package/src/{taskProgress.ts → runner/taskProgress.ts} +3 -3
  307. package/src/{taskRuntime.ts → runner/taskRuntime.ts} +6 -3
  308. package/src/runner/taskStatusStore.ts +69 -0
  309. package/src/runner/watch.ts +348 -52
  310. package/src/security/contentRedaction.ts +2 -2
  311. package/src/security/discoveryTokenStore.ts +18 -4
  312. package/src/security/loopbackHost.ts +19 -0
  313. package/src/security/pathGuard.ts +35 -16
  314. package/src/security/planGuard.ts +2 -1
  315. package/src/security/runtimeGuard.ts +9 -6
  316. package/src/security/secretComparison.ts +13 -0
  317. package/src/security/sensitiveGuard.ts +27 -8
  318. package/src/security/toolInvocationGuard.ts +2 -2
  319. package/src/security/workspaceRootGuard.ts +53 -0
  320. package/src/smoke-test.ts +27 -26
  321. package/src/tools/catalog/index.ts +4 -0
  322. package/src/tools/{toolCatalog.ts → catalog/toolCatalog.ts} +3 -12
  323. package/src/tools/{toolRegistry.ts → catalog/toolRegistry.ts} +7 -16
  324. package/src/tools/definitions/toolDefs.ts +1264 -0
  325. package/src/tools/{auditSession.ts → diagnostics/auditSession.ts} +2 -2
  326. package/src/tools/{auditTask.ts → diagnostics/auditTask.ts} +136 -39
  327. package/src/tools/{healthCheck.ts → diagnostics/healthCheck.ts} +37 -9
  328. package/src/tools/diagnostics/index.ts +6 -0
  329. package/src/tools/{safeStatus.ts → diagnostics/safeStatus.ts} +7 -7
  330. package/src/tools/{safeViews.ts → diagnostics/safeViews.ts} +27 -17
  331. package/src/tools/{schemaDriftCheck.ts → diagnostics/schemaDriftCheck.ts} +3 -3
  332. package/src/tools/{createDirectSession.ts → direct/createDirectSession.ts} +6 -6
  333. package/src/tools/{finalizeDirectSession.ts → direct/finalizeDirectSession.ts} +7 -5
  334. package/src/tools/direct/index.ts +3 -0
  335. package/src/tools/{runDirectVerificationBundle.ts → direct/runDirectVerificationBundle.ts} +2 -2
  336. package/src/tools/{discoverTools.ts → discovery/discoverTools.ts} +6 -6
  337. package/src/tools/{explainTool.ts → discovery/explainTool.ts} +3 -3
  338. package/src/tools/discovery/index.ts +3 -0
  339. package/src/tools/{invokeDiscoveredTool.ts → discovery/invokeDiscoveredTool.ts} +7 -7
  340. package/src/tools/dispatch/coreDispatch.ts +36 -31
  341. package/src/tools/dispatch/diagnosticDispatch.ts +26 -21
  342. package/src/tools/dispatch/directDispatch.ts +11 -10
  343. package/src/tools/dispatch/goalDispatch.ts +5 -4
  344. package/src/tools/dispatch/releaseDispatch.ts +3 -2
  345. package/src/tools/dispatch/validation.ts +78 -0
  346. package/src/tools/{getPlan.ts → goals/getPlan.ts} +4 -4
  347. package/src/tools/{goalSubgoalTask.ts → goals/goalSubgoalTask.ts} +41 -26
  348. package/src/tools/goals/index.ts +3 -0
  349. package/src/tools/{savePlan.ts → goals/savePlan.ts} +38 -8
  350. package/src/tools/registry.ts +17 -1261
  351. package/src/tools/{checkReleaseGate.ts → release/checkReleaseGate.ts} +3 -3
  352. package/src/tools/release/index.ts +2 -0
  353. package/src/tools/{releaseMode.ts → release/releaseMode.ts} +42 -24
  354. package/src/tools/tasks/cancelTask.ts +110 -0
  355. package/src/tools/{createTask.ts → tasks/createTask.ts} +161 -33
  356. package/src/tools/{diagnoseTask.ts → tasks/diagnoseTask.ts} +12 -16
  357. package/src/tools/{evidencePack.ts → tasks/evidencePack.ts} +36 -22
  358. package/src/tools/{getTaskFile.ts → tasks/getTaskFile.ts} +4 -4
  359. package/src/tools/{getTaskStatus.ts → tasks/getTaskStatus.ts} +13 -6
  360. package/src/tools/{getTaskStdoutTail.ts → tasks/getTaskStdoutTail.ts} +13 -11
  361. package/src/tools/{getTaskSummary.ts → tasks/getTaskSummary.ts} +46 -44
  362. package/src/tools/tasks/index.ts +18 -0
  363. package/src/tools/{listTasks.ts → tasks/listTasks.ts} +6 -5
  364. package/src/tools/{reconcileTasks.ts → tasks/reconcileTasks.ts} +228 -77
  365. package/src/tools/tasks/retryTask.ts +69 -0
  366. package/src/tools/{runTaskLoop.ts → tasks/runTaskLoop.ts} +73 -46
  367. package/src/tools/{runVerification.ts → tasks/runVerification.ts} +6 -3
  368. package/src/tools/{taskLineage.ts → tasks/taskLineage.ts} +8 -7
  369. package/src/tools/{taskOutputs.ts → tasks/taskOutputs.ts} +27 -20
  370. package/src/tools/tasks/taskStates.ts +54 -0
  371. package/src/tools/{waitForTask.ts → tasks/waitForTask.ts} +3 -12
  372. package/src/tools/{androidDoctor.ts → workspace/androidDoctor.ts} +15 -10
  373. package/src/tools/{applyPatch.ts → workspace/applyPatch.ts} +38 -16
  374. package/src/tools/{discardWorktree.ts → workspace/discardWorktree.ts} +3 -3
  375. package/src/tools/workspace/index.ts +10 -0
  376. package/src/tools/workspace/listAgents.ts +75 -0
  377. package/src/tools/{listWorkspace.ts → workspace/listWorkspace.ts} +3 -3
  378. package/src/tools/{mergeWorktree.ts → workspace/mergeWorktree.ts} +3 -3
  379. package/src/tools/{readWorkspaceFile.ts → workspace/readWorkspaceFile.ts} +8 -8
  380. package/src/tools/{recommendAgentForTask.ts → workspace/recommendAgentForTask.ts} +3 -3
  381. package/src/tools/{searchWorkspace.ts → workspace/searchWorkspace.ts} +5 -5
  382. package/src/tools/workspace/syncFile.ts +292 -0
  383. package/src/utils/atomicFile.ts +74 -0
  384. package/src/utils/boundedFile.ts +116 -0
  385. package/src/utils/lockedJsonFile.ts +251 -0
  386. package/src/utils/platform.ts +31 -0
  387. package/src/utils/stableJson.ts +12 -0
  388. package/src/version.ts +3 -2
  389. package/src/watcherStatus.ts +19 -1
  390. package/ui/desktop-bootstrap.js +11 -0
  391. package/ui/desktop-bridge.js +36 -0
  392. package/ui/desktop.css +160 -0
  393. package/ui/getting-started.js +93 -0
  394. package/ui/i18n.js +484 -0
  395. package/ui/log-parser.js +30 -0
  396. package/ui/pages/audit.html +12 -0
  397. package/ui/pages/dashboard.html +94 -147
  398. package/ui/pages/direct-sessions.html +123 -26
  399. package/ui/pages/getting-started.html +43 -0
  400. package/ui/pages/logs.html +134 -22
  401. package/ui/pages/settings.html +101 -0
  402. package/ui/pages/task-detail.html +12 -0
  403. package/ui/pages/tasks.html +54 -8
  404. package/ui/pages/workspace.html +38 -1
  405. package/ui/settings.js +254 -0
  406. package/PatchWarden-Control.cmd +0 -6
  407. package/Restart-PatchWarden-Control.cmd +0 -6
  408. package/dist/test/unit/acceptance-engine.test.d.ts +0 -1
  409. package/dist/test/unit/acceptance-engine.test.js +0 -228
  410. package/dist/test/unit/agent-router.test.d.ts +0 -1
  411. package/dist/test/unit/agent-router.test.js +0 -287
  412. package/dist/test/unit/android-doctor.test.d.ts +0 -1
  413. package/dist/test/unit/android-doctor.test.js +0 -118
  414. package/dist/test/unit/apply-patch.test.d.ts +0 -1
  415. package/dist/test/unit/apply-patch.test.js +0 -225
  416. package/dist/test/unit/audit-checks.test.d.ts +0 -1
  417. package/dist/test/unit/audit-checks.test.js +0 -350
  418. package/dist/test/unit/chinese-path.test.d.ts +0 -1
  419. package/dist/test/unit/chinese-path.test.js +0 -91
  420. package/dist/test/unit/command-guard.test.d.ts +0 -1
  421. package/dist/test/unit/command-guard.test.js +0 -160
  422. package/dist/test/unit/create-task.test.d.ts +0 -1
  423. package/dist/test/unit/create-task.test.js +0 -197
  424. package/dist/test/unit/diagnose-task.test.d.ts +0 -1
  425. package/dist/test/unit/diagnose-task.test.js +0 -457
  426. package/dist/test/unit/direct-guards.test.d.ts +0 -1
  427. package/dist/test/unit/direct-guards.test.js +0 -328
  428. package/dist/test/unit/discovery-token-store.test.d.ts +0 -1
  429. package/dist/test/unit/discovery-token-store.test.js +0 -139
  430. package/dist/test/unit/evidence-pack.test.d.ts +0 -1
  431. package/dist/test/unit/evidence-pack.test.js +0 -224
  432. package/dist/test/unit/get-task-status.test.d.ts +0 -1
  433. package/dist/test/unit/get-task-status.test.js +0 -174
  434. package/dist/test/unit/get-task-summary.test.d.ts +0 -1
  435. package/dist/test/unit/get-task-summary.test.js +0 -146
  436. package/dist/test/unit/goal-graph.test.d.ts +0 -1
  437. package/dist/test/unit/goal-graph.test.js +0 -298
  438. package/dist/test/unit/goal-progress.test.d.ts +0 -1
  439. package/dist/test/unit/goal-progress.test.js +0 -381
  440. package/dist/test/unit/goal-report.test.d.ts +0 -1
  441. package/dist/test/unit/goal-report.test.js +0 -159
  442. package/dist/test/unit/goal-status.test.d.ts +0 -1
  443. package/dist/test/unit/goal-status.test.js +0 -215
  444. package/dist/test/unit/goal-store.test.d.ts +0 -1
  445. package/dist/test/unit/goal-store.test.js +0 -253
  446. package/dist/test/unit/goal-subgoal-task.test.d.ts +0 -1
  447. package/dist/test/unit/goal-subgoal-task.test.js +0 -55
  448. package/dist/test/unit/goal-tools-registry.test.d.ts +0 -1
  449. package/dist/test/unit/goal-tools-registry.test.js +0 -192
  450. package/dist/test/unit/handoff-export.test.d.ts +0 -1
  451. package/dist/test/unit/handoff-export.test.js +0 -263
  452. package/dist/test/unit/invoke-discovered-tool.test.d.ts +0 -1
  453. package/dist/test/unit/invoke-discovered-tool.test.js +0 -167
  454. package/dist/test/unit/logging.test.d.ts +0 -1
  455. package/dist/test/unit/logging.test.js +0 -397
  456. package/dist/test/unit/path-guard.test.d.ts +0 -1
  457. package/dist/test/unit/path-guard.test.js +0 -133
  458. package/dist/test/unit/post-task-cleanup.test.d.ts +0 -1
  459. package/dist/test/unit/post-task-cleanup.test.js +0 -48
  460. package/dist/test/unit/project-policy-release-mode.test.d.ts +0 -1
  461. package/dist/test/unit/project-policy-release-mode.test.js +0 -125
  462. package/dist/test/unit/reconcile-tasks.test.d.ts +0 -1
  463. package/dist/test/unit/reconcile-tasks.test.js +0 -456
  464. package/dist/test/unit/release-gate.test.d.ts +0 -1
  465. package/dist/test/unit/release-gate.test.js +0 -242
  466. package/dist/test/unit/run-task-loop.test.d.ts +0 -1
  467. package/dist/test/unit/run-task-loop.test.js +0 -380
  468. package/dist/test/unit/safe-status.test.d.ts +0 -1
  469. package/dist/test/unit/safe-status.test.js +0 -165
  470. package/dist/test/unit/safe-views.test.d.ts +0 -1
  471. package/dist/test/unit/safe-views.test.js +0 -171
  472. package/dist/test/unit/schema-drift-check.test.d.ts +0 -1
  473. package/dist/test/unit/schema-drift-check.test.js +0 -176
  474. package/dist/test/unit/sensitive-guard.test.d.ts +0 -1
  475. package/dist/test/unit/sensitive-guard.test.js +0 -104
  476. package/dist/test/unit/spec-kit-import.test.d.ts +0 -1
  477. package/dist/test/unit/spec-kit-import.test.js +0 -341
  478. package/dist/test/unit/subgoal-sync.test.d.ts +0 -1
  479. package/dist/test/unit/subgoal-sync.test.js +0 -183
  480. package/dist/test/unit/sync-file.test.d.ts +0 -1
  481. package/dist/test/unit/sync-file.test.js +0 -154
  482. package/dist/test/unit/tool-invocation-guard.test.d.ts +0 -1
  483. package/dist/test/unit/tool-invocation-guard.test.js +0 -432
  484. package/dist/test/unit/tool-usage-stats.test.d.ts +0 -1
  485. package/dist/test/unit/tool-usage-stats.test.js +0 -300
  486. package/dist/test/unit/toolSearch.test.d.ts +0 -1
  487. package/dist/test/unit/toolSearch.test.js +0 -571
  488. package/dist/test/unit/wait-for-task.test.d.ts +0 -1
  489. package/dist/test/unit/wait-for-task.test.js +0 -144
  490. package/dist/test/unit/watcher-status.test.d.ts +0 -1
  491. package/dist/test/unit/watcher-status.test.js +0 -169
  492. package/dist/test/unit/worktree-manager.test.d.ts +0 -1
  493. package/dist/test/unit/worktree-manager.test.js +0 -176
  494. package/dist/tools/applyPatch.js +0 -41
  495. package/dist/tools/cancelTask.d.ts +0 -30
  496. package/dist/tools/cancelTask.js +0 -64
  497. package/dist/tools/finalizeDirectSession.js +0 -84
  498. package/dist/tools/goalSubgoalTask.js +0 -110
  499. package/dist/tools/killTask.d.ts +0 -15
  500. package/dist/tools/listAgents.d.ts +0 -12
  501. package/dist/tools/listAgents.js +0 -42
  502. package/dist/tools/reconcileTasks.js +0 -352
  503. package/dist/tools/retryTask.js +0 -45
  504. package/dist/tools/runVerification.js +0 -36
  505. package/dist/tools/syncFile.js +0 -65
  506. package/docs/control-center/control-center-daily-driver.md +0 -211
  507. package/docs/control-center/control-center-mvp.md +0 -205
  508. package/docs/control-center/control-center-phase2.md +0 -159
  509. package/docs/execution-plan-2026-07-09.md +0 -315
  510. package/docs/release-v0.6.0.md +0 -71
  511. package/docs/release-v0.6.1.md +0 -75
  512. package/docs/release-v0.6.4.md +0 -45
  513. package/docs/roadmap-execution-and-acceptance.md +0 -365
  514. package/src/test/unit/acceptance-engine.test.ts +0 -261
  515. package/src/test/unit/agent-router.test.ts +0 -342
  516. package/src/test/unit/android-doctor.test.ts +0 -158
  517. package/src/test/unit/apply-patch.test.ts +0 -293
  518. package/src/test/unit/audit-checks.test.ts +0 -567
  519. package/src/test/unit/chinese-path.test.ts +0 -106
  520. package/src/test/unit/command-guard.test.ts +0 -221
  521. package/src/test/unit/create-task.test.ts +0 -255
  522. package/src/test/unit/diagnose-task.test.ts +0 -544
  523. package/src/test/unit/direct-guards.test.ts +0 -467
  524. package/src/test/unit/discovery-token-store.test.ts +0 -181
  525. package/src/test/unit/evidence-pack.test.ts +0 -251
  526. package/src/test/unit/get-task-status.test.ts +0 -203
  527. package/src/test/unit/get-task-summary.test.ts +0 -173
  528. package/src/test/unit/goal-graph.test.ts +0 -347
  529. package/src/test/unit/goal-progress.test.ts +0 -538
  530. package/src/test/unit/goal-report.test.ts +0 -189
  531. package/src/test/unit/goal-status.test.ts +0 -270
  532. package/src/test/unit/goal-store.test.ts +0 -318
  533. package/src/test/unit/goal-subgoal-task.test.ts +0 -72
  534. package/src/test/unit/goal-tools-registry.test.ts +0 -245
  535. package/src/test/unit/handoff-export.test.ts +0 -295
  536. package/src/test/unit/invoke-discovered-tool.test.ts +0 -216
  537. package/src/test/unit/logging.test.ts +0 -497
  538. package/src/test/unit/path-guard.test.ts +0 -180
  539. package/src/test/unit/post-task-cleanup.test.ts +0 -53
  540. package/src/test/unit/project-policy-release-mode.test.ts +0 -156
  541. package/src/test/unit/reconcile-tasks.test.ts +0 -551
  542. package/src/test/unit/release-gate.test.ts +0 -314
  543. package/src/test/unit/run-task-loop.test.ts +0 -425
  544. package/src/test/unit/safe-status.test.ts +0 -187
  545. package/src/test/unit/safe-views.test.ts +0 -184
  546. package/src/test/unit/schema-drift-check.test.ts +0 -260
  547. package/src/test/unit/sensitive-guard.test.ts +0 -124
  548. package/src/test/unit/spec-kit-import.test.ts +0 -429
  549. package/src/test/unit/subgoal-sync.test.ts +0 -236
  550. package/src/test/unit/sync-file.test.ts +0 -231
  551. package/src/test/unit/tool-invocation-guard.test.ts +0 -542
  552. package/src/test/unit/tool-usage-stats.test.ts +0 -384
  553. package/src/test/unit/toolSearch.test.ts +0 -756
  554. package/src/test/unit/wait-for-task.test.ts +0 -176
  555. package/src/test/unit/watcher-status.test.ts +0 -190
  556. package/src/test/unit/worktree-manager.test.ts +0 -247
  557. package/src/tools/cancelTask.ts +0 -70
  558. package/src/tools/listAgents.ts +0 -54
  559. package/src/tools/retryTask.ts +0 -53
  560. package/src/tools/syncFile.ts +0 -122
  561. /package/dist/tools/{toolCatalog.d.ts → catalog/toolCatalog.d.ts} +0 -0
  562. /package/dist/tools/{toolSearch.d.ts → catalog/toolSearch.d.ts} +0 -0
  563. /package/dist/tools/{toolSearch.js → catalog/toolSearch.js} +0 -0
  564. /package/dist/tools/{toolUsageStats.d.ts → catalog/toolUsageStats.d.ts} +0 -0
  565. /package/dist/tools/{toolUsageStats.js → catalog/toolUsageStats.js} +0 -0
  566. /package/dist/tools/{createDirectSession.d.ts → direct/createDirectSession.d.ts} +0 -0
  567. /package/dist/tools/{runDirectVerificationBundle.d.ts → direct/runDirectVerificationBundle.d.ts} +0 -0
  568. /package/dist/tools/{getPlan.d.ts → goals/getPlan.d.ts} +0 -0
  569. /package/dist/tools/{savePlan.d.ts → goals/savePlan.d.ts} +0 -0
  570. /package/dist/tools/{evidencePack.d.ts → tasks/evidencePack.d.ts} +0 -0
  571. /package/dist/tools/{getTaskFile.d.ts → tasks/getTaskFile.d.ts} +0 -0
  572. /package/dist/tools/{getTaskProgress.d.ts → tasks/getTaskProgress.d.ts} +0 -0
  573. /package/dist/tools/{getTaskProgress.js → tasks/getTaskProgress.js} +0 -0
  574. /package/dist/tools/{getTaskStdoutTail.d.ts → tasks/getTaskStdoutTail.d.ts} +0 -0
  575. /package/dist/tools/{getTaskSummary.d.ts → tasks/getTaskSummary.d.ts} +0 -0
  576. /package/dist/tools/{killTask.js → tasks/killTask.js} +0 -0
  577. /package/dist/tools/{retryTask.d.ts → tasks/retryTask.d.ts} +0 -0
  578. /package/dist/tools/{runVerification.d.ts → tasks/runVerification.d.ts} +0 -0
  579. /package/dist/tools/{taskLineage.d.ts → tasks/taskLineage.d.ts} +0 -0
  580. /package/dist/tools/{waitForTask.d.ts → tasks/waitForTask.d.ts} +0 -0
  581. /package/dist/tools/{androidDoctor.d.ts → workspace/androidDoctor.d.ts} +0 -0
  582. /package/dist/tools/{discardWorktree.d.ts → workspace/discardWorktree.d.ts} +0 -0
  583. /package/dist/tools/{listWorkspace.d.ts → workspace/listWorkspace.d.ts} +0 -0
  584. /package/dist/tools/{mergeWorktree.d.ts → workspace/mergeWorktree.d.ts} +0 -0
  585. /package/dist/tools/{readWorkspaceFile.d.ts → workspace/readWorkspaceFile.d.ts} +0 -0
  586. /package/dist/tools/{recommendAgentForTask.d.ts → workspace/recommendAgentForTask.d.ts} +0 -0
  587. /package/dist/tools/{searchWorkspace.d.ts → workspace/searchWorkspace.d.ts} +0 -0
  588. /package/src/tools/{toolSearch.ts → catalog/toolSearch.ts} +0 -0
  589. /package/src/tools/{toolUsageStats.ts → catalog/toolUsageStats.ts} +0 -0
  590. /package/src/tools/{getTaskProgress.ts → tasks/getTaskProgress.ts} +0 -0
  591. /package/src/tools/{killTask.ts → tasks/killTask.ts} +0 -0
@@ -133,6 +133,8 @@ html.dark {
133
133
  background-color: currentColor;
134
134
  }
135
135
  </style>
136
+ <script src="/desktop-bootstrap.js"></script>
137
+ <link rel="stylesheet" href="/desktop.css">
136
138
  </head>
137
139
  <body class="flex h-screen overflow-hidden">
138
140
 
@@ -150,6 +152,10 @@ html.dark {
150
152
 
151
153
  <!-- Navigation -->
152
154
  <nav class="flex-1 flex flex-col gap-1 px-3 pt-4 overflow-y-auto">
155
+ <a href="/pages/getting-started.html" data-nav-key="getting-started" class="desktop-only-nav flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium transition-colors truncate" style="color: var(--pw-text-secondary); font-family: var(--pw-font-sans);">
156
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="shrink-0"><path d="M4.5 16.5c-1.5 1.26-2 5-2 5s3.74-.5 5-2c.71-.84.7-2.13-.09-2.91a2.18 2.18 0 0 0-2.91-.09z"/><path d="m12 15-3-3a22 22 0 0 1 2-3.95A12.87 12.87 0 0 1 22 2c0 2.72-.78 7.5-6.05 11a22.35 22.35 0 0 1-3.95 2z"/></svg>
157
+ <span class="truncate" data-i18n="nav.gettingStarted">开始使用</span>
158
+ </a>
153
159
 
154
160
  <a href="/pages/dashboard.html" data-nav-key="dashboard" data-active="true" class="flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium transition-colors truncate" style="color: var(--pw-text-secondary); font-family: var(--pw-font-sans);">
155
161
  <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="shrink-0">
@@ -205,6 +211,10 @@ html.dark {
205
211
  <span class="truncate" data-zh="日志" data-en="Logs">日志</span>
206
212
  </a>
207
213
 
214
+ <a href="/pages/settings.html" data-nav-key="settings" class="desktop-only-nav flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium transition-colors truncate" style="color: var(--pw-text-secondary); font-family: var(--pw-font-sans);">
215
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="shrink-0"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.7 1.7 0 0 0 .3 1.9l.1.1-2.8 2.8-.1-.1a1.7 1.7 0 0 0-1.9-.3 1.7 1.7 0 0 0-1 1.6v.2h-4V21a1.7 1.7 0 0 0-1-1.6 1.7 1.7 0 0 0-1.9.3l-.1.1L4.2 17l.1-.1a1.7 1.7 0 0 0 .3-1.9A1.7 1.7 0 0 0 3 14H2.8v-4H3a1.7 1.7 0 0 0 1.6-1 1.7 1.7 0 0 0-.3-1.9L4.2 7 7 4.2l.1.1A1.7 1.7 0 0 0 9 4.6 1.7 1.7 0 0 0 10 3V2.8h4V3a1.7 1.7 0 0 0 1 1.6 1.7 1.7 0 0 0 1.9-.3l.1-.1L19.8 7l-.1.1a1.7 1.7 0 0 0-.3 1.9A1.7 1.7 0 0 0 21 10h.2v4H21a1.7 1.7 0 0 0-1.6 1z"/></svg>
216
+ <span class="truncate" data-i18n="nav.settings">设置</span>
217
+ </a>
208
218
  </nav>
209
219
 
210
220
  <!-- Bottom Section -->
@@ -238,63 +248,67 @@ html.dark {
238
248
  <main class="flex-1 overflow-y-auto p-6" style="background-color: var(--pw-bg-elevated);">
239
249
 
240
250
  <!-- ===== TOP TOOLBAR ===== -->
241
- <div class="flex flex-wrap items-center gap-2 mb-4">
251
+ <div class="pw-dashboard-toolbar mb-4">
252
+ <div class="pw-toolbar-actions">
242
253
  <button data-action="start-all" class="flex items-center gap-1.5 px-3.5 py-2 rounded-lg text-sm font-medium transition-colors whitespace-nowrap" style="background-color: var(--pw-state-success); color: var(--pw-text-inverse); font-family: var(--pw-font-sans);">
243
254
  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polygon points="5 3 19 12 5 21 5 3"/></svg>
244
- <span>Start All</span>
255
+ <span data-zh="全部启动" data-en="Start All">全部启动</span>
245
256
  </button>
246
257
  <button data-action="stop-all" class="flex items-center gap-1.5 px-3.5 py-2 rounded-lg text-sm font-medium transition-colors whitespace-nowrap" style="background-color: var(--pw-state-error); color: #fff; font-family: var(--pw-font-sans);">
247
258
  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><rect x="6" y="6" width="12" height="12" rx="1"/></svg>
248
- <span>Stop All</span>
259
+ <span data-zh="全部停止" data-en="Stop All">全部停止</span>
249
260
  </button>
250
261
  <button data-action="restart-all" class="flex items-center gap-1.5 px-3.5 py-2 rounded-lg text-sm font-medium transition-colors whitespace-nowrap" style="background-color: var(--pw-state-warning); color: var(--pw-text-inverse); font-family: var(--pw-font-sans);">
251
262
  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8"/><path d="M21 3v5h-5"/><path d="M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16"/><path d="M3 21v-5h5"/></svg>
252
- <span>Restart All</span>
263
+ <span data-zh="全部重启" data-en="Restart All">全部重启</span>
253
264
  </button>
254
265
  <button data-action="refresh" class="flex items-center gap-1.5 px-3.5 py-2 rounded-lg text-sm font-medium transition-colors whitespace-nowrap" style="background-color: var(--pw-bg-surface); color: var(--pw-text-primary); border: 1px solid var(--pw-border); font-family: var(--pw-font-sans);">
255
266
  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8"/><path d="M21 3v5h-5"/><path d="M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16"/><path d="M3 21v-5h5"/></svg>
256
- <span>Refresh</span>
267
+ <span data-zh="刷新" data-en="Refresh">刷新</span>
257
268
  </button>
258
- <div class="flex items-center gap-2 px-3 py-1.5 rounded-lg" style="background-color: var(--pw-bg-surface); border: 1px solid var(--pw-border); font-family: var(--pw-font-sans);">
269
+ </div>
270
+ <div class="pw-toolbar-repo flex items-center gap-2 px-3 py-1.5 rounded-lg" style="background-color: var(--pw-bg-surface); border: 1px solid var(--pw-border); font-family: var(--pw-font-sans);">
259
271
  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="color: var(--pw-text-tertiary);"><path d="M4 20h16a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.93a2 2 0 0 1-1.66-.9l-.82-1.2A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13c0 1.1.9 2 2 2z"/></svg>
260
272
  <select id="repo-selector" class="bg-transparent text-sm outline-none cursor-pointer" style="color: var(--pw-text-primary); font-family: var(--pw-font-sans); min-width: 180px;">
261
- <option value=".">workspace root</option>
273
+ <option value=".">工作区根目录</option>
262
274
  </select>
263
275
  </div>
264
- <div class="flex-1 min-w-0"></div>
276
+ <div class="pw-toolbar-links">
265
277
  <button data-action="open-core-tunnel" class="flex items-center gap-1.5 px-3.5 py-2 rounded-lg text-sm font-medium transition-colors whitespace-nowrap" style="background-color: transparent; color: var(--pw-accent); border: 1px solid var(--pw-accent); font-family: var(--pw-font-sans);">
266
278
  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg>
267
- <span>Open Core Tunnel UI</span>
279
+ <span data-zh="Core 隧道" data-en="Open Core Tunnel UI">Core 隧道</span>
268
280
  </button>
269
281
  <button data-action="open-direct-tunnel" class="flex items-center gap-1.5 px-3.5 py-2 rounded-lg text-sm font-medium transition-colors whitespace-nowrap" style="background-color: transparent; color: var(--pw-accent); border: 1px solid var(--pw-accent); font-family: var(--pw-font-sans);">
270
282
  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg>
271
- <span>Open Direct Tunnel UI</span>
283
+ <span data-zh="Direct 隧道" data-en="Open Direct Tunnel UI">Direct 隧道</span>
272
284
  </button>
273
285
  <button data-action="open-logs-folder" class="flex items-center gap-1.5 px-3.5 py-2 rounded-lg text-sm font-medium transition-colors whitespace-nowrap" style="background-color: var(--pw-bg-surface); color: var(--pw-text-primary); border: 1px solid var(--pw-border); font-family: var(--pw-font-sans);">
274
286
  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 20h16a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.93a2 2 0 0 1-1.66-.9l-.82-1.2A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13c0 1.1.9 2 2 2z"/></svg>
275
- <span>Open Logs Folder</span>
287
+ <span data-zh="日志目录" data-en="Open Logs Folder">日志目录</span>
276
288
  </button>
289
+ </div>
277
290
  </div>
278
291
 
279
292
  <!-- ===== ERROR BANNER ===== -->
280
293
  <div id="error-banner" class="hidden mb-4 rounded-lg px-4 py-3 text-sm" style="background-color: var(--pw-state-error-bg); border: 1px solid var(--pw-state-error); color: var(--pw-state-error); font-family: var(--pw-font-sans);"></div>
281
294
 
282
- <!-- ===== HEALTH SCORE CARD ===== -->
295
+ <!-- ===== LIVE READINESS CARD ===== -->
296
+ <div class="mb-2"><h2 class="text-xs font-semibold uppercase tracking-wide" style="color:var(--pw-text-tertiary);" data-zh="运行状态" data-en="Live status">运行状态</h2></div>
283
297
  <div id="health-score-card" class="rounded-lg mb-4" style="background-color: var(--pw-bg-surface); border: 1px solid var(--pw-border);">
284
298
  <div class="flex items-center justify-between px-4 py-3" style="border-bottom: 1px solid var(--pw-border);">
285
- <h2 class="text-sm font-semibold truncate" data-zh="健康评分" data-en="Health Score" style="color: var(--pw-text-primary); font-family: var(--pw-font-sans);">健康评分</h2>
299
+ <h2 class="text-sm font-semibold truncate" data-zh="实时就绪状态" data-en="Live Readiness" style="color: var(--pw-text-primary); font-family: var(--pw-font-sans);">实时就绪状态</h2>
286
300
  <span id="health-score-badge" class="text-xs font-semibold px-2.5 py-1 rounded-full whitespace-nowrap" style="color: var(--pw-text-tertiary); background-color: var(--pw-bg-hover);">—</span>
287
301
  </div>
288
302
  <div id="health-score-body" class="px-4 py-3 grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-2">
289
- <div class="text-xs" style="color: var(--pw-text-tertiary);">loading…</div>
303
+ <div class="text-xs" style="color: var(--pw-text-tertiary);">正在加载…</div>
290
304
  </div>
291
305
  </div>
292
306
 
293
307
  <!-- ===== SETUP CHECKLIST ===== -->
294
308
  <div id="setup-checklist-card" class="rounded-lg mb-4" style="background-color: var(--pw-bg-surface); border: 1px solid var(--pw-border);">
295
309
  <div class="flex items-center justify-between px-4 py-3" style="border-bottom: 1px solid var(--pw-border);">
296
- <h2 class="text-sm font-semibold truncate" style="color: var(--pw-text-primary);">Setup checklist</h2>
297
- <span id="setup-checklist-summary" class="text-xs whitespace-nowrap" style="color: var(--pw-text-tertiary);">checking</span>
310
+ <h2 class="text-sm font-semibold truncate" style="color: var(--pw-text-primary);">启动准备</h2>
311
+ <span id="setup-checklist-summary" class="text-xs whitespace-nowrap" style="color: var(--pw-text-tertiary);">正在检查</span>
298
312
  </div>
299
313
  <div id="setup-checklist-body" class="grid grid-cols-1 md:grid-cols-3 gap-0"></div>
300
314
  </div>
@@ -313,6 +327,7 @@ html.dark {
313
327
  </div>
314
328
 
315
329
  <!-- ===== HEALTH SUGGESTIONS CARD ===== -->
330
+ <div class="mb-2"><h2 class="text-xs font-semibold uppercase tracking-wide" style="color:var(--pw-text-tertiary);" data-zh="待处理项" data-en="Needs attention">待处理项</h2></div>
316
331
  <div id="suggestions-card" class="hidden rounded-lg mb-6" style="background-color: var(--pw-bg-surface); border: 1px solid var(--pw-border);">
317
332
  <div class="flex items-center justify-between px-4 py-3" style="border-bottom: 1px solid var(--pw-border);">
318
333
  <h2 class="text-sm font-semibold truncate" data-zh="健康建议" data-en="Health Suggestions" style="color: var(--pw-text-primary);">健康建议</h2>
@@ -322,44 +337,45 @@ html.dark {
322
337
  </div>
323
338
 
324
339
  <!-- ===== V1.5 RELEASE / POLICY / LINEAGE / EVIDENCE OVERVIEW ===== -->
340
+ <div class="mb-2 flex items-center justify-between gap-3"><h2 class="text-xs font-semibold uppercase tracking-wide" style="color:var(--pw-text-tertiary);" data-zh="历史概览" data-en="History overview">历史概览</h2><span class="text-xs" style="color:var(--pw-text-tertiary);" data-zh="历史任务、审计和发布检查不影响实时健康" data-en="History, audits, and release checks do not affect live health">历史任务、审计和发布检查不影响实时健康</span></div>
325
341
  <div class="grid grid-cols-1 lg:grid-cols-4 gap-4 mb-6">
326
342
  <div class="rounded-lg" style="background-color: var(--pw-bg-surface); border: 1px solid var(--pw-border);">
327
343
  <div class="flex items-center justify-between px-4 py-3" style="border-bottom: 1px solid var(--pw-border);">
328
- <h2 class="text-sm font-semibold truncate" style="color: var(--pw-text-primary);">Lineage</h2>
344
+ <h2 class="text-sm font-semibold truncate" style="color: var(--pw-text-primary);">任务链路</h2>
329
345
  <span id="lineage-count" class="text-xs whitespace-nowrap" style="color: var(--pw-text-tertiary);">...</span>
330
346
  </div>
331
- <div id="lineage-overview-body" class="px-4 py-3 text-sm" style="color: var(--pw-text-tertiary);">Loading</div>
347
+ <div id="lineage-overview-body" class="px-4 py-3 text-sm" style="color: var(--pw-text-tertiary);">正在加载…</div>
332
348
  </div>
333
349
  <div class="rounded-lg" style="background-color: var(--pw-bg-surface); border: 1px solid var(--pw-border);">
334
350
  <div class="flex items-center justify-between px-4 py-3" style="border-bottom: 1px solid var(--pw-border);">
335
- <h2 class="text-sm font-semibold truncate" style="color: var(--pw-text-primary);">Project Policy</h2>
351
+ <h2 class="text-sm font-semibold truncate" style="color: var(--pw-text-primary);">项目策略</h2>
336
352
  <span id="policy-status" class="text-xs whitespace-nowrap" style="color: var(--pw-text-tertiary);">...</span>
337
353
  </div>
338
- <div id="policy-overview-body" class="px-4 py-3 text-sm" style="color: var(--pw-text-tertiary);">Loading</div>
354
+ <div id="policy-overview-body" class="px-4 py-3 text-sm" style="color: var(--pw-text-tertiary);">正在加载…</div>
339
355
  </div>
340
356
  <div class="rounded-lg" style="background-color: var(--pw-bg-surface); border: 1px solid var(--pw-border);">
341
357
  <div class="flex items-center justify-between px-4 py-3" style="border-bottom: 1px solid var(--pw-border);">
342
- <h2 class="text-sm font-semibold truncate" style="color: var(--pw-text-primary);">Release</h2>
358
+ <h2 class="text-sm font-semibold truncate" style="color: var(--pw-text-primary);">发布检查</h2>
343
359
  <span id="release-status" class="text-xs whitespace-nowrap" style="color: var(--pw-text-tertiary);">...</span>
344
360
  </div>
345
- <div id="release-overview-body" class="px-4 py-3 text-sm" style="color: var(--pw-text-tertiary);">Loading</div>
361
+ <div id="release-overview-body" class="px-4 py-3 text-sm" style="color: var(--pw-text-tertiary);">正在加载…</div>
346
362
  </div>
347
363
  <div id="evidence-pack-card" class="rounded-lg" style="background-color: var(--pw-bg-surface); border: 1px solid var(--pw-border);">
348
364
  <div class="flex items-center justify-between px-4 py-3" style="border-bottom: 1px solid var(--pw-border);">
349
- <h2 class="text-sm font-semibold truncate" style="color: var(--pw-text-primary);">Evidence Pack</h2>
365
+ <h2 class="text-sm font-semibold truncate" style="color: var(--pw-text-primary);">证据包</h2>
350
366
  <span id="evidence-pack-status" class="text-xs whitespace-nowrap" style="color: var(--pw-text-tertiary);">...</span>
351
367
  </div>
352
- <div id="evidence-pack-overview-body" class="px-4 py-3 text-sm" style="color: var(--pw-text-tertiary);">Loading</div>
368
+ <div id="evidence-pack-overview-body" class="px-4 py-3 text-sm" style="color: var(--pw-text-tertiary);">正在加载…</div>
353
369
  </div>
354
370
  </div>
355
371
 
356
372
  <!-- ===== STALE TASKS CARD ===== -->
357
373
  <div id="stale-tasks-card" class="hidden rounded-lg mb-6" style="background-color: var(--pw-bg-surface); border: 1px solid var(--pw-border); border-left: 3px solid var(--pw-state-warning);">
358
374
  <div class="flex items-center justify-between px-4 py-3" style="border-bottom: 1px solid var(--pw-border);">
359
- <h2 class="text-sm font-semibold truncate" data-zh="Stale 任务" data-en="Stale Tasks" style="color: var(--pw-text-primary);">Stale 任务</h2>
375
+ <h2 class="text-sm font-semibold truncate" data-zh="过期任务" data-en="Stale Tasks" style="color: var(--pw-text-primary);">过期任务</h2>
360
376
  <span id="stale-tasks-count" class="text-xs whitespace-nowrap" style="color: var(--pw-text-tertiary);">—</span>
361
377
  </div>
362
- <div id="stale-tasks-body" class="px-4 py-3 text-sm" style="color: var(--pw-text-tertiary);">Loading</div>
378
+ <div id="stale-tasks-body" class="px-4 py-3 text-sm" style="color: var(--pw-text-tertiary);">正在加载…</div>
363
379
  </div>
364
380
 
365
381
  <!-- ===== TWO-COLUMN LAYOUT ===== -->
@@ -396,7 +412,7 @@ html.dark {
396
412
  <div class="rounded-lg mb-6" style="background-color: var(--pw-bg-surface); border: 1px solid var(--pw-border);">
397
413
  <div class="flex items-center justify-between px-4 py-3" style="border-bottom: 1px solid var(--pw-border);">
398
414
  <h2 class="text-sm font-semibold truncate" data-zh="活动日志" data-en="Activity Log" style="color: var(--pw-text-primary);">活动日志</h2>
399
- <span class="text-xs whitespace-nowrap" style="color: var(--pw-text-tertiary);">Core + Direct stdout 尾部</span>
415
+ <span class="text-xs whitespace-nowrap" style="color: var(--pw-text-tertiary);">Core + Direct 输出摘要</span>
400
416
  </div>
401
417
  <div id="activity-log-body">
402
418
  <div class="px-4 py-3 text-xs" style="color: var(--pw-text-tertiary);">加载日志中…</div>
@@ -736,26 +752,26 @@ html.dark {
736
752
  {
737
753
  label: 'tunnel-client.exe',
738
754
  ok: !!tunnel.available,
739
- value: tunnel.available ? (tunnel.path || 'available') : 'missing',
740
- hint: tunnel.available ? 'Ready for Web UI and tray start/restart.' : 'Expected at TUNNEL_CLIENT_EXE, PATCHWARDEN_TUNNEL_CLIENT_EXE, PATH, or the saved D:\\ai_agent tunnel-client folder.'
755
+ value: tunnel.available ? (tunnel.path || '已找到') : '未找到',
756
+ hint: tunnel.available ? '已可供桌面启动和重启使用。' : '请在设置中自动检测或选择 tunnel-client.exe。'
741
757
  },
742
758
  {
743
- label: 'workspaceRoot',
759
+ label: '工作区',
744
760
  ok: !!workspaceRoot,
745
- value: workspaceRoot || 'not loaded',
746
- hint: 'This is the workspace currently managed by PatchWarden tasks.'
761
+ value: workspaceRoot || '未加载',
762
+ hint: 'PatchWarden 任务仅在此工作区内运行。'
747
763
  },
748
764
  {
749
- label: 'Watcher',
765
+ label: '任务监视器',
750
766
  ok: watcher.status === 'healthy',
751
- value: watcher.status || 'missing',
752
- hint: watcher.status === 'healthy' ? 'Task execution watcher is healthy.' : (watcher.reason || 'Start Core/Watcher when you want queued tasks to execute.')
767
+ value: watcher.status || '未运行',
768
+ hint: watcher.status === 'healthy' ? '任务监视器运行正常。' : (watcher.reason || '启动 Core 后,任务监视器会处理排队任务。')
753
769
  }
754
770
  ];
755
771
 
756
772
  const missingCount = items.filter(function (item) { return !item.ok; }).length;
757
773
  if (summary) {
758
- summary.textContent = missingCount === 0 ? 'ready' : (missingCount + ' needs attention');
774
+ summary.textContent = missingCount === 0 ? '已就绪' : (missingCount + ' 项需要处理');
759
775
  summary.style.color = missingCount === 0 ? 'var(--pw-state-success)' : 'var(--pw-state-warning)';
760
776
  }
761
777
 
@@ -768,7 +784,7 @@ html.dark {
768
784
  + '<div class="flex items-center gap-2 mb-1">'
769
785
  + dotHtml(kind)
770
786
  + '<span class="text-xs font-semibold whitespace-nowrap" style="color: var(--pw-text-primary); font-family: var(--pw-font-mono);">' + escapeHtml(item.label) + '</span>'
771
- + '<span class="ml-auto text-xs px-2 py-0.5 rounded-full" style="color: ' + c.color + '; background-color: ' + c.bg + ';">' + (item.ok ? 'ok' : 'check') + '</span>'
787
+ + '<span class="ml-auto text-xs px-2 py-0.5 rounded-full" style="color: ' + c.color + '; background-color: ' + c.bg + ';">' + (item.ok ? '正常' : '处理') + '</span>'
772
788
  + '</div>'
773
789
  + '<div class="text-xs truncate" style="color: var(--pw-text-secondary); font-family: var(--pw-font-mono);" title="' + escapeHtml(item.value) + '">' + escapeHtml(item.value) + '</div>'
774
790
  + '<div class="text-xs mt-1" style="color: var(--pw-text-tertiary);">' + escapeHtml(item.hint) + '</div>'
@@ -946,9 +962,11 @@ html.dark {
946
962
  let data = null;
947
963
  try { data = await res.json(); } catch (_) { /* ignore */ }
948
964
  if (!res.ok) {
949
- const msg = (data && (data.error || data.reason || data.message)) || ('HTTP ' + res.status);
965
+ var msg = (data && (data.error || data.reason || data.message)) || ('HTTP ' + res.status);
966
+ if (data && Array.isArray(data.next_steps) && data.next_steps.length) msg += ' 下一步:' + data.next_steps.join(';');
950
967
  throw new Error(msg);
951
968
  }
969
+ if (data && data.ok === false) throw new Error(data.error || data.reason || '操作未完成');
952
970
  return data;
953
971
  } finally {
954
972
  if (btnEl) {
@@ -1114,6 +1132,7 @@ html.dark {
1114
1132
  const svc = (status && status[prefix]) || {};
1115
1133
  const tunnel = (status && status.tunnel && status.tunnel[prefix]) || {};
1116
1134
  const tools = (status && status.tools && status.tools[prefix]) || {};
1135
+ const connection = (status && status.connections && status.connections[prefix]) || {};
1117
1136
 
1118
1137
  const available = !!svc.available;
1119
1138
  const kind = available ? 'success' : 'error';
@@ -1122,6 +1141,9 @@ html.dark {
1122
1141
  const reasonText = svc.reason ? escapeHtml(svc.reason) : '—';
1123
1142
 
1124
1143
  const rows = [
1144
+ { label: 'profile', html: connection.profile ? escapeHtml(connection.profile) : '&mdash;' },
1145
+ { label: 'tunnel_id', html: connection.tunnel_id_masked ? escapeHtml(connection.tunnel_id_masked) : '&mdash;' },
1146
+ { label: 'reconnect', html: connection.reconnect_guidance ? escapeHtml(connection.reconnect_guidance) : '&mdash;' },
1125
1147
  { label: 'PID', html: tunnel.pid != null ? escapeHtml(tunnel.pid) : '—' },
1126
1148
  { label: 'tool_profile', html: tools.tool_profile ? escapeHtml(tools.tool_profile) : '—' },
1127
1149
  { label: 'tool_count', html: tools.tool_count != null ? escapeHtml(tools.tool_count) : '—' },
@@ -1167,11 +1189,12 @@ html.dark {
1167
1189
  const tunnel = (status && status.tunnel) || {};
1168
1190
  const tools = (status && status.tools && status.tools.core) || {};
1169
1191
  const agents = (status && status.agents) || [];
1192
+ const directProfileEnabled = !!(status && status.direct_profile_enabled);
1170
1193
 
1171
1194
  const watcherKind = statusKind(watcher.status);
1172
1195
  const coreReady = !!(tunnel.core && tunnel.core.ready);
1173
1196
  const directReady = !!(tunnel.direct && tunnel.direct.ready);
1174
- const tunnelReady = coreReady && directReady;
1197
+ const tunnelReady = coreReady && (!directProfileEnabled || directReady);
1175
1198
  const tunnelKind = tunnelReady ? 'success' : (coreReady || directReady ? 'warning' : 'error');
1176
1199
 
1177
1200
  let agentsHtml = '';
@@ -1201,7 +1224,7 @@ html.dark {
1201
1224
  row('Watcher',
1202
1225
  '<span class="text-xs whitespace-nowrap" style="color: var(--pw-text-primary); font-family: var(--pw-font-mono);">' + watcherText + '</span>',
1203
1226
  watcherKind)
1204
- + row('Tunnel ready',
1227
+ + row('隧道就绪',
1205
1228
  '<span class="text-xs whitespace-nowrap" style="color: var(--pw-text-primary); font-family: var(--pw-font-mono);">core ' + (coreReady ? '✓' : '✗') + ' / direct ' + (directReady ? '✓' : '✗') + '</span>',
1206
1229
  tunnelKind)
1207
1230
  + row('schema_epoch',
@@ -1339,7 +1362,7 @@ html.dark {
1339
1362
 
1340
1363
  el.innerHTML =
1341
1364
  '<details class="px-4 py-3">'
1342
- + '<summary class="cursor-pointer text-xs font-medium" style="color: var(--pw-text-primary); font-family: var(--pw-font-sans);">Show Core / Direct log tails</summary>'
1365
+ + '<summary class="cursor-pointer text-xs font-medium" style="color: var(--pw-text-primary); font-family: var(--pw-font-sans);">查看 Core / Direct 本次日志尾部</summary>'
1343
1366
  + '<pre class="mt-3 text-xs overflow-auto m-0" style="color: var(--pw-text-secondary); font-family: var(--pw-font-mono); white-space: pre-wrap; word-break: break-all; max-height: 320px;">' + escapeHtml(merged) + '</pre>'
1344
1367
  + '</details>';
1345
1368
  }
@@ -1355,10 +1378,10 @@ html.dark {
1355
1378
  if (count) count.textContent = String(data.total || lineages.length);
1356
1379
  if (!lineages.length) {
1357
1380
  body.innerHTML =
1358
- '<div class="text-xs mb-2" style="color: var(--pw-text-tertiary);">No loop lineage yet</div>'
1381
+ '<div class="text-xs mb-2" style="color: var(--pw-text-tertiary);">暂无任务链路</div>'
1359
1382
  + '<div class="flex items-center gap-2">'
1360
- + '<a href="/tasks.html" class="text-xs px-2.5 py-1 rounded whitespace-nowrap" style="background-color: var(--pw-accent-muted); color: var(--pw-accent); border: 1px solid var(--pw-accent);">Start guarded loop</a>'
1361
- + '<a href="/tasks.html" class="text-xs px-2.5 py-1 rounded whitespace-nowrap" style="background-color: var(--pw-bg-hover); color: var(--pw-text-secondary); border: 1px solid var(--pw-border-subtle);">View recent loop runs</a>'
1383
+ + '<a href="/tasks.html" class="text-xs px-2.5 py-1 rounded whitespace-nowrap" style="background-color: var(--pw-accent-muted); color: var(--pw-accent); border: 1px solid var(--pw-accent);">创建受控任务链</a>'
1384
+ + '<a href="/tasks.html" class="text-xs px-2.5 py-1 rounded whitespace-nowrap" style="background-color: var(--pw-bg-hover); color: var(--pw-text-secondary); border: 1px solid var(--pw-border-subtle);">查看最近运行</a>'
1362
1385
  + '</div>';
1363
1386
  return;
1364
1387
  }
@@ -1486,55 +1509,26 @@ html.dark {
1486
1509
  + section('Direct Verification', directSessions, directRow);
1487
1510
  }
1488
1511
 
1489
- // ---------- Health Score ----------
1490
- // Computes a health score from the /api/status payload and supplementary data.
1491
- // Returns: { level: 'healthy'|'warning'|'degraded'|'blocked', dimensions: [{key,label,ok,detail}] }
1492
- function calculateHealthScore(status, opts) {
1493
- opts = opts || {};
1494
- const staleCount = typeof opts.staleTaskCount === 'number' ? opts.staleTaskCount : 0;
1495
- const failedCount = typeof opts.failedTaskCount === 'number' ? opts.failedTaskCount : 0;
1496
- const policyValid = opts.policyValid === true;
1497
- const releaseReady = opts.releaseReady === true;
1498
- const directProfileEnabled = opts.directProfileEnabled === true;
1499
-
1500
- const watcher = (status && status.watcher) || {};
1501
- const tunnel = (status && status.tunnel) || {};
1502
- const agents = (status && status.agents) || [];
1503
-
1504
- const watcherHealthy = watcher.status === 'healthy';
1505
- const coreReady = !!(tunnel.core && tunnel.core.ready);
1506
- const directReady = !!(tunnel.direct && tunnel.direct.ready);
1507
- const tunnelReady = coreReady && directReady;
1508
- const agentsAvailable = Array.isArray(agents) && agents.some(function (a) { return a && a.available; });
1509
-
1510
- const dimensions = [
1511
- { key: 'watcher_healthy', label: 'Watcher healthy', ok: watcherHealthy, detail: watcher.status || 'unknown' },
1512
- { key: 'tunnel_ready', label: 'Tunnel ready', ok: tunnelReady, detail: 'core ' + (coreReady ? '✓' : '✗') + ' / direct ' + (directReady ? '✓' : '✗') },
1513
- { key: 'agents_available', label: 'Agents available', ok: agentsAvailable, detail: Array.isArray(agents) ? agents.length + ' agent(s)' : '0' },
1514
- { key: 'stale_tasks', label: 'Stale tasks', ok: staleCount === 0, detail: String(staleCount) },
1515
- { key: 'failed_tasks', label: 'Failed tasks', ok: failedCount === 0, detail: String(failedCount) },
1516
- { key: 'policy_valid', label: 'Policy valid', ok: policyValid, detail: policyValid ? 'valid' : 'invalid' },
1517
- { key: 'release_ready', label: 'Release ready', ok: releaseReady, detail: opts.releaseReadyState || 'unknown' },
1518
- { key: 'direct_profile', label: 'Direct profile', ok: directProfileEnabled, detail: directProfileEnabled ? 'enabled' : 'disabled' }
1519
- ];
1520
-
1521
- // Scoring logic (order: blocked > degraded > warning > healthy)
1522
- let level = 'healthy';
1523
- const watcherDownAndFailed = (!watcherHealthy && failedCount > 0);
1524
- const tunnelDownNoAgents = (!tunnelReady && !agentsAvailable);
1525
- if (watcherDownAndFailed || tunnelDownNoAgents) {
1526
- level = 'blocked';
1527
- } else if (failedCount > 2 || staleCount > 3 || !watcherHealthy) {
1528
- level = 'degraded';
1529
- } else if (staleCount > 0 || failedCount > 0 || !directProfileEnabled || !releaseReady) {
1530
- level = 'warning';
1512
+ // ---------- Live readiness ----------
1513
+ // The status route owns this classification. Historic task records remain
1514
+ // visible elsewhere and never change the live readiness result.
1515
+ function calculateHealthScore(status) {
1516
+ const experience = status && status.experience;
1517
+ if (!experience || !Array.isArray(experience.live_checks)) {
1518
+ return { level: 'blocked', dimensions: [] };
1531
1519
  }
1532
-
1533
- return { level: level, dimensions: dimensions };
1520
+ return {
1521
+ level: experience.readiness === 'ready' ? 'healthy' : experience.readiness,
1522
+ dimensions: experience.live_checks.map(function (check) {
1523
+ return { key: check.key, label: check.label, ok: check.state === 'ready' || check.state === 'optional', optional: check.state === 'optional', detail: check.detail };
1524
+ }),
1525
+ history: experience.historical_summary || null
1526
+ };
1534
1527
  }
1535
1528
 
1536
1529
  function healthScoreColor(level) {
1537
1530
  if (level === 'healthy') return { color: 'var(--pw-state-success)', bg: 'var(--pw-state-success-bg)' };
1531
+ if (level === 'needs_action') return { color: 'var(--pw-state-warning)', bg: 'var(--pw-state-warning-bg)' };
1538
1532
  if (level === 'warning') return { color: 'var(--pw-state-warning)', bg: 'var(--pw-state-warning-bg)' };
1539
1533
  if (level === 'degraded') return { color: '#f97316', bg: 'rgba(249, 115, 22, 0.1)' };
1540
1534
  if (level === 'blocked') return { color: 'var(--pw-state-error)', bg: 'var(--pw-state-error-bg)' };
@@ -1554,8 +1548,8 @@ html.dark {
1554
1548
 
1555
1549
  let html = '';
1556
1550
  score.dimensions.forEach(function (d) {
1557
- const okColor = d.ok ? 'var(--pw-state-success)' : 'var(--pw-state-error)';
1558
- const icon = d.ok ? '✓' : '✗';
1551
+ const okColor = d.optional ? 'var(--pw-text-tertiary)' : (d.ok ? 'var(--pw-state-success)' : 'var(--pw-state-error)');
1552
+ const icon = d.optional ? '○' : (d.ok ? '✓' : '✗');
1559
1553
  html +=
1560
1554
  '<div class="flex items-center gap-2 px-2 py-1.5 rounded" style="background-color: var(--pw-bg-hover); border: 1px solid var(--pw-border-subtle);">'
1561
1555
  + '<span class="shrink-0 text-xs font-semibold" style="color: ' + okColor + '; font-family: var(--pw-font-mono);">' + icon + '</span>'
@@ -1565,6 +1559,9 @@ html.dark {
1565
1559
  + '</div>'
1566
1560
  + '</div>';
1567
1561
  });
1562
+ if (score.history) {
1563
+ html += '<div class="md:col-span-2 lg:col-span-4 text-xs px-2 py-1" style="color: var(--pw-text-tertiary);">历史摘要:' + escapeHtml(String(score.history.stale_tasks || 0)) + ' 个过期任务,' + escapeHtml(String(score.history.failed_tasks || 0)) + ' 个失败任务</div>';
1564
+ }
1568
1565
  body.innerHTML = html;
1569
1566
  }
1570
1567
 
@@ -1572,61 +1569,8 @@ html.dark {
1572
1569
  const card = $('health-score-card');
1573
1570
  if (!card) return;
1574
1571
  try {
1575
- // Fetch all required data in parallel
1576
- const [statusRes, staleRes, policyRes, releaseRes, diagRes] = await Promise.allSettled([
1577
- fetchJson('/api/status'),
1578
- fetchJson('/api/tasks/stale'),
1579
- fetchJson('/api/project-policy?repo_path=' + encodeURIComponent(currentRepoPath)),
1580
- fetchJson('/api/release/status?repo_path=' + encodeURIComponent(currentRepoPath)),
1581
- fetchJson('/api/diagnostics')
1582
- ]);
1583
-
1584
- const status = statusRes.status === 'fulfilled' ? statusRes.value : null;
1585
- const staleData = staleRes.status === 'fulfilled' ? staleRes.value : null;
1586
- const policyData = policyRes.status === 'fulfilled' ? policyRes.value : null;
1587
- const releaseData = releaseRes.status === 'fulfilled' ? releaseRes.value : null;
1588
- const diagData = diagRes.status === 'fulfilled' ? diagRes.value : null;
1589
-
1590
- // stale task count
1591
- let staleTaskCount = 0;
1592
- if (staleData) {
1593
- const arr = Array.isArray(staleData.stale_tasks) ? staleData.stale_tasks
1594
- : (Array.isArray(staleData.tasks) ? staleData.tasks : []);
1595
- staleTaskCount = arr.length;
1596
- }
1597
-
1598
- // failed task count - derive from status.tasks
1599
- let failedTaskCount = 0;
1600
- if (status && status.tasks && Array.isArray(status.tasks.tasks)) {
1601
- failedTaskCount = status.tasks.tasks.filter(function (t) {
1602
- const s = String(t && t.status || '').toLowerCase();
1603
- return s.indexOf('fail') >= 0;
1604
- }).length;
1605
- }
1606
-
1607
- // policy valid
1608
- const policyValid = !!(policyData && policyData.valid !== false);
1609
-
1610
- // release ready
1611
- const readyState = releaseData ? (releaseData.ready_state || 'unknown') : 'unknown';
1612
- const releaseReady = readyState === 'ready';
1613
-
1614
- // direct profile enabled - from diagnostics or status
1615
- let directProfileEnabled = false;
1616
- if (diagData && typeof diagData.direct_profile_enabled === 'boolean') {
1617
- directProfileEnabled = diagData.direct_profile_enabled;
1618
- } else if (status && status.config && typeof status.config.enableDirectProfile === 'boolean') {
1619
- directProfileEnabled = status.config.enableDirectProfile;
1620
- }
1621
-
1622
- const score = calculateHealthScore(status, {
1623
- staleTaskCount: staleTaskCount,
1624
- failedTaskCount: failedTaskCount,
1625
- policyValid: policyValid,
1626
- releaseReady: releaseReady,
1627
- releaseReadyState: readyState,
1628
- directProfileEnabled: directProfileEnabled
1629
- });
1572
+ const status = await fetchJson('/api/status');
1573
+ const score = calculateHealthScore(status);
1630
1574
  renderHealthScore(score);
1631
1575
  } catch (err) {
1632
1576
  const body = $('health-score-body');
@@ -1949,7 +1893,7 @@ html.dark {
1949
1893
  try {
1950
1894
  const data = await fetchJson('/api/workspace/repos');
1951
1895
  const repos = Array.isArray(data.repos) ? data.repos : [];
1952
- let html = '<option value=".">workspace root</option>';
1896
+ let html = '<option value=".">工作区根目录</option>';
1953
1897
  repos.forEach(function (r) {
1954
1898
  const label = r.name + (r.has_package_json && r.version ? ' (v' + r.version + ')' : '');
1955
1899
  const val = r.path || r.name;
@@ -2135,7 +2079,8 @@ html.dark {
2135
2079
  };
2136
2080
  const url = map[action];
2137
2081
  if (!url) return;
2138
- await postAction(url, btnEl);
2082
+ const result = await postAction(url, btnEl);
2083
+ if (action !== 'open-logs-folder') showToast('success', '操作完成', result && result.verified ? '服务已通过就绪检查。' : '命令已完成。');
2139
2084
  // Refresh state after state-changing POSTs (open-logs-folder has no state change)
2140
2085
  if (action !== 'open-logs-folder') {
2141
2086
  await Promise.all([refreshStatus(), refreshTasks()]);
@@ -2206,5 +2151,7 @@ html.dark {
2206
2151
  </script>
2207
2152
 
2208
2153
  <script>lucide.createIcons();</script>
2154
+ <script src="/i18n.js"></script>
2155
+ <script src="/desktop-bridge.js"></script>
2209
2156
  </body>
2210
2157
  </html>