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
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { setTimeout as sleep } from "node:timers/promises";
|
|
2
|
-
import { getConfig } from "
|
|
3
|
-
import { createWorktree } from "
|
|
4
|
-
import { guardWorkspacePath } from "
|
|
5
|
-
import { createDirectSession } from "
|
|
2
|
+
import { getConfig } from "../../config.js";
|
|
3
|
+
import { createWorktree } from "../../goal/worktreeManager.js";
|
|
4
|
+
import { guardWorkspacePath } from "../../security/pathGuard.js";
|
|
5
|
+
import { createDirectSession } from "../direct/createDirectSession.js";
|
|
6
6
|
import { createTask } from "./createTask.js";
|
|
7
|
-
import { recommendAgentForTask } from "
|
|
8
|
-
import { runDirectVerificationBundle } from "
|
|
7
|
+
import { recommendAgentForTask } from "../workspace/recommendAgentForTask.js";
|
|
8
|
+
import { runDirectVerificationBundle } from "../direct/runDirectVerificationBundle.js";
|
|
9
9
|
import { waitForTask } from "./waitForTask.js";
|
|
10
|
-
import { safeAudit, safeAuditDirectSession, safeFinalizeDirectSession, safeResult, safeTestSummary } from "
|
|
10
|
+
import { safeAudit, safeAuditDirectSession, safeFinalizeDirectSession, safeResult, safeTestSummary } from "../diagnostics/safeViews.js";
|
|
11
|
+
import { isTerminalTaskStatus } from "./taskStates.js";
|
|
11
12
|
import { createLineageId, writeTaskLineage, } from "./taskLineage.js";
|
|
12
13
|
const DEFAULT_DEPS = {
|
|
13
14
|
createTask,
|
|
@@ -26,15 +27,6 @@ const DEFAULT_DEPS = {
|
|
|
26
27
|
now: () => new Date(),
|
|
27
28
|
sleep,
|
|
28
29
|
};
|
|
29
|
-
const TERMINAL_STATUSES = new Set([
|
|
30
|
-
"done",
|
|
31
|
-
"done_by_agent",
|
|
32
|
-
"failed",
|
|
33
|
-
"failed_verification",
|
|
34
|
-
"failed_scope_violation",
|
|
35
|
-
"failed_policy_violation",
|
|
36
|
-
"canceled",
|
|
37
|
-
]);
|
|
38
30
|
export async function runTaskLoop(input) {
|
|
39
31
|
return runTaskLoopWithDeps(input, DEFAULT_DEPS);
|
|
40
32
|
}
|
|
@@ -130,17 +122,17 @@ export async function runTaskLoopWithDeps(input, deps) {
|
|
|
130
122
|
timeout_seconds: normalized.task_timeout_seconds,
|
|
131
123
|
execution_mode: "assess_only",
|
|
132
124
|
};
|
|
133
|
-
const assessment = await deps.createTask(assessmentInput);
|
|
125
|
+
const assessment = asRecord(await deps.createTask(assessmentInput));
|
|
134
126
|
if (assessment.decision === "blocked") {
|
|
135
|
-
return finalize("blocked", "high_risk_blocked", "Risk assessment blocked task execution.", assessment.reason_codes
|
|
127
|
+
return finalize("blocked", "high_risk_blocked", "Risk assessment blocked task execution.", asArray(assessment.reason_codes).map(String).join(", "));
|
|
136
128
|
}
|
|
137
129
|
if (assessment.decision === "needs_confirm") {
|
|
138
130
|
return finalize("blocked", "user_confirmation_required", "Ask the user to confirm the assessment before executing the loop.");
|
|
139
131
|
}
|
|
140
|
-
const created = await deps.createTask({
|
|
132
|
+
const created = asRecord(await deps.createTask({
|
|
141
133
|
execution_mode: "execute",
|
|
142
134
|
assessment_id: String(assessment.assessment_id || ""),
|
|
143
|
-
});
|
|
135
|
+
}));
|
|
144
136
|
const taskId = String(created.task_id || "");
|
|
145
137
|
if (!taskId) {
|
|
146
138
|
return finalize("failed", "policy_blocked", "create_task returned no task_id.", "create_task returned no task_id");
|
|
@@ -153,9 +145,9 @@ export async function runTaskLoopWithDeps(input, deps) {
|
|
|
153
145
|
if (wait.stop_reason) {
|
|
154
146
|
return finalize("blocked", wait.stop_reason, wait.next_action, wait.error);
|
|
155
147
|
}
|
|
156
|
-
const result = deps.safeResult(taskId, { max_items: 8 });
|
|
157
|
-
const tests = deps.safeTestSummary(taskId);
|
|
158
|
-
const audit = deps.safeAudit(taskId, { max_items: 8 });
|
|
148
|
+
const result = asRecord(deps.safeResult(taskId, { max_items: 8 }));
|
|
149
|
+
const tests = asRecord(deps.safeTestSummary(taskId));
|
|
150
|
+
const audit = asRecord(deps.safeAudit(taskId, { max_items: 8 }));
|
|
159
151
|
const round = buildRound(iteration, taskId, role, result, tests, audit);
|
|
160
152
|
lineage.rounds.push(round);
|
|
161
153
|
lineage.updated_at = deps.now().toISOString();
|
|
@@ -186,7 +178,7 @@ async function waitUntilTerminal(taskId, timeoutSeconds, deps) {
|
|
|
186
178
|
const deadline = Date.now() + timeoutSeconds * 1000;
|
|
187
179
|
while (Date.now() < deadline) {
|
|
188
180
|
const waited = await deps.waitForTask(taskId, 30);
|
|
189
|
-
if (waited.terminal ||
|
|
181
|
+
if (waited.terminal || isTerminalTaskStatus(String(waited.status))) {
|
|
190
182
|
return { next_action: waited.next_action || "safe_audit" };
|
|
191
183
|
}
|
|
192
184
|
if (waited.next_tool_call?.name === "health_check" || waited.continuation_required === false) {
|
|
@@ -204,20 +196,32 @@ async function waitUntilTerminal(taskId, timeoutSeconds, deps) {
|
|
|
204
196
|
error: `Task loop timed out waiting for ${taskId}.`,
|
|
205
197
|
};
|
|
206
198
|
}
|
|
207
|
-
function buildRound(iteration, taskId, role,
|
|
208
|
-
const
|
|
209
|
-
const
|
|
199
|
+
function buildRound(iteration, taskId, role, resultValue, testsValue, auditValue) {
|
|
200
|
+
const result = asRecord(resultValue);
|
|
201
|
+
const tests = asRecord(testsValue);
|
|
202
|
+
const audit = asRecord(auditValue);
|
|
203
|
+
const resultVerification = asRecord(result.verification);
|
|
204
|
+
const auditAcceptance = asRecord(audit.acceptance);
|
|
205
|
+
const failChecks = asArray(audit.fail_checks).map((entry) => {
|
|
206
|
+
const check = asRecord(entry);
|
|
207
|
+
return String(check.name || entry);
|
|
208
|
+
});
|
|
209
|
+
const warnChecks = asArray(audit.warn_checks).map((entry) => {
|
|
210
|
+
const check = asRecord(entry);
|
|
211
|
+
return String(check.name || entry);
|
|
212
|
+
});
|
|
213
|
+
const recommendedActions = asArray(audit.recommended_next_actions);
|
|
210
214
|
return {
|
|
211
215
|
iteration,
|
|
212
216
|
task_id: taskId,
|
|
213
217
|
role,
|
|
214
218
|
status: String(result.status || "unknown"),
|
|
215
219
|
terminal: Boolean(result.terminal),
|
|
216
|
-
verification_status: String(tests.status ||
|
|
217
|
-
audit_verdict: String(audit.verdict ||
|
|
220
|
+
verification_status: String(tests.status || resultVerification.status || "not_available"),
|
|
221
|
+
audit_verdict: String(audit.verdict || auditAcceptance.verdict || "unknown"),
|
|
218
222
|
fail_checks: failChecks,
|
|
219
223
|
warn_checks: warnChecks,
|
|
220
|
-
next_action: String(result.next_action ||
|
|
224
|
+
next_action: String(result.next_action || recommendedActions[0] || "review_task"),
|
|
221
225
|
};
|
|
222
226
|
}
|
|
223
227
|
function isSuccessfulRound(round) {
|
|
@@ -228,23 +232,29 @@ function isSuccessfulRound(round) {
|
|
|
228
232
|
round.warn_checks.length === 0 &&
|
|
229
233
|
round.audit_verdict === "pass");
|
|
230
234
|
}
|
|
231
|
-
function isHardStop(round,
|
|
232
|
-
if (["failed_scope_violation", "failed_policy_violation", "canceled"].includes(round.status))
|
|
235
|
+
function isHardStop(round, resultValue, auditValue, stopOnHighRisk) {
|
|
236
|
+
if (["failed_scope_violation", "failed_policy_violation", "canceled", "timeout"].includes(round.status))
|
|
233
237
|
return true;
|
|
234
238
|
if (!stopOnHighRisk)
|
|
235
239
|
return false;
|
|
236
240
|
const checkNames = [...round.fail_checks, ...round.warn_checks].join(" ").toLowerCase();
|
|
237
|
-
const
|
|
241
|
+
const result = asRecord(resultValue);
|
|
242
|
+
const audit = asRecord(auditValue);
|
|
243
|
+
const reason = String(result.failure_reason || asRecord(audit.acceptance).reason || "").toLowerCase();
|
|
238
244
|
return /scope|secret|sensitive|publish|release|policy|push/.test(`${checkNames} ${reason}`);
|
|
239
245
|
}
|
|
240
|
-
function hardStopReason(round,
|
|
246
|
+
function hardStopReason(round, resultValue) {
|
|
247
|
+
const result = asRecord(resultValue);
|
|
241
248
|
if (round.status === "failed_scope_violation" || round.status === "failed_policy_violation")
|
|
242
249
|
return "policy_blocked";
|
|
250
|
+
if (round.status === "timeout")
|
|
251
|
+
return "agent_timeout";
|
|
243
252
|
if (String(result.failure_reason || "").toLowerCase().includes("timeout"))
|
|
244
253
|
return "agent_timeout";
|
|
245
254
|
return "high_risk_blocked";
|
|
246
255
|
}
|
|
247
|
-
function buildFixGoal(originalGoal,
|
|
256
|
+
function buildFixGoal(originalGoal, resultValue, round) {
|
|
257
|
+
const result = asRecord(resultValue);
|
|
248
258
|
const failedCommand = result.failed_command ? ` Failed command: ${result.failed_command}.` : "";
|
|
249
259
|
return [
|
|
250
260
|
`Fix the failing verification for this PatchWarden loop without changing unrelated behavior.`,
|
|
@@ -303,8 +313,12 @@ async function runDirectVerification(lineageId, normalized, repoPath, deps) {
|
|
|
303
313
|
commands: normalized.direct_verify_commands,
|
|
304
314
|
timeout_seconds: normalized.direct_verify_timeout_seconds,
|
|
305
315
|
});
|
|
306
|
-
const finalized = await deps.safeFinalizeDirectSession(sessionId, { max_items: 8 });
|
|
307
|
-
const audit = deps.safeAuditDirectSession(sessionId, { max_items: 8 });
|
|
316
|
+
const finalized = asRecord(await deps.safeFinalizeDirectSession(sessionId, { max_items: 8 }));
|
|
317
|
+
const audit = asRecord(deps.safeAuditDirectSession(sessionId, { max_items: 8 }));
|
|
318
|
+
const auditEvidence = asRecord(audit.evidence);
|
|
319
|
+
const auditDecision = audit.decision === "pass" || audit.decision === "warn" || audit.decision === "fail"
|
|
320
|
+
? audit.decision
|
|
321
|
+
: "not_run";
|
|
308
322
|
const evidence = {
|
|
309
323
|
session_id: sessionId,
|
|
310
324
|
status: bundle.status,
|
|
@@ -312,8 +326,8 @@ async function runDirectVerification(lineageId, normalized, repoPath, deps) {
|
|
|
312
326
|
passed_commands: bundle.passed_commands,
|
|
313
327
|
failed_commands: bundle.failed_commands,
|
|
314
328
|
timed_out_commands: bundle.timed_out_commands,
|
|
315
|
-
audit_decision:
|
|
316
|
-
changed_files_total: Number(finalized.changed_files_total ||
|
|
329
|
+
audit_decision: auditDecision,
|
|
330
|
+
changed_files_total: Number(finalized.changed_files_total || auditEvidence.changed_files_total || 0),
|
|
317
331
|
next_action: String(audit.next_action || bundle.next_action || "review_direct_session"),
|
|
318
332
|
};
|
|
319
333
|
if (bundle.status !== "passed") {
|
|
@@ -325,7 +339,7 @@ async function runDirectVerification(lineageId, normalized, repoPath, deps) {
|
|
|
325
339
|
error: "Direct verification failed.",
|
|
326
340
|
};
|
|
327
341
|
}
|
|
328
|
-
if (
|
|
342
|
+
if (auditDecision === "fail") {
|
|
329
343
|
return {
|
|
330
344
|
evidence,
|
|
331
345
|
stop_reason: "direct_audit_failed",
|
|
@@ -338,7 +352,7 @@ async function runDirectVerification(lineageId, normalized, repoPath, deps) {
|
|
|
338
352
|
evidence,
|
|
339
353
|
final_status: "accepted",
|
|
340
354
|
next_action: "accept",
|
|
341
|
-
warning:
|
|
355
|
+
warning: auditDecision === "warn" ? "Direct audit completed with warnings." : undefined,
|
|
342
356
|
};
|
|
343
357
|
}
|
|
344
358
|
catch (err) {
|
|
@@ -357,6 +371,14 @@ async function runDirectVerification(lineageId, normalized, repoPath, deps) {
|
|
|
357
371
|
};
|
|
358
372
|
}
|
|
359
373
|
}
|
|
374
|
+
function asRecord(value) {
|
|
375
|
+
return value && typeof value === "object" && !Array.isArray(value)
|
|
376
|
+
? value
|
|
377
|
+
: {};
|
|
378
|
+
}
|
|
379
|
+
function asArray(value) {
|
|
380
|
+
return Array.isArray(value) ? value : [];
|
|
381
|
+
}
|
|
360
382
|
function normalizeInput(input) {
|
|
361
383
|
const config = getConfig();
|
|
362
384
|
const repoPath = String(input.repo_path || "").trim();
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { readDirectSession, appendDirectSessionVerificationRun, withDirectSessionMutationLockAsync, } from "../../direct/directSessionStore.js";
|
|
2
|
+
import { guardDirectSessionActive } from "../../direct/directGuards.js";
|
|
3
|
+
import { runDirectVerification } from "../../direct/directVerification.js";
|
|
4
|
+
export async function runVerification(input) {
|
|
5
|
+
return withDirectSessionMutationLockAsync(input.session_id, async () => {
|
|
6
|
+
// 1. Read session and guard active
|
|
7
|
+
const session = readDirectSession(input.session_id);
|
|
8
|
+
guardDirectSessionActive(session);
|
|
9
|
+
// 2. Call runDirectVerification with command, resolvedRepoPath,
|
|
10
|
+
// sessionId, and timeoutSeconds
|
|
11
|
+
const timeoutSeconds = input.timeout_seconds ?? 120;
|
|
12
|
+
const result = await runDirectVerification({
|
|
13
|
+
command: input.command,
|
|
14
|
+
resolvedRepoPath: session.resolved_repo_path,
|
|
15
|
+
sessionId: input.session_id,
|
|
16
|
+
timeoutSeconds,
|
|
17
|
+
});
|
|
18
|
+
// 3. Append verification run to session
|
|
19
|
+
appendDirectSessionVerificationRun(input.session_id, result.run);
|
|
20
|
+
// 4. Return result
|
|
21
|
+
return {
|
|
22
|
+
command: result.run.command,
|
|
23
|
+
exit_code: result.run.exit_code,
|
|
24
|
+
passed: result.run.passed,
|
|
25
|
+
timed_out: result.run.timed_out,
|
|
26
|
+
redacted: Boolean(result.run.redacted),
|
|
27
|
+
redaction_categories: result.run.redaction_categories || [],
|
|
28
|
+
started_at: result.run.started_at,
|
|
29
|
+
finished_at: result.run.finished_at,
|
|
30
|
+
stdout_tail: result.run.stdout_tail,
|
|
31
|
+
stderr_tail: result.run.stderr_tail,
|
|
32
|
+
log_path: result.run.log_path,
|
|
33
|
+
next_action: result.run.passed
|
|
34
|
+
? "Call finalize_direct_session to complete the session."
|
|
35
|
+
: "Review the verification output and apply_patch to fix issues.",
|
|
36
|
+
};
|
|
37
|
+
});
|
|
38
|
+
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { randomBytes } from "node:crypto";
|
|
2
|
-
import { existsSync, mkdirSync, readFileSync
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync } from "node:fs";
|
|
3
3
|
import { join, resolve } from "node:path";
|
|
4
|
-
import { getConfig } from "
|
|
5
|
-
import { guardReadPath } from "
|
|
6
|
-
import { redactSensitiveValue } from "
|
|
7
|
-
import { PatchWardenError } from "
|
|
4
|
+
import { getConfig } from "../../config.js";
|
|
5
|
+
import { guardReadPath } from "../../security/pathGuard.js";
|
|
6
|
+
import { redactSensitiveValue } from "../../security/contentRedaction.js";
|
|
7
|
+
import { PatchWardenError } from "../../errors.js";
|
|
8
|
+
import { atomicWriteFileSync, atomicWriteJsonFileSync } from "../../utils/atomicFile.js";
|
|
8
9
|
export function createLineageId(now = new Date()) {
|
|
9
10
|
const stamp = now.toISOString().replace(/[-:.TZ]/g, "").slice(0, 14);
|
|
10
11
|
return `lineage_${stamp}_${randomBytes(4).toString("hex")}`;
|
|
@@ -14,8 +15,8 @@ export function writeTaskLineage(record) {
|
|
|
14
15
|
const lineageDir = resolve(config.workspaceRoot, ".patchwarden", "lineages", record.lineage_id);
|
|
15
16
|
mkdirSync(lineageDir, { recursive: true });
|
|
16
17
|
const safeRecord = redactSensitiveValue(record).value;
|
|
17
|
-
|
|
18
|
-
|
|
18
|
+
atomicWriteJsonFileSync(join(lineageDir, "lineage.json"), safeRecord);
|
|
19
|
+
atomicWriteFileSync(join(lineageDir, "SUMMARY.md"), buildSummaryMarkdown(safeRecord));
|
|
19
20
|
return toSafeTaskLineage(safeRecord);
|
|
20
21
|
}
|
|
21
22
|
export function getTaskLineage(lineageId, options = {}) {
|
|
@@ -14,7 +14,7 @@ export declare function getTaskLogTail(taskId: string, file: "stdout" | "stderr"
|
|
|
14
14
|
lines?: number;
|
|
15
15
|
redact?: boolean;
|
|
16
16
|
}): {
|
|
17
|
-
file: "
|
|
17
|
+
file: "stdout" | "stderr" | "test" | "verify";
|
|
18
18
|
lines: number;
|
|
19
19
|
total_bytes: number;
|
|
20
20
|
task_id: string;
|
|
@@ -37,7 +37,7 @@ export declare function getTaskLogTail(taskId: string, file: "stdout" | "stderr"
|
|
|
37
37
|
truncated?: undefined;
|
|
38
38
|
} | {
|
|
39
39
|
task_id: string;
|
|
40
|
-
file: "
|
|
40
|
+
file: "stdout" | "stderr" | "test" | "verify";
|
|
41
41
|
filename: string;
|
|
42
42
|
content: string;
|
|
43
43
|
available: boolean;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { getTaskFile } from "./getTaskFile.js";
|
|
2
|
-
import { existsSync,
|
|
2
|
+
import { existsSync, statSync } from "node:fs";
|
|
3
3
|
import { join, resolve } from "node:path";
|
|
4
|
-
import { getConfig, getTasksDir } from "
|
|
5
|
-
import { guardPath } from "
|
|
6
|
-
import { redactSensitiveContent } from "
|
|
4
|
+
import { getConfig, getTasksDir } from "../../config.js";
|
|
5
|
+
import { guardPath } from "../../security/pathGuard.js";
|
|
6
|
+
import { redactSensitiveContent } from "../../security/contentRedaction.js";
|
|
7
|
+
import { readTextFilePrefixSync, readTextFileTailLinesSync, } from "../../utils/boundedFile.js";
|
|
7
8
|
export function getResult(taskId) {
|
|
8
9
|
return getTaskFile(taskId, "result.md");
|
|
9
10
|
}
|
|
@@ -20,10 +21,9 @@ export function getDiff(taskId) {
|
|
|
20
21
|
}
|
|
21
22
|
const filePath = existsSync(preferred) ? preferred : fallback;
|
|
22
23
|
guardPath(filePath, config.workspaceRoot, config.tasksDir);
|
|
23
|
-
const
|
|
24
|
-
const
|
|
25
|
-
const patchHead =
|
|
26
|
-
const rawReturnedBytes = Buffer.byteLength(patchHead, "utf-8");
|
|
24
|
+
const bounded = readTextFilePrefixSync(filePath, config.maxReadFileBytes);
|
|
25
|
+
const size = bounded.totalBytes;
|
|
26
|
+
const patchHead = bounded.content;
|
|
27
27
|
const redaction = redactSensitiveContent(patchHead);
|
|
28
28
|
const content = redaction.content;
|
|
29
29
|
const diff = {
|
|
@@ -32,7 +32,7 @@ export function getDiff(taskId) {
|
|
|
32
32
|
content,
|
|
33
33
|
path: filePath,
|
|
34
34
|
available: true,
|
|
35
|
-
truncated:
|
|
35
|
+
truncated: bounded.truncated,
|
|
36
36
|
total_bytes: size,
|
|
37
37
|
returned_bytes: Buffer.byteLength(content, "utf-8"),
|
|
38
38
|
patch_head: content,
|
|
@@ -90,8 +90,7 @@ export function getTaskLogTail(taskId, file, options) {
|
|
|
90
90
|
}
|
|
91
91
|
const stat = statSync(filePath);
|
|
92
92
|
const totalBytes = stat.size;
|
|
93
|
-
const
|
|
94
|
-
const tail = raw.split("\n").slice(-maxLines).join("\n");
|
|
93
|
+
const tail = readTextFileTailLinesSync(filePath, maxLines);
|
|
95
94
|
const content = applyRedact ? redactSensitiveContent(tail) : { content: tail, redacted: false, redaction_categories: [] };
|
|
96
95
|
return {
|
|
97
96
|
task_id: taskId,
|
|
@@ -115,13 +114,15 @@ function getTaskFileTail(taskId, filename, options) {
|
|
|
115
114
|
return getTaskFile(taskId, filename);
|
|
116
115
|
}
|
|
117
116
|
const stat = statSync(filePath);
|
|
118
|
-
const
|
|
119
|
-
|
|
117
|
+
const maxBytes = options.maxBytes > 0
|
|
118
|
+
? Math.min(options.maxBytes, config.maxReadFileBytes)
|
|
119
|
+
: config.maxReadFileBytes;
|
|
120
|
+
let content;
|
|
120
121
|
if (options.tailLines > 0) {
|
|
121
|
-
content =
|
|
122
|
+
content = readTextFileTailLinesSync(filePath, Math.min(Math.max(1, options.tailLines), 1000), maxBytes);
|
|
122
123
|
}
|
|
123
|
-
|
|
124
|
-
content =
|
|
124
|
+
else {
|
|
125
|
+
content = readTextFilePrefixSync(filePath, maxBytes).content;
|
|
125
126
|
}
|
|
126
127
|
const redaction = redactSensitiveContent(content);
|
|
127
128
|
return {
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare const ACTIVE_TASK_STATUSES: Set<string>;
|
|
2
|
+
export declare const TERMINAL_TASK_STATUSES: Set<string>;
|
|
3
|
+
export declare function isTerminalTaskStatus(status: string): boolean;
|
|
4
|
+
export declare function isActiveTaskStatus(status: string): boolean;
|
|
5
|
+
/** Terminal states are immutable; active states may only advance or terminate. */
|
|
6
|
+
export declare function isAllowedTaskStatusTransition(from: string, to: string): boolean;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export const ACTIVE_TASK_STATUSES = new Set([
|
|
2
|
+
"pending",
|
|
3
|
+
"running",
|
|
4
|
+
"executing_agent",
|
|
5
|
+
"verifying",
|
|
6
|
+
"collecting_artifacts",
|
|
7
|
+
"cancel_requested",
|
|
8
|
+
]);
|
|
9
|
+
export const TERMINAL_TASK_STATUSES = new Set([
|
|
10
|
+
"done",
|
|
11
|
+
"done_by_agent",
|
|
12
|
+
"accepted",
|
|
13
|
+
"rejected",
|
|
14
|
+
"needs_fix",
|
|
15
|
+
"blocked",
|
|
16
|
+
"failed",
|
|
17
|
+
"failed_verification",
|
|
18
|
+
"failed_scope_violation",
|
|
19
|
+
"failed_policy_violation",
|
|
20
|
+
"failed_stale",
|
|
21
|
+
"orphaned",
|
|
22
|
+
"timeout",
|
|
23
|
+
"canceled",
|
|
24
|
+
]);
|
|
25
|
+
export function isTerminalTaskStatus(status) {
|
|
26
|
+
return TERMINAL_TASK_STATUSES.has(status);
|
|
27
|
+
}
|
|
28
|
+
export function isActiveTaskStatus(status) {
|
|
29
|
+
return ACTIVE_TASK_STATUSES.has(status);
|
|
30
|
+
}
|
|
31
|
+
/** Terminal states are immutable; active states may only advance or terminate. */
|
|
32
|
+
export function isAllowedTaskStatusTransition(from, to) {
|
|
33
|
+
if (from === to)
|
|
34
|
+
return true;
|
|
35
|
+
if (isTerminalTaskStatus(from))
|
|
36
|
+
return false;
|
|
37
|
+
if (!isActiveTaskStatus(from) || !isActiveTaskStatus(to) && !isTerminalTaskStatus(to))
|
|
38
|
+
return false;
|
|
39
|
+
if (from === "pending") {
|
|
40
|
+
return to === "running" || isTerminalTaskStatus(to);
|
|
41
|
+
}
|
|
42
|
+
if (to === "pending")
|
|
43
|
+
return false;
|
|
44
|
+
const forwardActive = {
|
|
45
|
+
running: new Set(["executing_agent", "verifying", "collecting_artifacts", "cancel_requested"]),
|
|
46
|
+
executing_agent: new Set(["verifying", "collecting_artifacts", "cancel_requested"]),
|
|
47
|
+
verifying: new Set(["collecting_artifacts", "cancel_requested"]),
|
|
48
|
+
collecting_artifacts: new Set(["cancel_requested"]),
|
|
49
|
+
cancel_requested: new Set(),
|
|
50
|
+
};
|
|
51
|
+
return isTerminalTaskStatus(to) || Boolean(forwardActive[from]?.has(to));
|
|
52
|
+
}
|
|
@@ -1,15 +1,7 @@
|
|
|
1
1
|
import { setTimeout as sleep } from "node:timers/promises";
|
|
2
2
|
import { getTaskStatus } from "./getTaskStatus.js";
|
|
3
3
|
import { getTaskSummary } from "./getTaskSummary.js";
|
|
4
|
-
|
|
5
|
-
"done",
|
|
6
|
-
"done_by_agent",
|
|
7
|
-
"failed",
|
|
8
|
-
"failed_verification",
|
|
9
|
-
"failed_scope_violation",
|
|
10
|
-
"failed_policy_violation",
|
|
11
|
-
"canceled",
|
|
12
|
-
]);
|
|
4
|
+
import { isTerminalTaskStatus } from "./taskStates.js";
|
|
13
5
|
export async function waitForTask(taskId, waitSeconds = 25) {
|
|
14
6
|
if (!Number.isInteger(waitSeconds) || waitSeconds < 1 || waitSeconds > 30) {
|
|
15
7
|
throw new Error("wait_seconds must be an integer from 1 to 30.");
|
|
@@ -17,11 +9,11 @@ export async function waitForTask(taskId, waitSeconds = 25) {
|
|
|
17
9
|
const started = Date.now();
|
|
18
10
|
const deadline = started + waitSeconds * 1000;
|
|
19
11
|
let status = getTaskStatus(taskId);
|
|
20
|
-
while (!
|
|
12
|
+
while (!isTerminalTaskStatus(status.status) && Date.now() < deadline) {
|
|
21
13
|
await sleep(Math.min(500, Math.max(1, deadline - Date.now())));
|
|
22
14
|
status = getTaskStatus(taskId);
|
|
23
15
|
}
|
|
24
|
-
const terminal =
|
|
16
|
+
const terminal = isTerminalTaskStatus(status.status);
|
|
25
17
|
const executionBlocked = !terminal && status.execution_blocked;
|
|
26
18
|
const elapsed = Math.round((Date.now() - started) / 1000);
|
|
27
19
|
const progressSummary = {
|
|
@@ -7,9 +7,9 @@
|
|
|
7
7
|
* and never installs global dependencies. It only runs `java -version` (read-only)
|
|
8
8
|
* and inspects files/directories/env vars that already exist.
|
|
9
9
|
*/
|
|
10
|
-
import { execSync } from "node:child_process";
|
|
11
10
|
import { existsSync, readFileSync, statSync } from "node:fs";
|
|
12
11
|
import { join } from "node:path";
|
|
12
|
+
import { runSimpleProcessSync } from "../../runner/simpleProcess.js";
|
|
13
13
|
// ── Constants ──────────────────────────────────────────────────────
|
|
14
14
|
/**
|
|
15
15
|
* Required explanatory sentence emitted whenever the Android SDK is missing.
|
|
@@ -18,17 +18,23 @@ import { join } from "node:path";
|
|
|
18
18
|
const SDK_MISSING_REASON = "Android project exists, APK not built because Android SDK is missing.";
|
|
19
19
|
// ── Helpers ────────────────────────────────────────────────────────
|
|
20
20
|
/**
|
|
21
|
-
* Run a shell command and return its trimmed combined stdout/stderr output.
|
|
21
|
+
* Run a shell-free command and return its trimmed combined stdout/stderr output.
|
|
22
22
|
* Returns an empty string when the command is missing or fails so callers can
|
|
23
23
|
* treat absence gracefully. A timeout guards against hanging processes.
|
|
24
24
|
*/
|
|
25
|
-
function runCmd(
|
|
25
|
+
function runCmd(command, args, cwd = process.cwd()) {
|
|
26
26
|
try {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
const result = runSimpleProcessSync({
|
|
28
|
+
command,
|
|
29
|
+
args: [...args],
|
|
30
|
+
cwd,
|
|
31
|
+
timeoutMs: 8000,
|
|
32
|
+
maxStdoutBytes: 64 * 1024,
|
|
33
|
+
maxStderrBytes: 64 * 1024,
|
|
34
|
+
});
|
|
35
|
+
if (result.exitCode !== 0)
|
|
36
|
+
return "";
|
|
37
|
+
return `${result.stdout}\n${result.stderr}`.trim();
|
|
32
38
|
}
|
|
33
39
|
catch {
|
|
34
40
|
return "";
|
|
@@ -95,8 +101,8 @@ export function diagnoseAndroidBuild(repoPath) {
|
|
|
95
101
|
const sdkRoot = androidHomeEnv || androidSdkRootEnv;
|
|
96
102
|
const sdkExists = sdkRoot !== "" && isDirectory(sdkRoot);
|
|
97
103
|
// 1. java -version ------------------------------------------------------
|
|
98
|
-
// `java -version` writes to stderr;
|
|
99
|
-
const javaOutput = runCmd("java -version
|
|
104
|
+
// `java -version` normally writes to stderr; runSimpleProcessSync captures both.
|
|
105
|
+
const javaOutput = runCmd("java", ["-version"], repoPath);
|
|
100
106
|
const javaVersion = parseJavaVersion(javaOutput);
|
|
101
107
|
if (javaVersion) {
|
|
102
108
|
const major = parseJavaMajor(javaVersion);
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { getConfig } from "../../config.js";
|
|
2
|
+
import { PatchWardenError } from "../../errors.js";
|
|
3
|
+
import { readDirectSession, appendDirectSessionOperation, withDirectSessionMutationLock, } from "../../direct/directSessionStore.js";
|
|
4
|
+
import { guardDirectSessionActive, guardDirectWritePath, guardDirectPatchSize, } from "../../direct/directGuards.js";
|
|
5
|
+
import { applyPatchOperations, computeFileSha256, } from "../../direct/directPatch.js";
|
|
6
|
+
export function applyPatch(input) {
|
|
7
|
+
const config = getConfig();
|
|
8
|
+
return withDirectSessionMutationLock(input.session_id, () => {
|
|
9
|
+
// 1. Read session and guard active (not expired, not finalized)
|
|
10
|
+
const session = readDirectSession(input.session_id);
|
|
11
|
+
guardDirectSessionActive(session);
|
|
12
|
+
// 2. Guard write path (inside repo, not sensitive, not binary,
|
|
13
|
+
// not node_modules/release/dist)
|
|
14
|
+
const resolvedPath = guardDirectWritePath(input.path, session.resolved_repo_path, config.workspaceRoot);
|
|
15
|
+
// 3. Calculate patch size and guard against directMaxPatchBytes
|
|
16
|
+
const patchBytes = Buffer.byteLength(JSON.stringify(input.operations), "utf-8");
|
|
17
|
+
guardDirectPatchSize(patchBytes);
|
|
18
|
+
// 4. Apply against the same bytes whose hash is validated. Re-resolve the
|
|
19
|
+
// target immediately before replacement to detect link/reparse-point swaps.
|
|
20
|
+
const patchResult = applyPatchOperations(resolvedPath, input.operations, {
|
|
21
|
+
expectedSha256: input.expected_sha256,
|
|
22
|
+
maxFileBytes: config.directMaxFileBytes,
|
|
23
|
+
revalidatePath: () => guardDirectWritePath(input.path, session.resolved_repo_path, config.workspaceRoot),
|
|
24
|
+
});
|
|
25
|
+
const beforeSha256 = patchResult.before_sha256;
|
|
26
|
+
// Re-read the file from disk to compute the authoritative after_sha256
|
|
27
|
+
const finalPath = guardDirectWritePath(input.path, session.resolved_repo_path, config.workspaceRoot);
|
|
28
|
+
const afterSha256 = computeFileSha256(finalPath);
|
|
29
|
+
if (afterSha256 !== patchResult.after_sha256) {
|
|
30
|
+
throw new PatchWardenError("direct_target_changed_after_write", `Patch target "${input.path}" changed before the operation could be recorded.`, "Inspect the file and retry only after concurrent filesystem changes stop.", true, { path: input.path, expected_sha256: patchResult.after_sha256, actual_sha256: afterSha256 });
|
|
31
|
+
}
|
|
32
|
+
// 6. Append operation record to session
|
|
33
|
+
appendDirectSessionOperation(input.session_id, {
|
|
34
|
+
index: 0,
|
|
35
|
+
timestamp: new Date().toISOString(),
|
|
36
|
+
path: input.path,
|
|
37
|
+
operation_type: "patch",
|
|
38
|
+
before_sha256: beforeSha256,
|
|
39
|
+
after_sha256: afterSha256,
|
|
40
|
+
operations_applied: patchResult.operations_applied,
|
|
41
|
+
bytes_changed: patchResult.bytes_changed,
|
|
42
|
+
});
|
|
43
|
+
// 7. Return result
|
|
44
|
+
return {
|
|
45
|
+
path: input.path,
|
|
46
|
+
before_sha256: beforeSha256,
|
|
47
|
+
after_sha256: afterSha256,
|
|
48
|
+
operations_applied: patchResult.operations_applied,
|
|
49
|
+
bytes_changed: patchResult.bytes_changed,
|
|
50
|
+
next_action: "Call run_verification to test the changes, or apply_patch for more edits.",
|
|
51
|
+
};
|
|
52
|
+
}, config);
|
|
53
|
+
}
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
*
|
|
5
5
|
* 参考 src/tools/auditTask.ts 的导出/返回风格。
|
|
6
6
|
*/
|
|
7
|
-
import { getConfig } from "
|
|
8
|
-
import { guardWorkspacePath } from "
|
|
9
|
-
import { discardWorktree } from "
|
|
7
|
+
import { getConfig } from "../../config.js";
|
|
8
|
+
import { guardWorkspacePath } from "../../security/pathGuard.js";
|
|
9
|
+
import { discardWorktree } from "../../goal/worktreeManager.js";
|
|
10
10
|
/**
|
|
11
11
|
* 丢弃指定 worktree:移除 worktree 目录、删除临时 branch、归档状态。
|
|
12
12
|
*
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export * from "./androidDoctor.js";
|
|
2
|
+
export * from "./applyPatch.js";
|
|
3
|
+
export * from "./discardWorktree.js";
|
|
4
|
+
export * from "./listAgents.js";
|
|
5
|
+
export * from "./listWorkspace.js";
|
|
6
|
+
export * from "./mergeWorktree.js";
|
|
7
|
+
export * from "./readWorkspaceFile.js";
|
|
8
|
+
export * from "./recommendAgentForTask.js";
|
|
9
|
+
export * from "./searchWorkspace.js";
|
|
10
|
+
export * from "./syncFile.js";
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export * from "./androidDoctor.js";
|
|
2
|
+
export * from "./applyPatch.js";
|
|
3
|
+
export * from "./discardWorktree.js";
|
|
4
|
+
export * from "./listAgents.js";
|
|
5
|
+
export * from "./listWorkspace.js";
|
|
6
|
+
export * from "./mergeWorktree.js";
|
|
7
|
+
export * from "./readWorkspaceFile.js";
|
|
8
|
+
export * from "./recommendAgentForTask.js";
|
|
9
|
+
export * from "./searchWorkspace.js";
|
|
10
|
+
export * from "./syncFile.js";
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface AgentAvailability {
|
|
2
|
+
name: string;
|
|
3
|
+
configured: true;
|
|
4
|
+
available: boolean;
|
|
5
|
+
command: string;
|
|
6
|
+
reason: string | null;
|
|
7
|
+
checked_at: string;
|
|
8
|
+
adapter: string | null;
|
|
9
|
+
model: string | null;
|
|
10
|
+
capabilities: {
|
|
11
|
+
model_override: boolean;
|
|
12
|
+
};
|
|
13
|
+
availability_scope: "executable_only";
|
|
14
|
+
provider_status: "not_checked";
|
|
15
|
+
invocation_ready?: boolean;
|
|
16
|
+
model_argument_present?: boolean;
|
|
17
|
+
}
|
|
18
|
+
export declare function listAgents(): {
|
|
19
|
+
agents: AgentAvailability[];
|
|
20
|
+
total: number;
|
|
21
|
+
config_path: string;
|
|
22
|
+
workspace_root: string;
|
|
23
|
+
};
|