patchwarden 1.5.1 → 1.6.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 (573) hide show
  1. package/PatchWarden.cmd +32 -2
  2. package/README.en.md +152 -25
  3. package/README.md +120 -23
  4. package/dist/assessments/agentAssessor.js +21 -12
  5. package/dist/assessments/assessmentStore.js +42 -34
  6. package/dist/config.d.ts +15 -0
  7. package/dist/config.js +66 -13
  8. package/dist/control/fileManager.d.ts +2 -0
  9. package/dist/control/fileManager.js +39 -0
  10. package/dist/control/middleware/auth.d.ts +6 -0
  11. package/dist/control/middleware/auth.js +14 -5
  12. package/dist/control/middleware/static.js +16 -3
  13. package/dist/control/routeTable.d.ts +24 -0
  14. package/dist/control/routeTable.js +263 -0
  15. package/dist/control/routes/audit.js +17 -7
  16. package/dist/control/routes/evidence.js +1 -1
  17. package/dist/control/routes/lineage.js +1 -1
  18. package/dist/control/routes/process.d.ts +7 -0
  19. package/dist/control/routes/process.js +329 -42
  20. package/dist/control/routes/sessions.d.ts +9 -1
  21. package/dist/control/routes/sessions.js +84 -21
  22. package/dist/control/routes/status.d.ts +46 -1
  23. package/dist/control/routes/status.js +72 -15
  24. package/dist/control/routes/taskActions.js +24 -60
  25. package/dist/control/routes/tasks.d.ts +4 -0
  26. package/dist/control/routes/tasks.js +61 -62
  27. package/dist/control/routes/workspace.js +50 -23
  28. package/dist/control/runtime.d.ts +3 -2
  29. package/dist/control/runtime.js +63 -30
  30. package/dist/control/server.js +36 -365
  31. package/dist/control/shared.d.ts +25 -1
  32. package/dist/control/shared.js +64 -11
  33. package/dist/direct/directAudit.js +234 -225
  34. package/dist/direct/directGuards.d.ts +2 -1
  35. package/dist/direct/directGuards.js +42 -29
  36. package/dist/direct/directPatch.d.ts +6 -1
  37. package/dist/direct/directPatch.js +55 -8
  38. package/dist/direct/directSessionStore.d.ts +16 -6
  39. package/dist/direct/directSessionStore.js +127 -35
  40. package/dist/direct/directVerification.js +8 -16
  41. package/dist/doctor.js +62 -52
  42. package/dist/goal/acceptanceEngine.d.ts +1 -1
  43. package/dist/goal/goalProgress.js +75 -69
  44. package/dist/goal/goalReport.js +5 -12
  45. package/dist/goal/goalStatus.d.ts +2 -0
  46. package/dist/goal/goalStatus.js +10 -3
  47. package/dist/goal/goalStore.d.ts +9 -2
  48. package/dist/goal/goalStore.js +152 -45
  49. package/dist/goal/handoffExport.js +6 -6
  50. package/dist/goal/specKitImport.js +97 -96
  51. package/dist/goal/subgoalSync.js +11 -9
  52. package/dist/goal/worktreeManager.d.ts +2 -0
  53. package/dist/goal/worktreeManager.js +209 -136
  54. package/dist/httpServer.js +111 -32
  55. package/dist/logging.js +5 -3
  56. package/dist/policy/projectPolicy.js +5 -2
  57. package/dist/release/releaseGate.d.ts +1 -1
  58. package/dist/release/releaseGate.js +78 -25
  59. package/dist/runner/agentInvocation.d.ts +14 -0
  60. package/dist/runner/agentInvocation.js +96 -4
  61. package/dist/runner/changeCapture.d.ts +13 -5
  62. package/dist/runner/changeCapture.js +243 -61
  63. package/dist/runner/postTaskCleanup.js +48 -19
  64. package/dist/runner/processSecurity.d.ts +56 -0
  65. package/dist/runner/processSecurity.js +373 -0
  66. package/dist/runner/runTask.d.ts +1 -1
  67. package/dist/runner/runTask.js +115 -87
  68. package/dist/runner/simpleProcess.d.ts +3 -0
  69. package/dist/runner/simpleProcess.js +50 -36
  70. package/dist/{taskProgress.d.ts → runner/taskProgress.d.ts} +1 -1
  71. package/dist/{taskProgress.js → runner/taskProgress.js} +2 -2
  72. package/dist/{taskRuntime.d.ts → runner/taskRuntime.d.ts} +1 -1
  73. package/dist/{taskRuntime.js → runner/taskRuntime.js} +3 -2
  74. package/dist/runner/taskStatusStore.d.ts +11 -0
  75. package/dist/runner/taskStatusStore.js +24 -0
  76. package/dist/runner/watch.d.ts +14 -1
  77. package/dist/runner/watch.js +256 -48
  78. package/dist/security/contentRedaction.js +2 -2
  79. package/dist/security/discoveryTokenStore.d.ts +3 -2
  80. package/dist/security/discoveryTokenStore.js +17 -2
  81. package/dist/security/loopbackHost.d.ts +2 -0
  82. package/dist/security/loopbackHost.js +16 -0
  83. package/dist/security/pathGuard.js +32 -17
  84. package/dist/security/planGuard.js +2 -1
  85. package/dist/security/runtimeGuard.js +9 -6
  86. package/dist/security/secretComparison.d.ts +3 -0
  87. package/dist/security/secretComparison.js +11 -0
  88. package/dist/security/sensitiveGuard.d.ts +5 -0
  89. package/dist/security/sensitiveGuard.js +27 -8
  90. package/dist/security/toolInvocationGuard.d.ts +2 -2
  91. package/dist/security/toolInvocationGuard.js +1 -1
  92. package/dist/security/workspaceRootGuard.d.ts +8 -0
  93. package/dist/security/workspaceRootGuard.js +47 -0
  94. package/dist/smoke-test.js +24 -23
  95. package/dist/tools/catalog/index.d.ts +4 -0
  96. package/dist/tools/catalog/index.js +4 -0
  97. package/dist/tools/{toolCatalog.js → catalog/toolCatalog.js} +3 -12
  98. package/dist/tools/{toolRegistry.d.ts → catalog/toolRegistry.d.ts} +3 -3
  99. package/dist/tools/{toolRegistry.js → catalog/toolRegistry.js} +6 -15
  100. package/dist/tools/definitions/toolDefs.d.ts +18 -0
  101. package/dist/tools/definitions/toolDefs.js +1177 -0
  102. package/dist/tools/{auditSession.d.ts → diagnostics/auditSession.d.ts} +1 -1
  103. package/dist/tools/{auditSession.js → diagnostics/auditSession.js} +2 -2
  104. package/dist/tools/{auditTask.d.ts → diagnostics/auditTask.d.ts} +1 -1
  105. package/dist/tools/{auditTask.js → diagnostics/auditTask.js} +99 -29
  106. package/dist/tools/{healthCheck.d.ts → diagnostics/healthCheck.d.ts} +6 -6
  107. package/dist/tools/{healthCheck.js → diagnostics/healthCheck.js} +7 -7
  108. package/dist/tools/diagnostics/index.d.ts +6 -0
  109. package/dist/tools/diagnostics/index.js +6 -0
  110. package/dist/tools/{safeStatus.d.ts → diagnostics/safeStatus.d.ts} +3 -3
  111. package/dist/tools/{safeStatus.js → diagnostics/safeStatus.js} +6 -6
  112. package/dist/tools/{safeViews.d.ts → diagnostics/safeViews.d.ts} +12 -8
  113. package/dist/tools/{safeViews.js → diagnostics/safeViews.js} +23 -13
  114. package/dist/tools/{schemaDriftCheck.d.ts → diagnostics/schemaDriftCheck.d.ts} +1 -1
  115. package/dist/tools/{schemaDriftCheck.js → diagnostics/schemaDriftCheck.js} +2 -2
  116. package/dist/tools/{createDirectSession.js → direct/createDirectSession.js} +6 -6
  117. package/dist/tools/{finalizeDirectSession.d.ts → direct/finalizeDirectSession.d.ts} +1 -1
  118. package/dist/tools/direct/finalizeDirectSession.js +86 -0
  119. package/dist/tools/direct/index.d.ts +3 -0
  120. package/dist/tools/direct/index.js +3 -0
  121. package/dist/tools/{runDirectVerificationBundle.js → direct/runDirectVerificationBundle.js} +2 -2
  122. package/dist/tools/{discoverTools.d.ts → discovery/discoverTools.d.ts} +2 -2
  123. package/dist/tools/{discoverTools.js → discovery/discoverTools.js} +5 -5
  124. package/dist/tools/{explainTool.d.ts → discovery/explainTool.d.ts} +2 -2
  125. package/dist/tools/{explainTool.js → discovery/explainTool.js} +2 -2
  126. package/dist/tools/discovery/index.d.ts +3 -0
  127. package/dist/tools/discovery/index.js +3 -0
  128. package/dist/tools/{invokeDiscoveredTool.d.ts → discovery/invokeDiscoveredTool.d.ts} +2 -2
  129. package/dist/tools/{invokeDiscoveredTool.js → discovery/invokeDiscoveredTool.js} +5 -5
  130. package/dist/tools/dispatch/coreDispatch.js +32 -31
  131. package/dist/tools/dispatch/diagnosticDispatch.d.ts +3 -5
  132. package/dist/tools/dispatch/diagnosticDispatch.js +70 -68
  133. package/dist/tools/dispatch/directDispatch.js +11 -10
  134. package/dist/tools/dispatch/goalDispatch.js +5 -4
  135. package/dist/tools/dispatch/releaseDispatch.js +3 -2
  136. package/dist/tools/dispatch/validation.d.ts +7 -0
  137. package/dist/tools/dispatch/validation.js +71 -0
  138. package/dist/tools/{getPlan.js → goals/getPlan.js} +4 -4
  139. package/dist/tools/{goalSubgoalTask.d.ts → goals/goalSubgoalTask.d.ts} +1 -1
  140. package/dist/tools/goals/goalSubgoalTask.js +118 -0
  141. package/dist/tools/goals/index.d.ts +3 -0
  142. package/dist/tools/goals/index.js +3 -0
  143. package/dist/tools/{savePlan.js → goals/savePlan.js} +28 -8
  144. package/dist/tools/registry.d.ts +7 -11
  145. package/dist/tools/registry.js +17 -1178
  146. package/dist/tools/{checkReleaseGate.d.ts → release/checkReleaseGate.d.ts} +1 -1
  147. package/dist/tools/{checkReleaseGate.js → release/checkReleaseGate.js} +3 -3
  148. package/dist/tools/release/index.d.ts +2 -0
  149. package/dist/tools/release/index.js +2 -0
  150. package/dist/tools/{releaseMode.d.ts → release/releaseMode.d.ts} +2 -2
  151. package/dist/tools/{releaseMode.js → release/releaseMode.js} +46 -26
  152. package/dist/tools/tasks/cancelTask.d.ts +11 -0
  153. package/dist/tools/tasks/cancelTask.js +85 -0
  154. package/dist/tools/{createTask.d.ts → tasks/createTask.d.ts} +10 -2
  155. package/dist/tools/{createTask.js → tasks/createTask.js} +42 -27
  156. package/dist/tools/{diagnoseTask.d.ts → tasks/diagnoseTask.d.ts} +1 -1
  157. package/dist/tools/{diagnoseTask.js → tasks/diagnoseTask.js} +8 -8
  158. package/dist/tools/{evidencePack.js → tasks/evidencePack.js} +34 -22
  159. package/dist/tools/{getTaskFile.js → tasks/getTaskFile.js} +4 -4
  160. package/dist/tools/{getTaskStatus.d.ts → tasks/getTaskStatus.d.ts} +6 -1
  161. package/dist/tools/{getTaskStatus.js → tasks/getTaskStatus.js} +5 -5
  162. package/dist/tools/{getTaskStdoutTail.js → tasks/getTaskStdoutTail.js} +13 -11
  163. package/dist/tools/{getTaskSummary.js → tasks/getTaskSummary.js} +33 -26
  164. package/dist/tools/tasks/index.d.ts +18 -0
  165. package/dist/tools/tasks/index.js +18 -0
  166. package/dist/tools/tasks/killTask.d.ts +1 -0
  167. package/dist/tools/{listTasks.d.ts → tasks/listTasks.d.ts} +1 -1
  168. package/dist/tools/{listTasks.js → tasks/listTasks.js} +3 -3
  169. package/dist/tools/{reconcileTasks.d.ts → tasks/reconcileTasks.d.ts} +1 -1
  170. package/dist/tools/{reconcileTasks.js → tasks/reconcileTasks.js} +64 -66
  171. package/dist/tools/tasks/retryTask.js +60 -0
  172. package/dist/tools/{runTaskLoop.d.ts → tasks/runTaskLoop.d.ts} +6 -6
  173. package/dist/tools/{runTaskLoop.js → tasks/runTaskLoop.js} +58 -30
  174. package/dist/tools/tasks/runVerification.js +38 -0
  175. package/dist/tools/{taskLineage.js → tasks/taskLineage.js} +8 -7
  176. package/dist/tools/{taskOutputs.js → tasks/taskOutputs.js} +17 -16
  177. package/dist/tools/{androidDoctor.js → workspace/androidDoctor.js} +16 -10
  178. package/dist/tools/{applyPatch.d.ts → workspace/applyPatch.d.ts} +1 -1
  179. package/dist/tools/workspace/applyPatch.js +53 -0
  180. package/dist/tools/{discardWorktree.js → workspace/discardWorktree.js} +3 -3
  181. package/dist/tools/workspace/index.d.ts +10 -0
  182. package/dist/tools/workspace/index.js +10 -0
  183. package/dist/tools/{listAgents.d.ts → workspace/listAgents.d.ts} +5 -0
  184. package/dist/tools/{listAgents.js → workspace/listAgents.js} +8 -4
  185. package/dist/tools/{listWorkspace.js → workspace/listWorkspace.js} +3 -3
  186. package/dist/tools/{mergeWorktree.js → workspace/mergeWorktree.js} +3 -3
  187. package/dist/tools/{readWorkspaceFile.js → workspace/readWorkspaceFile.js} +8 -8
  188. package/dist/tools/{recommendAgentForTask.js → workspace/recommendAgentForTask.js} +3 -3
  189. package/dist/tools/{searchWorkspace.js → workspace/searchWorkspace.js} +5 -5
  190. package/dist/tools/{syncFile.d.ts → workspace/syncFile.d.ts} +1 -1
  191. package/dist/tools/workspace/syncFile.js +134 -0
  192. package/dist/utils/atomicFile.d.ts +7 -0
  193. package/dist/utils/atomicFile.js +48 -0
  194. package/dist/utils/boundedFile.d.ts +8 -0
  195. package/dist/utils/boundedFile.js +93 -0
  196. package/dist/utils/lockedJsonFile.d.ts +15 -0
  197. package/dist/utils/lockedJsonFile.js +224 -0
  198. package/dist/utils/platform.d.ts +11 -0
  199. package/dist/utils/platform.js +26 -0
  200. package/dist/utils/stableJson.d.ts +2 -0
  201. package/dist/utils/stableJson.js +12 -0
  202. package/dist/version.d.ts +3 -2
  203. package/dist/version.js +3 -2
  204. package/dist/watcherStatus.d.ts +2 -2
  205. package/dist/watcherStatus.js +18 -0
  206. package/docs/CODE_WIKI.md +808 -143
  207. package/docs/architecture.md +15 -55
  208. package/docs/assets/patchwarden-desktop-onboarding.png +0 -0
  209. package/docs/control-center/README.md +4 -4
  210. package/docs/dashboard-overview.md +4 -4
  211. package/docs/desktop-app.md +175 -0
  212. package/docs/evidence-pack-schema.md +3 -3
  213. package/docs/open-source-application.md +17 -11
  214. package/docs/release-checklist.md +1 -1
  215. package/docs/release-evidence.md +39 -29
  216. package/docs/task-safe-review-workflow.md +5 -5
  217. package/docs/threat-model.md +19 -1
  218. package/examples/config.example.json +4 -2
  219. package/package.json +27 -10
  220. package/scripts/README.md +15 -6
  221. package/scripts/build.js +11 -0
  222. package/scripts/checks/brand-check.js +3 -0
  223. package/scripts/checks/build-output-check.js +37 -0
  224. package/scripts/checks/control-center-smoke.js +91 -6
  225. package/scripts/checks/control-smoke.js +19 -8
  226. package/scripts/checks/http-mcp-smoke.js +82 -4
  227. package/scripts/checks/lifecycle-smoke.js +10 -10
  228. package/scripts/checks/mcp-manifest-check.js +1 -1
  229. package/scripts/checks/mcp-smoke.js +27 -3
  230. package/scripts/checks/package-manifest-check.js +20 -7
  231. package/scripts/checks/unit-tests.js +3 -5
  232. package/scripts/checks/watcher-supervisor-smoke.js +9 -0
  233. package/scripts/control/get-patchwarden-health.ps1 +1 -1
  234. package/scripts/control/manage-patchwarden.ps1 +69 -4
  235. package/scripts/control/provision-patchwarden-tunnel.ps1 +127 -0
  236. package/scripts/control/run-background-supervisor.ps1 +41 -0
  237. package/scripts/control/start-patchwarden-tunnel.ps1 +126 -32
  238. package/{PatchWarden-Control-Tray.cmd → scripts/launchers/PatchWarden-Control-Tray.cmd} +3 -3
  239. package/scripts/launchers/PatchWarden-Control.cmd +6 -0
  240. package/{PatchWarden-Desktop.cmd → scripts/launchers/PatchWarden-Desktop.cmd} +2 -2
  241. package/scripts/launchers/Restart-PatchWarden-Control.cmd +6 -0
  242. package/{Stop-PatchWarden.cmd → scripts/launchers/Stop-PatchWarden.cmd} +2 -2
  243. package/scripts/lib/clean-generated-output.js +11 -0
  244. package/scripts/lib/file-discovery.js +12 -0
  245. package/scripts/release/desktop-preflight.js +211 -0
  246. package/scripts/release/pack-clean.js +59 -14
  247. package/src/assessments/agentAssessor.ts +26 -12
  248. package/src/assessments/assessmentStore.ts +52 -40
  249. package/src/config.ts +70 -13
  250. package/src/control/fileManager.ts +40 -0
  251. package/src/control/middleware/auth.ts +22 -4
  252. package/src/control/middleware/static.ts +16 -3
  253. package/src/control/routeTable.ts +301 -0
  254. package/src/control/routes/audit.ts +14 -6
  255. package/src/control/routes/evidence.ts +1 -1
  256. package/src/control/routes/lineage.ts +1 -1
  257. package/src/control/routes/process.ts +341 -40
  258. package/src/control/routes/sessions.ts +88 -25
  259. package/src/control/routes/status.ts +97 -17
  260. package/src/control/routes/taskActions.ts +24 -58
  261. package/src/control/routes/tasks.ts +66 -58
  262. package/src/control/routes/workspace.ts +56 -25
  263. package/src/control/runtime.ts +69 -33
  264. package/src/control/server.ts +36 -342
  265. package/src/control/shared.ts +77 -11
  266. package/src/direct/directAudit.ts +17 -9
  267. package/src/direct/directGuards.ts +72 -44
  268. package/src/direct/directPatch.ts +95 -8
  269. package/src/direct/directSessionStore.ts +211 -55
  270. package/src/direct/directVerification.ts +9 -23
  271. package/src/doctor.ts +73 -59
  272. package/src/goal/acceptanceEngine.ts +1 -1
  273. package/src/goal/goalProgress.ts +17 -13
  274. package/src/goal/goalReport.ts +5 -13
  275. package/src/goal/goalStatus.ts +19 -3
  276. package/src/goal/goalStore.ts +241 -54
  277. package/src/goal/handoffExport.ts +6 -6
  278. package/src/goal/specKitImport.ts +12 -12
  279. package/src/goal/subgoalSync.ts +11 -8
  280. package/src/goal/worktreeManager.ts +139 -22
  281. package/src/httpServer.ts +113 -30
  282. package/src/logging.ts +10 -3
  283. package/src/policy/projectPolicy.ts +5 -2
  284. package/src/release/releaseGate.ts +74 -27
  285. package/src/runner/agentInvocation.ts +126 -4
  286. package/src/runner/changeCapture.ts +291 -57
  287. package/src/runner/postTaskCleanup.ts +41 -17
  288. package/src/runner/processSecurity.ts +433 -0
  289. package/src/runner/runTask.ts +138 -91
  290. package/src/runner/simpleProcess.ts +66 -31
  291. package/src/{taskProgress.ts → runner/taskProgress.ts} +3 -3
  292. package/src/{taskRuntime.ts → runner/taskRuntime.ts} +4 -3
  293. package/src/runner/taskStatusStore.ts +54 -0
  294. package/src/runner/watch.ts +281 -51
  295. package/src/security/contentRedaction.ts +2 -2
  296. package/src/security/discoveryTokenStore.ts +18 -4
  297. package/src/security/loopbackHost.ts +19 -0
  298. package/src/security/pathGuard.ts +35 -16
  299. package/src/security/planGuard.ts +2 -1
  300. package/src/security/runtimeGuard.ts +9 -6
  301. package/src/security/secretComparison.ts +13 -0
  302. package/src/security/sensitiveGuard.ts +27 -8
  303. package/src/security/toolInvocationGuard.ts +2 -2
  304. package/src/security/workspaceRootGuard.ts +53 -0
  305. package/src/smoke-test.ts +25 -24
  306. package/src/tools/catalog/index.ts +4 -0
  307. package/src/tools/{toolCatalog.ts → catalog/toolCatalog.ts} +3 -12
  308. package/src/tools/{toolRegistry.ts → catalog/toolRegistry.ts} +7 -16
  309. package/src/tools/definitions/toolDefs.ts +1264 -0
  310. package/src/tools/{auditSession.ts → diagnostics/auditSession.ts} +2 -2
  311. package/src/tools/{auditTask.ts → diagnostics/auditTask.ts} +99 -32
  312. package/src/tools/{healthCheck.ts → diagnostics/healthCheck.ts} +8 -8
  313. package/src/tools/diagnostics/index.ts +6 -0
  314. package/src/tools/{safeStatus.ts → diagnostics/safeStatus.ts} +7 -7
  315. package/src/tools/{safeViews.ts → diagnostics/safeViews.ts} +27 -17
  316. package/src/tools/{schemaDriftCheck.ts → diagnostics/schemaDriftCheck.ts} +3 -3
  317. package/src/tools/{createDirectSession.ts → direct/createDirectSession.ts} +6 -6
  318. package/src/tools/{finalizeDirectSession.ts → direct/finalizeDirectSession.ts} +7 -5
  319. package/src/tools/direct/index.ts +3 -0
  320. package/src/tools/{runDirectVerificationBundle.ts → direct/runDirectVerificationBundle.ts} +2 -2
  321. package/src/tools/{discoverTools.ts → discovery/discoverTools.ts} +6 -6
  322. package/src/tools/{explainTool.ts → discovery/explainTool.ts} +3 -3
  323. package/src/tools/discovery/index.ts +3 -0
  324. package/src/tools/{invokeDiscoveredTool.ts → discovery/invokeDiscoveredTool.ts} +7 -7
  325. package/src/tools/dispatch/coreDispatch.ts +36 -31
  326. package/src/tools/dispatch/diagnosticDispatch.ts +26 -21
  327. package/src/tools/dispatch/directDispatch.ts +11 -10
  328. package/src/tools/dispatch/goalDispatch.ts +5 -4
  329. package/src/tools/dispatch/releaseDispatch.ts +3 -2
  330. package/src/tools/dispatch/validation.ts +78 -0
  331. package/src/tools/{getPlan.ts → goals/getPlan.ts} +4 -4
  332. package/src/tools/{goalSubgoalTask.ts → goals/goalSubgoalTask.ts} +41 -26
  333. package/src/tools/goals/index.ts +3 -0
  334. package/src/tools/{savePlan.ts → goals/savePlan.ts} +38 -8
  335. package/src/tools/registry.ts +17 -1261
  336. package/src/tools/{checkReleaseGate.ts → release/checkReleaseGate.ts} +3 -3
  337. package/src/tools/release/index.ts +2 -0
  338. package/src/tools/{releaseMode.ts → release/releaseMode.ts} +42 -24
  339. package/src/tools/tasks/cancelTask.ts +109 -0
  340. package/src/tools/{createTask.ts → tasks/createTask.ts} +49 -26
  341. package/src/tools/{diagnoseTask.ts → tasks/diagnoseTask.ts} +8 -8
  342. package/src/tools/{evidencePack.ts → tasks/evidencePack.ts} +36 -22
  343. package/src/tools/{getTaskFile.ts → tasks/getTaskFile.ts} +4 -4
  344. package/src/tools/{getTaskStatus.ts → tasks/getTaskStatus.ts} +7 -5
  345. package/src/tools/{getTaskStdoutTail.ts → tasks/getTaskStdoutTail.ts} +13 -11
  346. package/src/tools/{getTaskSummary.ts → tasks/getTaskSummary.ts} +44 -33
  347. package/src/tools/tasks/index.ts +18 -0
  348. package/src/tools/{listTasks.ts → tasks/listTasks.ts} +4 -4
  349. package/src/tools/{reconcileTasks.ts → tasks/reconcileTasks.ts} +68 -66
  350. package/src/tools/tasks/retryTask.ts +69 -0
  351. package/src/tools/{runTaskLoop.ts → tasks/runTaskLoop.ts} +69 -34
  352. package/src/tools/{runVerification.ts → tasks/runVerification.ts} +6 -3
  353. package/src/tools/{taskLineage.ts → tasks/taskLineage.ts} +8 -7
  354. package/src/tools/{taskOutputs.ts → tasks/taskOutputs.ts} +27 -20
  355. package/src/tools/{androidDoctor.ts → workspace/androidDoctor.ts} +15 -10
  356. package/src/tools/{applyPatch.ts → workspace/applyPatch.ts} +38 -16
  357. package/src/tools/{discardWorktree.ts → workspace/discardWorktree.ts} +3 -3
  358. package/src/tools/workspace/index.ts +10 -0
  359. package/src/tools/{listAgents.ts → workspace/listAgents.ts} +11 -4
  360. package/src/tools/{listWorkspace.ts → workspace/listWorkspace.ts} +3 -3
  361. package/src/tools/{mergeWorktree.ts → workspace/mergeWorktree.ts} +3 -3
  362. package/src/tools/{readWorkspaceFile.ts → workspace/readWorkspaceFile.ts} +8 -8
  363. package/src/tools/{recommendAgentForTask.ts → workspace/recommendAgentForTask.ts} +3 -3
  364. package/src/tools/{searchWorkspace.ts → workspace/searchWorkspace.ts} +5 -5
  365. package/src/tools/workspace/syncFile.ts +292 -0
  366. package/src/utils/atomicFile.ts +58 -0
  367. package/src/utils/boundedFile.ts +116 -0
  368. package/src/utils/lockedJsonFile.ts +251 -0
  369. package/src/utils/platform.ts +31 -0
  370. package/src/utils/stableJson.ts +12 -0
  371. package/src/version.ts +3 -2
  372. package/src/watcherStatus.ts +19 -1
  373. package/ui/desktop-bootstrap.js +11 -0
  374. package/ui/desktop-bridge.js +36 -0
  375. package/ui/desktop.css +160 -0
  376. package/ui/getting-started.js +93 -0
  377. package/ui/i18n.js +484 -0
  378. package/ui/log-parser.js +30 -0
  379. package/ui/pages/audit.html +12 -0
  380. package/ui/pages/dashboard.html +90 -147
  381. package/ui/pages/direct-sessions.html +123 -26
  382. package/ui/pages/getting-started.html +43 -0
  383. package/ui/pages/logs.html +105 -22
  384. package/ui/pages/settings.html +101 -0
  385. package/ui/pages/task-detail.html +12 -0
  386. package/ui/pages/tasks.html +54 -8
  387. package/ui/pages/workspace.html +38 -1
  388. package/ui/settings.js +245 -0
  389. package/PatchWarden-Control.cmd +0 -6
  390. package/Restart-PatchWarden-Control.cmd +0 -6
  391. package/dist/test/unit/acceptance-engine.test.d.ts +0 -1
  392. package/dist/test/unit/acceptance-engine.test.js +0 -228
  393. package/dist/test/unit/agent-router.test.d.ts +0 -1
  394. package/dist/test/unit/agent-router.test.js +0 -287
  395. package/dist/test/unit/android-doctor.test.d.ts +0 -1
  396. package/dist/test/unit/android-doctor.test.js +0 -118
  397. package/dist/test/unit/apply-patch.test.d.ts +0 -1
  398. package/dist/test/unit/apply-patch.test.js +0 -225
  399. package/dist/test/unit/audit-checks.test.d.ts +0 -1
  400. package/dist/test/unit/audit-checks.test.js +0 -350
  401. package/dist/test/unit/chinese-path.test.d.ts +0 -1
  402. package/dist/test/unit/chinese-path.test.js +0 -91
  403. package/dist/test/unit/command-guard.test.d.ts +0 -1
  404. package/dist/test/unit/command-guard.test.js +0 -160
  405. package/dist/test/unit/create-task.test.d.ts +0 -1
  406. package/dist/test/unit/create-task.test.js +0 -197
  407. package/dist/test/unit/diagnose-task.test.d.ts +0 -1
  408. package/dist/test/unit/diagnose-task.test.js +0 -457
  409. package/dist/test/unit/direct-guards.test.d.ts +0 -1
  410. package/dist/test/unit/direct-guards.test.js +0 -328
  411. package/dist/test/unit/discovery-token-store.test.d.ts +0 -1
  412. package/dist/test/unit/discovery-token-store.test.js +0 -139
  413. package/dist/test/unit/evidence-pack.test.d.ts +0 -1
  414. package/dist/test/unit/evidence-pack.test.js +0 -224
  415. package/dist/test/unit/get-task-status.test.d.ts +0 -1
  416. package/dist/test/unit/get-task-status.test.js +0 -174
  417. package/dist/test/unit/get-task-summary.test.d.ts +0 -1
  418. package/dist/test/unit/get-task-summary.test.js +0 -146
  419. package/dist/test/unit/goal-graph.test.d.ts +0 -1
  420. package/dist/test/unit/goal-graph.test.js +0 -298
  421. package/dist/test/unit/goal-progress.test.d.ts +0 -1
  422. package/dist/test/unit/goal-progress.test.js +0 -381
  423. package/dist/test/unit/goal-report.test.d.ts +0 -1
  424. package/dist/test/unit/goal-report.test.js +0 -159
  425. package/dist/test/unit/goal-status.test.d.ts +0 -1
  426. package/dist/test/unit/goal-status.test.js +0 -215
  427. package/dist/test/unit/goal-store.test.d.ts +0 -1
  428. package/dist/test/unit/goal-store.test.js +0 -253
  429. package/dist/test/unit/goal-subgoal-task.test.d.ts +0 -1
  430. package/dist/test/unit/goal-subgoal-task.test.js +0 -55
  431. package/dist/test/unit/goal-tools-registry.test.d.ts +0 -1
  432. package/dist/test/unit/goal-tools-registry.test.js +0 -192
  433. package/dist/test/unit/handoff-export.test.d.ts +0 -1
  434. package/dist/test/unit/handoff-export.test.js +0 -263
  435. package/dist/test/unit/invoke-discovered-tool.test.d.ts +0 -1
  436. package/dist/test/unit/invoke-discovered-tool.test.js +0 -167
  437. package/dist/test/unit/logging.test.d.ts +0 -1
  438. package/dist/test/unit/logging.test.js +0 -397
  439. package/dist/test/unit/path-guard.test.d.ts +0 -1
  440. package/dist/test/unit/path-guard.test.js +0 -133
  441. package/dist/test/unit/post-task-cleanup.test.d.ts +0 -1
  442. package/dist/test/unit/post-task-cleanup.test.js +0 -48
  443. package/dist/test/unit/project-policy-release-mode.test.d.ts +0 -1
  444. package/dist/test/unit/project-policy-release-mode.test.js +0 -125
  445. package/dist/test/unit/reconcile-tasks.test.d.ts +0 -1
  446. package/dist/test/unit/reconcile-tasks.test.js +0 -456
  447. package/dist/test/unit/release-gate.test.d.ts +0 -1
  448. package/dist/test/unit/release-gate.test.js +0 -242
  449. package/dist/test/unit/run-task-loop.test.d.ts +0 -1
  450. package/dist/test/unit/run-task-loop.test.js +0 -380
  451. package/dist/test/unit/safe-status.test.d.ts +0 -1
  452. package/dist/test/unit/safe-status.test.js +0 -165
  453. package/dist/test/unit/safe-views.test.d.ts +0 -1
  454. package/dist/test/unit/safe-views.test.js +0 -171
  455. package/dist/test/unit/schema-drift-check.test.d.ts +0 -1
  456. package/dist/test/unit/schema-drift-check.test.js +0 -176
  457. package/dist/test/unit/sensitive-guard.test.d.ts +0 -1
  458. package/dist/test/unit/sensitive-guard.test.js +0 -104
  459. package/dist/test/unit/spec-kit-import.test.d.ts +0 -1
  460. package/dist/test/unit/spec-kit-import.test.js +0 -341
  461. package/dist/test/unit/subgoal-sync.test.d.ts +0 -1
  462. package/dist/test/unit/subgoal-sync.test.js +0 -183
  463. package/dist/test/unit/sync-file.test.d.ts +0 -1
  464. package/dist/test/unit/sync-file.test.js +0 -154
  465. package/dist/test/unit/tool-invocation-guard.test.d.ts +0 -1
  466. package/dist/test/unit/tool-invocation-guard.test.js +0 -432
  467. package/dist/test/unit/tool-usage-stats.test.d.ts +0 -1
  468. package/dist/test/unit/tool-usage-stats.test.js +0 -300
  469. package/dist/test/unit/toolSearch.test.d.ts +0 -1
  470. package/dist/test/unit/toolSearch.test.js +0 -571
  471. package/dist/test/unit/wait-for-task.test.d.ts +0 -1
  472. package/dist/test/unit/wait-for-task.test.js +0 -144
  473. package/dist/test/unit/watcher-status.test.d.ts +0 -1
  474. package/dist/test/unit/watcher-status.test.js +0 -169
  475. package/dist/test/unit/worktree-manager.test.d.ts +0 -1
  476. package/dist/test/unit/worktree-manager.test.js +0 -176
  477. package/dist/tools/applyPatch.js +0 -41
  478. package/dist/tools/cancelTask.d.ts +0 -30
  479. package/dist/tools/cancelTask.js +0 -64
  480. package/dist/tools/finalizeDirectSession.js +0 -84
  481. package/dist/tools/goalSubgoalTask.js +0 -110
  482. package/dist/tools/killTask.d.ts +0 -15
  483. package/dist/tools/retryTask.js +0 -45
  484. package/dist/tools/runVerification.js +0 -36
  485. package/dist/tools/syncFile.js +0 -65
  486. package/docs/control-center/control-center-daily-driver.md +0 -211
  487. package/docs/control-center/control-center-mvp.md +0 -205
  488. package/docs/control-center/control-center-phase2.md +0 -159
  489. package/docs/execution-plan-2026-07-09.md +0 -315
  490. package/docs/release-v0.6.0.md +0 -71
  491. package/docs/release-v0.6.1.md +0 -75
  492. package/docs/release-v0.6.4.md +0 -45
  493. package/docs/roadmap-execution-and-acceptance.md +0 -365
  494. package/src/test/unit/acceptance-engine.test.ts +0 -261
  495. package/src/test/unit/agent-router.test.ts +0 -342
  496. package/src/test/unit/android-doctor.test.ts +0 -158
  497. package/src/test/unit/apply-patch.test.ts +0 -293
  498. package/src/test/unit/audit-checks.test.ts +0 -567
  499. package/src/test/unit/chinese-path.test.ts +0 -106
  500. package/src/test/unit/command-guard.test.ts +0 -221
  501. package/src/test/unit/create-task.test.ts +0 -255
  502. package/src/test/unit/diagnose-task.test.ts +0 -544
  503. package/src/test/unit/direct-guards.test.ts +0 -467
  504. package/src/test/unit/discovery-token-store.test.ts +0 -181
  505. package/src/test/unit/evidence-pack.test.ts +0 -251
  506. package/src/test/unit/get-task-status.test.ts +0 -203
  507. package/src/test/unit/get-task-summary.test.ts +0 -173
  508. package/src/test/unit/goal-graph.test.ts +0 -347
  509. package/src/test/unit/goal-progress.test.ts +0 -538
  510. package/src/test/unit/goal-report.test.ts +0 -189
  511. package/src/test/unit/goal-status.test.ts +0 -270
  512. package/src/test/unit/goal-store.test.ts +0 -318
  513. package/src/test/unit/goal-subgoal-task.test.ts +0 -72
  514. package/src/test/unit/goal-tools-registry.test.ts +0 -245
  515. package/src/test/unit/handoff-export.test.ts +0 -295
  516. package/src/test/unit/invoke-discovered-tool.test.ts +0 -216
  517. package/src/test/unit/logging.test.ts +0 -497
  518. package/src/test/unit/path-guard.test.ts +0 -180
  519. package/src/test/unit/post-task-cleanup.test.ts +0 -53
  520. package/src/test/unit/project-policy-release-mode.test.ts +0 -156
  521. package/src/test/unit/reconcile-tasks.test.ts +0 -551
  522. package/src/test/unit/release-gate.test.ts +0 -314
  523. package/src/test/unit/run-task-loop.test.ts +0 -425
  524. package/src/test/unit/safe-status.test.ts +0 -187
  525. package/src/test/unit/safe-views.test.ts +0 -184
  526. package/src/test/unit/schema-drift-check.test.ts +0 -260
  527. package/src/test/unit/sensitive-guard.test.ts +0 -124
  528. package/src/test/unit/spec-kit-import.test.ts +0 -429
  529. package/src/test/unit/subgoal-sync.test.ts +0 -236
  530. package/src/test/unit/sync-file.test.ts +0 -231
  531. package/src/test/unit/tool-invocation-guard.test.ts +0 -542
  532. package/src/test/unit/tool-usage-stats.test.ts +0 -384
  533. package/src/test/unit/toolSearch.test.ts +0 -756
  534. package/src/test/unit/wait-for-task.test.ts +0 -176
  535. package/src/test/unit/watcher-status.test.ts +0 -190
  536. package/src/test/unit/worktree-manager.test.ts +0 -247
  537. package/src/tools/cancelTask.ts +0 -70
  538. package/src/tools/retryTask.ts +0 -53
  539. package/src/tools/syncFile.ts +0 -122
  540. /package/dist/tools/{toolCatalog.d.ts → catalog/toolCatalog.d.ts} +0 -0
  541. /package/dist/tools/{toolSearch.d.ts → catalog/toolSearch.d.ts} +0 -0
  542. /package/dist/tools/{toolSearch.js → catalog/toolSearch.js} +0 -0
  543. /package/dist/tools/{toolUsageStats.d.ts → catalog/toolUsageStats.d.ts} +0 -0
  544. /package/dist/tools/{toolUsageStats.js → catalog/toolUsageStats.js} +0 -0
  545. /package/dist/tools/{createDirectSession.d.ts → direct/createDirectSession.d.ts} +0 -0
  546. /package/dist/tools/{runDirectVerificationBundle.d.ts → direct/runDirectVerificationBundle.d.ts} +0 -0
  547. /package/dist/tools/{getPlan.d.ts → goals/getPlan.d.ts} +0 -0
  548. /package/dist/tools/{savePlan.d.ts → goals/savePlan.d.ts} +0 -0
  549. /package/dist/tools/{evidencePack.d.ts → tasks/evidencePack.d.ts} +0 -0
  550. /package/dist/tools/{getTaskFile.d.ts → tasks/getTaskFile.d.ts} +0 -0
  551. /package/dist/tools/{getTaskProgress.d.ts → tasks/getTaskProgress.d.ts} +0 -0
  552. /package/dist/tools/{getTaskProgress.js → tasks/getTaskProgress.js} +0 -0
  553. /package/dist/tools/{getTaskStdoutTail.d.ts → tasks/getTaskStdoutTail.d.ts} +0 -0
  554. /package/dist/tools/{getTaskSummary.d.ts → tasks/getTaskSummary.d.ts} +0 -0
  555. /package/dist/tools/{killTask.js → tasks/killTask.js} +0 -0
  556. /package/dist/tools/{retryTask.d.ts → tasks/retryTask.d.ts} +0 -0
  557. /package/dist/tools/{runVerification.d.ts → tasks/runVerification.d.ts} +0 -0
  558. /package/dist/tools/{taskLineage.d.ts → tasks/taskLineage.d.ts} +0 -0
  559. /package/dist/tools/{taskOutputs.d.ts → tasks/taskOutputs.d.ts} +0 -0
  560. /package/dist/tools/{waitForTask.d.ts → tasks/waitForTask.d.ts} +0 -0
  561. /package/dist/tools/{waitForTask.js → tasks/waitForTask.js} +0 -0
  562. /package/dist/tools/{androidDoctor.d.ts → workspace/androidDoctor.d.ts} +0 -0
  563. /package/dist/tools/{discardWorktree.d.ts → workspace/discardWorktree.d.ts} +0 -0
  564. /package/dist/tools/{listWorkspace.d.ts → workspace/listWorkspace.d.ts} +0 -0
  565. /package/dist/tools/{mergeWorktree.d.ts → workspace/mergeWorktree.d.ts} +0 -0
  566. /package/dist/tools/{readWorkspaceFile.d.ts → workspace/readWorkspaceFile.d.ts} +0 -0
  567. /package/dist/tools/{recommendAgentForTask.d.ts → workspace/recommendAgentForTask.d.ts} +0 -0
  568. /package/dist/tools/{searchWorkspace.d.ts → workspace/searchWorkspace.d.ts} +0 -0
  569. /package/src/tools/{toolSearch.ts → catalog/toolSearch.ts} +0 -0
  570. /package/src/tools/{toolUsageStats.ts → catalog/toolUsageStats.ts} +0 -0
  571. /package/src/tools/{getTaskProgress.ts → tasks/getTaskProgress.ts} +0 -0
  572. /package/src/tools/{killTask.ts → tasks/killTask.ts} +0 -0
  573. /package/src/tools/{waitForTask.ts → tasks/waitForTask.ts} +0 -0
