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.
- package/PatchWarden.cmd +32 -2
- package/README.en.md +152 -25
- package/README.md +120 -23
- package/dist/assessments/agentAssessor.js +21 -12
- package/dist/assessments/assessmentStore.js +42 -34
- package/dist/config.d.ts +15 -0
- package/dist/config.js +66 -13
- package/dist/control/fileManager.d.ts +2 -0
- package/dist/control/fileManager.js +39 -0
- package/dist/control/middleware/auth.d.ts +6 -0
- package/dist/control/middleware/auth.js +14 -5
- package/dist/control/middleware/static.js +16 -3
- package/dist/control/routeTable.d.ts +24 -0
- package/dist/control/routeTable.js +263 -0
- package/dist/control/routes/audit.js +17 -7
- package/dist/control/routes/evidence.js +1 -1
- package/dist/control/routes/lineage.js +1 -1
- package/dist/control/routes/process.d.ts +7 -0
- package/dist/control/routes/process.js +329 -42
- package/dist/control/routes/sessions.d.ts +9 -1
- package/dist/control/routes/sessions.js +84 -21
- package/dist/control/routes/status.d.ts +46 -1
- package/dist/control/routes/status.js +72 -15
- package/dist/control/routes/taskActions.js +24 -60
- package/dist/control/routes/tasks.d.ts +4 -0
- package/dist/control/routes/tasks.js +61 -62
- package/dist/control/routes/workspace.js +50 -23
- package/dist/control/runtime.d.ts +3 -2
- package/dist/control/runtime.js +63 -30
- package/dist/control/server.js +36 -365
- package/dist/control/shared.d.ts +25 -1
- package/dist/control/shared.js +64 -11
- package/dist/direct/directAudit.js +234 -225
- package/dist/direct/directGuards.d.ts +2 -1
- package/dist/direct/directGuards.js +42 -29
- 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.js +62 -52
- package/dist/goal/acceptanceEngine.d.ts +1 -1
- package/dist/goal/goalProgress.js +75 -69
- package/dist/goal/goalReport.js +5 -12
- package/dist/goal/goalStatus.d.ts +2 -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.js +97 -96
- package/dist/goal/subgoalSync.js +11 -9
- package/dist/goal/worktreeManager.d.ts +2 -0
- package/dist/goal/worktreeManager.js +209 -136
- package/dist/httpServer.js +111 -32
- package/dist/logging.js +5 -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 +13 -5
- package/dist/runner/changeCapture.js +243 -61
- package/dist/runner/postTaskCleanup.js +48 -19
- 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 +115 -87
- package/dist/runner/simpleProcess.d.ts +3 -0
- package/dist/runner/simpleProcess.js +50 -36
- 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 +256 -48
- package/dist/security/contentRedaction.js +2 -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 +24 -23
- 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} +6 -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} +1 -1
- package/dist/tools/{auditTask.js → diagnostics/auditTask.js} +99 -29
- package/dist/tools/{healthCheck.d.ts → diagnostics/healthCheck.d.ts} +6 -6
- package/dist/tools/{healthCheck.js → diagnostics/healthCheck.js} +7 -7
- 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} +12 -8
- package/dist/tools/{safeViews.js → diagnostics/safeViews.js} +23 -13
- 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.js → direct/createDirectSession.js} +6 -6
- package/dist/tools/{finalizeDirectSession.d.ts → direct/finalizeDirectSession.d.ts} +1 -1
- 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.js +32 -31
- package/dist/tools/dispatch/diagnosticDispatch.d.ts +3 -5
- package/dist/tools/dispatch/diagnosticDispatch.js +70 -68
- package/dist/tools/dispatch/directDispatch.js +11 -10
- package/dist/tools/dispatch/goalDispatch.js +5 -4
- package/dist/tools/dispatch/releaseDispatch.js +3 -2
- 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} +1 -1
- 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 +7 -11
- package/dist/tools/registry.js +17 -1178
- 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} +10 -2
- package/dist/tools/{createTask.js → tasks/createTask.js} +42 -27
- 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.js → tasks/evidencePack.js} +34 -22
- 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/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} +58 -30
- 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 +808 -143
- package/docs/architecture.md +15 -55
- package/docs/assets/patchwarden-desktop-onboarding.png +0 -0
- package/docs/control-center/README.md +4 -4
- package/docs/dashboard-overview.md +4 -4
- package/docs/desktop-app.md +175 -0
- package/docs/evidence-pack-schema.md +3 -3
- package/docs/open-source-application.md +17 -11
- package/docs/release-checklist.md +1 -1
- package/docs/release-evidence.md +39 -29
- package/docs/task-safe-review-workflow.md +5 -5
- package/docs/threat-model.md +19 -1
- package/examples/config.example.json +4 -2
- package/package.json +27 -10
- 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 +91 -6
- package/scripts/checks/control-smoke.js +19 -8
- package/scripts/checks/http-mcp-smoke.js +82 -4
- package/scripts/checks/lifecycle-smoke.js +10 -10
- package/scripts/checks/mcp-manifest-check.js +1 -1
- package/scripts/checks/mcp-smoke.js +27 -3
- 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/{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 +26 -12
- package/src/assessments/assessmentStore.ts +52 -40
- package/src/config.ts +70 -13
- package/src/control/fileManager.ts +40 -0
- package/src/control/middleware/auth.ts +22 -4
- package/src/control/middleware/static.ts +16 -3
- package/src/control/routeTable.ts +301 -0
- package/src/control/routes/audit.ts +14 -6
- package/src/control/routes/evidence.ts +1 -1
- package/src/control/routes/lineage.ts +1 -1
- package/src/control/routes/process.ts +341 -40
- package/src/control/routes/sessions.ts +88 -25
- package/src/control/routes/status.ts +97 -17
- package/src/control/routes/taskActions.ts +24 -58
- package/src/control/routes/tasks.ts +66 -58
- package/src/control/routes/workspace.ts +56 -25
- package/src/control/runtime.ts +69 -33
- package/src/control/server.ts +36 -342
- package/src/control/shared.ts +77 -11
- package/src/direct/directAudit.ts +17 -9
- package/src/direct/directGuards.ts +72 -44
- 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 +73 -59
- package/src/goal/acceptanceEngine.ts +1 -1
- package/src/goal/goalProgress.ts +17 -13
- package/src/goal/goalReport.ts +5 -13
- package/src/goal/goalStatus.ts +19 -3
- package/src/goal/goalStore.ts +241 -54
- package/src/goal/handoffExport.ts +6 -6
- package/src/goal/specKitImport.ts +12 -12
- package/src/goal/subgoalSync.ts +11 -8
- package/src/goal/worktreeManager.ts +139 -22
- package/src/httpServer.ts +113 -30
- package/src/logging.ts +10 -3
- 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 +291 -57
- package/src/runner/postTaskCleanup.ts +41 -17
- package/src/runner/processSecurity.ts +433 -0
- package/src/runner/runTask.ts +138 -91
- package/src/runner/simpleProcess.ts +66 -31
- 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 +281 -51
- package/src/security/contentRedaction.ts +2 -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 +25 -24
- 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} +7 -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} +99 -32
- package/src/tools/{healthCheck.ts → diagnostics/healthCheck.ts} +8 -8
- 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} +27 -17
- package/src/tools/{schemaDriftCheck.ts → diagnostics/schemaDriftCheck.ts} +3 -3
- package/src/tools/{createDirectSession.ts → direct/createDirectSession.ts} +6 -6
- package/src/tools/{finalizeDirectSession.ts → direct/finalizeDirectSession.ts} +7 -5
- 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 +36 -31
- package/src/tools/dispatch/diagnosticDispatch.ts +26 -21
- package/src/tools/dispatch/directDispatch.ts +11 -10
- package/src/tools/dispatch/goalDispatch.ts +5 -4
- package/src/tools/dispatch/releaseDispatch.ts +3 -2
- 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} +41 -26
- package/src/tools/goals/index.ts +3 -0
- package/src/tools/{savePlan.ts → goals/savePlan.ts} +38 -8
- package/src/tools/registry.ts +17 -1261
- 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} +49 -26
- package/src/tools/{diagnoseTask.ts → tasks/diagnoseTask.ts} +8 -8
- package/src/tools/{evidencePack.ts → tasks/evidencePack.ts} +36 -22
- 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} +69 -34
- 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 +12 -0
- package/ui/pages/dashboard.html +90 -147
- package/ui/pages/direct-sessions.html +123 -26
- 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 +12 -0
- package/ui/pages/tasks.html +54 -8
- 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/apply-patch.test.d.ts +0 -1
- package/dist/test/unit/apply-patch.test.js +0 -225
- 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/create-task.test.d.ts +0 -1
- package/dist/test/unit/create-task.test.js +0 -197
- 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 -328
- 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 -224
- package/dist/test/unit/get-task-status.test.d.ts +0 -1
- package/dist/test/unit/get-task-status.test.js +0 -174
- package/dist/test/unit/get-task-summary.test.d.ts +0 -1
- package/dist/test/unit/get-task-summary.test.js +0 -146
- 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-report.test.d.ts +0 -1
- package/dist/test/unit/goal-report.test.js +0 -159
- 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 -192
- 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 -133
- 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/spec-kit-import.test.d.ts +0 -1
- package/dist/test/unit/spec-kit-import.test.js +0 -341
- 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/wait-for-task.test.d.ts +0 -1
- package/dist/test/unit/wait-for-task.test.js +0 -144
- 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/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/execution-plan-2026-07-09.md +0 -315
- 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/docs/roadmap-execution-and-acceptance.md +0 -365
- 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/apply-patch.test.ts +0 -293
- 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/create-task.test.ts +0 -255
- package/src/test/unit/diagnose-task.test.ts +0 -544
- package/src/test/unit/direct-guards.test.ts +0 -467
- package/src/test/unit/discovery-token-store.test.ts +0 -181
- package/src/test/unit/evidence-pack.test.ts +0 -251
- package/src/test/unit/get-task-status.test.ts +0 -203
- package/src/test/unit/get-task-summary.test.ts +0 -173
- 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-report.test.ts +0 -189
- 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 -245
- 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 -180
- 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/spec-kit-import.test.ts +0 -429
- 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/wait-for-task.test.ts +0 -176
- 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/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/{createDirectSession.d.ts → direct/createDirectSession.d.ts} +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/{evidencePack.d.ts → tasks/evidencePack.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/{retryTask.d.ts → tasks/retryTask.d.ts} +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
|
@@ -124,7 +124,7 @@ html.dark {
|
|
|
124
124
|
.pw-toast.pw-toast-info { border-left: 3px solid var(--pw-state-info); }
|
|
125
125
|
.pw-toast .pw-toast-title { font-weight: 600; margin-bottom: 2px; }
|
|
126
126
|
.pw-toast .pw-toast-msg { color: var(--pw-text-secondary); word-break: break-word; }
|
|
127
|
-
.pw-toast .pw-toast-close { margin-left: auto; cursor: pointer; color: var(--pw-text-tertiary); font-size: 14px; line-height: 1; padding: 0 2px; }
|
|
127
|
+
.pw-toast .pw-toast-close { margin-left: auto; cursor: pointer; color: var(--pw-text-tertiary); background: transparent; border: 0; font-size: 14px; line-height: 1; padding: 0 2px; }
|
|
128
128
|
.pw-toast .pw-toast-close:hover { color: var(--pw-text-primary); }
|
|
129
129
|
@keyframes pw-toast-in {
|
|
130
130
|
from { opacity: 0; transform: translateX(20px); }
|
|
@@ -172,6 +172,8 @@ html.dark {
|
|
|
172
172
|
background-color: var(--pw-accent-muted);
|
|
173
173
|
}
|
|
174
174
|
</style>
|
|
175
|
+
<script src="/desktop-bootstrap.js"></script>
|
|
176
|
+
<link rel="stylesheet" href="/desktop.css">
|
|
175
177
|
</head>
|
|
176
178
|
<body class="flex h-screen overflow-hidden">
|
|
177
179
|
|
|
@@ -189,6 +191,10 @@ html.dark {
|
|
|
189
191
|
|
|
190
192
|
<!-- Navigation -->
|
|
191
193
|
<nav class="flex-1 flex flex-col gap-1 px-3 pt-4 overflow-y-auto">
|
|
194
|
+
<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);">
|
|
195
|
+
<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>
|
|
196
|
+
<span class="truncate" data-i18n="nav.gettingStarted">开始使用</span>
|
|
197
|
+
</a>
|
|
192
198
|
|
|
193
199
|
<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);">
|
|
194
200
|
<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">
|
|
@@ -244,6 +250,10 @@ html.dark {
|
|
|
244
250
|
<span class="truncate" data-zh="日志" data-en="Logs">日志</span>
|
|
245
251
|
</a>
|
|
246
252
|
|
|
253
|
+
<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);">
|
|
254
|
+
<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>
|
|
255
|
+
<span class="truncate" data-i18n="nav.settings">设置</span>
|
|
256
|
+
</a>
|
|
247
257
|
</nav>
|
|
248
258
|
|
|
249
259
|
<!-- Bottom Section -->
|
|
@@ -268,6 +278,12 @@ html.dark {
|
|
|
268
278
|
Direct 会话
|
|
269
279
|
</h1>
|
|
270
280
|
<div class="flex items-center gap-4 shrink-0">
|
|
281
|
+
<select id="session-state" class="px-2 py-1.5 rounded-md text-xs font-medium" 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);">
|
|
282
|
+
<option value="active">进行中</option>
|
|
283
|
+
<option value="archive">历史记录</option>
|
|
284
|
+
<option value="audited">仅审计完成</option>
|
|
285
|
+
<option value="expired">仅已过期</option>
|
|
286
|
+
</select>
|
|
271
287
|
<span id="lastUpdated" class="text-xs whitespace-nowrap hidden" style="color: var(--pw-text-tertiary); font-family: var(--pw-font-mono);"></span>
|
|
272
288
|
<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);">
|
|
273
289
|
<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">
|
|
@@ -286,6 +302,18 @@ html.dark {
|
|
|
286
302
|
<!-- Page Content Area -->
|
|
287
303
|
<main class="flex-1 overflow-y-auto p-6" style="background-color: var(--pw-bg-elevated);">
|
|
288
304
|
|
|
305
|
+
<div class="mb-4 flex flex-wrap items-end gap-3 rounded-lg px-4 py-3" style="background-color: var(--pw-bg-surface); border: 1px solid var(--pw-border);">
|
|
306
|
+
<label class="grid gap-1 text-xs" style="color: var(--pw-text-tertiary);"><span data-zh="项目" data-en="Project">项目</span><select id="session-repo" aria-label="Direct 会话项目" class="px-2 py-1.5 rounded-md text-xs" style="min-width:180px;background-color:var(--pw-bg-elevated);color:var(--pw-text-primary);border:1px solid var(--pw-border-subtle);"><option value="">全部项目</option></select></label>
|
|
307
|
+
<label class="grid gap-1 text-xs" style="color: var(--pw-text-tertiary);"><span data-zh="开始日期" data-en="From date">开始日期</span><input id="session-date-from" type="date" aria-label="Direct 会话开始日期" class="px-2 py-1.5 rounded-md text-xs" style="background-color:var(--pw-bg-elevated);color:var(--pw-text-primary);border:1px solid var(--pw-border-subtle);"></label>
|
|
308
|
+
<label class="grid gap-1 text-xs" style="color: var(--pw-text-tertiary);"><span data-zh="结束日期" data-en="To date">结束日期</span><input id="session-date-to" type="date" aria-label="Direct 会话结束日期" class="px-2 py-1.5 rounded-md text-xs" style="background-color:var(--pw-bg-elevated);color:var(--pw-text-primary);border:1px solid var(--pw-border-subtle);"></label>
|
|
309
|
+
</div>
|
|
310
|
+
|
|
311
|
+
<section id="direct-disabled" class="hidden rounded-lg p-6 mb-4" style="background-color: var(--pw-bg-surface); border: 1px solid var(--pw-border);">
|
|
312
|
+
<h2 class="text-base font-semibold" style="color:var(--pw-text-primary);" data-zh="Direct 是可选高级能力" data-en="Direct is an optional advanced capability">Direct 是可选高级能力</h2>
|
|
313
|
+
<p class="mt-2 text-sm" style="color:var(--pw-text-secondary);" data-zh="未启用不会影响 Core、Tunnel 或普通任务。需要受控的直接编辑会话时,可在设置中启用。" data-en="Leaving Direct disabled does not affect Core, Tunnel, or regular tasks. Enable it in Settings when you need controlled direct editing sessions.">未启用不会影响 Core、Tunnel 或普通任务。需要受控的直接编辑会话时,可在设置中启用。</p>
|
|
314
|
+
<a href="/pages/settings.html" class="inline-flex mt-4 px-3 py-2 rounded-md text-sm font-semibold" style="background-color:var(--pw-accent);color:var(--pw-text-inverse);" data-zh="前往设置" data-en="Open Settings">前往设置</a>
|
|
315
|
+
</section>
|
|
316
|
+
|
|
289
317
|
<!-- ===== Error Banner ===== -->
|
|
290
318
|
<div id="error-banner" class="hidden mb-5 rounded-lg px-4 py-3 flex items-start gap-3" style="background-color: var(--pw-state-error-bg); border: 1px solid var(--pw-state-error);">
|
|
291
319
|
<svg class="shrink-0 mt-0.5" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="var(--pw-state-error)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
@@ -327,6 +355,7 @@ html.dark {
|
|
|
327
355
|
|
|
328
356
|
<!-- ===== Sessions List ===== -->
|
|
329
357
|
<div id="sessions-list" class="hidden flex flex-col gap-3"></div>
|
|
358
|
+
<div id="sessions-more-wrap" class="hidden mt-4 text-center"><button id="sessions-more" type="button" class="px-4 py-2 rounded-md text-sm font-medium" style="background-color:var(--pw-bg-surface);color:var(--pw-text-primary);border:1px solid var(--pw-border);" data-zh="加载更多" data-en="Load more">加载更多</button></div>
|
|
330
359
|
|
|
331
360
|
<!-- ===== Session Detail ===== -->
|
|
332
361
|
<div id="session-detail" class="hidden flex flex-col gap-6"></div>
|
|
@@ -339,7 +368,7 @@ html.dark {
|
|
|
339
368
|
<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);">
|
|
340
369
|
<div class="flex items-center justify-between px-4 py-3" style="border-bottom: 1px solid var(--pw-border);">
|
|
341
370
|
<h3 id="safe-modal-title" class="text-sm font-semibold truncate" style="color: var(--pw-text-primary);">—</h3>
|
|
342
|
-
<button id="safe-modal-close" class="text-lg leading-none" style="color: var(--pw-text-tertiary);" type="button">×</button>
|
|
371
|
+
<button id="safe-modal-close" class="text-lg leading-none" style="color: var(--pw-text-tertiary);" type="button" title="关闭" aria-label="关闭结果面板">×</button>
|
|
343
372
|
</div>
|
|
344
373
|
<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>
|
|
345
374
|
</div>
|
|
@@ -373,6 +402,8 @@ html.dark {
|
|
|
373
402
|
|
|
374
403
|
var API_URL = '/api/direct-sessions';
|
|
375
404
|
var controlToken = null;
|
|
405
|
+
var loadedSessions = [];
|
|
406
|
+
var nextCursor = null;
|
|
376
407
|
|
|
377
408
|
function $(id) { return document.getElementById(id); }
|
|
378
409
|
function hide(el) { if (el) el.classList.add('hidden'); }
|
|
@@ -432,6 +463,7 @@ html.dark {
|
|
|
432
463
|
|
|
433
464
|
function showLoading() {
|
|
434
465
|
show($('loading-state'));
|
|
466
|
+
hide($('direct-disabled'));
|
|
435
467
|
hide($('empty-state'));
|
|
436
468
|
hide($('sessions-list'));
|
|
437
469
|
hide($('session-detail'));
|
|
@@ -441,6 +473,8 @@ html.dark {
|
|
|
441
473
|
show($('empty-state'));
|
|
442
474
|
hide($('sessions-list'));
|
|
443
475
|
hide($('session-detail'));
|
|
476
|
+
hide($('direct-disabled'));
|
|
477
|
+
hide($('sessions-more-wrap'));
|
|
444
478
|
var rEl = $('empty-reason');
|
|
445
479
|
if (rEl) rEl.textContent = reason || '';
|
|
446
480
|
}
|
|
@@ -449,12 +483,24 @@ html.dark {
|
|
|
449
483
|
hide($('empty-state'));
|
|
450
484
|
show($('sessions-list'));
|
|
451
485
|
hide($('session-detail'));
|
|
486
|
+
hide($('direct-disabled'));
|
|
452
487
|
}
|
|
453
488
|
function showDetail() {
|
|
454
489
|
hide($('loading-state'));
|
|
455
490
|
hide($('empty-state'));
|
|
456
491
|
hide($('sessions-list'));
|
|
457
492
|
show($('session-detail'));
|
|
493
|
+
hide($('direct-disabled'));
|
|
494
|
+
hide($('sessions-more-wrap'));
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
function showDirectDisabled() {
|
|
498
|
+
hide($('loading-state'));
|
|
499
|
+
hide($('empty-state'));
|
|
500
|
+
hide($('sessions-list'));
|
|
501
|
+
hide($('session-detail'));
|
|
502
|
+
hide($('sessions-more-wrap'));
|
|
503
|
+
show($('direct-disabled'));
|
|
458
504
|
}
|
|
459
505
|
|
|
460
506
|
function verdictColor(v) {
|
|
@@ -489,7 +535,7 @@ html.dark {
|
|
|
489
535
|
+ '<div class="pw-toast-title">' + escapeHtml(title || '') + '</div>'
|
|
490
536
|
+ (msg ? '<div class="pw-toast-msg">' + escapeHtml(msg) + '</div>' : '')
|
|
491
537
|
+ '</div>'
|
|
492
|
-
+ '<
|
|
538
|
+
+ '<button type="button" class="pw-toast-close" title="关闭" aria-label="关闭通知">×</button>';
|
|
493
539
|
var closeBtn = el.querySelector('.pw-toast-close');
|
|
494
540
|
if (closeBtn) closeBtn.addEventListener('click', function () { dismissToast(el); });
|
|
495
541
|
container.appendChild(el);
|
|
@@ -650,7 +696,7 @@ html.dark {
|
|
|
650
696
|
var c = COLOR_VARS[meta.color] || COLOR_VARS.muted;
|
|
651
697
|
return '<div class="flex items-center gap-2 mt-2 mb-1 px-1">'
|
|
652
698
|
+ '<span class="w-2 h-2 rounded-full" style="background-color: ' + c.fg + ';"></span>'
|
|
653
|
-
+ '<h2 class="text-sm font-semibold" style="color: var(--pw-text-primary); font-family: var(--pw-font-sans);">' + escapeHtml(meta.zh) + '</h2>'
|
|
699
|
+
+ '<h2 class="text-sm font-semibold" data-zh="' + escapeHtml(meta.zh) + '" data-en="' + escapeHtml(meta.en) + '" style="color: var(--pw-text-primary); font-family: var(--pw-font-sans);">' + escapeHtml(meta.zh) + '</h2>'
|
|
654
700
|
+ '<span class="text-xs" style="color: var(--pw-text-tertiary);">(' + count + ')</span>'
|
|
655
701
|
+ '</div>';
|
|
656
702
|
}
|
|
@@ -662,7 +708,7 @@ html.dark {
|
|
|
662
708
|
'<summary class="flex items-center gap-2 cursor-pointer px-3 py-2" style="color: var(--pw-text-primary); font-family: var(--pw-font-sans;">'
|
|
663
709
|
+ '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="shrink-0"><polyline points="6 9 12 15 18 9"/></svg>'
|
|
664
710
|
+ '<span class="w-2 h-2 rounded-full" style="background-color: ' + c.fg + ';"></span>'
|
|
665
|
-
+ '<span class="text-sm font-semibold">' + escapeHtml(meta.zh) + '</span>'
|
|
711
|
+
+ '<span class="text-sm font-semibold" data-zh="' + escapeHtml(meta.zh) + '" data-en="' + escapeHtml(meta.en) + '">' + escapeHtml(meta.zh) + '</span>'
|
|
666
712
|
+ '<span class="text-xs" style="color: var(--pw-text-tertiary);">(' + sessions.length + ')</span>'
|
|
667
713
|
+ '<span class="ml-auto text-xs" style="color: var(--pw-text-tertiary);">点击展开 / 折叠</span>'
|
|
668
714
|
+ '</summary>';
|
|
@@ -690,11 +736,11 @@ html.dark {
|
|
|
690
736
|
var decision = s.audit_decision || null;
|
|
691
737
|
var decisionBadge = decision
|
|
692
738
|
? badgeHtml(decision, verdictColor(decision))
|
|
693
|
-
: '<span class="text-xs px-2 py-0.5 rounded-md" style="color: var(--pw-text-tertiary); background-color: var(--pw-bg-hover);"
|
|
739
|
+
: '<span class="text-xs px-2 py-0.5 rounded-md" style="color: var(--pw-text-tertiary); background-color: var(--pw-bg-hover);">未审计</span>';
|
|
694
740
|
var stateBadge = finalized
|
|
695
|
-
? badgeHtml('
|
|
696
|
-
: (isExpired ? badgeHtml('
|
|
697
|
-
var auditedBadge = audited ? badgeHtml('
|
|
741
|
+
? badgeHtml('已完成', 'success')
|
|
742
|
+
: (isExpired ? badgeHtml('已过期', 'warning') : badgeHtml('进行中', 'warning'));
|
|
743
|
+
var auditedBadge = audited ? badgeHtml('已审计', 'success') : '';
|
|
698
744
|
var titleText = s.title || s.repo_path || sid;
|
|
699
745
|
|
|
700
746
|
// Verification status summary
|
|
@@ -706,21 +752,21 @@ html.dark {
|
|
|
706
752
|
// Quick action buttons
|
|
707
753
|
var actions = '';
|
|
708
754
|
// safe_direct_summary
|
|
709
|
-
actions += quickBtnHtml('summary', '
|
|
755
|
+
actions += quickBtnHtml('summary', '查看摘要', 'View summary', sid, '查看脱敏后的安全摘要', 'View the redacted safe summary', false, false);
|
|
710
756
|
// run_direct_verification_bundle — informational button (links to tasks page)
|
|
711
|
-
actions += quickBtnHtml('verify-bundle', '
|
|
757
|
+
actions += quickBtnHtml('verify-bundle', '创建验证任务', 'Create verification task', sid, '前往任务页创建受控验证任务', 'Open Tasks to create a controlled verification task', false, false);
|
|
712
758
|
// safe_finalize_direct_session (disabled if already finalized)
|
|
713
|
-
actions += quickBtnHtml('finalize', '
|
|
759
|
+
actions += quickBtnHtml('finalize', '完成会话', 'Finalize session', sid, '完成并生成会话摘要', 'Finalize and generate the session summary', finalized, true);
|
|
714
760
|
// safe_audit_direct_session (disabled if already audited)
|
|
715
|
-
actions += quickBtnHtml('audit', '
|
|
761
|
+
actions += quickBtnHtml('audit', '运行审计', 'Run audit', sid, '运行安全审计', 'Run the security audit', audited, true);
|
|
716
762
|
// copy session_id
|
|
717
|
-
actions += quickBtnHtml('copy', '
|
|
763
|
+
actions += quickBtnHtml('copy', '复制 ID', 'Copy ID', sid, '复制会话 ID', 'Copy session ID', false, false);
|
|
718
764
|
// hide (expired only)
|
|
719
765
|
if (isExpired) {
|
|
720
|
-
actions += quickBtnHtml('hide', '
|
|
766
|
+
actions += quickBtnHtml('hide', '隐藏记录', 'Hide record', sid, '仅从列表隐藏,不删除证据', 'Hide from the list without deleting evidence', false, false, true);
|
|
721
767
|
}
|
|
722
768
|
|
|
723
|
-
return '<div class="rounded-lg p-4 transition-colors session-card" data-session-id="' + escapeHtml(sid) + '" '
|
|
769
|
+
return '<div class="rounded-lg p-4 transition-colors session-card" role="button" tabindex="0" aria-label="查看 Direct 会话 ' + escapeHtml(shortId(sid)) + '" data-session-id="' + escapeHtml(sid) + '" '
|
|
724
770
|
+ 'onmouseover="this.style.backgroundColor=\'var(--pw-bg-hover)\'" '
|
|
725
771
|
+ 'onmouseout="this.style.backgroundColor=\'var(--pw-bg-surface)\'" '
|
|
726
772
|
+ 'style="background-color: var(--pw-bg-surface); border: 1px solid var(--pw-border); cursor: pointer;">'
|
|
@@ -765,13 +811,13 @@ html.dark {
|
|
|
765
811
|
+ '</div>';
|
|
766
812
|
}
|
|
767
813
|
|
|
768
|
-
function quickBtnHtml(action,
|
|
814
|
+
function quickBtnHtml(action, labelZh, labelEn, sid, titleZh, titleEn, disabled, accent, danger) {
|
|
769
815
|
var cls = 'pw-quick-btn';
|
|
770
816
|
if (accent) cls += ' pw-quick-accent';
|
|
771
817
|
if (danger) cls += ' pw-quick-danger';
|
|
772
818
|
var disAttr = disabled ? ' disabled' : '';
|
|
773
|
-
return '<button type="button" class="' + cls + '" data-action="' + escapeHtml(action) + '" data-session-id="' + escapeHtml(sid) + '" title="' + escapeHtml(
|
|
774
|
-
+ escapeHtml(
|
|
819
|
+
return '<button type="button" class="' + cls + '" data-action="' + escapeHtml(action) + '" data-session-id="' + escapeHtml(sid) + '" title="' + escapeHtml(titleZh) + '" aria-label="' + escapeHtml(titleZh) + '" data-zh="' + escapeHtml(labelZh) + '" data-en="' + escapeHtml(labelEn) + '"' + disAttr + '>'
|
|
820
|
+
+ escapeHtml(labelZh)
|
|
775
821
|
+ '</button>';
|
|
776
822
|
}
|
|
777
823
|
|
|
@@ -803,6 +849,13 @@ html.dark {
|
|
|
803
849
|
var sid2 = ev.currentTarget.getAttribute('data-session-id');
|
|
804
850
|
if (sid2) loadSessionDetail(sid2);
|
|
805
851
|
});
|
|
852
|
+
card.addEventListener('keydown', function (ev) {
|
|
853
|
+
if (ev.key !== 'Enter' && ev.key !== ' ') return;
|
|
854
|
+
if (ev.target.closest('.pw-quick-btn') || ev.target.closest('summary')) return;
|
|
855
|
+
ev.preventDefault();
|
|
856
|
+
var sid2 = ev.currentTarget.getAttribute('data-session-id');
|
|
857
|
+
if (sid2) loadSessionDetail(sid2);
|
|
858
|
+
});
|
|
806
859
|
}
|
|
807
860
|
}
|
|
808
861
|
|
|
@@ -1009,11 +1062,29 @@ html.dark {
|
|
|
1009
1062
|
}
|
|
1010
1063
|
|
|
1011
1064
|
// ---------- Network ----------
|
|
1012
|
-
function
|
|
1065
|
+
function updateRepoOptions(data) {
|
|
1066
|
+
var select = $('session-repo');
|
|
1067
|
+
if (!select) return;
|
|
1068
|
+
var selected = select.value;
|
|
1069
|
+
var repos = data && data.filters && data.filters.options && Array.isArray(data.filters.options.repos) ? data.filters.options.repos : [];
|
|
1070
|
+
select.innerHTML = '<option value="">全部项目</option>' + repos.map(function (repo) { return '<option value="' + escapeHtml(repo) + '">' + escapeHtml(repo) + '</option>'; }).join('');
|
|
1071
|
+
select.value = repos.indexOf(selected) >= 0 ? selected : '';
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
function loadSessions(cursor, append) {
|
|
1013
1075
|
clearError();
|
|
1014
|
-
showLoading();
|
|
1076
|
+
if (!append) showLoading();
|
|
1015
1077
|
setRefreshing(true);
|
|
1016
|
-
|
|
1078
|
+
var state = $('session-state') ? $('session-state').value : 'active';
|
|
1079
|
+
var params = ['state=' + encodeURIComponent(state), 'limit=50'];
|
|
1080
|
+
var repo = $('session-repo') ? $('session-repo').value : '';
|
|
1081
|
+
var dateFrom = $('session-date-from') ? $('session-date-from').value : '';
|
|
1082
|
+
var dateTo = $('session-date-to') ? $('session-date-to').value : '';
|
|
1083
|
+
if (repo) params.push('repo_path=' + encodeURIComponent(repo));
|
|
1084
|
+
if (dateFrom) params.push('date_from=' + encodeURIComponent(dateFrom));
|
|
1085
|
+
if (dateTo) params.push('date_to=' + encodeURIComponent(dateTo));
|
|
1086
|
+
if (cursor) params.push('cursor=' + encodeURIComponent(cursor));
|
|
1087
|
+
fetch(API_URL + '?' + params.join('&'), { method: 'GET', headers: { 'Accept': 'application/json' }, cache: 'no-store' })
|
|
1017
1088
|
.then(function (res) {
|
|
1018
1089
|
if (!res.ok) {
|
|
1019
1090
|
return res.text().then(function (body) {
|
|
@@ -1024,7 +1095,23 @@ html.dark {
|
|
|
1024
1095
|
})
|
|
1025
1096
|
.then(function (data) {
|
|
1026
1097
|
data = data || {};
|
|
1027
|
-
|
|
1098
|
+
updateRepoOptions(data);
|
|
1099
|
+
if (data.direct_profile_enabled === false) {
|
|
1100
|
+
loadedSessions = append ? loadedSessions.concat(data.sessions || []) : (data.sessions || []);
|
|
1101
|
+
nextCursor = data.nextCursor || data.next_cursor || null;
|
|
1102
|
+
if (loadedSessions.length) {
|
|
1103
|
+
renderSessions(loadedSessions);
|
|
1104
|
+
show($('direct-disabled'));
|
|
1105
|
+
nextCursor ? show($('sessions-more-wrap')) : hide($('sessions-more-wrap'));
|
|
1106
|
+
} else {
|
|
1107
|
+
showDirectDisabled();
|
|
1108
|
+
}
|
|
1109
|
+
} else {
|
|
1110
|
+
loadedSessions = append ? loadedSessions.concat(data.sessions || []) : (data.sessions || []);
|
|
1111
|
+
nextCursor = data.nextCursor || data.next_cursor || null;
|
|
1112
|
+
renderSessions(loadedSessions);
|
|
1113
|
+
nextCursor ? show($('sessions-more-wrap')) : hide($('sessions-more-wrap'));
|
|
1114
|
+
}
|
|
1028
1115
|
setLastUpdated();
|
|
1029
1116
|
})
|
|
1030
1117
|
.catch(function (err) {
|
|
@@ -1080,9 +1167,17 @@ html.dark {
|
|
|
1080
1167
|
|
|
1081
1168
|
// ---------- Event wiring ----------
|
|
1082
1169
|
var refreshBtn = $('refreshBtn');
|
|
1083
|
-
if (refreshBtn) refreshBtn.addEventListener('click', loadSessions);
|
|
1170
|
+
if (refreshBtn) refreshBtn.addEventListener('click', function () { loadSessions(null, false); });
|
|
1084
1171
|
var retryBtn = $('retry-btn');
|
|
1085
|
-
if (retryBtn) retryBtn.addEventListener('click', loadSessions);
|
|
1172
|
+
if (retryBtn) retryBtn.addEventListener('click', function () { loadSessions(null, false); });
|
|
1173
|
+
var stateSelect = $('session-state');
|
|
1174
|
+
if (stateSelect) stateSelect.addEventListener('change', function () { loadSessions(null, false); });
|
|
1175
|
+
['session-repo', 'session-date-from', 'session-date-to'].forEach(function (id) {
|
|
1176
|
+
var input = $(id);
|
|
1177
|
+
if (input) input.addEventListener('change', function () { loadSessions(null, false); });
|
|
1178
|
+
});
|
|
1179
|
+
var moreBtn = $('sessions-more');
|
|
1180
|
+
if (moreBtn) moreBtn.addEventListener('click', function () { if (nextCursor) loadSessions(nextCursor, true); });
|
|
1086
1181
|
|
|
1087
1182
|
var modalClose = $('safe-modal-close');
|
|
1088
1183
|
if (modalClose) modalClose.addEventListener('click', closeSafeModal);
|
|
@@ -1097,8 +1192,10 @@ html.dark {
|
|
|
1097
1192
|
});
|
|
1098
1193
|
|
|
1099
1194
|
// Initial load
|
|
1100
|
-
loadSessions();
|
|
1195
|
+
loadSessions(null, false);
|
|
1101
1196
|
})();
|
|
1102
1197
|
</script>
|
|
1198
|
+
<script src="/i18n.js"></script>
|
|
1199
|
+
<script src="/desktop-bridge.js"></script>
|
|
1103
1200
|
</body>
|
|
1104
1201
|
</html>
|
|
@@ -0,0 +1,43 @@
|
|
|
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>PatchWarden</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/lucide.js"></script>
|
|
11
|
+
</head>
|
|
12
|
+
<body class="pw-app-shell">
|
|
13
|
+
<aside class="pw-sidebar">
|
|
14
|
+
<div class="pw-brand"><i data-lucide="shield-check"></i><strong>PatchWarden</strong></div>
|
|
15
|
+
<nav>
|
|
16
|
+
<a href="/pages/getting-started.html" data-nav-key="getting-started" data-active="true"><i data-lucide="rocket"></i><span data-i18n="nav.gettingStarted"></span></a>
|
|
17
|
+
<a href="/pages/dashboard.html" data-nav-key="dashboard"><i data-lucide="layout-dashboard"></i><span data-i18n="nav.dashboard"></span></a>
|
|
18
|
+
<a href="/pages/tasks.html" data-nav-key="tasks"><i data-lucide="list-checks"></i><span data-i18n="nav.tasks"></span></a>
|
|
19
|
+
<a href="/pages/workspace.html" data-nav-key="workspace"><i data-lucide="folder"></i><span data-i18n="nav.workspace"></span></a>
|
|
20
|
+
<a href="/pages/audit.html" data-nav-key="audit"><i data-lucide="file-search"></i><span data-i18n="nav.audit"></span></a>
|
|
21
|
+
<a href="/pages/direct-sessions.html" data-nav-key="direct-sessions"><i data-lucide="route"></i><span data-i18n="nav.direct"></span></a>
|
|
22
|
+
<a href="/pages/logs.html" data-nav-key="logs"><i data-lucide="scroll-text"></i><span data-i18n="nav.logs"></span></a>
|
|
23
|
+
<a href="/pages/settings.html" data-nav-key="settings" class="desktop-only-nav"><i data-lucide="settings"></i><span data-i18n="nav.settings"></span></a>
|
|
24
|
+
</nav>
|
|
25
|
+
</aside>
|
|
26
|
+
<div class="pw-page">
|
|
27
|
+
<header class="pw-page-header"><div><h1 data-i18n="home.title"></h1><p data-i18n="home.subtitle"></p></div><select id="language" aria-label="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></header>
|
|
28
|
+
<main class="getting-started-main">
|
|
29
|
+
<div class="readiness-list">
|
|
30
|
+
<section class="readiness-item" data-check="workspace"><span class="check-index">1</span><div><div class="check-heading"><h2 data-i18n="home.workspace"></h2><span class="check-status" data-status>…</span></div><p data-message data-i18n="home.checking"></p><p class="reason-detail" data-reason></p></div><a class="primary-command" href="/pages/settings.html" data-i18n="home.openSettings"></a></section>
|
|
31
|
+
<section class="readiness-item" data-check="core"><span class="check-index">2</span><div><div class="check-heading"><h2 data-i18n="home.core"></h2><span class="check-status" data-status>…</span></div><p data-message data-i18n="home.checking"></p><p class="reason-detail" data-reason></p></div><button class="primary-command" id="startCore" data-i18n="home.startCore"></button></section>
|
|
32
|
+
<section class="readiness-item" data-check="tunnel"><span class="check-index">3</span><div><div class="check-heading"><h2 data-i18n="home.platform"></h2><span class="check-status" data-status>…</span></div><p data-message data-i18n="home.checking"></p><p class="reason-detail" data-reason></p></div><a class="primary-command" href="https://platform.openai.com/settings/organization/tunnels" target="_blank" rel="noreferrer" data-i18n="home.openPlatform"></a></section>
|
|
33
|
+
<section class="readiness-item" data-check="chatgpt"><span class="check-index">4</span><div><div class="check-heading"><h2 data-i18n="home.chatgpt"></h2><span class="check-status manual" data-status data-i18n="home.manual"></span></div><p data-message data-i18n="home.chatgptManual"></p><p class="reason-detail" data-reason></p></div><button class="primary-command" id="copyPrompt" data-i18n="home.copyPrompt"></button></section>
|
|
34
|
+
</div>
|
|
35
|
+
<section class="guide-band"><h2 data-i18n="home.docs"></h2><div class="guide-links"><a href="https://developers.openai.com/api/docs/guides/secure-mcp-tunnels" target="_blank" rel="noreferrer" data-i18n="home.secureGuide"></a><a href="https://chatgpt.com/#settings/Plugins" target="_blank" rel="noreferrer" data-i18n="home.pluginsGuide"></a><a href="https://github.com/jiezeng2004-design/PatchWarden/blob/main/README.md" target="_blank" rel="noreferrer" data-i18n="home.readmeZh"></a><a href="https://github.com/jiezeng2004-design/PatchWarden/blob/main/README.en.md" target="_blank" rel="noreferrer" data-i18n="home.readmeEn"></a></div></section>
|
|
36
|
+
<div id="toast" class="pw-toast" role="status" aria-live="polite"></div>
|
|
37
|
+
</main>
|
|
38
|
+
</div>
|
|
39
|
+
<script src="/i18n.js"></script>
|
|
40
|
+
<script src="/desktop-bridge.js"></script>
|
|
41
|
+
<script src="/getting-started.js"></script>
|
|
42
|
+
</body>
|
|
43
|
+
</html>
|
package/ui/pages/logs.html
CHANGED
|
@@ -95,13 +95,16 @@ html.dark {
|
|
|
95
95
|
}
|
|
96
96
|
</style>
|
|
97
97
|
<script src="/vendor/tailwindcss-browser.js"></script>
|
|
98
|
-
|
|
98
|
+
<script src="/vendor/lucide.js"></script>
|
|
99
|
+
<script src="/log-parser.js"></script>
|
|
99
100
|
<style>
|
|
100
101
|
.no-scrollbar::-webkit-scrollbar { display: none; }
|
|
101
102
|
.no-scrollbar { -ms-overflow-style: none; scrollbar-width: none; }
|
|
102
103
|
.pw-spin { animation: pw-spin 1s linear infinite; }
|
|
103
104
|
@keyframes pw-spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
|
|
104
105
|
</style>
|
|
106
|
+
<script src="/desktop-bootstrap.js"></script>
|
|
107
|
+
<link rel="stylesheet" href="/desktop.css">
|
|
105
108
|
</head>
|
|
106
109
|
<body class="flex h-screen overflow-hidden">
|
|
107
110
|
|
|
@@ -119,6 +122,10 @@ html.dark {
|
|
|
119
122
|
|
|
120
123
|
<!-- Navigation -->
|
|
121
124
|
<nav class="flex-1 flex flex-col gap-1 px-3 pt-4 overflow-y-auto">
|
|
125
|
+
<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);">
|
|
126
|
+
<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>
|
|
127
|
+
<span class="truncate" data-i18n="nav.gettingStarted">开始使用</span>
|
|
128
|
+
</a>
|
|
122
129
|
|
|
123
130
|
<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);">
|
|
124
131
|
<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">
|
|
@@ -174,6 +181,10 @@ html.dark {
|
|
|
174
181
|
<span class="truncate" data-zh="日志" data-en="Logs">日志</span>
|
|
175
182
|
</a>
|
|
176
183
|
|
|
184
|
+
<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);">
|
|
185
|
+
<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>
|
|
186
|
+
<span class="truncate" data-i18n="nav.settings">设置</span>
|
|
187
|
+
</a>
|
|
177
188
|
</nav>
|
|
178
189
|
|
|
179
190
|
<!-- Bottom Section -->
|
|
@@ -211,6 +222,11 @@ html.dark {
|
|
|
211
222
|
<option value="300">tail 300</option>
|
|
212
223
|
<option value="1000">tail 1000</option>
|
|
213
224
|
</select>
|
|
225
|
+
<button id="clearView" class="px-2.5 py-1 rounded-md text-xs font-medium" type="button" title="仅清空当前显示,不删除日志文件" 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);">清空视图</button>
|
|
226
|
+
<select id="levelFilter" aria-label="日志级别" class="px-2 py-1 rounded-md text-xs font-medium" style="background-color: var(--pw-bg-surface); color: var(--pw-text-secondary); border: 1px solid var(--pw-border-subtle);">
|
|
227
|
+
<option value="">全部级别</option><option value="error">Error</option><option value="warn">Warning</option><option value="info">Info</option>
|
|
228
|
+
</select>
|
|
229
|
+
<input id="logSearch" type="search" aria-label="搜索日志" placeholder="搜索日志" class="px-2 py-1 rounded-md text-xs outline-none" style="width: 140px; background-color: var(--pw-bg-surface); color: var(--pw-text-primary); border: 1px solid var(--pw-border-subtle);">
|
|
214
230
|
<!-- Auto-refresh toggle -->
|
|
215
231
|
<label class="flex items-center gap-1.5 text-xs cursor-pointer select-none" style="color: var(--pw-text-secondary); font-family: var(--pw-font-sans);">
|
|
216
232
|
<input id="autoRefresh" type="checkbox" style="accent-color: var(--pw-accent);" />
|
|
@@ -260,20 +276,20 @@ html.dark {
|
|
|
260
276
|
<span id="stdoutMeta" class="text-xs whitespace-nowrap" style="color: var(--pw-text-tertiary); font-family: var(--pw-font-mono);">—</span>
|
|
261
277
|
</div>
|
|
262
278
|
<div id="stdoutEmpty" class="px-4 py-8 text-center text-sm" style="color: var(--pw-text-tertiary); font-family: var(--pw-font-sans);" data-zh="暂无 stdout 日志" data-en="No stdout log">暂无 stdout 日志</div>
|
|
263
|
-
<
|
|
279
|
+
<div id="stdoutContent" class="hidden log-list"></div>
|
|
264
280
|
</section>
|
|
265
281
|
|
|
266
282
|
<!-- stderr -->
|
|
267
283
|
<section class="rounded-lg overflow-hidden" style="background-color: var(--pw-bg-surface); border: 1px solid var(--pw-border);">
|
|
268
284
|
<div class="flex items-center justify-between px-4 py-3" style="border-bottom: 1px solid var(--pw-border);">
|
|
269
285
|
<div class="flex items-center gap-2">
|
|
270
|
-
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="var(--pw-
|
|
286
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="var(--pw-text-secondary)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="4 17 10 11 4 5"/><line x1="12" y1="19" x2="20" y2="19"/></svg>
|
|
271
287
|
<h2 class="text-sm font-semibold" style="color: var(--pw-text-primary); font-family: var(--pw-font-sans);">stderr</h2>
|
|
272
288
|
</div>
|
|
273
289
|
<span id="stderrMeta" class="text-xs whitespace-nowrap" style="color: var(--pw-text-tertiary); font-family: var(--pw-font-mono);">—</span>
|
|
274
290
|
</div>
|
|
275
291
|
<div id="stderrEmpty" class="px-4 py-8 text-center text-sm" style="color: var(--pw-text-tertiary); font-family: var(--pw-font-sans);" data-zh="暂无 stderr 日志" data-en="No stderr log">暂无 stderr 日志</div>
|
|
276
|
-
<
|
|
292
|
+
<div id="stderrContent" class="hidden log-list"></div>
|
|
277
293
|
</section>
|
|
278
294
|
|
|
279
295
|
</div>
|
|
@@ -309,6 +325,19 @@ html.dark {
|
|
|
309
325
|
background-color: var(--pw-accent-muted);
|
|
310
326
|
color: var(--pw-accent);
|
|
311
327
|
}
|
|
328
|
+
.log-list { max-height: 480px; overflow-y: auto; background: #0d1117; }
|
|
329
|
+
.log-row { border-bottom: 1px solid var(--pw-border-subtle); color: var(--pw-text-secondary); font-family: var(--pw-font-mono); }
|
|
330
|
+
.log-row:last-child { border-bottom: 0; }
|
|
331
|
+
.log-row > summary { display: grid; grid-template-columns: minmax(132px,auto) 64px minmax(90px,140px) minmax(180px,1fr) auto; gap: 10px; align-items: center; padding: 9px 12px; cursor: pointer; list-style: none; }
|
|
332
|
+
.log-row > summary::-webkit-details-marker { display: none; }
|
|
333
|
+
.log-time,.log-component,.log-summary { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
334
|
+
.log-level { font-weight: 700; text-transform: uppercase; }
|
|
335
|
+
.log-row[data-level="error"] .log-level { color: var(--pw-state-error); }
|
|
336
|
+
.log-row[data-level="warn"] .log-level { color: var(--pw-state-warning); }
|
|
337
|
+
.log-row[data-level="info"] .log-level { color: var(--pw-state-info); }
|
|
338
|
+
.log-detail { margin: 0; padding: 10px 12px; color: var(--pw-text-tertiary); background: var(--pw-code-bg); white-space: pre-wrap; word-break: break-all; }
|
|
339
|
+
.copy-log-line { padding: 3px 7px; border: 1px solid var(--pw-border-subtle); border-radius: 4px; color: var(--pw-text-secondary); background: var(--pw-bg-hover); font: 11px var(--pw-font-sans); }
|
|
340
|
+
@media (max-width: 900px) { .log-row > summary { grid-template-columns: 92px 52px minmax(0,1fr) auto; }.log-component { display:none; } }
|
|
312
341
|
</style>
|
|
313
342
|
|
|
314
343
|
<script>lucide.createIcons();</script>
|
|
@@ -381,37 +410,57 @@ html.dark {
|
|
|
381
410
|
}
|
|
382
411
|
}
|
|
383
412
|
|
|
413
|
+
var lastLogData = null;
|
|
414
|
+
var visibleLogLines = {};
|
|
415
|
+
function parseLogEntries(value, stream) {
|
|
416
|
+
var query = $('logSearch') ? $('logSearch').value.trim().toLowerCase() : '';
|
|
417
|
+
var level = $('levelFilter') ? $('levelFilter').value : '';
|
|
418
|
+
return String(value || '').split(/\r?\n/).filter(Boolean).map(function (line) {
|
|
419
|
+
var parsed = window.PatchWardenLogParser.parseLine(line, stream);
|
|
420
|
+
if (level && parsed.level !== level) return null;
|
|
421
|
+
var searchable = [parsed.time, parsed.level, parsed.component, parsed.summary, line].join(' ').toLowerCase();
|
|
422
|
+
if (query && searchable.indexOf(query) < 0) return null;
|
|
423
|
+
return parsed;
|
|
424
|
+
}).filter(Boolean);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
function renderLogRows(container, emptyState, value, stream) {
|
|
428
|
+
var entries = parseLogEntries(value, stream);
|
|
429
|
+
if (!entries.length) { hide(container); show(emptyState); return 0; }
|
|
430
|
+
container.innerHTML = entries.map(function (entry, index) {
|
|
431
|
+
var copyId = stream + '-' + index;
|
|
432
|
+
visibleLogLines[copyId] = entry.raw;
|
|
433
|
+
return '<details class="log-row" data-level="' + escapeHtml(entry.level || 'unknown') + '">'
|
|
434
|
+
+ '<summary><span class="log-time" title="' + escapeHtml(entry.time || '无时间字段') + '">' + escapeHtml(entry.time || '—') + '</span>'
|
|
435
|
+
+ '<span class="log-level">' + escapeHtml(entry.level || 'raw') + '</span>'
|
|
436
|
+
+ '<span class="log-component" title="' + escapeHtml(entry.component) + '">' + escapeHtml(entry.component) + '</span>'
|
|
437
|
+
+ '<span class="log-summary" title="' + escapeHtml(entry.summary) + '">' + escapeHtml(entry.summary) + '</span>'
|
|
438
|
+
+ '<button type="button" class="copy-log-line" data-copy-id="' + copyId + '" title="复制脱敏日志行" aria-label="复制脱敏日志行" data-zh="复制" data-en="Copy">复制</button></summary>'
|
|
439
|
+
+ '<pre class="log-detail">' + escapeHtml(entry.detail) + '</pre></details>';
|
|
440
|
+
}).join('');
|
|
441
|
+
show(container); hide(emptyState);
|
|
442
|
+
return entries.length;
|
|
443
|
+
}
|
|
444
|
+
|
|
384
445
|
function renderLogs(data) {
|
|
446
|
+
lastLogData = data || {};
|
|
385
447
|
var stdout = (data && data.stdout) || '';
|
|
386
448
|
var stderr = (data && data.stderr) || '';
|
|
449
|
+
visibleLogLines = {};
|
|
387
450
|
var reason = (data && data.reason) || null;
|
|
388
451
|
var tail = (data && data.tail) || currentTail;
|
|
389
452
|
|
|
390
453
|
// stdout
|
|
391
454
|
var stdoutEl = $('stdoutContent');
|
|
392
455
|
var stdoutEmpty = $('stdoutEmpty');
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
show(stdoutEl);
|
|
396
|
-
hide(stdoutEmpty);
|
|
397
|
-
} else {
|
|
398
|
-
hide(stdoutEl);
|
|
399
|
-
show(stdoutEmpty);
|
|
400
|
-
}
|
|
401
|
-
text($('stdoutMeta'), 'tail=' + tail + (reason ? ' · ' + reason : ''));
|
|
456
|
+
var stdoutCount = renderLogRows(stdoutEl, stdoutEmpty, stdout, 'stdout');
|
|
457
|
+
text($('stdoutMeta'), (data && data.historical_snapshot ? '历史日志 · ' : '') + stdoutCount + ' 行 · tail=' + tail + (reason ? ' · ' + reason : ''));
|
|
402
458
|
|
|
403
459
|
// stderr
|
|
404
460
|
var stderrEl = $('stderrContent');
|
|
405
461
|
var stderrEmpty = $('stderrEmpty');
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
show(stderrEl);
|
|
409
|
-
hide(stderrEmpty);
|
|
410
|
-
} else {
|
|
411
|
-
hide(stderrEl);
|
|
412
|
-
show(stderrEmpty);
|
|
413
|
-
}
|
|
414
|
-
text($('stderrMeta'), 'tail=' + tail + (reason ? ' · ' + reason : ''));
|
|
462
|
+
var stderrCount = renderLogRows(stderrEl, stderrEmpty, stderr, 'stderr');
|
|
463
|
+
text($('stderrMeta'), (data && data.historical_snapshot ? '历史日志 · ' : '') + stderrCount + ' 行 · tail=' + tail + (reason ? ' · ' + reason : ''));
|
|
415
464
|
}
|
|
416
465
|
|
|
417
466
|
function loadLogs() {
|
|
@@ -443,6 +492,15 @@ html.dark {
|
|
|
443
492
|
});
|
|
444
493
|
}
|
|
445
494
|
|
|
495
|
+
function clearLogView() {
|
|
496
|
+
clearError();
|
|
497
|
+
text($('stdoutMeta'), '已清空当前视图');
|
|
498
|
+
text($('stderrMeta'), '日志文件未删除');
|
|
499
|
+
$('stdoutContent').innerHTML = ''; $('stderrContent').innerHTML = '';
|
|
500
|
+
show($('stdoutEmpty')); show($('stderrEmpty'));
|
|
501
|
+
hide($('stdoutContent')); hide($('stderrContent'));
|
|
502
|
+
}
|
|
503
|
+
|
|
446
504
|
// ---------- Auto-refresh ----------
|
|
447
505
|
function startAutoRefresh() {
|
|
448
506
|
stopAutoRefresh();
|
|
@@ -492,11 +550,36 @@ html.dark {
|
|
|
492
550
|
|
|
493
551
|
var refreshBtn = $('refreshBtn');
|
|
494
552
|
if (refreshBtn) refreshBtn.addEventListener('click', loadLogs);
|
|
553
|
+
var clearView = $('clearView');
|
|
554
|
+
if (clearView) clearView.addEventListener('click', clearLogView);
|
|
555
|
+
var levelFilter = $('levelFilter');
|
|
556
|
+
if (levelFilter) levelFilter.addEventListener('change', function () { if (lastLogData) renderLogs(lastLogData); });
|
|
557
|
+
var logSearch = $('logSearch');
|
|
558
|
+
if (logSearch) logSearch.addEventListener('input', function () { if (lastLogData) renderLogs(lastLogData); });
|
|
559
|
+
['stdoutContent', 'stderrContent'].forEach(function (id) {
|
|
560
|
+
var container = $(id);
|
|
561
|
+
if (!container) return;
|
|
562
|
+
container.addEventListener('click', function (event) {
|
|
563
|
+
var button = event.target.closest && event.target.closest('.copy-log-line');
|
|
564
|
+
if (!button) return;
|
|
565
|
+
event.preventDefault();
|
|
566
|
+
event.stopPropagation();
|
|
567
|
+
var line = visibleLogLines[button.getAttribute('data-copy-id')] || '';
|
|
568
|
+
if (navigator.clipboard && navigator.clipboard.writeText) {
|
|
569
|
+
navigator.clipboard.writeText(line).then(function () {
|
|
570
|
+
button.textContent = '已复制';
|
|
571
|
+
setTimeout(function () { button.textContent = '复制'; }, 1200);
|
|
572
|
+
});
|
|
573
|
+
}
|
|
574
|
+
});
|
|
575
|
+
});
|
|
495
576
|
|
|
496
577
|
// ---------- Initial load ----------
|
|
497
578
|
setCategory(DEFAULT_CATEGORY);
|
|
498
579
|
loadLogs();
|
|
499
580
|
})();
|
|
500
581
|
</script>
|
|
582
|
+
<script src="/i18n.js"></script>
|
|
583
|
+
<script src="/desktop-bridge.js"></script>
|
|
501
584
|
</body>
|
|
502
585
|
</html>
|