patchwarden 1.5.0 → 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.
- package/PatchWarden.cmd +32 -2
- package/README.en.md +194 -26
- package/README.md +160 -22
- package/dist/assessments/agentAssessor.d.ts +1 -1
- package/dist/assessments/agentAssessor.js +24 -15
- package/dist/assessments/assessmentStore.d.ts +1 -1
- package/dist/assessments/assessmentStore.js +44 -36
- package/dist/assessments/confirmCli.js +5 -4
- package/dist/config.d.ts +22 -0
- package/dist/config.js +98 -11
- package/dist/control/fileManager.d.ts +2 -0
- package/dist/control/fileManager.js +39 -0
- package/dist/control/middleware/auth.d.ts +16 -0
- package/dist/control/middleware/auth.js +17 -0
- package/dist/control/middleware/static.d.ts +3 -0
- package/dist/control/middleware/static.js +78 -0
- package/dist/control/routeTable.d.ts +24 -0
- package/dist/control/routeTable.js +263 -0
- package/dist/control/routes/audit.d.ts +15 -0
- package/dist/control/routes/audit.js +287 -0
- package/dist/control/routes/evidence.d.ts +4 -0
- package/dist/control/routes/evidence.js +96 -0
- package/dist/control/routes/lineage.d.ts +3 -0
- package/dist/control/routes/lineage.js +71 -0
- package/dist/control/routes/policy.d.ts +3 -0
- package/dist/control/routes/policy.js +81 -0
- package/dist/control/routes/process.d.ts +12 -0
- package/dist/control/routes/process.js +487 -0
- package/dist/control/routes/sessions.d.ts +30 -0
- package/dist/control/routes/sessions.js +287 -0
- package/dist/control/routes/status.d.ts +51 -0
- package/dist/control/routes/status.js +307 -0
- package/dist/control/routes/taskActions.d.ts +21 -0
- package/dist/control/routes/taskActions.js +197 -0
- package/dist/control/routes/tasks.d.ts +24 -0
- package/dist/control/routes/tasks.js +309 -0
- package/dist/control/routes/workspace.d.ts +15 -0
- package/dist/control/routes/workspace.js +220 -0
- package/dist/control/runtime.d.ts +92 -0
- package/dist/control/runtime.js +425 -0
- package/dist/control/server.d.ts +13 -0
- package/dist/control/server.js +150 -0
- package/dist/control/shared.d.ts +59 -0
- package/dist/control/shared.js +341 -0
- package/dist/controlCenter.d.ts +6 -0
- package/dist/controlCenter.js +7 -2197
- package/dist/direct/directAudit.js +234 -225
- package/dist/direct/directGuards.d.ts +2 -1
- package/dist/direct/directGuards.js +72 -37
- package/dist/direct/directPatch.d.ts +6 -1
- package/dist/direct/directPatch.js +55 -8
- package/dist/direct/directSessionStore.d.ts +16 -6
- package/dist/direct/directSessionStore.js +127 -35
- package/dist/direct/directVerification.js +8 -16
- package/dist/doctor.d.ts +18 -1
- package/dist/doctor.js +614 -373
- package/dist/goal/acceptanceEngine.d.ts +1 -1
- package/dist/goal/goalProgress.js +75 -69
- package/dist/goal/goalReport.d.ts +54 -0
- package/dist/goal/goalReport.js +197 -0
- package/dist/goal/goalStatus.d.ts +8 -0
- package/dist/goal/goalStatus.js +10 -3
- package/dist/goal/goalStore.d.ts +9 -2
- package/dist/goal/goalStore.js +152 -45
- package/dist/goal/handoffExport.js +6 -6
- package/dist/goal/specKitImport.d.ts +63 -0
- package/dist/goal/specKitImport.js +221 -0
- package/dist/goal/subgoalSync.js +13 -10
- package/dist/goal/worktreeManager.d.ts +2 -0
- package/dist/goal/worktreeManager.js +209 -136
- package/dist/httpServer.js +126 -44
- package/dist/index.js +7 -4
- package/dist/logging.d.ts +7 -1
- package/dist/logging.js +13 -3
- package/dist/policy/projectPolicy.js +5 -2
- package/dist/release/releaseGate.d.ts +1 -1
- package/dist/release/releaseGate.js +78 -25
- package/dist/runner/agentInvocation.d.ts +14 -0
- package/dist/runner/agentInvocation.js +96 -4
- package/dist/runner/changeCapture.d.ts +14 -6
- package/dist/runner/changeCapture.js +287 -81
- package/dist/runner/cli.js +7 -6
- package/dist/runner/postTaskCleanup.js +60 -7
- package/dist/runner/processSecurity.d.ts +56 -0
- package/dist/runner/processSecurity.js +373 -0
- package/dist/runner/runTask.d.ts +1 -1
- package/dist/runner/runTask.js +339 -287
- package/dist/runner/simpleProcess.d.ts +3 -0
- package/dist/runner/simpleProcess.js +52 -38
- package/dist/{taskProgress.d.ts → runner/taskProgress.d.ts} +1 -1
- package/dist/{taskProgress.js → runner/taskProgress.js} +2 -2
- package/dist/{taskRuntime.d.ts → runner/taskRuntime.d.ts} +1 -1
- package/dist/{taskRuntime.js → runner/taskRuntime.js} +3 -2
- package/dist/runner/taskStatusStore.d.ts +11 -0
- package/dist/runner/taskStatusStore.js +24 -0
- package/dist/runner/watch.d.ts +14 -1
- package/dist/runner/watch.js +265 -54
- package/dist/security/contentRedaction.d.ts +6 -0
- package/dist/security/contentRedaction.js +24 -2
- package/dist/security/discoveryTokenStore.d.ts +3 -2
- package/dist/security/discoveryTokenStore.js +17 -2
- package/dist/security/loopbackHost.d.ts +2 -0
- package/dist/security/loopbackHost.js +16 -0
- package/dist/security/pathGuard.js +32 -17
- package/dist/security/planGuard.js +2 -1
- package/dist/security/runtimeGuard.js +9 -6
- package/dist/security/secretComparison.d.ts +3 -0
- package/dist/security/secretComparison.js +11 -0
- package/dist/security/sensitiveGuard.d.ts +5 -0
- package/dist/security/sensitiveGuard.js +27 -8
- package/dist/security/toolInvocationGuard.d.ts +2 -2
- package/dist/security/toolInvocationGuard.js +1 -1
- package/dist/security/workspaceRootGuard.d.ts +8 -0
- package/dist/security/workspaceRootGuard.js +47 -0
- package/dist/smoke-test.js +280 -273
- package/dist/tools/catalog/index.d.ts +4 -0
- package/dist/tools/catalog/index.js +4 -0
- package/dist/tools/{toolCatalog.js → catalog/toolCatalog.js} +3 -12
- package/dist/tools/{toolRegistry.d.ts → catalog/toolRegistry.d.ts} +3 -3
- package/dist/tools/{toolRegistry.js → catalog/toolRegistry.js} +28 -15
- package/dist/tools/definitions/toolDefs.d.ts +18 -0
- package/dist/tools/definitions/toolDefs.js +1177 -0
- package/dist/tools/{auditSession.d.ts → diagnostics/auditSession.d.ts} +1 -1
- package/dist/tools/{auditSession.js → diagnostics/auditSession.js} +2 -2
- package/dist/tools/{auditTask.d.ts → diagnostics/auditTask.d.ts} +8 -63
- package/dist/tools/{auditTask.js → diagnostics/auditTask.js} +111 -37
- package/dist/tools/{healthCheck.d.ts → diagnostics/healthCheck.d.ts} +6 -6
- package/dist/tools/{healthCheck.js → diagnostics/healthCheck.js} +10 -10
- package/dist/tools/diagnostics/index.d.ts +6 -0
- package/dist/tools/diagnostics/index.js +6 -0
- package/dist/tools/{safeStatus.d.ts → diagnostics/safeStatus.d.ts} +3 -3
- package/dist/tools/{safeStatus.js → diagnostics/safeStatus.js} +6 -6
- package/dist/tools/{safeViews.d.ts → diagnostics/safeViews.d.ts} +14 -10
- package/dist/tools/{safeViews.js → diagnostics/safeViews.js} +25 -15
- package/dist/tools/{schemaDriftCheck.d.ts → diagnostics/schemaDriftCheck.d.ts} +1 -1
- package/dist/tools/{schemaDriftCheck.js → diagnostics/schemaDriftCheck.js} +2 -2
- package/dist/tools/{createDirectSession.d.ts → direct/createDirectSession.d.ts} +1 -1
- package/dist/tools/{createDirectSession.js → direct/createDirectSession.js} +8 -8
- package/dist/tools/{finalizeDirectSession.d.ts → direct/finalizeDirectSession.d.ts} +2 -2
- package/dist/tools/direct/finalizeDirectSession.js +86 -0
- package/dist/tools/direct/index.d.ts +3 -0
- package/dist/tools/direct/index.js +3 -0
- package/dist/tools/{runDirectVerificationBundle.js → direct/runDirectVerificationBundle.js} +2 -2
- package/dist/tools/{discoverTools.d.ts → discovery/discoverTools.d.ts} +2 -2
- package/dist/tools/{discoverTools.js → discovery/discoverTools.js} +5 -5
- package/dist/tools/{explainTool.d.ts → discovery/explainTool.d.ts} +2 -2
- package/dist/tools/{explainTool.js → discovery/explainTool.js} +2 -2
- package/dist/tools/discovery/index.d.ts +3 -0
- package/dist/tools/discovery/index.js +3 -0
- package/dist/tools/{invokeDiscoveredTool.d.ts → discovery/invokeDiscoveredTool.d.ts} +2 -2
- package/dist/tools/{invokeDiscoveredTool.js → discovery/invokeDiscoveredTool.js} +5 -5
- package/dist/tools/dispatch/coreDispatch.d.ts +9 -0
- package/dist/tools/dispatch/coreDispatch.js +283 -0
- package/dist/tools/dispatch/diagnosticDispatch.d.ts +12 -0
- package/dist/tools/dispatch/diagnosticDispatch.js +80 -0
- package/dist/tools/dispatch/directDispatch.d.ts +8 -0
- package/dist/tools/dispatch/directDispatch.js +116 -0
- package/dist/tools/dispatch/goalDispatch.d.ts +8 -0
- package/dist/tools/dispatch/goalDispatch.js +92 -0
- package/dist/tools/dispatch/releaseDispatch.d.ts +8 -0
- package/dist/tools/dispatch/releaseDispatch.js +46 -0
- package/dist/tools/dispatch/types.d.ts +23 -0
- package/dist/tools/dispatch/types.js +15 -0
- package/dist/tools/dispatch/validation.d.ts +7 -0
- package/dist/tools/dispatch/validation.js +71 -0
- package/dist/tools/{getPlan.js → goals/getPlan.js} +4 -4
- package/dist/tools/{goalSubgoalTask.d.ts → goals/goalSubgoalTask.d.ts} +2 -2
- package/dist/tools/goals/goalSubgoalTask.js +118 -0
- package/dist/tools/goals/index.d.ts +3 -0
- package/dist/tools/goals/index.js +3 -0
- package/dist/tools/{savePlan.js → goals/savePlan.js} +28 -8
- package/dist/tools/registry.d.ts +10 -14
- package/dist/tools/registry.js +47 -1651
- package/dist/tools/{checkReleaseGate.d.ts → release/checkReleaseGate.d.ts} +1 -1
- package/dist/tools/{checkReleaseGate.js → release/checkReleaseGate.js} +3 -3
- package/dist/tools/release/index.d.ts +2 -0
- package/dist/tools/release/index.js +2 -0
- package/dist/tools/{releaseMode.d.ts → release/releaseMode.d.ts} +2 -2
- package/dist/tools/{releaseMode.js → release/releaseMode.js} +46 -26
- package/dist/tools/tasks/cancelTask.d.ts +11 -0
- package/dist/tools/tasks/cancelTask.js +85 -0
- package/dist/tools/{createTask.d.ts → tasks/createTask.d.ts} +12 -4
- package/dist/tools/{createTask.js → tasks/createTask.js} +46 -31
- package/dist/tools/{diagnoseTask.d.ts → tasks/diagnoseTask.d.ts} +1 -1
- package/dist/tools/{diagnoseTask.js → tasks/diagnoseTask.js} +8 -8
- package/dist/tools/{evidencePack.d.ts → tasks/evidencePack.d.ts} +6 -0
- package/dist/tools/tasks/evidencePack.js +387 -0
- package/dist/tools/{getTaskFile.js → tasks/getTaskFile.js} +4 -4
- package/dist/tools/{getTaskStatus.d.ts → tasks/getTaskStatus.d.ts} +6 -1
- package/dist/tools/{getTaskStatus.js → tasks/getTaskStatus.js} +5 -5
- package/dist/tools/{getTaskStdoutTail.js → tasks/getTaskStdoutTail.js} +13 -11
- package/dist/tools/{getTaskSummary.js → tasks/getTaskSummary.js} +33 -26
- package/dist/tools/tasks/index.d.ts +18 -0
- package/dist/tools/tasks/index.js +18 -0
- package/dist/tools/tasks/killTask.d.ts +1 -0
- package/dist/tools/{listTasks.d.ts → tasks/listTasks.d.ts} +1 -1
- package/dist/tools/{listTasks.js → tasks/listTasks.js} +3 -3
- package/dist/tools/{reconcileTasks.d.ts → tasks/reconcileTasks.d.ts} +1 -1
- package/dist/tools/{reconcileTasks.js → tasks/reconcileTasks.js} +64 -66
- package/dist/tools/{retryTask.d.ts → tasks/retryTask.d.ts} +2 -2
- package/dist/tools/tasks/retryTask.js +60 -0
- package/dist/tools/{runTaskLoop.d.ts → tasks/runTaskLoop.d.ts} +6 -6
- package/dist/tools/{runTaskLoop.js → tasks/runTaskLoop.js} +59 -31
- package/dist/tools/tasks/runVerification.js +38 -0
- package/dist/tools/{taskLineage.js → tasks/taskLineage.js} +8 -7
- package/dist/tools/{taskOutputs.js → tasks/taskOutputs.js} +17 -16
- package/dist/tools/{androidDoctor.js → workspace/androidDoctor.js} +16 -10
- package/dist/tools/{applyPatch.d.ts → workspace/applyPatch.d.ts} +1 -1
- package/dist/tools/workspace/applyPatch.js +53 -0
- package/dist/tools/{discardWorktree.js → workspace/discardWorktree.js} +3 -3
- package/dist/tools/workspace/index.d.ts +10 -0
- package/dist/tools/workspace/index.js +10 -0
- package/dist/tools/{listAgents.d.ts → workspace/listAgents.d.ts} +5 -0
- package/dist/tools/{listAgents.js → workspace/listAgents.js} +8 -4
- package/dist/tools/{listWorkspace.js → workspace/listWorkspace.js} +3 -3
- package/dist/tools/{mergeWorktree.js → workspace/mergeWorktree.js} +3 -3
- package/dist/tools/{readWorkspaceFile.js → workspace/readWorkspaceFile.js} +8 -8
- package/dist/tools/{recommendAgentForTask.js → workspace/recommendAgentForTask.js} +3 -3
- package/dist/tools/{searchWorkspace.js → workspace/searchWorkspace.js} +5 -5
- package/dist/tools/{syncFile.d.ts → workspace/syncFile.d.ts} +1 -1
- package/dist/tools/workspace/syncFile.js +134 -0
- package/dist/utils/atomicFile.d.ts +7 -0
- package/dist/utils/atomicFile.js +48 -0
- package/dist/utils/boundedFile.d.ts +8 -0
- package/dist/utils/boundedFile.js +93 -0
- package/dist/utils/lockedJsonFile.d.ts +15 -0
- package/dist/utils/lockedJsonFile.js +224 -0
- package/dist/utils/platform.d.ts +11 -0
- package/dist/utils/platform.js +26 -0
- package/dist/utils/stableJson.d.ts +2 -0
- package/dist/utils/stableJson.js +12 -0
- package/dist/version.d.ts +3 -2
- package/dist/version.js +3 -2
- package/dist/watcherStatus.d.ts +2 -2
- package/dist/watcherStatus.js +18 -0
- package/docs/CODE_WIKI.md +1648 -0
- package/docs/agentseal-integration.md +150 -0
- package/docs/architecture.md +23 -0
- package/docs/assets/patchwarden-desktop-onboarding.png +0 -0
- package/docs/assets/patchwarden-oss-demo.gif +0 -0
- package/docs/control-center/README.md +4 -4
- package/docs/dashboard-overview.md +86 -0
- package/docs/demo.md +8 -0
- package/docs/desktop-app.md +175 -0
- package/docs/direct-session-workflow.md +98 -0
- package/docs/evidence-pack-schema.md +215 -0
- package/docs/lineage-evidence-pack-workflow.md +127 -0
- package/docs/mcp-inspector-testing.md +200 -0
- package/docs/open-source-application.md +168 -0
- package/docs/opencode-worker.md +151 -0
- package/docs/openhands-worker.md +181 -0
- package/docs/release-checklist.md +1 -1
- package/docs/release-evidence.md +82 -0
- package/docs/spec-kit-integration.md +131 -0
- package/docs/task-safe-review-workflow.md +98 -0
- package/docs/threat-model.md +97 -0
- package/docs/user-feedback.md +40 -0
- package/docs/why-patchwarden.md +110 -0
- package/examples/config.example.json +4 -2
- package/package.json +28 -11
- package/scripts/README.md +15 -6
- package/scripts/build.js +11 -0
- package/scripts/checks/brand-check.js +3 -0
- package/scripts/checks/build-output-check.js +37 -0
- package/scripts/checks/control-center-smoke.js +447 -6
- package/scripts/checks/control-smoke.js +19 -8
- package/scripts/checks/http-mcp-smoke.js +82 -4
- package/scripts/checks/lifecycle-smoke.js +39 -33
- package/scripts/checks/mcp-manifest-check.js +1 -1
- package/scripts/checks/mcp-smoke.js +30 -4
- package/scripts/checks/package-manifest-check.js +20 -7
- package/scripts/checks/unit-tests.js +3 -5
- package/scripts/checks/watcher-supervisor-smoke.js +9 -0
- package/scripts/control/get-patchwarden-health.ps1 +1 -1
- package/scripts/control/manage-patchwarden.ps1 +69 -4
- package/scripts/control/provision-patchwarden-tunnel.ps1 +127 -0
- package/scripts/control/run-background-supervisor.ps1 +41 -0
- package/scripts/control/start-patchwarden-tunnel.ps1 +126 -32
- package/scripts/generate-demo-gif.py +320 -0
- package/{PatchWarden-Control-Tray.cmd → scripts/launchers/PatchWarden-Control-Tray.cmd} +3 -3
- package/scripts/launchers/PatchWarden-Control.cmd +6 -0
- package/{PatchWarden-Desktop.cmd → scripts/launchers/PatchWarden-Desktop.cmd} +2 -2
- package/scripts/launchers/Restart-PatchWarden-Control.cmd +6 -0
- package/{Stop-PatchWarden.cmd → scripts/launchers/Stop-PatchWarden.cmd} +2 -2
- package/scripts/lib/clean-generated-output.js +11 -0
- package/scripts/lib/file-discovery.js +12 -0
- package/scripts/release/desktop-preflight.js +211 -0
- package/scripts/release/pack-clean.js +59 -14
- package/src/assessments/agentAssessor.ts +29 -15
- package/src/assessments/assessmentStore.ts +55 -43
- package/src/assessments/confirmCli.ts +5 -4
- package/src/config.ts +105 -11
- package/src/control/fileManager.ts +40 -0
- package/src/control/middleware/auth.ts +35 -0
- package/src/control/middleware/static.ts +84 -0
- package/src/control/routeTable.ts +301 -0
- package/src/control/routes/audit.ts +329 -0
- package/src/control/routes/evidence.ts +107 -0
- package/src/control/routes/lineage.ts +92 -0
- package/src/control/routes/policy.ts +81 -0
- package/src/control/routes/process.ts +505 -0
- package/src/control/routes/sessions.ts +314 -0
- package/src/control/routes/status.ts +405 -0
- package/src/control/routes/taskActions.ts +214 -0
- package/src/control/routes/tasks.ts +331 -0
- package/src/control/routes/workspace.ts +234 -0
- package/src/control/runtime.ts +508 -0
- package/src/control/server.ts +165 -0
- package/src/control/shared.ts +360 -0
- package/src/controlCenter.ts +7 -2347
- package/src/direct/directAudit.ts +17 -9
- package/src/direct/directGuards.ts +100 -51
- package/src/direct/directPatch.ts +95 -8
- package/src/direct/directSessionStore.ts +211 -55
- package/src/direct/directVerification.ts +9 -23
- package/src/doctor.ts +766 -492
- package/src/goal/acceptanceEngine.ts +1 -1
- package/src/goal/goalProgress.ts +17 -13
- package/src/goal/goalReport.ts +263 -0
- package/src/goal/goalStatus.ts +25 -3
- package/src/goal/goalStore.ts +241 -54
- package/src/goal/handoffExport.ts +6 -6
- package/src/goal/specKitImport.ts +355 -0
- package/src/goal/subgoalSync.ts +15 -10
- package/src/goal/worktreeManager.ts +139 -22
- package/src/httpServer.ts +130 -44
- package/src/index.ts +7 -4
- package/src/logging.ts +20 -4
- package/src/policy/projectPolicy.ts +5 -2
- package/src/release/releaseGate.ts +74 -27
- package/src/runner/agentInvocation.ts +126 -4
- package/src/runner/changeCapture.ts +342 -80
- package/src/runner/cli.ts +7 -6
- package/src/runner/postTaskCleanup.ts +55 -7
- package/src/runner/processSecurity.ts +433 -0
- package/src/runner/runTask.ts +441 -292
- package/src/runner/simpleProcess.ts +68 -33
- package/src/{taskProgress.ts → runner/taskProgress.ts} +3 -3
- package/src/{taskRuntime.ts → runner/taskRuntime.ts} +4 -3
- package/src/runner/taskStatusStore.ts +54 -0
- package/src/runner/watch.ts +290 -57
- package/src/security/contentRedaction.ts +31 -2
- package/src/security/discoveryTokenStore.ts +18 -4
- package/src/security/loopbackHost.ts +19 -0
- package/src/security/pathGuard.ts +35 -16
- package/src/security/planGuard.ts +2 -1
- package/src/security/runtimeGuard.ts +9 -6
- package/src/security/secretComparison.ts +13 -0
- package/src/security/sensitiveGuard.ts +27 -8
- package/src/security/toolInvocationGuard.ts +2 -2
- package/src/security/workspaceRootGuard.ts +53 -0
- package/src/smoke-test.ts +276 -273
- package/src/tools/catalog/index.ts +4 -0
- package/src/tools/{toolCatalog.ts → catalog/toolCatalog.ts} +3 -12
- package/src/tools/{toolRegistry.ts → catalog/toolRegistry.ts} +29 -16
- package/src/tools/definitions/toolDefs.ts +1264 -0
- package/src/tools/{auditSession.ts → diagnostics/auditSession.ts} +2 -2
- package/src/tools/{auditTask.ts → diagnostics/auditTask.ts} +196 -89
- package/src/tools/{healthCheck.ts → diagnostics/healthCheck.ts} +11 -11
- package/src/tools/diagnostics/index.ts +6 -0
- package/src/tools/{safeStatus.ts → diagnostics/safeStatus.ts} +7 -7
- package/src/tools/{safeViews.ts → diagnostics/safeViews.ts} +29 -19
- package/src/tools/{schemaDriftCheck.ts → diagnostics/schemaDriftCheck.ts} +3 -3
- package/src/tools/{createDirectSession.ts → direct/createDirectSession.ts} +9 -9
- package/src/tools/{finalizeDirectSession.ts → direct/finalizeDirectSession.ts} +11 -9
- package/src/tools/direct/index.ts +3 -0
- package/src/tools/{runDirectVerificationBundle.ts → direct/runDirectVerificationBundle.ts} +2 -2
- package/src/tools/{discoverTools.ts → discovery/discoverTools.ts} +6 -6
- package/src/tools/{explainTool.ts → discovery/explainTool.ts} +3 -3
- package/src/tools/discovery/index.ts +3 -0
- package/src/tools/{invokeDiscoveredTool.ts → discovery/invokeDiscoveredTool.ts} +7 -7
- package/src/tools/dispatch/coreDispatch.ts +379 -0
- package/src/tools/dispatch/diagnosticDispatch.ts +106 -0
- package/src/tools/dispatch/directDispatch.ts +168 -0
- package/src/tools/dispatch/goalDispatch.ts +128 -0
- package/src/tools/dispatch/releaseDispatch.ts +66 -0
- package/src/tools/dispatch/types.ts +24 -0
- package/src/tools/dispatch/validation.ts +78 -0
- package/src/tools/{getPlan.ts → goals/getPlan.ts} +4 -4
- package/src/tools/{goalSubgoalTask.ts → goals/goalSubgoalTask.ts} +43 -28
- package/src/tools/goals/index.ts +3 -0
- package/src/tools/{savePlan.ts → goals/savePlan.ts} +38 -8
- package/src/tools/registry.ts +54 -1858
- package/src/tools/{checkReleaseGate.ts → release/checkReleaseGate.ts} +3 -3
- package/src/tools/release/index.ts +2 -0
- package/src/tools/{releaseMode.ts → release/releaseMode.ts} +42 -24
- package/src/tools/tasks/cancelTask.ts +109 -0
- package/src/tools/{createTask.ts → tasks/createTask.ts} +56 -33
- package/src/tools/{diagnoseTask.ts → tasks/diagnoseTask.ts} +8 -8
- package/src/tools/tasks/evidencePack.ts +504 -0
- package/src/tools/{getTaskFile.ts → tasks/getTaskFile.ts} +4 -4
- package/src/tools/{getTaskStatus.ts → tasks/getTaskStatus.ts} +7 -5
- package/src/tools/{getTaskStdoutTail.ts → tasks/getTaskStdoutTail.ts} +13 -11
- package/src/tools/{getTaskSummary.ts → tasks/getTaskSummary.ts} +44 -33
- package/src/tools/tasks/index.ts +18 -0
- package/src/tools/{listTasks.ts → tasks/listTasks.ts} +4 -4
- package/src/tools/{reconcileTasks.ts → tasks/reconcileTasks.ts} +68 -66
- package/src/tools/tasks/retryTask.ts +69 -0
- package/src/tools/{runTaskLoop.ts → tasks/runTaskLoop.ts} +70 -35
- package/src/tools/{runVerification.ts → tasks/runVerification.ts} +6 -3
- package/src/tools/{taskLineage.ts → tasks/taskLineage.ts} +8 -7
- package/src/tools/{taskOutputs.ts → tasks/taskOutputs.ts} +27 -20
- package/src/tools/{androidDoctor.ts → workspace/androidDoctor.ts} +15 -10
- package/src/tools/{applyPatch.ts → workspace/applyPatch.ts} +38 -16
- package/src/tools/{discardWorktree.ts → workspace/discardWorktree.ts} +3 -3
- package/src/tools/workspace/index.ts +10 -0
- package/src/tools/{listAgents.ts → workspace/listAgents.ts} +11 -4
- package/src/tools/{listWorkspace.ts → workspace/listWorkspace.ts} +3 -3
- package/src/tools/{mergeWorktree.ts → workspace/mergeWorktree.ts} +3 -3
- package/src/tools/{readWorkspaceFile.ts → workspace/readWorkspaceFile.ts} +8 -8
- package/src/tools/{recommendAgentForTask.ts → workspace/recommendAgentForTask.ts} +3 -3
- package/src/tools/{searchWorkspace.ts → workspace/searchWorkspace.ts} +5 -5
- package/src/tools/workspace/syncFile.ts +292 -0
- package/src/utils/atomicFile.ts +58 -0
- package/src/utils/boundedFile.ts +116 -0
- package/src/utils/lockedJsonFile.ts +251 -0
- package/src/utils/platform.ts +31 -0
- package/src/utils/stableJson.ts +12 -0
- package/src/version.ts +3 -2
- package/src/watcherStatus.ts +19 -1
- package/ui/desktop-bootstrap.js +11 -0
- package/ui/desktop-bridge.js +36 -0
- package/ui/desktop.css +160 -0
- package/ui/getting-started.js +93 -0
- package/ui/i18n.js +484 -0
- package/ui/log-parser.js +30 -0
- package/ui/pages/audit.html +204 -3
- package/ui/pages/dashboard.html +937 -79
- package/ui/pages/direct-sessions.html +609 -60
- package/ui/pages/getting-started.html +43 -0
- package/ui/pages/logs.html +105 -22
- package/ui/pages/settings.html +101 -0
- package/ui/pages/task-detail.html +468 -438
- package/ui/pages/tasks.html +648 -65
- package/ui/pages/workspace.html +38 -1
- package/ui/settings.js +245 -0
- package/PatchWarden-Control.cmd +0 -6
- package/Restart-PatchWarden-Control.cmd +0 -6
- package/dist/test/unit/acceptance-engine.test.d.ts +0 -1
- package/dist/test/unit/acceptance-engine.test.js +0 -228
- package/dist/test/unit/agent-router.test.d.ts +0 -1
- package/dist/test/unit/agent-router.test.js +0 -287
- package/dist/test/unit/android-doctor.test.d.ts +0 -1
- package/dist/test/unit/android-doctor.test.js +0 -118
- package/dist/test/unit/audit-checks.test.d.ts +0 -1
- package/dist/test/unit/audit-checks.test.js +0 -350
- package/dist/test/unit/chinese-path.test.d.ts +0 -1
- package/dist/test/unit/chinese-path.test.js +0 -91
- package/dist/test/unit/command-guard.test.d.ts +0 -1
- package/dist/test/unit/command-guard.test.js +0 -160
- package/dist/test/unit/diagnose-task.test.d.ts +0 -1
- package/dist/test/unit/diagnose-task.test.js +0 -457
- package/dist/test/unit/direct-guards.test.d.ts +0 -1
- package/dist/test/unit/direct-guards.test.js +0 -213
- package/dist/test/unit/discovery-token-store.test.d.ts +0 -1
- package/dist/test/unit/discovery-token-store.test.js +0 -139
- package/dist/test/unit/evidence-pack.test.d.ts +0 -1
- package/dist/test/unit/evidence-pack.test.js +0 -130
- package/dist/test/unit/goal-graph.test.d.ts +0 -1
- package/dist/test/unit/goal-graph.test.js +0 -298
- package/dist/test/unit/goal-progress.test.d.ts +0 -1
- package/dist/test/unit/goal-progress.test.js +0 -381
- package/dist/test/unit/goal-status.test.d.ts +0 -1
- package/dist/test/unit/goal-status.test.js +0 -215
- package/dist/test/unit/goal-store.test.d.ts +0 -1
- package/dist/test/unit/goal-store.test.js +0 -253
- package/dist/test/unit/goal-subgoal-task.test.d.ts +0 -1
- package/dist/test/unit/goal-subgoal-task.test.js +0 -55
- package/dist/test/unit/goal-tools-registry.test.d.ts +0 -1
- package/dist/test/unit/goal-tools-registry.test.js +0 -190
- package/dist/test/unit/handoff-export.test.d.ts +0 -1
- package/dist/test/unit/handoff-export.test.js +0 -263
- package/dist/test/unit/invoke-discovered-tool.test.d.ts +0 -1
- package/dist/test/unit/invoke-discovered-tool.test.js +0 -167
- package/dist/test/unit/logging.test.d.ts +0 -1
- package/dist/test/unit/logging.test.js +0 -397
- package/dist/test/unit/path-guard.test.d.ts +0 -1
- package/dist/test/unit/path-guard.test.js +0 -109
- package/dist/test/unit/post-task-cleanup.test.d.ts +0 -1
- package/dist/test/unit/post-task-cleanup.test.js +0 -48
- package/dist/test/unit/project-policy-release-mode.test.d.ts +0 -1
- package/dist/test/unit/project-policy-release-mode.test.js +0 -125
- package/dist/test/unit/reconcile-tasks.test.d.ts +0 -1
- package/dist/test/unit/reconcile-tasks.test.js +0 -456
- package/dist/test/unit/release-gate.test.d.ts +0 -1
- package/dist/test/unit/release-gate.test.js +0 -242
- package/dist/test/unit/run-task-loop.test.d.ts +0 -1
- package/dist/test/unit/run-task-loop.test.js +0 -380
- package/dist/test/unit/safe-status.test.d.ts +0 -1
- package/dist/test/unit/safe-status.test.js +0 -165
- package/dist/test/unit/safe-views.test.d.ts +0 -1
- package/dist/test/unit/safe-views.test.js +0 -171
- package/dist/test/unit/schema-drift-check.test.d.ts +0 -1
- package/dist/test/unit/schema-drift-check.test.js +0 -176
- package/dist/test/unit/sensitive-guard.test.d.ts +0 -1
- package/dist/test/unit/sensitive-guard.test.js +0 -104
- package/dist/test/unit/subgoal-sync.test.d.ts +0 -1
- package/dist/test/unit/subgoal-sync.test.js +0 -183
- package/dist/test/unit/sync-file.test.d.ts +0 -1
- package/dist/test/unit/sync-file.test.js +0 -154
- package/dist/test/unit/tool-invocation-guard.test.d.ts +0 -1
- package/dist/test/unit/tool-invocation-guard.test.js +0 -432
- package/dist/test/unit/tool-usage-stats.test.d.ts +0 -1
- package/dist/test/unit/tool-usage-stats.test.js +0 -300
- package/dist/test/unit/toolSearch.test.d.ts +0 -1
- package/dist/test/unit/toolSearch.test.js +0 -571
- package/dist/test/unit/watcher-status.test.d.ts +0 -1
- package/dist/test/unit/watcher-status.test.js +0 -169
- package/dist/test/unit/worktree-manager.test.d.ts +0 -1
- package/dist/test/unit/worktree-manager.test.js +0 -176
- package/dist/tools/applyPatch.js +0 -41
- package/dist/tools/cancelTask.d.ts +0 -30
- package/dist/tools/cancelTask.js +0 -64
- package/dist/tools/evidencePack.js +0 -168
- package/dist/tools/finalizeDirectSession.js +0 -84
- package/dist/tools/goalSubgoalTask.js +0 -110
- package/dist/tools/killTask.d.ts +0 -15
- package/dist/tools/retryTask.js +0 -45
- package/dist/tools/runVerification.js +0 -36
- package/dist/tools/syncFile.js +0 -65
- package/docs/control-center/control-center-daily-driver.md +0 -211
- package/docs/control-center/control-center-mvp.md +0 -205
- package/docs/control-center/control-center-phase2.md +0 -159
- package/docs/release-v0.6.0.md +0 -71
- package/docs/release-v0.6.1.md +0 -75
- package/docs/release-v0.6.4.md +0 -45
- package/src/test/unit/acceptance-engine.test.ts +0 -261
- package/src/test/unit/agent-router.test.ts +0 -342
- package/src/test/unit/android-doctor.test.ts +0 -158
- package/src/test/unit/audit-checks.test.ts +0 -567
- package/src/test/unit/chinese-path.test.ts +0 -106
- package/src/test/unit/command-guard.test.ts +0 -221
- package/src/test/unit/diagnose-task.test.ts +0 -544
- package/src/test/unit/direct-guards.test.ts +0 -297
- package/src/test/unit/discovery-token-store.test.ts +0 -181
- package/src/test/unit/evidence-pack.test.ts +0 -142
- package/src/test/unit/goal-graph.test.ts +0 -347
- package/src/test/unit/goal-progress.test.ts +0 -538
- package/src/test/unit/goal-status.test.ts +0 -270
- package/src/test/unit/goal-store.test.ts +0 -318
- package/src/test/unit/goal-subgoal-task.test.ts +0 -72
- package/src/test/unit/goal-tools-registry.test.ts +0 -243
- package/src/test/unit/handoff-export.test.ts +0 -295
- package/src/test/unit/invoke-discovered-tool.test.ts +0 -216
- package/src/test/unit/logging.test.ts +0 -497
- package/src/test/unit/path-guard.test.ts +0 -150
- package/src/test/unit/post-task-cleanup.test.ts +0 -53
- package/src/test/unit/project-policy-release-mode.test.ts +0 -156
- package/src/test/unit/reconcile-tasks.test.ts +0 -551
- package/src/test/unit/release-gate.test.ts +0 -314
- package/src/test/unit/run-task-loop.test.ts +0 -425
- package/src/test/unit/safe-status.test.ts +0 -187
- package/src/test/unit/safe-views.test.ts +0 -184
- package/src/test/unit/schema-drift-check.test.ts +0 -260
- package/src/test/unit/sensitive-guard.test.ts +0 -124
- package/src/test/unit/subgoal-sync.test.ts +0 -236
- package/src/test/unit/sync-file.test.ts +0 -231
- package/src/test/unit/tool-invocation-guard.test.ts +0 -542
- package/src/test/unit/tool-usage-stats.test.ts +0 -384
- package/src/test/unit/toolSearch.test.ts +0 -756
- package/src/test/unit/watcher-status.test.ts +0 -190
- package/src/test/unit/worktree-manager.test.ts +0 -247
- package/src/tools/cancelTask.ts +0 -70
- package/src/tools/evidencePack.ts +0 -205
- package/src/tools/retryTask.ts +0 -53
- package/src/tools/syncFile.ts +0 -122
- /package/dist/tools/{toolCatalog.d.ts → catalog/toolCatalog.d.ts} +0 -0
- /package/dist/tools/{toolSearch.d.ts → catalog/toolSearch.d.ts} +0 -0
- /package/dist/tools/{toolSearch.js → catalog/toolSearch.js} +0 -0
- /package/dist/tools/{toolUsageStats.d.ts → catalog/toolUsageStats.d.ts} +0 -0
- /package/dist/tools/{toolUsageStats.js → catalog/toolUsageStats.js} +0 -0
- /package/dist/tools/{runDirectVerificationBundle.d.ts → direct/runDirectVerificationBundle.d.ts} +0 -0
- /package/dist/tools/{getPlan.d.ts → goals/getPlan.d.ts} +0 -0
- /package/dist/tools/{savePlan.d.ts → goals/savePlan.d.ts} +0 -0
- /package/dist/tools/{getTaskFile.d.ts → tasks/getTaskFile.d.ts} +0 -0
- /package/dist/tools/{getTaskProgress.d.ts → tasks/getTaskProgress.d.ts} +0 -0
- /package/dist/tools/{getTaskProgress.js → tasks/getTaskProgress.js} +0 -0
- /package/dist/tools/{getTaskStdoutTail.d.ts → tasks/getTaskStdoutTail.d.ts} +0 -0
- /package/dist/tools/{getTaskSummary.d.ts → tasks/getTaskSummary.d.ts} +0 -0
- /package/dist/tools/{killTask.js → tasks/killTask.js} +0 -0
- /package/dist/tools/{runVerification.d.ts → tasks/runVerification.d.ts} +0 -0
- /package/dist/tools/{taskLineage.d.ts → tasks/taskLineage.d.ts} +0 -0
- /package/dist/tools/{taskOutputs.d.ts → tasks/taskOutputs.d.ts} +0 -0
- /package/dist/tools/{waitForTask.d.ts → tasks/waitForTask.d.ts} +0 -0
- /package/dist/tools/{waitForTask.js → tasks/waitForTask.js} +0 -0
- /package/dist/tools/{androidDoctor.d.ts → workspace/androidDoctor.d.ts} +0 -0
- /package/dist/tools/{discardWorktree.d.ts → workspace/discardWorktree.d.ts} +0 -0
- /package/dist/tools/{listWorkspace.d.ts → workspace/listWorkspace.d.ts} +0 -0
- /package/dist/tools/{mergeWorktree.d.ts → workspace/mergeWorktree.d.ts} +0 -0
- /package/dist/tools/{readWorkspaceFile.d.ts → workspace/readWorkspaceFile.d.ts} +0 -0
- /package/dist/tools/{recommendAgentForTask.d.ts → workspace/recommendAgentForTask.d.ts} +0 -0
- /package/dist/tools/{searchWorkspace.d.ts → workspace/searchWorkspace.d.ts} +0 -0
- /package/src/tools/{toolSearch.ts → catalog/toolSearch.ts} +0 -0
- /package/src/tools/{toolUsageStats.ts → catalog/toolUsageStats.ts} +0 -0
- /package/src/tools/{getTaskProgress.ts → tasks/getTaskProgress.ts} +0 -0
- /package/src/tools/{killTask.ts → tasks/killTask.ts} +0 -0
- /package/src/tools/{waitForTask.ts → tasks/waitForTask.ts} +0 -0
package/ui/pages/tasks.html
CHANGED
|
@@ -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 -->
|
|
@@ -250,36 +260,134 @@ html.dark {
|
|
|
250
260
|
<main class="flex-1 overflow-y-auto p-6" style="background-color: var(--pw-bg-elevated);">
|
|
251
261
|
|
|
252
262
|
<!-- ===== Filter Bar ===== -->
|
|
253
|
-
<div class="
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
<
|
|
257
|
-
<
|
|
258
|
-
<
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
263
|
+
<div class="rounded-lg mb-5 p-4" style="background-color: var(--pw-bg-surface); border: 1px solid var(--pw-border);">
|
|
264
|
+
<div class="flex flex-wrap items-end gap-3">
|
|
265
|
+
<!-- Repo Path Filter -->
|
|
266
|
+
<div class="flex flex-col gap-1">
|
|
267
|
+
<label class="text-xs font-medium" style="color: var(--pw-text-tertiary); font-family: var(--pw-font-sans);" data-zh="仓库" data-en="Repo">仓库</label>
|
|
268
|
+
<div class="relative">
|
|
269
|
+
<select id="repoFilter" class="appearance-none pl-3 pr-8 py-1.5 rounded-lg text-xs font-medium outline-none cursor-pointer transition-colors" style="background-color: var(--pw-bg-elevated); border: 1px solid var(--pw-border-subtle); color: var(--pw-text-primary); font-family: var(--pw-font-sans); min-width: 180px;">
|
|
270
|
+
<option value="" data-zh="全部仓库" data-en="All repos">全部仓库</option>
|
|
271
|
+
</select>
|
|
272
|
+
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="var(--pw-text-tertiary)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="absolute right-2.5 top-1/2 -translate-y-1/2 pointer-events-none">
|
|
273
|
+
<polyline points="6 9 12 15 18 9"/>
|
|
274
|
+
</svg>
|
|
275
|
+
</div>
|
|
276
|
+
</div>
|
|
277
|
+
|
|
278
|
+
<!-- Status Filter -->
|
|
279
|
+
<div class="flex flex-col gap-1">
|
|
280
|
+
<label class="text-xs font-medium" style="color: var(--pw-text-tertiary); font-family: var(--pw-font-sans);" data-zh="状态" data-en="Status">状态</label>
|
|
281
|
+
<div class="relative">
|
|
282
|
+
<select id="statusFilter" class="appearance-none pl-3 pr-8 py-1.5 rounded-lg text-xs font-medium outline-none cursor-pointer transition-colors" style="background-color: var(--pw-bg-elevated); border: 1px solid var(--pw-border-subtle); color: var(--pw-text-primary); font-family: var(--pw-font-sans); min-width: 140px;">
|
|
283
|
+
<option value="" data-zh="全部状态" data-en="All Status">全部状态</option>
|
|
284
|
+
<option value="running">Running</option>
|
|
285
|
+
<option value="pending">Pending</option>
|
|
286
|
+
<option value="done">Done</option>
|
|
287
|
+
<option value="failed">Failed</option>
|
|
288
|
+
<option value="failed_verification">Failed Verification</option>
|
|
289
|
+
<option value="failed_policy_violation">Failed Policy Violation</option>
|
|
290
|
+
<option value="failed_scope_violation">Failed Scope Violation</option>
|
|
291
|
+
<option value="needs_fix">Needs Fix</option>
|
|
292
|
+
<option value="ready_for_review">Ready For Review</option>
|
|
293
|
+
<option value="done_by_agent">Done By Agent</option>
|
|
294
|
+
</select>
|
|
295
|
+
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="var(--pw-text-tertiary)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="absolute right-2.5 top-1/2 -translate-y-1/2 pointer-events-none">
|
|
296
|
+
<polyline points="6 9 12 15 18 9"/>
|
|
297
|
+
</svg>
|
|
298
|
+
</div>
|
|
299
|
+
</div>
|
|
300
|
+
|
|
301
|
+
<!-- Acceptance Status Filter -->
|
|
302
|
+
<div class="flex flex-col gap-1">
|
|
303
|
+
<label class="text-xs font-medium" style="color: var(--pw-text-tertiary); font-family: var(--pw-font-sans);" data-zh="验收" data-en="Acceptance">验收</label>
|
|
304
|
+
<div class="relative">
|
|
305
|
+
<select id="acceptanceFilter" class="appearance-none pl-3 pr-8 py-1.5 rounded-lg text-xs font-medium outline-none cursor-pointer transition-colors" style="background-color: var(--pw-bg-elevated); border: 1px solid var(--pw-border-subtle); color: var(--pw-text-primary); font-family: var(--pw-font-sans); min-width: 160px;">
|
|
306
|
+
<option value="" data-zh="全部验收" data-en="All Acceptance">全部验收</option>
|
|
307
|
+
<option value="ready_for_review">Ready For Review</option>
|
|
308
|
+
<option value="done_by_agent">Done By Agent</option>
|
|
309
|
+
<option value="needs_fix">Needs Fix</option>
|
|
310
|
+
<option value="failed_verification">Failed Verification</option>
|
|
311
|
+
<option value="failed_policy_violation">Failed Policy Violation</option>
|
|
312
|
+
<option value="failed_scope_violation">Failed Scope Violation</option>
|
|
313
|
+
</select>
|
|
314
|
+
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="var(--pw-text-tertiary)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="absolute right-2.5 top-1/2 -translate-y-1/2 pointer-events-none">
|
|
315
|
+
<polyline points="6 9 12 15 18 9"/>
|
|
316
|
+
</svg>
|
|
317
|
+
</div>
|
|
318
|
+
</div>
|
|
319
|
+
|
|
320
|
+
<!-- Warning Type Filter -->
|
|
321
|
+
<div class="flex flex-col gap-1">
|
|
322
|
+
<label class="text-xs font-medium" style="color: var(--pw-text-tertiary); font-family: var(--pw-font-sans);" data-zh="警告类型" data-en="Warning Type">警告类型</label>
|
|
323
|
+
<div class="relative">
|
|
324
|
+
<select id="warningTypeFilter" class="appearance-none pl-3 pr-8 py-1.5 rounded-lg text-xs font-medium outline-none cursor-pointer transition-colors" style="background-color: var(--pw-bg-elevated); border: 1px solid var(--pw-border-subtle); color: var(--pw-text-primary); font-family: var(--pw-font-sans); min-width: 180px;">
|
|
325
|
+
<option value="" data-zh="全部警告" data-en="All Warnings">全部警告</option>
|
|
326
|
+
<option value="unrecorded_command_execution">Unrecorded Command Execution</option>
|
|
327
|
+
<option value="artifact_hygiene">Artifact Hygiene</option>
|
|
328
|
+
<option value="scope_changes">Scope Changes</option>
|
|
329
|
+
<option value="release_publish_claim">Release Publish Claim</option>
|
|
330
|
+
<option value="manual_verification_required">Manual Verification Required</option>
|
|
331
|
+
<option value="stale_task">Stale Task</option>
|
|
332
|
+
<option value="failed_verification">Failed Verification</option>
|
|
333
|
+
</select>
|
|
334
|
+
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="var(--pw-text-tertiary)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="absolute right-2.5 top-1/2 -translate-y-1/2 pointer-events-none">
|
|
335
|
+
<polyline points="6 9 12 15 18 9"/>
|
|
336
|
+
</svg>
|
|
337
|
+
</div>
|
|
338
|
+
</div>
|
|
339
|
+
|
|
340
|
+
<!-- Agent Filter -->
|
|
341
|
+
<div class="flex flex-col gap-1">
|
|
342
|
+
<label class="text-xs font-medium" style="color: var(--pw-text-tertiary); font-family: var(--pw-font-sans);" data-zh="Agent" data-en="Agent">Agent</label>
|
|
343
|
+
<div class="relative">
|
|
344
|
+
<select id="agentFilter" class="appearance-none pl-3 pr-8 py-1.5 rounded-lg text-xs font-medium outline-none cursor-pointer transition-colors" style="background-color: var(--pw-bg-elevated); border: 1px solid var(--pw-border-subtle); color: var(--pw-text-primary); font-family: var(--pw-font-sans); min-width: 140px;">
|
|
345
|
+
<option value="" data-zh="全部 Agent" data-en="All Agents">全部 Agent</option>
|
|
346
|
+
</select>
|
|
347
|
+
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="var(--pw-text-tertiary)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="absolute right-2.5 top-1/2 -translate-y-1/2 pointer-events-none">
|
|
348
|
+
<polyline points="6 9 12 15 18 9"/>
|
|
349
|
+
</svg>
|
|
350
|
+
</div>
|
|
351
|
+
</div>
|
|
352
|
+
|
|
353
|
+
<!-- Date From -->
|
|
354
|
+
<div class="flex flex-col gap-1">
|
|
355
|
+
<label class="text-xs font-medium" style="color: var(--pw-text-tertiary); font-family: var(--pw-font-sans);" data-zh="更新从" data-en="Updated From">更新从</label>
|
|
356
|
+
<input id="dateFromFilter" type="date" class="px-3 py-1.5 rounded-lg text-xs font-medium outline-none cursor-pointer transition-colors" style="background-color: var(--pw-bg-elevated); border: 1px solid var(--pw-border-subtle); color: var(--pw-text-primary); font-family: var(--pw-font-sans); color-scheme: dark;" />
|
|
357
|
+
</div>
|
|
358
|
+
|
|
359
|
+
<!-- Date To -->
|
|
360
|
+
<div class="flex flex-col gap-1">
|
|
361
|
+
<label class="text-xs font-medium" style="color: var(--pw-text-tertiary); font-family: var(--pw-font-sans);" data-zh="更新至" data-en="Updated To">更新至</label>
|
|
362
|
+
<input id="dateToFilter" type="date" class="px-3 py-1.5 rounded-lg text-xs font-medium outline-none cursor-pointer transition-colors" style="background-color: var(--pw-bg-elevated); border: 1px solid var(--pw-border-subtle); color: var(--pw-text-primary); font-family: var(--pw-font-sans); color-scheme: dark;" />
|
|
363
|
+
</div>
|
|
364
|
+
|
|
365
|
+
<!-- Action Buttons -->
|
|
366
|
+
<div class="flex items-center gap-2">
|
|
367
|
+
<button id="applyFiltersBtn" class="flex items-center gap-1.5 px-3.5 py-1.5 rounded-lg text-xs font-semibold whitespace-nowrap transition-colors" style="background-color: var(--pw-accent); color: var(--pw-text-inverse); font-family: var(--pw-font-sans);">
|
|
368
|
+
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polygon points="22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3"/></svg>
|
|
369
|
+
<span data-zh="应用筛选" data-en="Apply Filters">应用筛选</span>
|
|
370
|
+
</button>
|
|
371
|
+
<button id="clearFiltersBtn" class="flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-xs font-semibold whitespace-nowrap transition-colors" 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);">
|
|
372
|
+
<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="M3 6h18"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"/><path d="M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/></svg>
|
|
373
|
+
<span data-zh="清空筛选" data-en="Clear Filters">清空筛选</span>
|
|
374
|
+
</button>
|
|
375
|
+
</div>
|
|
376
|
+
|
|
377
|
+
<!-- Refresh + Count -->
|
|
378
|
+
<button id="refreshBtn" class="flex items-center gap-2 px-4 py-1.5 rounded-lg text-xs font-semibold whitespace-nowrap transition-colors ml-auto" style="background-color: var(--pw-bg-elevated); color: var(--pw-text-secondary); border: 1px solid var(--pw-border-subtle); font-family: var(--pw-font-sans);">
|
|
379
|
+
<svg id="refreshIcon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
380
|
+
<polyline points="23 4 23 10 17 10"/>
|
|
381
|
+
<polyline points="1 20 1 14 7 14"/>
|
|
382
|
+
<path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"/>
|
|
383
|
+
</svg>
|
|
384
|
+
<span data-zh="刷新" data-en="Refresh">刷新</span>
|
|
385
|
+
</button>
|
|
386
|
+
</div>
|
|
387
|
+
<div class="flex items-center justify-between mt-3 pt-3" style="border-top: 1px solid var(--pw-border-subtle);">
|
|
388
|
+
<div id="filterStatusText" class="text-xs" style="color: var(--pw-text-tertiary); font-family: var(--pw-font-sans);">—</div>
|
|
389
|
+
<div id="countSummary" class="text-xs" style="color: var(--pw-text-tertiary); font-family: var(--pw-font-sans);">--</div>
|
|
266
390
|
</div>
|
|
267
|
-
|
|
268
|
-
<!-- Refresh Button -->
|
|
269
|
-
<button id="refreshBtn" class="flex items-center gap-2 px-4 py-1.5 rounded-lg text-xs font-semibold whitespace-nowrap transition-colors" style="background-color: var(--pw-bg-surface); color: var(--pw-text-secondary); border: 1px solid var(--pw-border-subtle); font-family: var(--pw-font-sans);">
|
|
270
|
-
<svg id="refreshIcon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
271
|
-
<polyline points="23 4 23 10 17 10"/>
|
|
272
|
-
<polyline points="1 20 1 14 7 14"/>
|
|
273
|
-
<path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"/>
|
|
274
|
-
</svg>
|
|
275
|
-
<span data-zh="刷新" data-en="Refresh">刷新</span>
|
|
276
|
-
</button>
|
|
277
|
-
|
|
278
|
-
<!-- Spacer -->
|
|
279
|
-
<div class="flex-1"></div>
|
|
280
|
-
|
|
281
|
-
<!-- Count Summary -->
|
|
282
|
-
<div id="countSummary" class="text-xs" style="color: var(--pw-text-tertiary); font-family: var(--pw-font-sans);">--</div>
|
|
283
391
|
</div>
|
|
284
392
|
|
|
285
393
|
<!-- ===== Task Table (border-led card) ===== -->
|
|
@@ -324,16 +432,18 @@ html.dark {
|
|
|
324
432
|
|
|
325
433
|
<!-- Table -->
|
|
326
434
|
<div id="tableWrapper" class="hidden overflow-x-auto">
|
|
327
|
-
<table class="w-full text-left" style="min-width:
|
|
435
|
+
<table class="w-full text-left" style="min-width: 1200px;">
|
|
328
436
|
<thead>
|
|
329
437
|
<tr style="border-bottom: 1px solid var(--pw-border);">
|
|
330
438
|
<th class="px-4 py-3 text-xs font-semibold whitespace-nowrap" style="color: var(--pw-text-tertiary); font-family: var(--pw-font-sans);" data-zh="任务ID" data-en="Task ID">任务ID</th>
|
|
331
439
|
<th class="px-4 py-3 text-xs font-semibold whitespace-nowrap" style="color: var(--pw-text-tertiary); font-family: var(--pw-font-sans);" data-zh="标题" data-en="Title">标题</th>
|
|
332
440
|
<th class="px-4 py-3 text-xs font-semibold whitespace-nowrap" style="color: var(--pw-text-tertiary); font-family: var(--pw-font-sans);">Agent</th>
|
|
333
441
|
<th class="px-4 py-3 text-xs font-semibold whitespace-nowrap" style="color: var(--pw-text-tertiary); font-family: var(--pw-font-sans);" data-zh="状态" data-en="Status">状态</th>
|
|
442
|
+
<th class="px-4 py-3 text-xs font-semibold whitespace-nowrap" style="color: var(--pw-text-tertiary); font-family: var(--pw-font-sans);" data-zh="验收" data-en="Acceptance">验收</th>
|
|
443
|
+
<th class="px-4 py-3 text-xs font-semibold whitespace-nowrap" style="color: var(--pw-text-tertiary); font-family: var(--pw-font-sans);" data-zh="验证" data-en="Verification">验证</th>
|
|
334
444
|
<th class="px-4 py-3 text-xs font-semibold whitespace-nowrap" style="color: var(--pw-text-tertiary); font-family: var(--pw-font-sans);" data-zh="阶段" data-en="Phase">阶段</th>
|
|
335
445
|
<th class="px-4 py-3 text-xs font-semibold whitespace-nowrap" style="color: var(--pw-text-tertiary); font-family: var(--pw-font-sans);" data-zh="创建时间" data-en="Created">创建时间</th>
|
|
336
|
-
<th class="px-4 py-3 text-xs font-semibold whitespace-nowrap" style="color: var(--pw-text-tertiary); font-family: var(--pw-font-sans);" data-zh="
|
|
446
|
+
<th class="px-4 py-3 text-xs font-semibold whitespace-nowrap" style="color: var(--pw-text-tertiary); font-family: var(--pw-font-sans);" data-zh="下一步" data-en="Next Action">下一步</th>
|
|
337
447
|
<th class="px-4 py-3 text-xs font-semibold whitespace-nowrap text-right" style="color: var(--pw-text-tertiary); font-family: var(--pw-font-sans);" data-zh="操作" data-en="Actions">操作</th>
|
|
338
448
|
</tr>
|
|
339
449
|
</thead>
|
|
@@ -342,6 +452,20 @@ html.dark {
|
|
|
342
452
|
</tbody>
|
|
343
453
|
</table>
|
|
344
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>
|
|
458
|
+
</div>
|
|
459
|
+
|
|
460
|
+
<!-- ===== SAFE MODAL ===== -->
|
|
461
|
+
<div id="safe-modal" class="hidden fixed inset-0 z-50 flex items-center justify-center p-4" style="background-color: rgba(0,0,0,0.6);">
|
|
462
|
+
<div class="rounded-lg w-full max-w-2xl max-h-[80vh] flex flex-col" style="background-color: var(--pw-bg-surface); border: 1px solid var(--pw-border); box-shadow: var(--pw-shadow-modal);">
|
|
463
|
+
<div class="flex items-center justify-between px-4 py-3" style="border-bottom: 1px solid var(--pw-border);">
|
|
464
|
+
<h3 id="safe-modal-title" class="text-sm font-semibold truncate" style="color: var(--pw-text-primary);">—</h3>
|
|
465
|
+
<button id="safe-modal-close" class="text-lg leading-none" style="color: var(--pw-text-tertiary);" type="button">×</button>
|
|
466
|
+
</div>
|
|
467
|
+
<div id="safe-modal-body" class="flex-1 overflow-auto px-4 py-3 text-xs" style="color: var(--pw-text-primary); font-family: var(--pw-font-mono); white-space: pre-wrap; word-break: break-all;"></div>
|
|
468
|
+
</div>
|
|
345
469
|
</div>
|
|
346
470
|
|
|
347
471
|
</main>
|
|
@@ -418,6 +542,51 @@ html.dark {
|
|
|
418
542
|
background-color: var(--pw-bg-active) !important;
|
|
419
543
|
color: var(--pw-text-primary) !important;
|
|
420
544
|
}
|
|
545
|
+
/* Quick action icon buttons */
|
|
546
|
+
.pw-quick-btn {
|
|
547
|
+
display: inline-flex;
|
|
548
|
+
align-items: center;
|
|
549
|
+
justify-content: center;
|
|
550
|
+
width: 24px;
|
|
551
|
+
height: 24px;
|
|
552
|
+
border-radius: 4px;
|
|
553
|
+
border: 1px solid var(--pw-border-subtle);
|
|
554
|
+
background-color: var(--pw-bg-hover);
|
|
555
|
+
color: var(--pw-text-secondary);
|
|
556
|
+
cursor: pointer;
|
|
557
|
+
transition: background-color var(--pw-transition-fast), color var(--pw-transition-fast);
|
|
558
|
+
text-decoration: none;
|
|
559
|
+
vertical-align: middle;
|
|
560
|
+
}
|
|
561
|
+
.pw-quick-btn:hover {
|
|
562
|
+
background-color: var(--pw-bg-active);
|
|
563
|
+
color: var(--pw-text-primary);
|
|
564
|
+
filter: none;
|
|
565
|
+
}
|
|
566
|
+
/* Acceptance status badge - more prominent than status */
|
|
567
|
+
.pw-acceptance-badge {
|
|
568
|
+
font-size: var(--pw-text-sm);
|
|
569
|
+
font-weight: var(--pw-weight-bold);
|
|
570
|
+
padding: 2px 8px;
|
|
571
|
+
border-width: 1px;
|
|
572
|
+
border-style: solid;
|
|
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
|
+
}
|
|
421
590
|
</style>
|
|
422
591
|
|
|
423
592
|
<script>
|
|
@@ -434,6 +603,11 @@ html.dark {
|
|
|
434
603
|
done: { color: 'success', text: '已完成' },
|
|
435
604
|
failed: { color: 'error', text: '失败' },
|
|
436
605
|
failed_scope_violation: { color: 'error', text: '范围违规' },
|
|
606
|
+
failed_policy_violation: { color: 'error', text: '策略违规' },
|
|
607
|
+
failed_verification: { color: 'error', text: '验证失败' },
|
|
608
|
+
needs_fix: { color: 'warning', text: '需修复' },
|
|
609
|
+
ready_for_review: { color: 'info', text: '待审核' },
|
|
610
|
+
done_by_agent: { color: 'success', text: 'Agent 完成' },
|
|
437
611
|
canceled: { color: 'muted', text: '已取消' },
|
|
438
612
|
timeout: { color: 'muted', text: '超时' }
|
|
439
613
|
};
|
|
@@ -448,7 +622,20 @@ html.dark {
|
|
|
448
622
|
};
|
|
449
623
|
|
|
450
624
|
var allTasks = [];
|
|
451
|
-
var
|
|
625
|
+
var nextCursor = null;
|
|
626
|
+
var totalTasks = 0;
|
|
627
|
+
// currentFilters holds the active filter values for all dimensions.
|
|
628
|
+
// repo_path / status / acceptance_status / agent are sent to the backend.
|
|
629
|
+
// warning_type / date_from / date_to are applied client-side.
|
|
630
|
+
var currentFilters = {
|
|
631
|
+
repo_path: '',
|
|
632
|
+
status: '',
|
|
633
|
+
acceptance_status: '',
|
|
634
|
+
agent: '',
|
|
635
|
+
warning_type: '',
|
|
636
|
+
date_from: '',
|
|
637
|
+
date_to: ''
|
|
638
|
+
};
|
|
452
639
|
|
|
453
640
|
// ---- DOM helpers ----
|
|
454
641
|
function $(id) { return document.getElementById(id); }
|
|
@@ -488,12 +675,131 @@ html.dark {
|
|
|
488
675
|
return PHASE_LABELS[phase] || phase || '—';
|
|
489
676
|
}
|
|
490
677
|
|
|
678
|
+
function shortId(id) {
|
|
679
|
+
if (!id) return '—';
|
|
680
|
+
var s = String(id);
|
|
681
|
+
return s.length > 22 ? s.slice(0, 10) + '…' + s.slice(-8) : s;
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
// ---- Safe summary + clipboard helpers ----
|
|
685
|
+
async function fetchJson(url) {
|
|
686
|
+
var res = await fetch(url);
|
|
687
|
+
if (!res.ok) throw new Error('HTTP ' + res.status + ' · ' + url);
|
|
688
|
+
return res.json();
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
function showToast(kind, title, msg) {
|
|
692
|
+
var container = document.getElementById('toast-container');
|
|
693
|
+
if (!container) {
|
|
694
|
+
container = document.createElement('div');
|
|
695
|
+
container.id = 'toast-container';
|
|
696
|
+
container.className = 'fixed top-4 right-4 z-50 flex flex-col gap-2 max-w-sm pointer-events-none';
|
|
697
|
+
document.body.appendChild(container);
|
|
698
|
+
}
|
|
699
|
+
var el = document.createElement('div');
|
|
700
|
+
var borderColors = {
|
|
701
|
+
success: 'var(--pw-state-success)',
|
|
702
|
+
error: 'var(--pw-state-error)',
|
|
703
|
+
warning: 'var(--pw-state-warning)',
|
|
704
|
+
info: 'var(--pw-state-info)'
|
|
705
|
+
};
|
|
706
|
+
el.className = 'pointer-events-auto flex items-start gap-2 px-3 py-2 rounded-lg text-xs';
|
|
707
|
+
el.style.cssText = 'background-color: var(--pw-bg-surface); border: 1px solid var(--pw-border); border-left: 3px solid ' + (borderColors[kind] || borderColors.info) + '; color: var(--pw-text-primary); box-shadow: var(--pw-shadow-float); max-width: 320px;';
|
|
708
|
+
el.innerHTML = '<div class="min-w-0 flex-1"><div style="font-weight:600;">' + escapeHtml(title || '') + '</div>' + (msg ? '<div style="color: var(--pw-text-secondary);">' + escapeHtml(msg) + '</div>' : '') + '</div>';
|
|
709
|
+
container.appendChild(el);
|
|
710
|
+
setTimeout(function () { if (el.parentNode) el.parentNode.removeChild(el); }, 4000);
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
function copyToClipboard(text, label) {
|
|
714
|
+
if (!text) return;
|
|
715
|
+
if (navigator.clipboard && navigator.clipboard.writeText) {
|
|
716
|
+
navigator.clipboard.writeText(text).then(function () {
|
|
717
|
+
showToast('success', '已复制', (label || '内容') + '已复制到剪贴板');
|
|
718
|
+
}).catch(function () {
|
|
719
|
+
showToast('error', '复制失败', '请手动复制');
|
|
720
|
+
});
|
|
721
|
+
} else {
|
|
722
|
+
showToast('warning', '复制不支持', '浏览器不支持剪贴板 API');
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
function showSafeModal(title, data) {
|
|
727
|
+
var modal = $('safe-modal');
|
|
728
|
+
var titleEl = $('safe-modal-title');
|
|
729
|
+
var bodyEl = $('safe-modal-body');
|
|
730
|
+
if (!modal || !titleEl || !bodyEl) return;
|
|
731
|
+
titleEl.textContent = title || '—';
|
|
732
|
+
var content;
|
|
733
|
+
if (data && typeof data === 'object') {
|
|
734
|
+
content = JSON.stringify(data, null, 2);
|
|
735
|
+
} else {
|
|
736
|
+
content = String(data || '');
|
|
737
|
+
}
|
|
738
|
+
bodyEl.textContent = content;
|
|
739
|
+
modal.classList.remove('hidden');
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
function closeSafeModal() {
|
|
743
|
+
var modal = $('safe-modal');
|
|
744
|
+
if (modal) modal.classList.add('hidden');
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
async function fetchSafeSummary(taskId, kind, title) {
|
|
748
|
+
if (!taskId) return;
|
|
749
|
+
try {
|
|
750
|
+
var data = await fetchJson('/api/tasks/' + encodeURIComponent(taskId) + '/' + kind);
|
|
751
|
+
showSafeModal(title, data);
|
|
752
|
+
} catch (err) {
|
|
753
|
+
showToast('error', '加载失败', title + ': ' + err.message);
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
// ---- Status priority ----
|
|
758
|
+
function primaryStatus(task) {
|
|
759
|
+
if (!task) return { key: '', label: '—', color: 'muted' };
|
|
760
|
+
var priority = [
|
|
761
|
+
'failed_policy_violation',
|
|
762
|
+
'failed_scope_violation',
|
|
763
|
+
'failed_verification',
|
|
764
|
+
'needs_fix',
|
|
765
|
+
'ready_for_review',
|
|
766
|
+
'done_by_agent',
|
|
767
|
+
'running',
|
|
768
|
+
'pending'
|
|
769
|
+
];
|
|
770
|
+
var status = task.status || '';
|
|
771
|
+
var acceptance = task.acceptance_status || '';
|
|
772
|
+
var statusIdx = priority.indexOf(status);
|
|
773
|
+
var acceptanceIdx = priority.indexOf(acceptance);
|
|
774
|
+
var chosen = '';
|
|
775
|
+
if (statusIdx >= 0 && acceptanceIdx >= 0) {
|
|
776
|
+
chosen = statusIdx <= acceptanceIdx ? status : acceptance;
|
|
777
|
+
} else if (statusIdx >= 0) {
|
|
778
|
+
chosen = status;
|
|
779
|
+
} else if (acceptanceIdx >= 0) {
|
|
780
|
+
chosen = acceptance;
|
|
781
|
+
} else {
|
|
782
|
+
chosen = acceptance || status || '';
|
|
783
|
+
}
|
|
784
|
+
var meta = getStatusMeta(chosen || status);
|
|
785
|
+
return { key: chosen, label: meta.text, color: meta.color };
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
function verificationHeadline(t) {
|
|
789
|
+
if (!t) return '—';
|
|
790
|
+
if (t.verification && t.verification.headline) return t.verification.headline;
|
|
791
|
+
if (t.safe_result && t.safe_result.verification && t.safe_result.verification.headline) return t.safe_result.verification.headline;
|
|
792
|
+
if (t.verification_headline) return t.verification_headline;
|
|
793
|
+
return '—';
|
|
794
|
+
}
|
|
795
|
+
|
|
491
796
|
// ---- State rendering ----
|
|
492
797
|
function showLoading() {
|
|
493
798
|
show($('loadingState'));
|
|
494
799
|
hide($('errorState'));
|
|
495
800
|
hide($('emptyState'));
|
|
496
801
|
hide($('tableWrapper'));
|
|
802
|
+
hide($('loadMoreWrap'));
|
|
497
803
|
$('countSummary').textContent = '--';
|
|
498
804
|
}
|
|
499
805
|
|
|
@@ -511,6 +817,7 @@ html.dark {
|
|
|
511
817
|
hide($('errorState'));
|
|
512
818
|
show($('emptyState'));
|
|
513
819
|
hide($('tableWrapper'));
|
|
820
|
+
hide($('loadMoreWrap'));
|
|
514
821
|
}
|
|
515
822
|
|
|
516
823
|
function showTable() {
|
|
@@ -541,52 +848,156 @@ html.dark {
|
|
|
541
848
|
|
|
542
849
|
// ---- Row rendering ----
|
|
543
850
|
function renderRow(task, idx) {
|
|
851
|
+
var taskId = task.task_id || '';
|
|
544
852
|
var meta = getStatusMeta(task.status);
|
|
545
853
|
var style = badgeStyle(meta.color);
|
|
546
854
|
var pulseClass = (task.status === 'running') ? ' pw-pulse-badge' : '';
|
|
547
|
-
var truncatedId = truncate(
|
|
855
|
+
var truncatedId = truncate(taskId, 12);
|
|
548
856
|
var createdAt = formatTime(task.created_at);
|
|
549
857
|
var phaseLabel = getPhaseLabel(task.phase);
|
|
550
858
|
var altBg = (idx % 2 === 1) ? ' background-color: var(--pw-bg-hover);' : '';
|
|
859
|
+
var detailHref = '/pages/task-detail.html?id=' + encodeURIComponent(taskId);
|
|
860
|
+
|
|
861
|
+
// Skip status badge if redundant with acceptance (done + done_by_agent)
|
|
862
|
+
var skipStatusBadge = (task.status === 'done' && task.acceptance_status === 'done_by_agent');
|
|
863
|
+
|
|
864
|
+
// Acceptance badge (more prominent)
|
|
865
|
+
var accCell;
|
|
866
|
+
if (task.acceptance_status) {
|
|
867
|
+
var accMeta = getStatusMeta(task.acceptance_status);
|
|
868
|
+
var accStyle = badgeStyle(accMeta.color);
|
|
869
|
+
accCell = '<span class="inline-flex items-center gap-1.5 pw-acceptance-badge rounded-md whitespace-nowrap" style="' + accStyle + ' font-family: var(--pw-font-sans); border-color: ' + getAccentColor(accMeta.color) + ';">'
|
|
870
|
+
+ '<span class="shrink-0 w-1.5 h-1.5 rounded-full" style="background-color: currentColor;"></span>'
|
|
871
|
+
+ escapeHtml(accMeta.text)
|
|
872
|
+
+ '</span>';
|
|
873
|
+
} else {
|
|
874
|
+
accCell = '<span style="color: var(--pw-text-tertiary);">—</span>';
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
// Verification headline
|
|
878
|
+
var headline = verificationHeadline(task);
|
|
879
|
+
var verifyCell = '<span class="inline-block truncate" style="max-width: 180px; color: var(--pw-text-secondary); font-family: var(--pw-font-sans);" title="' + escapeAttr(headline) + '">' + escapeHtml(truncate(headline, 30)) + '</span>';
|
|
551
880
|
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
881
|
+
// Next action cell
|
|
882
|
+
var nextActionCell;
|
|
883
|
+
if (task.next_action) {
|
|
884
|
+
nextActionCell = '<span class="inline-block truncate" style="max-width: 160px; color: var(--pw-text-secondary); font-family: var(--pw-font-sans);" title="' + escapeAttr(task.next_action) + '">' + escapeHtml(truncate(task.next_action, 28)) + '</span>';
|
|
885
|
+
} else if (task.pending_reason) {
|
|
886
|
+
nextActionCell = '<span class="inline-block truncate" style="max-width: 160px; color: var(--pw-state-warning); font-family: var(--pw-font-sans);" title="' + escapeAttr(task.pending_reason) + '">' + escapeHtml(truncate(task.pending_reason, 28)) + '</span>';
|
|
558
887
|
} else {
|
|
559
|
-
|
|
888
|
+
nextActionCell = '<span style="color: var(--pw-text-tertiary);">—</span>';
|
|
560
889
|
}
|
|
561
890
|
|
|
562
|
-
|
|
891
|
+
// Status cell (skip badge if redundant)
|
|
892
|
+
var statusCell;
|
|
893
|
+
if (skipStatusBadge) {
|
|
894
|
+
statusCell = '<span style="color: var(--pw-text-tertiary);">—</span>';
|
|
895
|
+
} else {
|
|
896
|
+
statusCell = '<span class="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-md text-xs font-medium whitespace-nowrap' + pulseClass + '" style="' + style + ' font-family: var(--pw-font-sans);" data-status="' + escapeAttr(task.status || '') + '">'
|
|
897
|
+
+ '<span class="shrink-0 w-1.5 h-1.5 rounded-full" style="background-color: currentColor;"></span>'
|
|
898
|
+
+ escapeHtml(meta.text)
|
|
899
|
+
+ '</span>';
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
// Quick action buttons
|
|
903
|
+
var quickActions =
|
|
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>'
|
|
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>'
|
|
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>'
|
|
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>'
|
|
909
|
+
+ '<a href="' + detailHref + '" class="pw-quick-btn" title="查看详情"><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="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></a>';
|
|
563
910
|
|
|
564
911
|
return ''
|
|
565
912
|
+ '<tr class="transition-colors" style="border-bottom: 1px solid var(--pw-border-subtle);' + altBg + '">'
|
|
566
|
-
+ '<td class="px-4 py-3
|
|
567
|
-
+
|
|
568
|
-
+
|
|
569
|
-
+
|
|
913
|
+
+ '<td class="px-4 py-3 whitespace-nowrap">'
|
|
914
|
+
+ '<div class="flex items-center gap-1">'
|
|
915
|
+
+ '<span class="text-xs" style="color: var(--pw-text-secondary); font-family: var(--pw-font-mono);" title="' + escapeAttr(taskId) + '">' + escapeHtml(truncatedId) + '</span>'
|
|
916
|
+
+ '<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>'
|
|
917
|
+
+ '</div>'
|
|
570
918
|
+ '</td>'
|
|
919
|
+
+ '<td class="px-4 py-3 text-sm" style="color: var(--pw-text-primary); font-family: var(--pw-font-sans); max-width: 280px;">' + escapeHtml(task.title || '—') + '</td>'
|
|
571
920
|
+ '<td class="px-4 py-3">'
|
|
572
|
-
+ '<span class="inline-flex items-center
|
|
573
|
-
+ '<span class="shrink-0 w-1.5 h-1.5 rounded-full" style="background-color: currentColor;"></span>'
|
|
574
|
-
+ escapeHtml(meta.text)
|
|
575
|
-
+ '</span>'
|
|
921
|
+
+ '<span class="inline-flex items-center px-2 py-0.5 rounded-md text-xs font-medium whitespace-nowrap" style="' + agentBadgeStyle(task.agent) + ' font-family: var(--pw-font-mono);">' + escapeHtml(task.agent || '—') + '</span>'
|
|
576
922
|
+ '</td>'
|
|
923
|
+
+ '<td class="px-4 py-3">' + statusCell + '</td>'
|
|
924
|
+
+ '<td class="px-4 py-3">' + accCell + '</td>'
|
|
925
|
+
+ '<td class="px-4 py-3 text-xs">' + verifyCell + '</td>'
|
|
577
926
|
+ '<td class="px-4 py-3 text-xs whitespace-nowrap" style="color: var(--pw-text-secondary); font-family: var(--pw-font-sans);" data-phase="' + escapeAttr(task.phase || '') + '">' + escapeHtml(phaseLabel) + '</td>'
|
|
578
927
|
+ '<td class="px-4 py-3 text-xs whitespace-nowrap" style="color: var(--pw-text-secondary); font-family: var(--pw-font-mono);" title="' + escapeAttr(task.created_at || '') + '">' + escapeHtml(createdAt) + '</td>'
|
|
579
|
-
+ '<td class="px-4 py-3 text-xs" style="font-family: var(--pw-font-sans);">' +
|
|
928
|
+
+ '<td class="px-4 py-3 text-xs" style="font-family: var(--pw-font-sans);">' + nextActionCell + '</td>'
|
|
580
929
|
+ '<td class="px-4 py-3 text-right">'
|
|
581
|
-
+ '<
|
|
930
|
+
+ '<div class="inline-flex items-center gap-1">' + quickActions + '</div>'
|
|
582
931
|
+ '</td>'
|
|
583
932
|
+ '</tr>';
|
|
584
933
|
}
|
|
585
934
|
|
|
935
|
+
function getAccentColor(color) {
|
|
936
|
+
switch (color) {
|
|
937
|
+
case 'success': return 'var(--pw-state-success)';
|
|
938
|
+
case 'info': return 'var(--pw-state-info)';
|
|
939
|
+
case 'warning': return 'var(--pw-state-warning)';
|
|
940
|
+
case 'error': return 'var(--pw-state-error)';
|
|
941
|
+
default: return 'var(--pw-text-secondary)';
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
// ---- Client-side filter helpers ----
|
|
946
|
+
// Extracts warning-type-related signals from a task for client-side filtering.
|
|
947
|
+
function taskMatchesWarningType(task, warningType) {
|
|
948
|
+
if (!warningType) return true;
|
|
949
|
+
if (!task) return false;
|
|
950
|
+
// Check warnings array (most precise)
|
|
951
|
+
if (Array.isArray(task.warnings)) {
|
|
952
|
+
for (var i = 0; i < task.warnings.length; i++) {
|
|
953
|
+
var w = task.warnings[i] || {};
|
|
954
|
+
if (w.type === warningType || w.code === warningType || w.kind === warningType) return true;
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
// Check stale_task flag
|
|
958
|
+
if (warningType === 'stale_task' && task.is_stale === true) return true;
|
|
959
|
+
// Check failed_verification mapping
|
|
960
|
+
if (warningType === 'failed_verification' &&
|
|
961
|
+
(task.status === 'failed_verification' || task.acceptance_status === 'failed_verification')) return true;
|
|
962
|
+
// Check status / acceptance_status containing the warning type
|
|
963
|
+
if (task.status === warningType || task.acceptance_status === warningType) return true;
|
|
964
|
+
// Check verification headline (loose contains for manual_verification_required, scope_changes, etc.)
|
|
965
|
+
var headline = verificationHeadline(task);
|
|
966
|
+
if (headline && headline.toLowerCase().indexOf(warningType.replace(/_/g, ' ')) >= 0) return true;
|
|
967
|
+
return false;
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
function taskMatchesDateRange(task, dateFrom, dateTo) {
|
|
971
|
+
if (!dateFrom && !dateTo) return true;
|
|
972
|
+
if (!task) return false;
|
|
973
|
+
var ts = task.updated_at || task.created_at;
|
|
974
|
+
if (!ts) return false;
|
|
975
|
+
var d = new Date(ts);
|
|
976
|
+
if (isNaN(d.getTime())) return false;
|
|
977
|
+
if (dateFrom) {
|
|
978
|
+
var from = new Date(dateFrom + 'T00:00:00');
|
|
979
|
+
if (d < from) return false;
|
|
980
|
+
}
|
|
981
|
+
if (dateTo) {
|
|
982
|
+
var to = new Date(dateTo + 'T23:59:59');
|
|
983
|
+
if (d > to) return false;
|
|
984
|
+
}
|
|
985
|
+
return true;
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
function applyClientSideFilters(tasks) {
|
|
989
|
+
var out = tasks.slice();
|
|
990
|
+
if (currentFilters.warning_type) {
|
|
991
|
+
out = out.filter(function (t) { return taskMatchesWarningType(t, currentFilters.warning_type); });
|
|
992
|
+
}
|
|
993
|
+
if (currentFilters.date_from || currentFilters.date_to) {
|
|
994
|
+
out = out.filter(function (t) { return taskMatchesDateRange(t, currentFilters.date_from, currentFilters.date_to); });
|
|
995
|
+
}
|
|
996
|
+
return out;
|
|
997
|
+
}
|
|
998
|
+
|
|
586
999
|
function renderTasks() {
|
|
587
|
-
var filtered =
|
|
588
|
-
? allTasks.filter(function (t) { return t && t.status === currentFilter; })
|
|
589
|
-
: allTasks.slice();
|
|
1000
|
+
var filtered = applyClientSideFilters(allTasks);
|
|
590
1001
|
|
|
591
1002
|
// Sort by created_at desc (newest first). Falls back gracefully if missing.
|
|
592
1003
|
filtered.sort(function (a, b) {
|
|
@@ -606,13 +1017,18 @@ html.dark {
|
|
|
606
1017
|
}
|
|
607
1018
|
$('taskTableBody').innerHTML = html;
|
|
608
1019
|
showTable();
|
|
1020
|
+
wireQuickActions();
|
|
609
1021
|
}
|
|
1022
|
+
var more = $('loadMoreWrap');
|
|
1023
|
+
if (more) nextCursor ? show(more) : hide(more);
|
|
610
1024
|
|
|
611
1025
|
// Count summary
|
|
612
|
-
|
|
613
|
-
|
|
1026
|
+
var hasFilters = currentFilters.repo_path || currentFilters.status || currentFilters.acceptance_status ||
|
|
1027
|
+
currentFilters.agent || currentFilters.warning_type || currentFilters.date_from || currentFilters.date_to;
|
|
1028
|
+
if (hasFilters) {
|
|
1029
|
+
$('countSummary').textContent = '显示 ' + filtered.length + ' / ' + totalTasks + ' 条';
|
|
614
1030
|
} else {
|
|
615
|
-
$('countSummary').textContent = '
|
|
1031
|
+
$('countSummary').textContent = '已加载 ' + filtered.length + ' / ' + totalTasks + ' 条';
|
|
616
1032
|
}
|
|
617
1033
|
}
|
|
618
1034
|
|
|
@@ -634,6 +1050,68 @@ html.dark {
|
|
|
634
1050
|
el.innerHTML = '<span class="shrink-0 w-1.5 h-1.5 rounded-full" style="background-color: ' + dotColor + ';"></span><span>Watcher: ' + escapeHtml(status) + '</span>';
|
|
635
1051
|
}
|
|
636
1052
|
|
|
1053
|
+
// ---- Filter query building ----
|
|
1054
|
+
// Builds a query string from the backend-supported filter dimensions.
|
|
1055
|
+
function buildFilterQueryString() {
|
|
1056
|
+
var params = [];
|
|
1057
|
+
if (currentFilters.repo_path) {
|
|
1058
|
+
params.push('repo_path=' + encodeURIComponent(currentFilters.repo_path));
|
|
1059
|
+
}
|
|
1060
|
+
if (currentFilters.status) {
|
|
1061
|
+
params.push('status=' + encodeURIComponent(currentFilters.status));
|
|
1062
|
+
}
|
|
1063
|
+
if (currentFilters.acceptance_status) {
|
|
1064
|
+
params.push('acceptance_status=' + encodeURIComponent(currentFilters.acceptance_status));
|
|
1065
|
+
}
|
|
1066
|
+
if (currentFilters.agent) {
|
|
1067
|
+
params.push('agent=' + encodeURIComponent(currentFilters.agent));
|
|
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');
|
|
1073
|
+
return params.length ? ('?' + params.join('&')) : '';
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
// Reads current dropdown/input values into currentFilters.
|
|
1077
|
+
function readFiltersFromUI() {
|
|
1078
|
+
currentFilters.repo_path = $('repoFilter') ? $('repoFilter').value : '';
|
|
1079
|
+
currentFilters.status = $('statusFilter') ? $('statusFilter').value : '';
|
|
1080
|
+
currentFilters.acceptance_status = $('acceptanceFilter') ? $('acceptanceFilter').value : '';
|
|
1081
|
+
currentFilters.agent = $('agentFilter') ? $('agentFilter').value : '';
|
|
1082
|
+
currentFilters.warning_type = $('warningTypeFilter') ? $('warningTypeFilter').value : '';
|
|
1083
|
+
currentFilters.date_from = $('dateFromFilter') ? $('dateFromFilter').value : '';
|
|
1084
|
+
currentFilters.date_to = $('dateToFilter') ? $('dateToFilter').value : '';
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
// Resets all filter UI inputs to empty.
|
|
1088
|
+
function clearFilterUI() {
|
|
1089
|
+
var ids = ['repoFilter', 'statusFilter', 'acceptanceFilter', 'agentFilter', 'warningTypeFilter', 'dateFromFilter', 'dateToFilter'];
|
|
1090
|
+
ids.forEach(function (id) {
|
|
1091
|
+
var el = $(id);
|
|
1092
|
+
if (el) el.value = '';
|
|
1093
|
+
});
|
|
1094
|
+
currentFilters = {
|
|
1095
|
+
repo_path: '', status: '', acceptance_status: '', agent: '',
|
|
1096
|
+
warning_type: '', date_from: '', date_to: ''
|
|
1097
|
+
};
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
// Updates the small status text describing active filters.
|
|
1101
|
+
function updateFilterStatusText() {
|
|
1102
|
+
var el = $('filterStatusText');
|
|
1103
|
+
if (!el) return;
|
|
1104
|
+
var parts = [];
|
|
1105
|
+
if (currentFilters.repo_path) parts.push('repo: ' + currentFilters.repo_path);
|
|
1106
|
+
if (currentFilters.status) parts.push('status: ' + currentFilters.status);
|
|
1107
|
+
if (currentFilters.acceptance_status) parts.push('acceptance: ' + currentFilters.acceptance_status);
|
|
1108
|
+
if (currentFilters.agent) parts.push('agent: ' + currentFilters.agent);
|
|
1109
|
+
if (currentFilters.warning_type) parts.push('warning: ' + currentFilters.warning_type);
|
|
1110
|
+
if (currentFilters.date_from) parts.push('from: ' + currentFilters.date_from);
|
|
1111
|
+
if (currentFilters.date_to) parts.push('to: ' + currentFilters.date_to);
|
|
1112
|
+
el.textContent = parts.length ? ('已应用筛选 · ' + parts.join(' · ')) : '无筛选';
|
|
1113
|
+
}
|
|
1114
|
+
|
|
637
1115
|
// ---- API call ----
|
|
638
1116
|
function setRefreshing(isRefreshing) {
|
|
639
1117
|
var icon = $('refreshIcon');
|
|
@@ -645,10 +1123,12 @@ html.dark {
|
|
|
645
1123
|
}
|
|
646
1124
|
}
|
|
647
1125
|
|
|
648
|
-
function fetchTasks() {
|
|
649
|
-
showLoading();
|
|
1126
|
+
function fetchTasks(cursor, append) {
|
|
1127
|
+
if (!append) showLoading();
|
|
650
1128
|
setRefreshing(true);
|
|
651
|
-
|
|
1129
|
+
var query = buildFilterQueryString();
|
|
1130
|
+
var url = API_URL + query + (query ? '&' : '?') + (cursor ? 'cursor=' + encodeURIComponent(cursor) : '');
|
|
1131
|
+
fetch(url, {
|
|
652
1132
|
method: 'GET',
|
|
653
1133
|
headers: { 'Accept': 'application/json' },
|
|
654
1134
|
cache: 'no-store'
|
|
@@ -662,9 +1142,13 @@ html.dark {
|
|
|
662
1142
|
return res.json();
|
|
663
1143
|
})
|
|
664
1144
|
.then(function (data) {
|
|
665
|
-
|
|
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;
|
|
666
1149
|
renderWatcher(data && data.watcher);
|
|
667
1150
|
renderTasks();
|
|
1151
|
+
updateFilterStatusText();
|
|
668
1152
|
})
|
|
669
1153
|
.catch(function (err) {
|
|
670
1154
|
var msg = (err && err.message) ? err.message : '未知错误';
|
|
@@ -679,24 +1163,123 @@ html.dark {
|
|
|
679
1163
|
});
|
|
680
1164
|
}
|
|
681
1165
|
|
|
1166
|
+
// ---- Dropdown population ----
|
|
1167
|
+
async function loadRepos() {
|
|
1168
|
+
var select = $('repoFilter');
|
|
1169
|
+
if (!select) return;
|
|
1170
|
+
try {
|
|
1171
|
+
var data = await fetchJson('/api/workspace/repos');
|
|
1172
|
+
var repos = Array.isArray(data.repos) ? data.repos : [];
|
|
1173
|
+
var html = '<option value="" data-zh="全部仓库" data-en="All repos">全部仓库</option>';
|
|
1174
|
+
repos.forEach(function (r) {
|
|
1175
|
+
var label = r.name + (r.has_package_json && r.version ? ' (v' + r.version + ')' : '');
|
|
1176
|
+
var val = r.path || r.name;
|
|
1177
|
+
html += '<option value="' + escapeAttr(val) + '">' + escapeHtml(label) + '</option>';
|
|
1178
|
+
});
|
|
1179
|
+
select.innerHTML = html;
|
|
1180
|
+
} catch (err) {
|
|
1181
|
+
// keep default option
|
|
1182
|
+
console.error('loadRepos failed:', err);
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1186
|
+
async function loadAgents() {
|
|
1187
|
+
var select = $('agentFilter');
|
|
1188
|
+
if (!select) return;
|
|
1189
|
+
try {
|
|
1190
|
+
var data = await fetchJson('/api/status');
|
|
1191
|
+
var agents = (data && Array.isArray(data.agents)) ? data.agents : [];
|
|
1192
|
+
var html = '<option value="" data-zh="全部 Agent" data-en="All Agents">全部 Agent</option>';
|
|
1193
|
+
agents.forEach(function (a) {
|
|
1194
|
+
if (a && a.name) {
|
|
1195
|
+
html += '<option value="' + escapeAttr(a.name) + '">' + escapeHtml(a.name) + (a.available ? '' : ' (unavailable)') + '</option>';
|
|
1196
|
+
}
|
|
1197
|
+
});
|
|
1198
|
+
select.innerHTML = html;
|
|
1199
|
+
} catch (err) {
|
|
1200
|
+
// keep default option
|
|
1201
|
+
console.error('loadAgents failed:', err);
|
|
1202
|
+
}
|
|
1203
|
+
}
|
|
1204
|
+
|
|
682
1205
|
// ---- Event wiring ----
|
|
1206
|
+
// Status filter: apply immediately on change (keeps original UX)
|
|
683
1207
|
$('statusFilter').addEventListener('change', function (e) {
|
|
684
|
-
|
|
685
|
-
|
|
1208
|
+
readFiltersFromUI();
|
|
1209
|
+
fetchTasks();
|
|
1210
|
+
});
|
|
1211
|
+
|
|
1212
|
+
// Apply Filters button: reads all filter values and refetches
|
|
1213
|
+
$('applyFiltersBtn').addEventListener('click', function () {
|
|
1214
|
+
readFiltersFromUI();
|
|
1215
|
+
fetchTasks();
|
|
1216
|
+
});
|
|
1217
|
+
|
|
1218
|
+
// Clear Filters button: resets all filters and refetches
|
|
1219
|
+
$('clearFiltersBtn').addEventListener('click', function () {
|
|
1220
|
+
clearFilterUI();
|
|
1221
|
+
fetchTasks();
|
|
686
1222
|
});
|
|
687
1223
|
|
|
688
1224
|
$('refreshBtn').addEventListener('click', fetchTasks);
|
|
1225
|
+
$('loadMoreBtn').addEventListener('click', function () { if (nextCursor) fetchTasks(nextCursor, true); });
|
|
689
1226
|
|
|
690
1227
|
var retryBtn = $('retryBtn');
|
|
691
1228
|
if (retryBtn) {
|
|
692
1229
|
retryBtn.addEventListener('click', fetchTasks);
|
|
693
1230
|
}
|
|
694
1231
|
|
|
695
|
-
//
|
|
696
|
-
|
|
1232
|
+
// Safe modal close handlers
|
|
1233
|
+
var modalClose = $('safe-modal-close');
|
|
1234
|
+
if (modalClose) {
|
|
1235
|
+
modalClose.addEventListener('click', function () { closeSafeModal(); });
|
|
1236
|
+
}
|
|
1237
|
+
var safeModal = $('safe-modal');
|
|
1238
|
+
if (safeModal) {
|
|
1239
|
+
safeModal.addEventListener('click', function (e) {
|
|
1240
|
+
if (e.target === safeModal) closeSafeModal();
|
|
1241
|
+
});
|
|
1242
|
+
}
|
|
1243
|
+
|
|
1244
|
+
// ---- Quick action button wiring (called after render) ----
|
|
1245
|
+
var SAFE_TITLE_MAP = {
|
|
1246
|
+
'safe-result': 'Safe Result',
|
|
1247
|
+
'safe-audit': 'Safe Audit',
|
|
1248
|
+
'safe-test-summary': 'Safe Test Summary',
|
|
1249
|
+
'safe-diff-summary': 'Safe Diff Summary'
|
|
1250
|
+
};
|
|
1251
|
+
|
|
1252
|
+
function wireQuickActions() {
|
|
1253
|
+
var tbody = $('taskTableBody');
|
|
1254
|
+
if (!tbody) return;
|
|
1255
|
+
tbody.querySelectorAll('[data-safe-action]').forEach(function (btn) {
|
|
1256
|
+
btn.addEventListener('click', function (e) {
|
|
1257
|
+
e.preventDefault();
|
|
1258
|
+
e.stopPropagation();
|
|
1259
|
+
var action = btn.getAttribute('data-safe-action');
|
|
1260
|
+
var tid = btn.getAttribute('data-task-id');
|
|
1261
|
+
fetchSafeSummary(tid, action, SAFE_TITLE_MAP[action] || action);
|
|
1262
|
+
});
|
|
1263
|
+
});
|
|
1264
|
+
tbody.querySelectorAll('[data-copy-id]').forEach(function (btn) {
|
|
1265
|
+
btn.addEventListener('click', function (e) {
|
|
1266
|
+
e.preventDefault();
|
|
1267
|
+
e.stopPropagation();
|
|
1268
|
+
copyToClipboard(btn.getAttribute('data-copy-id'), 'task_id');
|
|
1269
|
+
});
|
|
1270
|
+
});
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
// Initial load: populate filter dropdowns, then fetch tasks
|
|
1274
|
+
// Dropdowns load in parallel (best-effort); tasks fetch runs regardless.
|
|
1275
|
+
Promise.allSettled([loadRepos(), loadAgents()]).finally(function () {
|
|
1276
|
+
fetchTasks();
|
|
1277
|
+
});
|
|
697
1278
|
})();
|
|
698
1279
|
</script>
|
|
699
1280
|
|
|
700
1281
|
<script>lucide.createIcons();</script>
|
|
1282
|
+
<script src="/i18n.js"></script>
|
|
1283
|
+
<script src="/desktop-bridge.js"></script>
|
|
701
1284
|
</body>
|
|
702
1285
|
</html>
|