@@ -0,0 +1,101 @@
1
+ <!doctype html>
2
+ <html lang="zh-CN">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <title data-i18n="settings.pageTitle"></title>
7
+ <link rel="stylesheet" href="/colors_and_type.css">
8
+ <script src="/desktop-bootstrap.js"></script>
9
+ <link rel="stylesheet" href="/desktop.css">
10
+ <script src="/vendor/tailwindcss-browser.js"></script>
11
+ <script src="/vendor/lucide.js"></script>
12
+ </head>
13
+ <body class="flex h-screen overflow-hidden">
14
+ <aside class="flex flex-col w-60 shrink-0 h-screen" style="background:var(--pw-bg);border-right:1px solid var(--pw-border)">
15
+ <div class="flex items-center gap-3 px-5 py-5" style="border-bottom:1px solid var(--pw-border-subtle)">
16
+ <i data-lucide="shield-check" style="color:var(--pw-accent)"></i><span class="text-lg font-semibold">PatchWarden</span>
17
+ </div>
18
+ <nav class="flex-1 flex flex-col gap-1 px-3 pt-4 overflow-y-auto">
19
+ <a href="/pages/getting-started.html" data-nav-key="getting-started" class="flex items-center gap-3 px-3 py-2.5 text-sm"><i data-lucide="rocket" class="w-4 h-4"></i><span data-i18n="nav.gettingStarted"></span></a>
20
+ <a href="/pages/dashboard.html" data-nav-key="dashboard" class="flex items-center gap-3 px-3 py-2.5 text-sm"><i data-lucide="layout-dashboard" class="w-4 h-4"></i><span data-i18n="nav.dashboard"></span></a>
21
+ <a href="/pages/tasks.html" data-nav-key="tasks" class="flex items-center gap-3 px-3 py-2.5 text-sm"><i data-lucide="list-checks" class="w-4 h-4"></i><span data-i18n="nav.tasks"></span></a>
22
+ <a href="/pages/workspace.html" data-nav-key="workspace" class="flex items-center gap-3 px-3 py-2.5 text-sm"><i data-lucide="folder" class="w-4 h-4"></i><span data-i18n="nav.workspace"></span></a>
23
+ <a href="/pages/audit.html" data-nav-key="audit" class="flex items-center gap-3 px-3 py-2.5 text-sm"><i data-lucide="file-search" class="w-4 h-4"></i><span data-i18n="nav.audit"></span></a>
24
+ <a href="/pages/direct-sessions.html" data-nav-key="direct-sessions" class="flex items-center gap-3 px-3 py-2.5 text-sm"><i data-lucide="route" class="w-4 h-4"></i><span data-i18n="nav.direct"></span></a>
25
+ <a href="/pages/logs.html" data-nav-key="logs" class="flex items-center gap-3 px-3 py-2.5 text-sm"><i data-lucide="scroll-text" class="w-4 h-4"></i><span data-i18n="nav.logs"></span></a>
26
+ <a href="/pages/settings.html" data-nav-key="settings" data-active="true" class="desktop-only-nav flex items-center gap-3 px-3 py-2.5 text-sm"><i data-lucide="settings" class="w-4 h-4"></i><span data-i18n="nav.settings"></span></a>
27
+ </nav>
28
+ </aside>
29
+ <div class="flex flex-col flex-1 min-w-0 h-screen overflow-hidden">
30
+ <header class="flex items-center px-6 py-3" style="border-bottom:1px solid var(--pw-border);background:var(--pw-bg)"><h1 class="text-lg font-semibold" data-i18n="settings.title"></h1></header>
31
+ <main class="flex-1 overflow-y-auto p-6" style="background:var(--pw-bg-elevated)">
32
+ <div class="settings-layout">
33
+ <section>
34
+ <h2 data-i18n="settings.appearance"></h2>
35
+ <div class="setting-row"><div><strong data-i18n="settings.theme"></strong><p data-i18n="settings.themeHelp"></p></div><select id="theme"><option value="system" data-i18n="settings.themeSystem"></option><option value="light" data-i18n="settings.themeLight"></option><option value="dark" data-i18n="settings.themeDark"></option></select></div>
36
+ <div class="setting-row"><div><strong data-i18n="language.label"></strong><p data-i18n="settings.languageHelp"></p></div><select id="language"><option value="system" data-i18n="language.system"></option><option value="zh-CN" data-i18n="language.zh"></option><option value="en" data-i18n="language.en"></option></select></div>
37
+ <div class="setting-row"><div><strong data-i18n="settings.closeWindow"></strong><p data-i18n="settings.closeWindowHelp"></p></div><select id="closeBehavior"><option value="tray" data-i18n="settings.closeToTray"></option><option value="quit" data-i18n="settings.closeQuit"></option></select></div>
38
+ </section>
39
+ <section>
40
+ <h2 data-i18n="settings.localAgents"></h2>
41
+ <div class="agent-section-toolbar"><p data-i18n="settings.localAgentsHelp"></p><button id="detectAgents"><i data-lucide="scan-search"></i><span data-i18n="settings.detectAgents"></span></button></div>
42
+ <div id="agentSettingsList" class="agent-settings-list"><p class="agent-empty" data-i18n="settings.loadingAgents"></p></div>
43
+ <div class="setting-actions"><button id="saveAgents" class="primary-action"><i data-lucide="save"></i><span data-i18n="settings.saveAgents"></span></button><span id="agentSettingsStatus" class="status-text" aria-live="polite"></span></div>
44
+ </section>
45
+ <section>
46
+ <h2 data-i18n="settings.mcpTunnel"></h2>
47
+ <div class="setting-row">
48
+ <div class="min-w-0"><strong>tunnel-client.exe</strong><p id="tunnelClientPath" class="mono break-path" data-i18n="settings.tunnelUndetected"></p></div>
49
+ <div class="inline-actions"><button id="detectTunnel"><i data-lucide="scan-search"></i><span data-i18n="settings.detect"></span></button><button id="chooseTunnel"><i data-lucide="file-search"></i><span data-i18n="settings.choose"></span></button></div>
50
+ </div>
51
+ <div class="setting-row">
52
+ <div><strong>Direct profile</strong><p data-i18n="settings.directHelp"></p></div>
53
+ <label class="switch-label"><input id="enableDirectProfile" type="checkbox"><span data-i18n="settings.enable"></span></label>
54
+ </div>
55
+ <div class="setting-row">
56
+ <div><strong data-i18n="settings.proxy"></strong><p data-i18n="settings.proxyHelp"></p></div>
57
+ <select id="proxyScope"><option value="shared" data-i18n="settings.proxyShared"></option><option value="separate" data-i18n="settings.proxySeparate"></option></select>
58
+ </div>
59
+ <div class="proxy-grid">
60
+ <div class="proxy-endpoint">
61
+ <strong>Core</strong>
62
+ <select id="coreProxyMode"><option value="environment" data-i18n="settings.proxyEnvironment"></option><option value="none" data-i18n="settings.proxyNone"></option><option value="manual" data-i18n="settings.proxyManual"></option></select>
63
+ <input id="coreProxyUrl" type="url" placeholder="http://127.0.0.1:7890" autocomplete="off">
64
+ </div>
65
+ <div id="directProxyEndpoint" class="proxy-endpoint hidden">
66
+ <strong>Direct</strong>
67
+ <select id="directProxyMode"><option value="environment" data-i18n="settings.proxyEnvironment"></option><option value="none" data-i18n="settings.proxyNone"></option><option value="manual" data-i18n="settings.proxyManual"></option></select>
68
+ <input id="directProxyUrl" type="url" placeholder="socks5://127.0.0.1:1080" autocomplete="off">
69
+ </div>
70
+ </div>
71
+ <div class="setting-actions"><button id="saveRuntime" class="primary-action"><i data-lucide="save"></i><span data-i18n="settings.saveRuntime"></span></button><span id="runtimeStatus" class="status-text" aria-live="polite"></span></div>
72
+ <div class="credential-panel">
73
+ <div class="credential-heading"><div><strong data-i18n="settings.tunnelCredentials"></strong><p data-i18n="settings.runtimeKeyHelp"></p></div><span id="credentialState" class="credential-state"></span></div>
74
+ <div class="credential-grid">
75
+ <label>Profile<select id="tunnelMode"><option value="core">Core</option><option value="direct">Direct</option></select></label>
76
+ <label><span data-i18n="settings.tunnelId"></span><input id="tunnelId" type="text" autocomplete="off" spellcheck="false" placeholder="tun_..."></label>
77
+ <label><span data-i18n="settings.runtimeKey"></span><input id="runtimeKey" type="password" autocomplete="new-password" spellcheck="false"></label>
78
+ </div>
79
+ <div class="setting-actions credential-actions"><button id="provisionTunnel" class="primary-action"><i data-lucide="shield-check"></i><span data-i18n="settings.configureCore"></span></button><button id="revalidateCredential"><i data-lucide="activity"></i><span data-i18n="settings.revalidate"></span></button><button id="forgetCredential"><i data-lucide="key-round"></i><span data-i18n="settings.forgetCredential"></span></button><span id="provisionStatus" class="status-text" aria-live="polite"></span></div>
80
+ </div>
81
+ <details class="install-guide"><summary data-i18n="settings.installSummary"></summary><ol><li data-i18n="settings.installStep1"></li><li data-i18n="settings.installStep2"></li><li data-i18n="settings.installStep3"></li><li data-i18n="settings.installStep4"></li></ol></details>
82
+ </section>
83
+ <section>
84
+ <h2 data-i18n="settings.workspaceDiagnostics"></h2>
85
+ <div class="setting-row"><div class="min-w-0"><strong data-i18n="settings.currentConfig"></strong><p id="configPath" class="mono truncate" data-i18n="settings.loading"></p></div><button id="openConfig" data-i18n-title="settings.openConfig"><i data-lucide="external-link"></i></button></div>
86
+ <div class="setting-row"><div><strong data-i18n="settings.workspace"></strong><p id="workspacePath" class="mono" data-i18n="settings.workspaceHelp"></p></div><button id="changeWorkspace" data-i18n="settings.change"></button></div>
87
+ <div class="setting-actions"><button id="openLogs"><i data-lucide="folder-open"></i><span data-i18n="settings.openLogs"></span></button><button id="runDoctor"><i data-lucide="stethoscope"></i><span data-i18n="settings.runDoctor"></span></button></div>
88
+ <pre id="doctorOutput" class="hidden"></pre>
89
+ </section>
90
+ </div>
91
+ </main>
92
+ </div>
93
+ <style>
94
+ [data-nav-key]{color:var(--pw-text-secondary);border-radius:6px}[data-nav-key]:hover{background:var(--pw-bg-hover);color:var(--pw-text-primary)}[data-nav-key][data-active="true"]{background:var(--pw-accent-subtle);color:var(--pw-accent);border-left:2px solid var(--pw-accent)}
95
+ .settings-layout{display:grid;gap:18px;max-width:920px}.settings-layout section{background:var(--pw-bg-surface);border:1px solid var(--pw-border);border-radius:7px}.settings-layout h2{margin:0;padding:16px 18px;font-size:14px;border-bottom:1px solid var(--pw-border)}.setting-row{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:20px;align-items:center;padding:16px 18px;border-bottom:1px solid var(--pw-border-subtle)}.setting-row p,.credential-panel p,.agent-section-toolbar p{margin:4px 0 0;color:var(--pw-text-secondary);font-size:12px}.setting-row select,.setting-row button,.setting-actions button,.proxy-endpoint select,.proxy-endpoint input,.credential-grid select,.credential-grid input,.agent-section-toolbar button,.agent-controls select,.agent-controls input,.agent-controls button{min-height:36px;padding:0 12px;color:var(--pw-text-primary);background:var(--pw-bg-elevated);border:1px solid var(--pw-border);border-radius:6px}.setting-row button,.agent-section-toolbar button,.agent-controls button{display:flex;align-items:center;gap:6px}.setting-row svg,.agent-section-toolbar svg,.agent-controls svg{width:16px}.setting-actions{display:flex;align-items:center;gap:10px;padding:16px 18px;flex-wrap:wrap}.setting-actions button{display:flex;align-items:center;gap:8px}.setting-actions svg{width:16px}.inline-actions{display:flex;gap:8px}.switch-label{display:flex;align-items:center;gap:8px}.switch-label input{width:18px;height:18px;accent-color:var(--pw-accent)}.agent-section-toolbar{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:12px 18px;border-bottom:1px solid var(--pw-border-subtle)}.agent-settings-list{display:grid}.agent-setting-row{display:grid;grid-template-columns:minmax(180px,1fr) minmax(280px,1.4fr);align-items:center;gap:18px;padding:14px 18px;border-bottom:1px solid var(--pw-border-subtle)}.agent-identity{display:grid;grid-template-columns:20px minmax(0,1fr);gap:10px;align-items:center}.agent-identity input{width:18px;height:18px;accent-color:var(--pw-accent)}.agent-identity strong,.agent-identity small{display:block}.agent-identity small{margin-top:3px;color:var(--pw-text-secondary);font-size:11px}.agent-controls{display:grid;grid-template-columns:minmax(150px,1fr) minmax(150px,1fr) 38px;gap:8px}.agent-controls button{justify-content:center;padding:0}.agent-empty{padding:18px;color:var(--pw-text-secondary);font-size:12px}.proxy-grid{display:grid;grid-template-columns:1fr 1fr;gap:12px;padding:16px 18px;border-bottom:1px solid var(--pw-border-subtle)}.proxy-endpoint{display:grid;grid-template-columns:auto minmax(150px,auto) minmax(180px,1fr);align-items:center;gap:10px}.proxy-endpoint input:disabled{opacity:.55}.primary-action{background:var(--pw-accent)!important;color:var(--pw-text-inverse)!important}.status-text{font-size:12px;color:var(--pw-text-secondary)}.credential-panel{border-top:1px solid var(--pw-border)}.credential-heading{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;padding:16px 18px}.credential-state{padding:3px 7px;background:var(--pw-bg-hover);border-radius:4px;font-size:11px;white-space:nowrap}.credential-grid{display:grid;grid-template-columns:150px minmax(180px,1fr) minmax(220px,1.4fr);gap:12px;padding:0 18px 16px}.credential-grid label{display:grid;gap:6px;color:var(--pw-text-secondary);font-size:11px}.credential-actions{padding-top:0}.install-guide{margin:0 18px 18px;padding:12px 14px;border:1px solid var(--pw-border-subtle);border-radius:6px;color:var(--pw-text-secondary);font-size:12px}.install-guide summary{cursor:pointer;color:var(--pw-text-primary);font-weight:600}.install-guide ol{margin:10px 0 0 20px;line-height:1.7}.break-path{overflow-wrap:anywhere}.mono{font-family:var(--pw-font-mono)}#doctorOutput{max-height:320px;margin:0 18px 18px;padding:14px;overflow:auto;color:var(--pw-code-text,#dbe8e3);background:var(--pw-code-bg);border-radius:6px;font:11px/1.5 var(--pw-font-mono);white-space:pre-wrap}.hidden{display:none}@media(max-width:760px){.setting-row,.agent-setting-row{grid-template-columns:1fr}.agent-controls{grid-template-columns:1fr}.proxy-grid,.credential-grid{grid-template-columns:1fr}.proxy-endpoint{grid-template-columns:1fr}.inline-actions{justify-content:flex-start}}
96
+ </style>
97
+ <script src="/i18n.js"></script>
98
+ <script src="/desktop-bridge.js"></script>
99
+ <script src="/settings.js"></script>
100
+ </body>
101
+ </html>
@@ -135,6 +135,8 @@ html.dark {
135
135
  .pw-spin { animation: pw-spin 1s linear infinite; }
136
136
  @keyframes pw-spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
137
137
  </style>
138
+ <script src="/desktop-bootstrap.js"></script>
139
+ <link rel="stylesheet" href="/desktop.css">
138
140
  </head>
139
141
  <body class="flex h-screen overflow-hidden">
140
142
 
@@ -152,6 +154,10 @@ html.dark {
152
154
 
153
155
  <!-- Navigation -->
154
156
  <nav class="flex-1 flex flex-col gap-1 px-3 pt-4 overflow-y-auto">
157
+ <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);">
158
+ <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>
159
+ <span class="truncate" data-i18n="nav.gettingStarted">开始使用</span>
160
+ </a>
155
161
 
156
162
  <a href="/pages/dashboard.html" data-nav-key="dashboard" data-dom-id="nav-dashboard" 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);">
