patchwarden 1.5.1 → 1.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/PatchWarden.cmd +32 -2
- package/README.en.md +158 -26
- package/README.md +124 -24
- package/dist/assessments/agentAssessor.js +21 -12
- package/dist/assessments/assessmentDiagnostics.d.ts +29 -0
- package/dist/assessments/assessmentDiagnostics.js +132 -0
- package/dist/assessments/assessmentStore.d.ts +39 -0
- package/dist/assessments/assessmentStore.js +207 -45
- package/dist/assessments/securitySnapshot.d.ts +50 -0
- package/dist/assessments/securitySnapshot.js +158 -0
- 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 +60 -1
- package/dist/control/routes/status.js +94 -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 +65 -40
- package/dist/control/server.js +37 -365
- package/dist/control/shared.d.ts +25 -1
- package/dist/control/shared.js +64 -11
- package/dist/diagnostics/allowedTestCommandSafety.d.ts +1 -0
- package/dist/diagnostics/allowedTestCommandSafety.js +11 -0
- 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 +128 -35
- package/dist/direct/directVerification.js +8 -16
- package/dist/doctor.js +65 -57
- 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 +2 -1
- package/dist/runner/runTask.js +162 -93
- 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} +3 -1
- package/dist/{taskRuntime.js → runner/taskRuntime.js} +3 -2
- package/dist/runner/taskStatusStore.d.ts +11 -0
- package/dist/runner/taskStatusStore.js +35 -0
- package/dist/runner/watch.d.ts +14 -1
- package/dist/runner/watch.js +320 -49
- 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 +27 -26
- 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} +2 -1
- package/dist/tools/{auditTask.js → diagnostics/auditTask.js} +134 -36
- package/dist/tools/{healthCheck.d.ts → diagnostics/healthCheck.d.ts} +18 -6
- package/dist/tools/{healthCheck.js → diagnostics/healthCheck.js} +36 -8
- 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 +86 -0
- package/dist/tools/{createTask.d.ts → tasks/createTask.d.ts} +12 -4
- package/dist/tools/{createTask.js → tasks/createTask.js} +110 -34
- package/dist/tools/{diagnoseTask.d.ts → tasks/diagnoseTask.d.ts} +1 -1
- package/dist/tools/{diagnoseTask.js → tasks/diagnoseTask.js} +12 -16
- 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} +11 -6
- package/dist/tools/{getTaskStdoutTail.js → tasks/getTaskStdoutTail.js} +13 -11
- package/dist/tools/{getTaskSummary.js → tasks/getTaskSummary.js} +35 -36
- 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} +5 -4
- package/dist/tools/{reconcileTasks.d.ts → tasks/reconcileTasks.d.ts} +3 -2
- package/dist/tools/tasks/reconcileTasks.js +496 -0
- 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} +63 -41
- package/dist/tools/tasks/runVerification.js +38 -0
- package/dist/tools/{taskLineage.js → tasks/taskLineage.js} +8 -7
- package/dist/tools/{taskOutputs.d.ts → tasks/taskOutputs.d.ts} +2 -2
- package/dist/tools/{taskOutputs.js → tasks/taskOutputs.js} +17 -16
- package/dist/tools/tasks/taskStates.d.ts +6 -0
- package/dist/tools/tasks/taskStates.js +52 -0
- package/dist/tools/{waitForTask.js → tasks/waitForTask.js} +3 -11
- 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/workspace/listAgents.d.ts +23 -0
- package/dist/tools/workspace/listAgents.js +56 -0
- 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 +67 -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 +16 -11
- package/docs/release-checklist.md +1 -1
- package/docs/release-evidence.md +35 -39
- 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 +102 -10
- package/scripts/checks/control-smoke.js +19 -8
- package/scripts/checks/http-mcp-smoke.js +82 -4
- package/scripts/checks/lifecycle-smoke.js +15 -12
- package/scripts/checks/mcp-manifest-check.js +1 -1
- package/scripts/checks/mcp-smoke.js +58 -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 +38 -1
- 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 +191 -33
- package/scripts/e2e/demo-runtime.mjs +153 -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 +26 -12
- package/src/assessments/assessmentDiagnostics.ts +172 -0
- package/src/assessments/assessmentStore.ts +288 -51
- package/src/assessments/securitySnapshot.ts +231 -0
- 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 +134 -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 +71 -43
- package/src/control/server.ts +37 -342
- package/src/control/shared.ts +77 -11
- package/src/diagnostics/allowedTestCommandSafety.ts +12 -0
- 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 +213 -55
- package/src/direct/directVerification.ts +9 -23
- package/src/doctor.ts +76 -64
- 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 +197 -97
- package/src/runner/simpleProcess.ts +66 -31
- package/src/{taskProgress.ts → runner/taskProgress.ts} +3 -3
- package/src/{taskRuntime.ts → runner/taskRuntime.ts} +6 -3
- package/src/runner/taskStatusStore.ts +69 -0
- package/src/runner/watch.ts +348 -52
- 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 +27 -26
- 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} +136 -39
- package/src/tools/{healthCheck.ts → diagnostics/healthCheck.ts} +37 -9
- 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 +110 -0
- package/src/tools/{createTask.ts → tasks/createTask.ts} +161 -33
- package/src/tools/{diagnoseTask.ts → tasks/diagnoseTask.ts} +12 -16
- 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} +13 -6
- package/src/tools/{getTaskStdoutTail.ts → tasks/getTaskStdoutTail.ts} +13 -11
- package/src/tools/{getTaskSummary.ts → tasks/getTaskSummary.ts} +46 -44
- package/src/tools/tasks/index.ts +18 -0
- package/src/tools/{listTasks.ts → tasks/listTasks.ts} +6 -5
- package/src/tools/{reconcileTasks.ts → tasks/reconcileTasks.ts} +228 -77
- package/src/tools/tasks/retryTask.ts +69 -0
- package/src/tools/{runTaskLoop.ts → tasks/runTaskLoop.ts} +73 -46
- 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/tasks/taskStates.ts +54 -0
- package/src/tools/{waitForTask.ts → tasks/waitForTask.ts} +3 -12
- 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/workspace/listAgents.ts +75 -0
- 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 +74 -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 +94 -147
- package/ui/pages/direct-sessions.html +123 -26
- package/ui/pages/getting-started.html +43 -0
- package/ui/pages/logs.html +134 -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 +254 -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/listAgents.d.ts +0 -12
- package/dist/tools/listAgents.js +0 -42
- package/dist/tools/reconcileTasks.js +0 -352
- 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/listAgents.ts +0 -54
- 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/{waitForTask.d.ts → tasks/waitForTask.d.ts} +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/ui/pages/logs.html
CHANGED
|
@@ -95,13 +95,45 @@ 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>
|
|
100
|
+
<script>
|
|
101
|
+
// Keep the log page usable when an older packaged Control Center omits the
|
|
102
|
+
// parser asset. The server serves the canonical parser; this is only a
|
|
103
|
+
// bounded display fallback and never changes log contents.
|
|
104
|
+
if (!window.PatchWardenLogParser || typeof window.PatchWardenLogParser.parseLine !== 'function') {
|
|
105
|
+
window.PatchWardenLogParser = {
|
|
106
|
+
parseLine: function (rawLine, stream) {
|
|
107
|
+
var line = String(rawLine || '');
|
|
108
|
+
var source = String(stream || 'log');
|
|
109
|
+
var entry = null;
|
|
110
|
+
try {
|
|
111
|
+
var parsed = JSON.parse(line);
|
|
112
|
+
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) entry = parsed;
|
|
113
|
+
} catch (_) {}
|
|
114
|
+
var level = entry ? String(entry.level || entry.severity || '').toLowerCase() : '';
|
|
115
|
+
if (level === 'warning') level = 'warn';
|
|
116
|
+
return {
|
|
117
|
+
raw: line,
|
|
118
|
+
time: entry ? String(entry.time || entry.timestamp || '') : '',
|
|
119
|
+
level: level,
|
|
120
|
+
component: entry ? String(entry.component || entry.scope || entry.source || source) : source,
|
|
121
|
+
summary: entry ? String(entry.summary || entry.msg || entry.message || line) : line,
|
|
122
|
+
detail: entry ? JSON.stringify(entry, null, 2) : line,
|
|
123
|
+
structured: entry !== null
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
</script>
|
|
99
129
|
<style>
|
|
100
130
|
.no-scrollbar::-webkit-scrollbar { display: none; }
|
|
101
131
|
.no-scrollbar { -ms-overflow-style: none; scrollbar-width: none; }
|
|
102
132
|
.pw-spin { animation: pw-spin 1s linear infinite; }
|
|
103
133
|
@keyframes pw-spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
|
|
104
134
|
</style>
|
|
135
|
+
<script src="/desktop-bootstrap.js"></script>
|
|
136
|
+
<link rel="stylesheet" href="/desktop.css">
|
|
105
137
|
</head>
|
|
106
138
|
<body class="flex h-screen overflow-hidden">
|
|
107
139
|
|
|
@@ -119,6 +151,10 @@ html.dark {
|
|
|
119
151
|
|
|
120
152
|
<!-- Navigation -->
|
|
121
153
|
<nav class="flex-1 flex flex-col gap-1 px-3 pt-4 overflow-y-auto">
|
|
154
|
+
<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);">
|
|
155
|
+
<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>
|
|
156
|
+
<span class="truncate" data-i18n="nav.gettingStarted">开始使用</span>
|
|
157
|
+
</a>
|
|
122
158
|
|
|
123
159
|
<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
160
|
<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 +210,10 @@ html.dark {
|
|
|
174
210
|
<span class="truncate" data-zh="日志" data-en="Logs">日志</span>
|
|
175
211
|
</a>
|
|
176
212
|
|
|
213
|
+
<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);">
|
|
214
|
+
<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>
|
|
215
|
+
<span class="truncate" data-i18n="nav.settings">设置</span>
|
|
216
|
+
</a>
|
|
177
217
|
</nav>
|
|
178
218
|
|
|
179
219
|
<!-- Bottom Section -->
|
|
@@ -211,6 +251,11 @@ html.dark {
|
|
|
211
251
|
<option value="300">tail 300</option>
|
|
212
252
|
<option value="1000">tail 1000</option>
|
|
213
253
|
</select>
|
|
254
|
+
<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>
|
|
255
|
+
<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);">
|
|
256
|
+
<option value="">全部级别</option><option value="error">Error</option><option value="warn">Warning</option><option value="info">Info</option>
|
|
257
|
+
</select>
|
|
258
|
+
<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
259
|
<!-- Auto-refresh toggle -->
|
|
215
260
|
<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
261
|
<input id="autoRefresh" type="checkbox" style="accent-color: var(--pw-accent);" />
|
|
@@ -260,20 +305,20 @@ html.dark {
|
|
|
260
305
|
<span id="stdoutMeta" class="text-xs whitespace-nowrap" style="color: var(--pw-text-tertiary); font-family: var(--pw-font-mono);">—</span>
|
|
261
306
|
</div>
|
|
262
307
|
<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
|
-
<
|
|
308
|
+
<div id="stdoutContent" class="hidden log-list"></div>
|
|
264
309
|
</section>
|
|
265
310
|
|
|
266
311
|
<!-- stderr -->
|
|
267
312
|
<section class="rounded-lg overflow-hidden" style="background-color: var(--pw-bg-surface); border: 1px solid var(--pw-border);">
|
|
268
313
|
<div class="flex items-center justify-between px-4 py-3" style="border-bottom: 1px solid var(--pw-border);">
|
|
269
314
|
<div class="flex items-center gap-2">
|
|
270
|
-
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="var(--pw-
|
|
315
|
+
<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
316
|
<h2 class="text-sm font-semibold" style="color: var(--pw-text-primary); font-family: var(--pw-font-sans);">stderr</h2>
|
|
272
317
|
</div>
|
|
273
318
|
<span id="stderrMeta" class="text-xs whitespace-nowrap" style="color: var(--pw-text-tertiary); font-family: var(--pw-font-mono);">—</span>
|
|
274
319
|
</div>
|
|
275
320
|
<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
|
-
<
|
|
321
|
+
<div id="stderrContent" class="hidden log-list"></div>
|
|
277
322
|
</section>
|
|
278
323
|
|
|
279
324
|
</div>
|
|
@@ -309,6 +354,19 @@ html.dark {
|
|
|
309
354
|
background-color: var(--pw-accent-muted);
|
|
310
355
|
color: var(--pw-accent);
|
|
311
356
|
}
|
|
357
|
+
.log-list { max-height: 480px; overflow-y: auto; background: #0d1117; }
|
|
358
|
+
.log-row { border-bottom: 1px solid var(--pw-border-subtle); color: var(--pw-text-secondary); font-family: var(--pw-font-mono); }
|
|
359
|
+
.log-row:last-child { border-bottom: 0; }
|
|
360
|
+
.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; }
|
|
361
|
+
.log-row > summary::-webkit-details-marker { display: none; }
|
|
362
|
+
.log-time,.log-component,.log-summary { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
363
|
+
.log-level { font-weight: 700; text-transform: uppercase; }
|
|
364
|
+
.log-row[data-level="error"] .log-level { color: var(--pw-state-error); }
|
|
365
|
+
.log-row[data-level="warn"] .log-level { color: var(--pw-state-warning); }
|
|
366
|
+
.log-row[data-level="info"] .log-level { color: var(--pw-state-info); }
|
|
367
|
+
.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; }
|
|
368
|
+
.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); }
|
|
369
|
+
@media (max-width: 900px) { .log-row > summary { grid-template-columns: 92px 52px minmax(0,1fr) auto; }.log-component { display:none; } }
|
|
312
370
|
</style>
|
|
313
371
|
|
|
314
372
|
<script>lucide.createIcons();</script>
|
|
@@ -381,37 +439,57 @@ html.dark {
|
|
|
381
439
|
}
|
|
382
440
|
}
|
|
383
441
|
|
|
442
|
+
var lastLogData = null;
|
|
443
|
+
var visibleLogLines = {};
|
|
444
|
+
function parseLogEntries(value, stream) {
|
|
445
|
+
var query = $('logSearch') ? $('logSearch').value.trim().toLowerCase() : '';
|
|
446
|
+
var level = $('levelFilter') ? $('levelFilter').value : '';
|
|
447
|
+
return String(value || '').split(/\r?\n/).filter(Boolean).map(function (line) {
|
|
448
|
+
var parsed = window.PatchWardenLogParser.parseLine(line, stream);
|
|
449
|
+
if (level && parsed.level !== level) return null;
|
|
450
|
+
var searchable = [parsed.time, parsed.level, parsed.component, parsed.summary, line].join(' ').toLowerCase();
|
|
451
|
+
if (query && searchable.indexOf(query) < 0) return null;
|
|
452
|
+
return parsed;
|
|
453
|
+
}).filter(Boolean);
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
function renderLogRows(container, emptyState, value, stream) {
|
|
457
|
+
var entries = parseLogEntries(value, stream);
|
|
458
|
+
if (!entries.length) { hide(container); show(emptyState); return 0; }
|
|
459
|
+
container.innerHTML = entries.map(function (entry, index) {
|
|
460
|
+
var copyId = stream + '-' + index;
|
|
461
|
+
visibleLogLines[copyId] = entry.raw;
|
|
462
|
+
return '<details class="log-row" data-level="' + escapeHtml(entry.level || 'unknown') + '">'
|
|
463
|
+
+ '<summary><span class="log-time" title="' + escapeHtml(entry.time || '无时间字段') + '">' + escapeHtml(entry.time || '—') + '</span>'
|
|
464
|
+
+ '<span class="log-level">' + escapeHtml(entry.level || 'raw') + '</span>'
|
|
465
|
+
+ '<span class="log-component" title="' + escapeHtml(entry.component) + '">' + escapeHtml(entry.component) + '</span>'
|
|
466
|
+
+ '<span class="log-summary" title="' + escapeHtml(entry.summary) + '">' + escapeHtml(entry.summary) + '</span>'
|
|
467
|
+
+ '<button type="button" class="copy-log-line" data-copy-id="' + copyId + '" title="复制脱敏日志行" aria-label="复制脱敏日志行" data-zh="复制" data-en="Copy">复制</button></summary>'
|
|
468
|
+
+ '<pre class="log-detail">' + escapeHtml(entry.detail) + '</pre></details>';
|
|
469
|
+
}).join('');
|
|
470
|
+
show(container); hide(emptyState);
|
|
471
|
+
return entries.length;
|
|
472
|
+
}
|
|
473
|
+
|
|
384
474
|
function renderLogs(data) {
|
|
475
|
+
lastLogData = data || {};
|
|
385
476
|
var stdout = (data && data.stdout) || '';
|
|
386
477
|
var stderr = (data && data.stderr) || '';
|
|
478
|
+
visibleLogLines = {};
|
|
387
479
|
var reason = (data && data.reason) || null;
|
|
388
480
|
var tail = (data && data.tail) || currentTail;
|
|
389
481
|
|
|
390
482
|
// stdout
|
|
391
483
|
var stdoutEl = $('stdoutContent');
|
|
392
484
|
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 : ''));
|
|
485
|
+
var stdoutCount = renderLogRows(stdoutEl, stdoutEmpty, stdout, 'stdout');
|
|
486
|
+
text($('stdoutMeta'), (data && data.historical_snapshot ? '历史日志 · ' : '') + stdoutCount + ' 行 · tail=' + tail + (reason ? ' · ' + reason : ''));
|
|
402
487
|
|
|
403
488
|
// stderr
|
|
404
489
|
var stderrEl = $('stderrContent');
|
|
405
490
|
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 : ''));
|
|
491
|
+
var stderrCount = renderLogRows(stderrEl, stderrEmpty, stderr, 'stderr');
|
|
492
|
+
text($('stderrMeta'), (data && data.historical_snapshot ? '历史日志 · ' : '') + stderrCount + ' 行 · tail=' + tail + (reason ? ' · ' + reason : ''));
|
|
415
493
|
}
|
|
416
494
|
|
|
417
495
|
function loadLogs() {
|
|
@@ -443,6 +521,15 @@ html.dark {
|
|
|
443
521
|
});
|
|
444
522
|
}
|
|
445
523
|
|
|
524
|
+
function clearLogView() {
|
|
525
|
+
clearError();
|
|
526
|
+
text($('stdoutMeta'), '已清空当前视图');
|
|
527
|
+
text($('stderrMeta'), '日志文件未删除');
|
|
528
|
+
$('stdoutContent').innerHTML = ''; $('stderrContent').innerHTML = '';
|
|
529
|
+
show($('stdoutEmpty')); show($('stderrEmpty'));
|
|
530
|
+
hide($('stdoutContent')); hide($('stderrContent'));
|
|
531
|
+
}
|
|
532
|
+
|
|
446
533
|
// ---------- Auto-refresh ----------
|
|
447
534
|
function startAutoRefresh() {
|
|
448
535
|
stopAutoRefresh();
|
|
@@ -492,11 +579,36 @@ html.dark {
|
|
|
492
579
|
|
|
493
580
|
var refreshBtn = $('refreshBtn');
|
|
494
581
|
if (refreshBtn) refreshBtn.addEventListener('click', loadLogs);
|
|
582
|
+
var clearView = $('clearView');
|
|
583
|
+
if (clearView) clearView.addEventListener('click', clearLogView);
|
|
584
|
+
var levelFilter = $('levelFilter');
|
|
585
|
+
if (levelFilter) levelFilter.addEventListener('change', function () { if (lastLogData) renderLogs(lastLogData); });
|
|
586
|
+
var logSearch = $('logSearch');
|
|
587
|
+
if (logSearch) logSearch.addEventListener('input', function () { if (lastLogData) renderLogs(lastLogData); });
|
|
588
|
+
['stdoutContent', 'stderrContent'].forEach(function (id) {
|
|
589
|
+
var container = $(id);
|
|
590
|
+
if (!container) return;
|
|
591
|
+
container.addEventListener('click', function (event) {
|
|
592
|
+
var button = event.target.closest && event.target.closest('.copy-log-line');
|
|
593
|
+
if (!button) return;
|
|
594
|
+
event.preventDefault();
|
|
595
|
+
event.stopPropagation();
|
|
596
|
+
var line = visibleLogLines[button.getAttribute('data-copy-id')] || '';
|
|
597
|
+
if (navigator.clipboard && navigator.clipboard.writeText) {
|
|
598
|
+
navigator.clipboard.writeText(line).then(function () {
|
|
599
|
+
button.textContent = '已复制';
|
|
600
|
+
setTimeout(function () { button.textContent = '复制'; }, 1200);
|
|
601
|
+
});
|
|
602
|
+
}
|
|
603
|
+
});
|
|
604
|
+
});
|
|
495
605
|
|
|
496
606
|
// ---------- Initial load ----------
|
|
497
607
|
setCategory(DEFAULT_CATEGORY);
|
|
498
608
|
loadLogs();
|
|
499
609
|
})();
|
|
500
610
|
</script>
|
|
611
|
+
<script src="/i18n.js"></script>
|
|
612
|
+
<script src="/desktop-bridge.js"></script>
|
|
501
613
|
</body>
|
|
502
614
|
</html>
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="zh-CN">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
+
<title data-i18n="settings.pageTitle"></title>
|
|
7
|
+
<link rel="stylesheet" href="/colors_and_type.css">
|
|
8
|
+
<script src="/desktop-bootstrap.js"></script>
|
|
9
|
+
<link rel="stylesheet" href="/desktop.css">
|
|
10
|
+
<script src="/vendor/tailwindcss-browser.js"></script>
|
|
11
|
+
<script src="/vendor/lucide.js"></script>
|
|
12
|
+
</head>
|
|
13
|
+
<body class="flex h-screen overflow-hidden">
|
|
14
|
+
<aside class="flex flex-col w-60 shrink-0 h-screen" style="background:var(--pw-bg);border-right:1px solid var(--pw-border)">
|
|
15
|
+
<div class="flex items-center gap-3 px-5 py-5" style="border-bottom:1px solid var(--pw-border-subtle)">
|
|
16
|
+
<i data-lucide="shield-check" style="color:var(--pw-accent)"></i><span class="text-lg font-semibold">PatchWarden</span>
|
|
17
|
+
</div>
|
|
18
|
+
<nav class="flex-1 flex flex-col gap-1 px-3 pt-4 overflow-y-auto">
|
|
19
|
+
<a href="/pages/getting-started.html" data-nav-key="getting-started" class="flex items-center gap-3 px-3 py-2.5 text-sm"><i data-lucide="rocket" class="w-4 h-4"></i><span data-i18n="nav.gettingStarted"></span></a>
|
|
20
|
+
<a href="/pages/dashboard.html" data-nav-key="dashboard" class="flex items-center gap-3 px-3 py-2.5 text-sm"><i data-lucide="layout-dashboard" class="w-4 h-4"></i><span data-i18n="nav.dashboard"></span></a>
|
|
21
|
+
<a href="/pages/tasks.html" data-nav-key="tasks" class="flex items-center gap-3 px-3 py-2.5 text-sm"><i data-lucide="list-checks" class="w-4 h-4"></i><span data-i18n="nav.tasks"></span></a>
|
|
22
|
+
<a href="/pages/workspace.html" data-nav-key="workspace" class="flex items-center gap-3 px-3 py-2.5 text-sm"><i data-lucide="folder" class="w-4 h-4"></i><span data-i18n="nav.workspace"></span></a>
|
|
23
|
+
<a href="/pages/audit.html" data-nav-key="audit" class="flex items-center gap-3 px-3 py-2.5 text-sm"><i data-lucide="file-search" class="w-4 h-4"></i><span data-i18n="nav.audit"></span></a>
|
|
24
|
+
<a href="/pages/direct-sessions.html" data-nav-key="direct-sessions" class="flex items-center gap-3 px-3 py-2.5 text-sm"><i data-lucide="route" class="w-4 h-4"></i><span data-i18n="nav.direct"></span></a>
|
|
25
|
+
<a href="/pages/logs.html" data-nav-key="logs" class="flex items-center gap-3 px-3 py-2.5 text-sm"><i data-lucide="scroll-text" class="w-4 h-4"></i><span data-i18n="nav.logs"></span></a>
|
|
26
|
+
<a href="/pages/settings.html" data-nav-key="settings" data-active="true" class="desktop-only-nav flex items-center gap-3 px-3 py-2.5 text-sm"><i data-lucide="settings" class="w-4 h-4"></i><span data-i18n="nav.settings"></span></a>
|
|
27
|
+
</nav>
|
|
28
|
+
</aside>
|
|
29
|
+
<div class="flex flex-col flex-1 min-w-0 h-screen overflow-hidden">
|
|
30
|
+
<header class="flex items-center px-6 py-3" style="border-bottom:1px solid var(--pw-border);background:var(--pw-bg)"><h1 class="text-lg font-semibold" data-i18n="settings.title"></h1></header>
|
|
31
|
+
<main class="flex-1 overflow-y-auto p-6" style="background:var(--pw-bg-elevated)">
|
|
32
|
+
<div class="settings-layout">
|
|
33
|
+
<section>
|
|
34
|
+
<h2 data-i18n="settings.appearance"></h2>
|
|
35
|
+
<div class="setting-row"><div><strong data-i18n="settings.theme"></strong><p data-i18n="settings.themeHelp"></p></div><select id="theme"><option value="system" data-i18n="settings.themeSystem"></option><option value="light" data-i18n="settings.themeLight"></option><option value="dark" data-i18n="settings.themeDark"></option></select></div>
|
|
36
|
+
<div class="setting-row"><div><strong data-i18n="language.label"></strong><p data-i18n="settings.languageHelp"></p></div><select id="language"><option value="system" data-i18n="language.system"></option><option value="zh-CN" data-i18n="language.zh"></option><option value="en" data-i18n="language.en"></option></select></div>
|
|
37
|
+
<div class="setting-row"><div><strong data-i18n="settings.closeWindow"></strong><p data-i18n="settings.closeWindowHelp"></p></div><select id="closeBehavior"><option value="tray" data-i18n="settings.closeToTray"></option><option value="quit" data-i18n="settings.closeQuit"></option></select></div>
|
|
38
|
+
</section>
|
|
39
|
+
<section>
|
|
40
|
+
<h2 data-i18n="settings.localAgents"></h2>
|
|
41
|
+
<div class="agent-section-toolbar"><p data-i18n="settings.localAgentsHelp"></p><button id="detectAgents"><i data-lucide="scan-search"></i><span data-i18n="settings.detectAgents"></span></button></div>
|
|
42
|
+
<div id="agentSettingsList" class="agent-settings-list"><p class="agent-empty" data-i18n="settings.loadingAgents"></p></div>
|
|
43
|
+
<div class="setting-actions"><button id="saveAgents" class="primary-action"><i data-lucide="save"></i><span data-i18n="settings.saveAgents"></span></button><span id="agentSettingsStatus" class="status-text" aria-live="polite"></span></div>
|
|
44
|
+
</section>
|
|
45
|
+
<section>
|
|
46
|
+
<h2 data-i18n="settings.mcpTunnel"></h2>
|
|
47
|
+
<div class="setting-row">
|
|
48
|
+
<div class="min-w-0"><strong>tunnel-client.exe</strong><p id="tunnelClientPath" class="mono break-path"></p></div>
|
|
49
|
+
<div class="inline-actions"><button id="detectTunnel"><i data-lucide="scan-search"></i><span data-i18n="settings.detect"></span></button><button id="chooseTunnel"><i data-lucide="file-search"></i><span data-i18n="settings.choose"></span></button></div>
|
|
50
|
+
</div>
|
|
51
|
+
<div class="setting-row">
|
|
52
|
+
<div><strong>Direct profile</strong><p data-i18n="settings.directHelp"></p></div>
|
|
53
|
+
<label class="switch-label"><input id="enableDirectProfile" type="checkbox"><span data-i18n="settings.enable"></span></label>
|
|
54
|
+
</div>
|
|
55
|
+
<div class="setting-row">
|
|
56
|
+
<div><strong data-i18n="settings.proxy"></strong><p data-i18n="settings.proxyHelp"></p></div>
|
|
57
|
+
<select id="proxyScope"><option value="shared" data-i18n="settings.proxyShared"></option><option value="separate" data-i18n="settings.proxySeparate"></option></select>
|
|
58
|
+
</div>
|
|
59
|
+
<div class="proxy-grid">
|
|
60
|
+
<div class="proxy-endpoint">
|
|
61
|
+
<strong>Core</strong>
|
|
62
|
+
<select id="coreProxyMode"><option value="environment" data-i18n="settings.proxyEnvironment"></option><option value="none" data-i18n="settings.proxyNone"></option><option value="manual" data-i18n="settings.proxyManual"></option></select>
|
|
63
|
+
<input id="coreProxyUrl" type="url" placeholder="http://127.0.0.1:7890" autocomplete="off">
|
|
64
|
+
</div>
|
|
65
|
+
<div id="directProxyEndpoint" class="proxy-endpoint hidden">
|
|
66
|
+
<strong>Direct</strong>
|
|
67
|
+
<select id="directProxyMode"><option value="environment" data-i18n="settings.proxyEnvironment"></option><option value="none" data-i18n="settings.proxyNone"></option><option value="manual" data-i18n="settings.proxyManual"></option></select>
|
|
68
|
+
<input id="directProxyUrl" type="url" placeholder="socks5://127.0.0.1:1080" autocomplete="off">
|
|
69
|
+
</div>
|
|
70
|
+
</div>
|
|
71
|
+
<div class="setting-actions"><button id="saveRuntime" class="primary-action"><i data-lucide="save"></i><span data-i18n="settings.saveRuntime"></span></button><span id="runtimeStatus" class="status-text" aria-live="polite"></span></div>
|
|
72
|
+
<div class="credential-panel">
|
|
73
|
+
<div class="credential-heading"><div><strong data-i18n="settings.tunnelCredentials"></strong><p data-i18n="settings.runtimeKeyHelp"></p></div><span id="credentialState" class="credential-state"></span></div>
|
|
74
|
+
<div class="credential-grid">
|
|
75
|
+
<label>Profile<select id="tunnelMode"><option value="core">Core</option><option value="direct">Direct</option></select></label>
|
|
76
|
+
<label><span data-i18n="settings.tunnelId"></span><input id="tunnelId" type="text" autocomplete="off" spellcheck="false" placeholder="tun_..."></label>
|
|
77
|
+
<label><span data-i18n="settings.runtimeKey"></span><input id="runtimeKey" type="password" autocomplete="new-password" spellcheck="false"></label>
|
|
78
|
+
</div>
|
|
79
|
+
<div class="setting-actions credential-actions"><button id="provisionTunnel" class="primary-action"><i data-lucide="shield-check"></i><span data-i18n="settings.configureCore"></span></button><button id="revalidateCredential"><i data-lucide="activity"></i><span data-i18n="settings.revalidate"></span></button><button id="forgetCredential"><i data-lucide="key-round"></i><span data-i18n="settings.forgetCredential"></span></button><span id="provisionStatus" class="status-text" aria-live="polite"></span></div>
|
|
80
|
+
</div>
|
|
81
|
+
<details class="install-guide"><summary data-i18n="settings.installSummary"></summary><ol><li data-i18n="settings.installStep1"></li><li data-i18n="settings.installStep2"></li><li data-i18n="settings.installStep3"></li><li data-i18n="settings.installStep4"></li></ol></details>
|
|
82
|
+
</section>
|
|
83
|
+
<section>
|
|
84
|
+
<h2 data-i18n="settings.workspaceDiagnostics"></h2>
|
|
85
|
+
<div class="setting-row"><div class="min-w-0"><strong data-i18n="settings.currentConfig"></strong><p id="configPath" class="mono truncate"></p></div><button id="openConfig" data-i18n-title="settings.openConfig"><i data-lucide="external-link"></i></button></div>
|
|
86
|
+
<div class="setting-row"><div><strong data-i18n="settings.workspace"></strong><p id="workspacePath" class="mono"></p></div><button id="changeWorkspace" data-i18n="settings.change"></button></div>
|
|
87
|
+
<div class="setting-actions"><button id="openLogs"><i data-lucide="folder-open"></i><span data-i18n="settings.openLogs"></span></button><button id="runDoctor"><i data-lucide="stethoscope"></i><span data-i18n="settings.runDoctor"></span></button></div>
|
|
88
|
+
<pre id="doctorOutput" class="hidden"></pre>
|
|
89
|
+
</section>
|
|
90
|
+
</div>
|
|
91
|
+
</main>
|
|
92
|
+
</div>
|
|
93
|
+
<style>
|
|
94
|
+
[data-nav-key]{color:var(--pw-text-secondary);border-radius:6px}[data-nav-key]:hover{background:var(--pw-bg-hover);color:var(--pw-text-primary)}[data-nav-key][data-active="true"]{background:var(--pw-accent-subtle);color:var(--pw-accent);border-left:2px solid var(--pw-accent)}
|
|
95
|
+
.settings-layout{display:grid;gap:18px;max-width:920px}.settings-layout section{background:var(--pw-bg-surface);border:1px solid var(--pw-border);border-radius:7px}.settings-layout h2{margin:0;padding:16px 18px;font-size:14px;border-bottom:1px solid var(--pw-border)}.setting-row{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:20px;align-items:center;padding:16px 18px;border-bottom:1px solid var(--pw-border-subtle)}.setting-row p,.credential-panel p,.agent-section-toolbar p{margin:4px 0 0;color:var(--pw-text-secondary);font-size:12px}.setting-row select,.setting-row button,.setting-actions button,.proxy-endpoint select,.proxy-endpoint input,.credential-grid select,.credential-grid input,.agent-section-toolbar button,.agent-controls select,.agent-controls input,.agent-controls button{min-height:36px;padding:0 12px;color:var(--pw-text-primary);background:var(--pw-bg-elevated);border:1px solid var(--pw-border);border-radius:6px}.setting-row button,.agent-section-toolbar button,.agent-controls button{display:flex;align-items:center;gap:6px}.setting-row svg,.agent-section-toolbar svg,.agent-controls svg{width:16px}.setting-actions{display:flex;align-items:center;gap:10px;padding:16px 18px;flex-wrap:wrap}.setting-actions button{display:flex;align-items:center;gap:8px}.setting-actions svg{width:16px}.inline-actions{display:flex;gap:8px}.switch-label{display:flex;align-items:center;gap:8px}.switch-label input{width:18px;height:18px;accent-color:var(--pw-accent)}.agent-section-toolbar{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:12px 18px;border-bottom:1px solid var(--pw-border-subtle)}.agent-settings-list{display:grid}.agent-setting-row{display:grid;grid-template-columns:minmax(180px,1fr) minmax(280px,1.4fr);align-items:center;gap:18px;padding:14px 18px;border-bottom:1px solid var(--pw-border-subtle)}.agent-identity{display:grid;grid-template-columns:20px minmax(0,1fr);gap:10px;align-items:center}.agent-identity input{width:18px;height:18px;accent-color:var(--pw-accent)}.agent-identity strong,.agent-identity small{display:block}.agent-identity small{margin-top:3px;color:var(--pw-text-secondary);font-size:11px}.agent-controls{display:grid;grid-template-columns:minmax(150px,1fr) minmax(150px,1fr) 38px;gap:8px}.agent-controls button{justify-content:center;padding:0}.agent-empty{padding:18px;color:var(--pw-text-secondary);font-size:12px}.proxy-grid{display:grid;grid-template-columns:1fr 1fr;gap:12px;padding:16px 18px;border-bottom:1px solid var(--pw-border-subtle)}.proxy-endpoint{display:grid;grid-template-columns:auto minmax(150px,auto) minmax(180px,1fr);align-items:center;gap:10px}.proxy-endpoint input:disabled{opacity:.55}.primary-action{background:var(--pw-accent)!important;color:var(--pw-text-inverse)!important}.status-text{font-size:12px;color:var(--pw-text-secondary)}.credential-panel{border-top:1px solid var(--pw-border)}.credential-heading{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;padding:16px 18px}.credential-state{padding:3px 7px;background:var(--pw-bg-hover);border-radius:4px;font-size:11px;white-space:nowrap}.credential-grid{display:grid;grid-template-columns:150px minmax(180px,1fr) minmax(220px,1.4fr);gap:12px;padding:0 18px 16px}.credential-grid label{display:grid;gap:6px;color:var(--pw-text-secondary);font-size:11px}.credential-actions{padding-top:0}.install-guide{margin:0 18px 18px;padding:12px 14px;border:1px solid var(--pw-border-subtle);border-radius:6px;color:var(--pw-text-secondary);font-size:12px}.install-guide summary{cursor:pointer;color:var(--pw-text-primary);font-weight:600}.install-guide ol{margin:10px 0 0 20px;line-height:1.7}.break-path{overflow-wrap:anywhere}.mono{font-family:var(--pw-font-mono)}#doctorOutput{max-height:320px;margin:0 18px 18px;padding:14px;overflow:auto;color:var(--pw-code-text,#dbe8e3);background:var(--pw-code-bg);border-radius:6px;font:11px/1.5 var(--pw-font-mono);white-space:pre-wrap}.hidden{display:none}@media(max-width:760px){.setting-row,.agent-setting-row{grid-template-columns:1fr}.agent-controls{grid-template-columns:1fr}.proxy-grid,.credential-grid{grid-template-columns:1fr}.proxy-endpoint{grid-template-columns:1fr}.inline-actions{justify-content:flex-start}}
|
|
96
|
+
</style>
|
|
97
|
+
<script src="/i18n.js"></script>
|
|
98
|
+
<script src="/desktop-bridge.js"></script>
|
|
99
|
+
<script src="/settings.js"></script>
|
|
100
|
+
</body>
|
|
101
|
+
</html>
|
|
@@ -135,6 +135,8 @@ html.dark {
|
|
|
135
135
|
.pw-spin { animation: pw-spin 1s linear infinite; }
|
|
136
136
|
@keyframes pw-spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
|
|
137
137
|
</style>
|
|
138
|
+
<script src="/desktop-bootstrap.js"></script>
|
|
139
|
+
<link rel="stylesheet" href="/desktop.css">
|
|
138
140
|
</head>
|
|
139
141
|
<body class="flex h-screen overflow-hidden">
|
|
140
142
|
|
|
@@ -152,6 +154,10 @@ html.dark {
|
|
|
152
154
|
|
|
153
155
|
<!-- Navigation -->
|
|
154
156
|
<nav class="flex-1 flex flex-col gap-1 px-3 pt-4 overflow-y-auto">
|
|
157
|
+
<a href="/pages/getting-started.html" data-nav-key="getting-started" class="desktop-only-nav flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium transition-colors truncate" style="color: var(--pw-text-secondary); font-family: var(--pw-font-sans);">
|
|
158
|
+
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="shrink-0"><path d="M4.5 16.5c-1.5 1.26-2 5-2 5s3.74-.5 5-2c.71-.84.7-2.13-.09-2.91a2.18 2.18 0 0 0-2.91-.09z"/><path d="m12 15-3-3a22 22 0 0 1 2-3.95A12.87 12.87 0 0 1 22 2c0 2.72-.78 7.5-6.05 11a22.35 22.35 0 0 1-3.95 2z"/></svg>
|
|
159
|
+
<span class="truncate" data-i18n="nav.gettingStarted">开始使用</span>
|
|
160
|
+
</a>
|
|
155
161
|
|
|
156
162
|
<a href="/pages/dashboard.html" data-nav-key="dashboard" data-dom-id="nav-dashboard" class="flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium transition-colors truncate" style="color: var(--pw-text-secondary); font-family: var(--pw-font-sans);">
|
|
157
163
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="shrink-0">
|
|
@@ -207,6 +213,10 @@ html.dark {
|
|
|
207
213
|
<span class="truncate" data-zh="日志" data-en="Logs">日志</span>
|
|
208
214
|
</a>
|
|
209
215
|
|
|
216
|
+
<a href="/pages/settings.html" data-nav-key="settings" class="desktop-only-nav flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium transition-colors truncate" style="color: var(--pw-text-secondary); font-family: var(--pw-font-sans);">
|
|
217
|
+
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="shrink-0"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.7 1.7 0 0 0 .3 1.9l.1.1-2.8 2.8-.1-.1a1.7 1.7 0 0 0-1.9-.3 1.7 1.7 0 0 0-1 1.6v.2h-4V21a1.7 1.7 0 0 0-1-1.6 1.7 1.7 0 0 0-1.9.3l-.1.1L4.2 17l.1-.1a1.7 1.7 0 0 0 .3-1.9A1.7 1.7 0 0 0 3 14H2.8v-4H3a1.7 1.7 0 0 0 1.6-1 1.7 1.7 0 0 0-.3-1.9L4.2 7 7 4.2l.1.1A1.7 1.7 0 0 0 9 4.6 1.7 1.7 0 0 0 10 3V2.8h4V3a1.7 1.7 0 0 0 1 1.6 1.7 1.7 0 0 0 1.9-.3l.1-.1L19.8 7l-.1.1a1.7 1.7 0 0 0-.3 1.9A1.7 1.7 0 0 0 21 10h.2v4H21a1.7 1.7 0 0 0-1.6 1z"/></svg>
|
|
218
|
+
<span class="truncate" data-i18n="nav.settings">设置</span>
|
|
219
|
+
</a>
|
|
210
220
|
</nav>
|
|
211
221
|
|
|
212
222
|
<!-- Bottom Section -->
|
|
@@ -1243,5 +1253,7 @@ html.dark {
|
|
|
1243
1253
|
</script>
|
|
1244
1254
|
|
|
1245
1255
|
<script>lucide.createIcons();</script>
|
|
1256
|
+
<script src="/i18n.js"></script>
|
|
1257
|
+
<script src="/desktop-bridge.js"></script>
|
|
1246
1258
|
</body>
|
|
1247
1259
|
</html>
|
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 -->
|
|
@@ -442,6 +452,9 @@ html.dark {
|
|
|
442
452
|
</tbody>
|
|
443
453
|
</table>
|
|
444
454
|
</div>
|
|
455
|
+
<div id="loadMoreWrap" class="hidden px-4 py-3 text-center" style="border-top: 1px solid var(--pw-border-subtle);">
|
|
456
|
+
<button id="loadMoreBtn" class="px-3 py-1.5 rounded-md text-xs font-semibold" type="button" style="background-color: var(--pw-bg-hover); color: var(--pw-text-secondary); border: 1px solid var(--pw-border-subtle); font-family: var(--pw-font-sans);">加载更多</button>
|
|
457
|
+
</div>
|
|
445
458
|
</div>
|
|
446
459
|
|
|
447
460
|
<!-- ===== SAFE MODAL ===== -->
|
|
@@ -558,6 +571,22 @@ html.dark {
|
|
|
558
571
|
border-width: 1px;
|
|
559
572
|
border-style: solid;
|
|
560
573
|
}
|
|
574
|
+
#taskTableBody td:nth-child(2) {
|
|
575
|
+
display: -webkit-box;
|
|
576
|
+
-webkit-line-clamp: 2;
|
|
577
|
+
-webkit-box-orient: vertical;
|
|
578
|
+
overflow: hidden;
|
|
579
|
+
}
|
|
580
|
+
@media (max-width: 1100px) {
|
|
581
|
+
#tableWrapper { overflow-x: visible; padding: 10px; }
|
|
582
|
+
#tableWrapper table { min-width: 0 !important; display: block; }
|
|
583
|
+
#tableWrapper thead { display: none; }
|
|
584
|
+
#taskTableBody, #taskTableBody tr { display: block; }
|
|
585
|
+
#taskTableBody tr { margin-bottom: 10px; padding: 12px; border: 1px solid var(--pw-border-subtle); border-radius: 6px; }
|
|
586
|
+
#taskTableBody td { display: block; padding: 4px 0 !important; text-align: left !important; max-width: none !important; }
|
|
587
|
+
#taskTableBody td:nth-child(5), #taskTableBody td:nth-child(6), #taskTableBody td:nth-child(7), #taskTableBody td:nth-child(9) { display: none; }
|
|
588
|
+
#taskTableBody td:nth-child(10) > div { display: flex; justify-content: flex-start; flex-wrap: wrap; }
|
|
589
|
+
}
|
|
561
590
|
</style>
|
|
562
591
|
|
|
563
592
|
<script>
|
|
@@ -593,6 +622,8 @@ html.dark {
|
|
|
593
622
|
};
|
|
594
623
|
|
|
595
624
|
var allTasks = [];
|
|
625
|
+
var nextCursor = null;
|
|
626
|
+
var totalTasks = 0;
|
|
596
627
|
// currentFilters holds the active filter values for all dimensions.
|
|
597
628
|
// repo_path / status / acceptance_status / agent are sent to the backend.
|
|
598
629
|
// warning_type / date_from / date_to are applied client-side.
|
|
@@ -768,6 +799,7 @@ html.dark {
|
|
|
768
799
|
hide($('errorState'));
|
|
769
800
|
hide($('emptyState'));
|
|
770
801
|
hide($('tableWrapper'));
|
|
802
|
+
hide($('loadMoreWrap'));
|
|
771
803
|
$('countSummary').textContent = '--';
|
|
772
804
|
}
|
|
773
805
|
|
|
@@ -785,6 +817,7 @@ html.dark {
|
|
|
785
817
|
hide($('errorState'));
|
|
786
818
|
show($('emptyState'));
|
|
787
819
|
hide($('tableWrapper'));
|
|
820
|
+
hide($('loadMoreWrap'));
|
|
788
821
|
}
|
|
789
822
|
|
|
790
823
|
function showTable() {
|
|
@@ -868,8 +901,8 @@ html.dark {
|
|
|
868
901
|
|
|
869
902
|
// Quick action buttons
|
|
870
903
|
var quickActions =
|
|
871
|
-
'<button class="pw-quick-btn" data-safe-action="safe-result" data-task-id="' + escapeAttr(taskId) + '" title="
|
|
872
|
-
+ '<button class="pw-quick-btn" data-safe-action="safe-audit" data-task-id="' + escapeAttr(taskId) + '" title="
|
|
904
|
+
'<button class="pw-quick-btn" data-safe-action="safe-result" data-task-id="' + escapeAttr(taskId) + '" title="查看安全结果" aria-label="查看安全结果" type="button"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg></button>'
|
|
905
|
+
+ '<button class="pw-quick-btn" data-safe-action="safe-audit" data-task-id="' + escapeAttr(taskId) + '" title="查看安全审计" aria-label="查看安全审计" type="button"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg></button>'
|
|
873
906
|
+ '<button class="pw-quick-btn" data-safe-action="safe-test-summary" data-task-id="' + escapeAttr(taskId) + '" title="safe test summary" type="button"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/></svg></button>'
|
|
874
907
|
+ '<button class="pw-quick-btn" data-safe-action="safe-diff-summary" data-task-id="' + escapeAttr(taskId) + '" title="safe diff summary" type="button"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14"/><path d="M12 5l7 7-7 7"/></svg></button>'
|
|
875
908
|
+ '<button class="pw-quick-btn" data-copy-id="' + escapeAttr(taskId) + '" title="复制 task_id" type="button"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg></button>'
|
|
@@ -986,14 +1019,16 @@ html.dark {
|
|
|
986
1019
|
showTable();
|
|
987
1020
|
wireQuickActions();
|
|
988
1021
|
}
|
|
1022
|
+
var more = $('loadMoreWrap');
|
|
1023
|
+
if (more) nextCursor ? show(more) : hide(more);
|
|
989
1024
|
|
|
990
1025
|
// Count summary
|
|
991
1026
|
var hasFilters = currentFilters.repo_path || currentFilters.status || currentFilters.acceptance_status ||
|
|
992
1027
|
currentFilters.agent || currentFilters.warning_type || currentFilters.date_from || currentFilters.date_to;
|
|
993
1028
|
if (hasFilters) {
|
|
994
|
-
$('countSummary').textContent = '显示 ' + filtered.length + ' / ' +
|
|
1029
|
+
$('countSummary').textContent = '显示 ' + filtered.length + ' / ' + totalTasks + ' 条';
|
|
995
1030
|
} else {
|
|
996
|
-
$('countSummary').textContent = '
|
|
1031
|
+
$('countSummary').textContent = '已加载 ' + filtered.length + ' / ' + totalTasks + ' 条';
|
|
997
1032
|
}
|
|
998
1033
|
}
|
|
999
1034
|
|
|
@@ -1031,6 +1066,10 @@ html.dark {
|
|
|
1031
1066
|
if (currentFilters.agent) {
|
|
1032
1067
|
params.push('agent=' + encodeURIComponent(currentFilters.agent));
|
|
1033
1068
|
}
|
|
1069
|
+
if (currentFilters.warning_type) params.push('warning_type=' + encodeURIComponent(currentFilters.warning_type));
|
|
1070
|
+
if (currentFilters.date_from) params.push('date_from=' + encodeURIComponent(currentFilters.date_from));
|
|
1071
|
+
if (currentFilters.date_to) params.push('date_to=' + encodeURIComponent(currentFilters.date_to));
|
|
1072
|
+
params.push('limit=50');
|
|
1034
1073
|
return params.length ? ('?' + params.join('&')) : '';
|
|
1035
1074
|
}
|
|
1036
1075
|
|
|
@@ -1084,10 +1123,11 @@ html.dark {
|
|
|
1084
1123
|
}
|
|
1085
1124
|
}
|
|
1086
1125
|
|
|
1087
|
-
function fetchTasks() {
|
|
1088
|
-
showLoading();
|
|
1126
|
+
function fetchTasks(cursor, append) {
|
|
1127
|
+
if (!append) showLoading();
|
|
1089
1128
|
setRefreshing(true);
|
|
1090
|
-
var
|
|
1129
|
+
var query = buildFilterQueryString();
|
|
1130
|
+
var url = API_URL + query + (query ? '&' : '?') + (cursor ? 'cursor=' + encodeURIComponent(cursor) : '');
|
|
1091
1131
|
fetch(url, {
|
|
1092
1132
|
method: 'GET',
|
|
1093
1133
|
headers: { 'Accept': 'application/json' },
|
|
@@ -1102,7 +1142,10 @@ html.dark {
|
|
|
1102
1142
|
return res.json();
|
|
1103
1143
|
})
|
|
1104
1144
|
.then(function (data) {
|
|
1105
|
-
|
|
1145
|
+
var page = (data && Array.isArray(data.tasks)) ? data.tasks : [];
|
|
1146
|
+
allTasks = append ? allTasks.concat(page) : page;
|
|
1147
|
+
nextCursor = data && (data.nextCursor || data.next_cursor) ? (data.nextCursor || data.next_cursor) : null;
|
|
1148
|
+
totalTasks = data && typeof data.total === 'number' ? data.total : allTasks.length;
|
|
1106
1149
|
renderWatcher(data && data.watcher);
|
|
1107
1150
|
renderTasks();
|
|
1108
1151
|
updateFilterStatusText();
|
|
@@ -1179,6 +1222,7 @@ html.dark {
|
|
|
1179
1222
|
});
|
|
1180
1223
|
|
|
1181
1224
|
$('refreshBtn').addEventListener('click', fetchTasks);
|
|
1225
|
+
$('loadMoreBtn').addEventListener('click', function () { if (nextCursor) fetchTasks(nextCursor, true); });
|
|
1182
1226
|
|
|
1183
1227
|
var retryBtn = $('retryBtn');
|
|
1184
1228
|
if (retryBtn) {
|
|
@@ -1235,5 +1279,7 @@ html.dark {
|
|
|
1235
1279
|
</script>
|
|
1236
1280
|
|
|
1237
1281
|
<script>lucide.createIcons();</script>
|
|
1282
|
+
<script src="/i18n.js"></script>
|
|
1283
|
+
<script src="/desktop-bridge.js"></script>
|
|
1238
1284
|
</body>
|
|
1239
1285
|
</html>
|