157
163
  <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">
@@ -207,6 +213,10 @@ html.dark {
207
213
  <span class="truncate" data-zh="日志" data-en="Logs">日志</span>
208
214
  </a>
209
215
 
216
+ <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);">
217
+ <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>
218
+ <span class="truncate" data-i18n="nav.settings">设置</span>
219
+ </a>
210
220
  </nav>
211
221
 
212
222
  <!-- Bottom Section -->
@@ -1243,5 +1253,7 @@ html.dark {
1243
1253
  </script>
1244
1254
 
1245
1255
  <script>lucide.createIcons();</script>
1256
+ <script src="/i18n.js"></script>
1257
+ <script src="/desktop-bridge.js"></script>
1246
1258
  </body>
1247
1259
  </html>
@@ -140,6 +140,8 @@ html.dark {
140
140
  to { transform: rotate(360deg); }
141
141
  }
142
142
  </style>
143
+ <script src="/desktop-bootstrap.js"></script>
144
+ <link rel="stylesheet" href="/desktop.css">
143
145
  </head>
144
146
  <body class="flex h-screen overflow-hidden">
145
147
 
@@ -157,6 +159,10 @@ html.dark {
157
159
 
158
160
  <!-- Navigation -->
159
161
  <nav class="flex-1 flex flex-col gap-1 px-3 pt-4 overflow-y-auto">
162
+ <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);">
163
+ <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>
164
+ <span class="truncate" data-i18n="nav.gettingStarted">开始使用</span>
165
+ </a>
160
166
 
161
167
  <a href="/pages/dashboard.html" data-nav-key="dashboard" data-dom-id="nav-dashboard" 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);">
162
168
  <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">
@@ -212,6 +218,10 @@ html.dark {
212
218
  <span class="truncate" data-zh="日志" data-en="Logs">日志</span>
213
219
  </a>
214
220
 
221
+ <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);">
222
+ <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>
223
+ <span class="truncate" data-i18n="nav.settings">设置</span>
224
+ </a>
215
225
  </nav>
216
226
 
217
227
  <!-- Bottom Section -->
@@ -442,6 +452,9 @@ html.dark {
442
452
  </tbody>
443
453
  </table>
444
454
  </div>
455
+ <div id="loadMoreWrap" class="hidden px-4 py-3 text-center" style="border-top: 1px solid var(--pw-border-subtle);">
456
+ <button id="loadMoreBtn" class="px-3 py-1.5 rounded-md text-xs font-semibold" type="button" style="background-color: var(--pw-bg-hover); color: var(--pw-text-secondary); border: 1px solid var(--pw-border-subtle); font-family: var(--pw-font-sans);">加载更多</button>
457
+ </div>
445
458
  </div>
446
459
 
447
460
  <!-- ===== SAFE MODAL ===== -->
@@ -558,6 +571,22 @@ html.dark {
558
571
  border-width: 1px;
559
572
  border-style: solid;
560
573
  }
574
+ #taskTableBody td:nth-child(2) {
575
+ display: -webkit-box;
576
+ -webkit-line-clamp: 2;
577
+ -webkit-box-orient: vertical;
578
+ overflow: hidden;
579
+ }
580
+ @media (max-width: 1100px) {
581
+ #tableWrapper { overflow-x: visible; padding: 10px; }
582
+ #tableWrapper table { min-width: 0 !important; display: block; }
583
+ #tableWrapper thead { display: none; }
584
+ #taskTableBody, #taskTableBody tr { display: block; }
585
+ #taskTableBody tr { margin-bottom: 10px; padding: 12px; border: 1px solid var(--pw-border-subtle); border-radius: 6px; }
586
+ #taskTableBody td { display: block; padding: 4px 0 !important; text-align: left !important; max-width: none !important; }
587
+ #taskTableBody td:nth-child(5), #taskTableBody td:nth-child(6), #taskTableBody td:nth-child(7), #taskTableBody td:nth-child(9) { display: none; }
588
+ #taskTableBody td:nth-child(10) > div { display: flex; justify-content: flex-start; flex-wrap: wrap; }
589
+ }
561
590
  </style>
562
591
 
563
592
  <script>
@@ -593,6 +622,8 @@ html.dark {
593
622
  };
594
623
 
595
624
  var allTasks = [];
625
+ var nextCursor = null;
626
+ var totalTasks = 0;
596
627
  // currentFilters holds the active filter values for all dimensions.
597
628
  // repo_path / status / acceptance_status / agent are sent to the backend.
598
629
  // warning_type / date_from / date_to are applied client-side.
@@ -768,6 +799,7 @@ html.dark {
768
799
  hide($('errorState'));
769
800
  hide($('emptyState'));
770
801
  hide($('tableWrapper'));
802
+ hide($('loadMoreWrap'));
771
803
  $('countSummary').textContent = '--';
772
804
  }
773
805
 
@@ -785,6 +817,7 @@ html.dark {
785
817
  hide($('errorState'));
786
818
  show($('emptyState'));
787
819
  hide($('tableWrapper'));
820
+ hide($('loadMoreWrap'));
788
821
  }
789
822
 
790
823
  function showTable() {
@@ -868,8 +901,8 @@ html.dark {
868
901
 
869
902
  // Quick action buttons
870
903
  var quickActions =
871
- '<button class="pw-quick-btn" data-safe-action="safe-result" data-task-id="' + escapeAttr(taskId) + '" title="safe result" type="button"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg></button>'
872
- + '<button class="pw-quick-btn" data-safe-action="safe-audit" data-task-id="' + escapeAttr(taskId) + '" title="safe audit" type="button"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg></button>'
904
+ '<button class="pw-quick-btn" data-safe-action="safe-result" data-task-id="' + escapeAttr(taskId) + '" title="查看安全结果" aria-label="查看安全结果" type="button"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg></button>'
905
+ + '<button class="pw-quick-btn" data-safe-action="safe-audit" data-task-id="' + escapeAttr(taskId) + '" title="查看安全审计" aria-label="查看安全审计" type="button"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg></button>'
873
906
  + '<button class="pw-quick-btn" data-safe-action="safe-test-summary" data-task-id="' + escapeAttr(taskId) + '" title="safe test summary" type="button"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/></svg></button>'
874
907
  + '<button class="pw-quick-btn" data-safe-action="safe-diff-summary" data-task-id="' + escapeAttr(taskId) + '" title="safe diff summary" type="button"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14"/><path d="M12 5l7 7-7 7"/></svg></button>'
875
908
  + '<button class="pw-quick-btn" data-copy-id="' + escapeAttr(taskId) + '" title="复制 task_id" type="button"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg></button>'
@@ -986,14 +1019,16 @@ html.dark {
986
1019
  showTable();
987
1020
  wireQuickActions();
988
1021
  }
1022
+ var more = $('loadMoreWrap');
1023
+ if (more) nextCursor ? show(more) : hide(more);
989
1024
 
990
1025
  // Count summary
991
1026
  var hasFilters = currentFilters.repo_path || currentFilters.status || currentFilters.acceptance_status ||
992
1027
  currentFilters.agent || currentFilters.warning_type || currentFilters.date_from || currentFilters.date_to;
993
1028
  if (hasFilters) {
994
- $('countSummary').textContent = '显示 ' + filtered.length + ' / ' + allTasks.length + ' 条';
1029
+ $('countSummary').textContent = '显示 ' + filtered.length + ' / ' + totalTasks + ' 条';
995
1030
  } else {
996
- $('countSummary').textContent = ' ' + filtered.length + ' 条';
1031
+ $('countSummary').textContent = '已加载 ' + filtered.length + ' / ' + totalTasks + ' 条';
997
1032
  }
998
1033
  }
999
1034
 
@@ -1031,6 +1066,10 @@ html.dark {
1031
1066
  if (currentFilters.agent) {
1032
1067
  params.push('agent=' + encodeURIComponent(currentFilters.agent));
1033
1068
  }
1069
+ if (currentFilters.warning_type) params.push('warning_type=' + encodeURIComponent(currentFilters.warning_type));
1070
+ if (currentFilters.date_from) params.push('date_from=' + encodeURIComponent(currentFilters.date_from));
1071
+ if (currentFilters.date_to) params.push('date_to=' + encodeURIComponent(currentFilters.date_to));
1072
+ params.push('limit=50');
1034
1073
  return params.length ? ('?' + params.join('&')) : '';
1035
1074
  }
1036
1075
 
@@ -1084,10 +1123,11 @@ html.dark {
1084
1123
  }
1085
1124
  }
1086
1125
 
1087
- function fetchTasks() {
1088
- showLoading();
1126
+ function fetchTasks(cursor, append) {
1127
+ if (!append) showLoading();
1089
1128
  setRefreshing(true);
1090
- var url = API_URL + buildFilterQueryString();
1129
+ var query = buildFilterQueryString();
1130
+ var url = API_URL + query + (query ? '&' : '?') + (cursor ? 'cursor=' + encodeURIComponent(cursor) : '');
1091
1131
  fetch(url, {
1092
1132
  method: 'GET',
1093
1133
  headers: { 'Accept': 'application/json' },
@@ -1102,7 +1142,10 @@ html.dark {
1102
1142
  return res.json();
1103
1143
  })
1104
1144
  .then(function (data) {
1105
- allTasks = (data && Array.isArray(data.tasks)) ? data.tasks : [];
1145
+ var page = (data && Array.isArray(data.tasks)) ? data.tasks : [];
1146
+ allTasks = append ? allTasks.concat(page) : page;
1147
+ nextCursor = data && (data.nextCursor || data.next_cursor) ? (data.nextCursor || data.next_cursor) : null;
1148
+ totalTasks = data && typeof data.total === 'number' ? data.total : allTasks.length;
1106
1149
  renderWatcher(data && data.watcher);
1107
1150
  renderTasks();
1108
1151
  updateFilterStatusText();
@@ -1179,6 +1222,7 @@ html.dark {
1179
1222
  });
1180
1223
 
1181
1224
  $('refreshBtn').addEventListener('click', fetchTasks);
1225
+ $('loadMoreBtn').addEventListener('click', function () { if (nextCursor) fetchTasks(nextCursor, true); });
1182
1226
 
1183
1227
  var retryBtn = $('retryBtn');
1184
1228
  if (retryBtn) {
@@ -1235,5 +1279,7 @@ html.dark {
1235
1279
  </script>
1236
1280
 
1237
1281
  <script>lucide.createIcons();</script>
1282
+ <script src="/i18n.js"></script>
1283
+ <script src="/desktop-bridge.js"></script>
1238
1284
  </body>
1239
1285
  </html>
@@ -140,6 +140,8 @@ html.dark {
140
140
  to { transform: rotate(360deg); }
141
141
  }
142
142
  </style>
143
+ <script src="/desktop-bootstrap.js"></script>
144
+ <link rel="stylesheet" href="/desktop.css">
143
145
  </head>
144
146
 
145
147
  <body class="flex h-screen overflow-hidden">
@@ -158,6 +160,10 @@ html.dark {
158
160
 
159
161
  <!-- Navigation -->
160
162
  <nav class="flex-1 flex flex-col gap-1 px-3 pt-4 overflow-y-auto">
163
+ <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);">
164
+ <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>
165
+ <span class="truncate" data-i18n="nav.gettingStarted">开始使用</span>
166
+ </a>
161
167
 
162
168
  <a href="/pages/dashboard.html" data-nav-key="dashboard" data-dom-id="nav-dashboard" 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);">
163
169
  <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">
@@ -213,6 +219,10 @@ html.dark {
213
219
  <span class="truncate" data-zh="日志" data-en="Logs">日志</span>
214
220
  </a>
215
221
 
222
+ <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);">
223
+ <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>
224
+ <span class="truncate" data-i18n="nav.settings">设置</span>
225
+ </a>
216
226
  </nav>
217
227
 
218
228
  <!-- Bottom Section -->
@@ -308,6 +318,8 @@ html.dark {
308
318
 
309
319
  <!-- Project list body -->
310
320
  <div id="projects-body" class="p-4" style="font-family: var(--pw-font-mono); font-size: var(--pw-text-sm);">
321
+ <input id="project-search" type="search" placeholder="搜索 Git 项目" aria-label="搜索 Git 项目" class="w-full mb-3 px-3 py-2 rounded-md text-xs outline-none" style="background-color: var(--pw-bg-elevated); color: var(--pw-text-primary); border: 1px solid var(--pw-border-subtle); font-family: var(--pw-font-sans);">
322
+ <p class="mb-3 text-xs" style="color:var(--pw-text-tertiary);font-family:var(--pw-font-sans);" data-zh="项目检查为只读操作,不会修改工作区文件。" data-en="Project checks are read-only and never modify workspace files.">项目检查为只读操作,不会修改工作区文件。</p>
311
323
  <!-- Loading state -->
312
324
  <div id="projects-loading" class="py-10 text-center">
313
325
  <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">
@@ -329,6 +341,10 @@ html.dark {
329
341
  </div>
330
342
  <!-- Rendered project list -->
331
343
  <div id="projects-list" class="hidden flex flex-col gap-1"></div>
344
+ <details id="internal-directories" class="hidden mt-3 pt-3" style="border-top: 1px solid var(--pw-border-subtle);">
345
+ <summary class="text-xs cursor-pointer" style="color: var(--pw-text-tertiary); font-family: var(--pw-font-sans);">内部与非项目目录 <span id="internal-count"></span></summary>
346
+ <div id="internal-list" class="mt-2 text-xs break-words" style="color: var(--pw-text-tertiary);"></div>
347
+ </details>
332
348
  </div>
333
349
  </div>
334
350
 
@@ -609,6 +625,7 @@ html.dark {
609
625
  }
610
626
 
611
627
  // ---------- Render: Projects ----------
628
+ var allProjectDirectories = [];
612
629
  function renderProjects(directories) {
613
630
  var countEl = $('projects-count');
614
631
  var listEl = $('projects-list');
@@ -620,7 +637,9 @@ html.dark {
620
637
  hide(emptyEl);
621
638
  listEl.innerHTML = '';
622
639
 
623
- var dirs = Array.isArray(directories) ? directories : [];
640
+ allProjectDirectories = Array.isArray(directories) ? directories.slice() : [];
641
+ var query = $('project-search') ? $('project-search').value.trim().toLowerCase() : '';
642
+ var dirs = allProjectDirectories.filter(function (name) { return !query || String(name).toLowerCase().indexOf(query) >= 0; });
624
643
  if (countEl) countEl.textContent = dirs.length + ' 个目录';
625
644
 
626
645
  if (dirs.length === 0) {
@@ -646,6 +665,7 @@ html.dark {
646
665
  + '<span class="truncate flex-1 min-w-0" title="' + safeName + '">' + safeName + '/</span>'
647
666
  + '<button class="repo-check-btn shrink-0 flex items-center gap-1 px-2 py-0.5 rounded text-xs font-medium transition-colors" '
648
667
  + 'data-repo="' + safeName + '" '
668
+ + 'title="只读检查 Git 状态,不会修改文件" aria-label="只读检查 ' + safeName + ' 的 Git 状态" '
649
669
  + 'style="background-color: var(--pw-bg-hover); color: var(--pw-text-secondary); border: 1px solid var(--pw-border-subtle); font-family: var(--pw-font-sans);" '
650
670
  + 'onmouseover="this.style.backgroundColor=\'var(--pw-bg-active)\'" '
651
671
  + 'onmouseout="this.style.backgroundColor=\'var(--pw-bg-hover)\'">'
@@ -668,6 +688,18 @@ html.dark {
668
688
  }
669
689
  }
670
690
 
691
+ function renderInternalDirectories(directories) {
692
+ var details = $('internal-directories');
693
+ var list = $('internal-list');
694
+ var count = $('internal-count');
695
+ if (!details || !list) return;
696
+ var dirs = Array.isArray(directories) ? directories : [];
697
+ if (!dirs.length) { hide(details); return; }
698
+ list.textContent = dirs.join(' · ');
699
+ if (count) count.textContent = '(' + dirs.length + ')';
700
+ show(details);
701
+ }
702
+
671
703
  // ---------- Repo status (on-demand) ----------
672
704
  function checkRepoStatus(repo, btnEl) {
673
705
  var panelEl = $('repo-status-panel');
@@ -916,6 +948,7 @@ html.dark {
916
948
  data = data || {};
917
949
  renderWorkspaceRoot(data.workspace_root);
918
950
  renderProjects(data.directories);
951
+ renderInternalDirectories(data.internal_directories);
919
952
  renderAgents(data.agents);
920
953
  renderConfig(data.config);
921
954
  setLastUpdated();
@@ -938,10 +971,14 @@ html.dark {
938
971
 
939
972
  var retryBtn = $('retry-btn');
940
973
  if (retryBtn) retryBtn.addEventListener('click', loadWorkspace);
974
+ var projectSearch = $('project-search');
975
+ if (projectSearch) projectSearch.addEventListener('input', function () { renderProjects(allProjectDirectories); });
941
976
 
942
977
  // Initial load
943
978
  loadWorkspace();
944
979
  })();
945
980
  </script>
981
+ <script src="/i18n.js"></script>
982
+ <script src="/desktop-bridge.js"></script>
946
983
  </body>
947
984
  </html>