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/dist/logging.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
-
import {
|
|
2
|
+
import { mkdirSync } from "node:fs";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { redactSensitiveContent } from "./security/contentRedaction.js";
|
|
5
|
-
import { stableJsonStringify } from "./
|
|
5
|
+
import { stableJsonStringify } from "./utils/stableJson.js";
|
|
6
6
|
import { getConfig } from "./config.js";
|
|
7
|
+
import { appendBoundedTextFileSync } from "./utils/boundedFile.js";
|
|
8
|
+
const MAX_INVOCATION_LOG_BYTES = 5 * 1024 * 1024;
|
|
7
9
|
// ── Helpers ───────────────────────────────────────────────────────
|
|
8
10
|
/**
|
|
9
11
|
* Returns true when PATCHWARDEN_VERBOSE_LOG is set to "true".
|
|
@@ -179,7 +181,7 @@ export function logToolInvocation(entry, options) {
|
|
|
179
181
|
}
|
|
180
182
|
mkdirSync(logsDir, { recursive: true });
|
|
181
183
|
const logFilePath = join(logsDir, "invocation.log");
|
|
182
|
-
|
|
184
|
+
appendBoundedTextFileSync(logFilePath, JSON.stringify(entry) + "\n", MAX_INVOCATION_LOG_BYTES);
|
|
183
185
|
}
|
|
184
186
|
catch (err) {
|
|
185
187
|
// 日志失败不应阻断主流程,仅向 stderr 记录错误
|
|
@@ -276,10 +276,13 @@ function pathMatchesPattern(relPath, pattern) {
|
|
|
276
276
|
relPath.toLowerCase().startsWith(`${normalizedPattern.toLowerCase()}/`);
|
|
277
277
|
}
|
|
278
278
|
function parseGithubRepo(repository) {
|
|
279
|
+
const repositoryObject = repository && typeof repository === "object" && !Array.isArray(repository)
|
|
280
|
+
? repository
|
|
281
|
+
: null;
|
|
279
282
|
const raw = typeof repository === "string"
|
|
280
283
|
? repository
|
|
281
|
-
:
|
|
282
|
-
?
|
|
284
|
+
: typeof repositoryObject?.url === "string"
|
|
285
|
+
? repositoryObject.url
|
|
283
286
|
: "";
|
|
284
287
|
const match = raw.match(/github\.com[:/](.+?\/.+?)(?:\.git)?(?:[#?].*)?$/i);
|
|
285
288
|
return match ? match[1] : null;
|
|
@@ -30,7 +30,7 @@ export interface PackedCheckResult extends StageCheckResult {
|
|
|
30
30
|
}
|
|
31
31
|
export interface HttpResponse {
|
|
32
32
|
statusCode: number;
|
|
33
|
-
data:
|
|
33
|
+
data: unknown;
|
|
34
34
|
}
|
|
35
35
|
export type HttpGetFn = (url: string, headers?: Record<string, string>, timeoutMs?: number) => Promise<HttpResponse>;
|
|
36
36
|
export interface ReleaseGateOptions {
|
|
@@ -14,11 +14,13 @@
|
|
|
14
14
|
* Network errors resolve to "not_checked" so transient issues don't block.
|
|
15
15
|
* GITHUB_TOKEN is used as Bearer auth but never logged or returned.
|
|
16
16
|
*/
|
|
17
|
-
import { execSync } from "node:child_process";
|
|
18
17
|
import { createHash } from "node:crypto";
|
|
19
|
-
import { readFileSync
|
|
18
|
+
import { readFileSync } from "node:fs";
|
|
20
19
|
import { join } from "node:path";
|
|
21
20
|
import { get } from "node:https";
|
|
21
|
+
import { resolveTrustedCommandLine } from "../runner/processSecurity.js";
|
|
22
|
+
import { runSimpleProcessSync } from "../runner/simpleProcess.js";
|
|
23
|
+
import { atomicWriteJsonFileSync } from "../utils/atomicFile.js";
|
|
22
24
|
// ── Constants ──────────────────────────────────────────────────────
|
|
23
25
|
const STAGE_ORDER = [
|
|
24
26
|
"local_ready",
|
|
@@ -29,6 +31,7 @@ const STAGE_ORDER = [
|
|
|
29
31
|
];
|
|
30
32
|
const LOCAL_TIMEOUT_MS = 300000;
|
|
31
33
|
const REMOTE_TIMEOUT_MS = 10000;
|
|
34
|
+
const MAX_REMOTE_RESPONSE_BYTES = 5 * 1024 * 1024;
|
|
32
35
|
const USER_AGENT = "PatchWarden-ReleaseGate";
|
|
33
36
|
const PACK_FORBIDDEN_PATTERNS = [
|
|
34
37
|
/(^|[\\/])\.env$/,
|
|
@@ -55,6 +58,14 @@ export function computeTokenDigest(token) {
|
|
|
55
58
|
export async function httpsGetJson(url, headers, timeoutMs) {
|
|
56
59
|
const timeout = timeoutMs ?? REMOTE_TIMEOUT_MS;
|
|
57
60
|
return new Promise((resolve, reject) => {
|
|
61
|
+
let settled = false;
|
|
62
|
+
const fail = (error) => {
|
|
63
|
+
if (settled)
|
|
64
|
+
return;
|
|
65
|
+
settled = true;
|
|
66
|
+
clearTimeout(timer);
|
|
67
|
+
reject(error);
|
|
68
|
+
};
|
|
58
69
|
const timer = setTimeout(() => {
|
|
59
70
|
req.destroy(new Error(`Request timed out after ${timeout}ms`));
|
|
60
71
|
}, timeout);
|
|
@@ -65,9 +76,31 @@ export async function httpsGetJson(url, headers, timeoutMs) {
|
|
|
65
76
|
...(headers || {}),
|
|
66
77
|
},
|
|
67
78
|
}, (res) => {
|
|
79
|
+
const declaredLength = Number(res.headers["content-length"]);
|
|
80
|
+
if (Number.isFinite(declaredLength) && declaredLength > MAX_REMOTE_RESPONSE_BYTES) {
|
|
81
|
+
res.destroy();
|
|
82
|
+
fail(new Error(`Response exceeds ${MAX_REMOTE_RESPONSE_BYTES} bytes`));
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
68
85
|
const chunks = [];
|
|
69
|
-
|
|
86
|
+
let totalBytes = 0;
|
|
87
|
+
let oversized = false;
|
|
88
|
+
res.on("data", (chunk) => {
|
|
89
|
+
if (oversized)
|
|
90
|
+
return;
|
|
91
|
+
totalBytes += chunk.length;
|
|
92
|
+
if (totalBytes > MAX_REMOTE_RESPONSE_BYTES) {
|
|
93
|
+
oversized = true;
|
|
94
|
+
res.destroy();
|
|
95
|
+
fail(new Error(`Response exceeds ${MAX_REMOTE_RESPONSE_BYTES} bytes`));
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
chunks.push(chunk);
|
|
99
|
+
});
|
|
70
100
|
res.on("end", () => {
|
|
101
|
+
if (oversized || settled)
|
|
102
|
+
return;
|
|
103
|
+
settled = true;
|
|
71
104
|
clearTimeout(timer);
|
|
72
105
|
const body = Buffer.concat(chunks).toString("utf-8");
|
|
73
106
|
let data = null;
|
|
@@ -81,11 +114,10 @@ export async function httpsGetJson(url, headers, timeoutMs) {
|
|
|
81
114
|
}
|
|
82
115
|
resolve({ statusCode: res.statusCode ?? 0, data });
|
|
83
116
|
});
|
|
117
|
+
res.on("aborted", () => fail(new Error("Response was aborted before completion")));
|
|
118
|
+
res.on("error", fail);
|
|
84
119
|
});
|
|
85
|
-
req.on("error",
|
|
86
|
-
clearTimeout(timer);
|
|
87
|
-
reject(err);
|
|
88
|
-
});
|
|
120
|
+
req.on("error", fail);
|
|
89
121
|
});
|
|
90
122
|
}
|
|
91
123
|
/**
|
|
@@ -138,12 +170,14 @@ export function checkLocalReady(repoPath) {
|
|
|
138
170
|
const commands = ["npm.cmd run build", "npm.cmd test", "npm.cmd run doctor:ci"];
|
|
139
171
|
for (const cmdStr of commands) {
|
|
140
172
|
try {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
173
|
+
const result = runLocalCommand(repoPath, cmdStr, LOCAL_TIMEOUT_MS);
|
|
174
|
+
if (result.spawnError)
|
|
175
|
+
throw new Error(result.spawnError);
|
|
176
|
+
if (result.timedOut)
|
|
177
|
+
throw new Error(`Command timed out after ${LOCAL_TIMEOUT_MS}ms`);
|
|
178
|
+
if (result.exitCode !== 0) {
|
|
179
|
+
throw Object.assign(new Error(`Command exited with code ${result.exitCode ?? -1}`), { status: result.exitCode ?? -1 });
|
|
180
|
+
}
|
|
147
181
|
}
|
|
148
182
|
catch (err) {
|
|
149
183
|
if (err && typeof err === "object" && "status" in err) {
|
|
@@ -170,12 +204,14 @@ export function checkLocalReady(repoPath) {
|
|
|
170
204
|
export function checkPackedReady(repoPath) {
|
|
171
205
|
let packOutput;
|
|
172
206
|
try {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
207
|
+
const result = runLocalCommand(repoPath, "npm.cmd pack --dry-run --json", LOCAL_TIMEOUT_MS, 10 * 1024 * 1024);
|
|
208
|
+
if (result.spawnError)
|
|
209
|
+
throw new Error(result.spawnError);
|
|
210
|
+
if (result.timedOut)
|
|
211
|
+
throw new Error(`npm pack timed out after ${LOCAL_TIMEOUT_MS}ms`);
|
|
212
|
+
if (result.exitCode !== 0)
|
|
213
|
+
throw new Error(`npm pack exited with code ${result.exitCode ?? -1}`);
|
|
214
|
+
packOutput = result.stdout;
|
|
179
215
|
}
|
|
180
216
|
catch (err) {
|
|
181
217
|
return {
|
|
@@ -240,7 +276,7 @@ export function checkPackedReady(repoPath) {
|
|
|
240
276
|
};
|
|
241
277
|
const manifestPath = join(repoPath, "release-artifact-manifest.json");
|
|
242
278
|
try {
|
|
243
|
-
|
|
279
|
+
atomicWriteJsonFileSync(manifestPath, manifest);
|
|
244
280
|
}
|
|
245
281
|
catch (err) {
|
|
246
282
|
return {
|
|
@@ -264,6 +300,17 @@ export function checkPackedReady(repoPath) {
|
|
|
264
300
|
}
|
|
265
301
|
return { status: "passed", manifestPath };
|
|
266
302
|
}
|
|
303
|
+
function runLocalCommand(repoPath, commandLine, timeoutMs, maxStdoutBytes = 512 * 1024) {
|
|
304
|
+
const invocation = resolveTrustedCommandLine(commandLine, repoPath);
|
|
305
|
+
return runSimpleProcessSync({
|
|
306
|
+
command: invocation.command,
|
|
307
|
+
args: invocation.argsPrefix,
|
|
308
|
+
cwd: repoPath,
|
|
309
|
+
timeoutMs,
|
|
310
|
+
maxStdoutBytes,
|
|
311
|
+
maxStderrBytes: 512 * 1024,
|
|
312
|
+
});
|
|
313
|
+
}
|
|
267
314
|
/**
|
|
268
315
|
* Stage 3: published_verified
|
|
269
316
|
* Queries the npm registry and confirms the given version exists.
|
|
@@ -280,11 +327,12 @@ export async function checkPublishedVerified(packageName, version, httpGet) {
|
|
|
280
327
|
if (res.statusCode === 404) {
|
|
281
328
|
return { status: "failed", reason: `Package "${packageName}" not found on npm registry` };
|
|
282
329
|
}
|
|
283
|
-
const data = res.data;
|
|
284
|
-
|
|
330
|
+
const data = asRecord(res.data);
|
|
331
|
+
const versions = asRecord(data?.versions);
|
|
332
|
+
if (!versions) {
|
|
285
333
|
return { status: "failed", reason: "npm registry response missing versions object" };
|
|
286
334
|
}
|
|
287
|
-
if (Object.prototype.hasOwnProperty.call(
|
|
335
|
+
if (Object.prototype.hasOwnProperty.call(versions, version)) {
|
|
288
336
|
return { status: "passed" };
|
|
289
337
|
}
|
|
290
338
|
return {
|
|
@@ -340,12 +388,12 @@ export async function checkCiVerified(repo, branch, httpGet) {
|
|
|
340
388
|
if (res.statusCode !== 200) {
|
|
341
389
|
return { status: "not_checked", reason: `GitHub API returned ${res.statusCode}` };
|
|
342
390
|
}
|
|
343
|
-
const data = res.data;
|
|
391
|
+
const data = asRecord(res.data);
|
|
344
392
|
const runs = Array.isArray(data?.workflow_runs) ? data.workflow_runs : [];
|
|
345
393
|
if (runs.length === 0) {
|
|
346
394
|
return { status: "not_checked", reason: `No CI runs found for branch "${branch}"` };
|
|
347
395
|
}
|
|
348
|
-
const conclusion = runs[0]?.conclusion;
|
|
396
|
+
const conclusion = asRecord(runs[0])?.conclusion;
|
|
349
397
|
if (conclusion === "success") {
|
|
350
398
|
return { status: "passed" };
|
|
351
399
|
}
|
|
@@ -364,6 +412,11 @@ export async function checkCiVerified(repo, branch, httpGet) {
|
|
|
364
412
|
};
|
|
365
413
|
}
|
|
366
414
|
}
|
|
415
|
+
function asRecord(value) {
|
|
416
|
+
return value && typeof value === "object" && !Array.isArray(value)
|
|
417
|
+
? value
|
|
418
|
+
: null;
|
|
419
|
+
}
|
|
367
420
|
// ── Orchestrator ───────────────────────────────────────────────────
|
|
368
421
|
/**
|
|
369
422
|
* Run release-gate stages up to and including targetStage, in order.
|
|
@@ -6,7 +6,21 @@ export interface AgentInvocation {
|
|
|
6
6
|
commandLabel: string;
|
|
7
7
|
promptMode: "inline" | "file";
|
|
8
8
|
promptFilePath?: string;
|
|
9
|
+
environmentVariableNames: string[];
|
|
10
|
+
blockedEnvironmentVariableNames: string[];
|
|
9
11
|
}
|
|
12
|
+
export interface ResolvedAgentLaunch {
|
|
13
|
+
command: string;
|
|
14
|
+
argsPrefix: string[];
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Resolve the Windows npm shim used by OpenCode to its native executable.
|
|
18
|
+
* Node cannot spawn .cmd/.ps1 shims directly with shell disabled (EINVAL), and
|
|
19
|
+
* enabling a shell would make the task prompt part of shell parsing.
|
|
20
|
+
*/
|
|
21
|
+
export declare function resolveAgentExecutable(agentName: string, command: string, platform?: NodeJS.Platform, pathValue?: string, fileExists?: (path: string) => boolean, cwd?: string): string;
|
|
22
|
+
/** Resolve a configured Agent to a native executable or verified npm CLI. */
|
|
23
|
+
export declare function resolveAgentLaunch(agentName: string, command: string, platform?: NodeJS.Platform, pathValue?: string, fileExists?: (path: string) => boolean, cwd?: string, adapterName?: string, readText?: (path: string) => string): ResolvedAgentLaunch;
|
|
10
24
|
/**
|
|
11
25
|
* Build agent invocation parameters from config.
|
|
12
26
|
* Replaces {repo}, {prompt}, and {prompt_file} placeholders.
|
|
@@ -1,5 +1,89 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { basename, win32 } from "node:path";
|
|
2
3
|
import { guardAgentCommand, sanitizePromptArg } from "../security/commandGuard.js";
|
|
4
|
+
import { resolveTrustedExecutable, sanitizeTrustedPath } from "./processSecurity.js";
|
|
5
|
+
const KNOWN_AGENT_NPM_PACKAGES = Object.freeze({
|
|
6
|
+
codex: "@openai/codex",
|
|
7
|
+
claude: "@anthropic-ai/claude-code",
|
|
8
|
+
gemini: "@google/gemini-cli",
|
|
9
|
+
copilot: "@github/copilot",
|
|
10
|
+
qwen: "@qwen-code/qwen-code",
|
|
11
|
+
opencode: "opencode-ai",
|
|
12
|
+
});
|
|
13
|
+
/**
|
|
14
|
+
* Resolve the Windows npm shim used by OpenCode to its native executable.
|
|
15
|
+
* Node cannot spawn .cmd/.ps1 shims directly with shell disabled (EINVAL), and
|
|
16
|
+
* enabling a shell would make the task prompt part of shell parsing.
|
|
17
|
+
*/
|
|
18
|
+
export function resolveAgentExecutable(agentName, command, platform = process.platform, pathValue = process.env.PATH || "", fileExists = existsSync, cwd = process.cwd()) {
|
|
19
|
+
return resolveAgentLaunch(agentName, command, platform, pathValue, fileExists, cwd).command;
|
|
20
|
+
}
|
|
21
|
+
/** Resolve a configured Agent to a native executable or verified npm CLI. */
|
|
22
|
+
export function resolveAgentLaunch(agentName, command, platform = process.platform, pathValue = process.env.PATH || "", fileExists = existsSync, cwd = process.cwd(), adapterName = agentName, readText = (path) => readFileSync(path, "utf-8")) {
|
|
23
|
+
if (platform !== "win32")
|
|
24
|
+
return { command, argsPrefix: [] };
|
|
25
|
+
const commandName = win32.basename(command).toLowerCase();
|
|
26
|
+
if (adapterName === "opencode" && new Set(["opencode", "opencode.cmd", "opencode.ps1", "opencode.bat"]).has(commandName)) {
|
|
27
|
+
const roots = win32.isAbsolute(command)
|
|
28
|
+
? [win32.dirname(command)]
|
|
29
|
+
: sanitizeTrustedPath(pathValue, cwd, "win32").split(win32.delimiter).filter(Boolean);
|
|
30
|
+
for (const root of roots) {
|
|
31
|
+
const nativeExecutable = win32.join(root, "node_modules", "opencode-ai", "bin", "opencode.exe");
|
|
32
|
+
if (fileExists(nativeExecutable))
|
|
33
|
+
return { command: nativeExecutable, argsPrefix: [] };
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
const resolved = resolveTrustedExecutable(command, cwd, {
|
|
37
|
+
platform,
|
|
38
|
+
pathValue,
|
|
39
|
+
fileExists,
|
|
40
|
+
});
|
|
41
|
+
if (!/\.(?:cmd|bat|ps1)$/i.test(resolved))
|
|
42
|
+
return { command: resolved, argsPrefix: [] };
|
|
43
|
+
const packageName = KNOWN_AGENT_NPM_PACKAGES[adapterName] || KNOWN_AGENT_NPM_PACKAGES[agentName];
|
|
44
|
+
if (!packageName) {
|
|
45
|
+
throw new Error(`Windows shell shim is not allowed for Agent "${agentName}": ${resolved}`);
|
|
46
|
+
}
|
|
47
|
+
const packageRoot = win32.resolve(win32.dirname(resolved), "node_modules", ...packageName.split("/"));
|
|
48
|
+
const manifestPath = win32.join(packageRoot, "package.json");
|
|
49
|
+
if (!fileExists(manifestPath)) {
|
|
50
|
+
throw new Error(`Verified npm package manifest not found for Agent "${agentName}": ${manifestPath}`);
|
|
51
|
+
}
|
|
52
|
+
let manifest;
|
|
53
|
+
try {
|
|
54
|
+
manifest = JSON.parse(readText(manifestPath));
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
throw new Error(`Invalid npm package manifest for Agent "${agentName}": ${manifestPath}`);
|
|
58
|
+
}
|
|
59
|
+
if (manifest.name !== packageName) {
|
|
60
|
+
throw new Error(`Unexpected npm package identity for Agent "${agentName}"`);
|
|
61
|
+
}
|
|
62
|
+
const shimName = win32.basename(resolved).replace(/\.(?:cmd|bat|ps1)$/i, "");
|
|
63
|
+
const binPath = resolvePackageBin(manifest.bin, [agentName, adapterName, shimName]);
|
|
64
|
+
if (!binPath)
|
|
65
|
+
throw new Error(`npm package does not declare a CLI for Agent "${agentName}"`);
|
|
66
|
+
const cliPath = win32.resolve(packageRoot, binPath);
|
|
67
|
+
const relativeCli = win32.relative(packageRoot, cliPath);
|
|
68
|
+
if (!relativeCli || relativeCli === ".." || relativeCli.startsWith(`..${win32.sep}`) || win32.isAbsolute(relativeCli) || !fileExists(cliPath)) {
|
|
69
|
+
throw new Error(`npm CLI entry escapes or is missing for Agent "${agentName}"`);
|
|
70
|
+
}
|
|
71
|
+
const node = resolveTrustedExecutable("node", cwd, { platform, pathValue, fileExists });
|
|
72
|
+
return { command: node, argsPrefix: [cliPath] };
|
|
73
|
+
}
|
|
74
|
+
function resolvePackageBin(bin, names) {
|
|
75
|
+
if (typeof bin === "string")
|
|
76
|
+
return bin;
|
|
77
|
+
if (!bin || typeof bin !== "object" || Array.isArray(bin))
|
|
78
|
+
return null;
|
|
79
|
+
const entries = bin;
|
|
80
|
+
for (const name of names) {
|
|
81
|
+
if (typeof entries[name] === "string")
|
|
82
|
+
return entries[name];
|
|
83
|
+
}
|
|
84
|
+
const values = Object.values(entries).filter((value) => typeof value === "string");
|
|
85
|
+
return values.length === 1 ? values[0] : null;
|
|
86
|
+
}
|
|
3
87
|
/**
|
|
4
88
|
* Build agent invocation parameters from config.
|
|
5
89
|
* Replaces {repo}, {prompt}, and {prompt_file} placeholders.
|
|
@@ -7,6 +91,12 @@ import { guardAgentCommand, sanitizePromptArg } from "../security/commandGuard.j
|
|
|
7
91
|
*/
|
|
8
92
|
export function buildAgentInvocation(agentName, repoPath, prompt, config, promptFilePath) {
|
|
9
93
|
const agentCmd = guardAgentCommand(agentName, config);
|
|
94
|
+
const launch = resolveAgentLaunch(agentName, agentCmd.command, process.platform, process.env.PATH || "", existsSync, repoPath, config.agents[agentName]?.adapter || agentName);
|
|
95
|
+
const environmentVariableNames = [...(config.agents[agentName]?.envAllowlist ?? [])];
|
|
96
|
+
const blockedEnvironmentVariableNames = [
|
|
97
|
+
"CONTROL_PLANE_API_KEY",
|
|
98
|
+
config.http?.ownerTokenEnv || "PATCHWARDEN_OWNER_TOKEN",
|
|
99
|
+
];
|
|
10
100
|
const sanitizedPrompt = sanitizePromptArg(prompt);
|
|
11
101
|
const hasPromptFilePlaceholder = agentCmd.args.includes("{prompt_file}");
|
|
12
102
|
const promptMode = hasPromptFilePlaceholder && promptFilePath ? "file" : "inline";
|
|
@@ -20,11 +110,13 @@ export function buildAgentInvocation(agentName, repoPath, prompt, config, prompt
|
|
|
20
110
|
return arg;
|
|
21
111
|
});
|
|
22
112
|
return {
|
|
23
|
-
command:
|
|
24
|
-
args: resolvedArgs,
|
|
113
|
+
command: launch.command,
|
|
114
|
+
args: [...launch.argsPrefix, ...resolvedArgs],
|
|
25
115
|
cwd: repoPath,
|
|
26
|
-
commandLabel: `${basename(
|
|
116
|
+
commandLabel: `${basename(launch.command)} (configured agent command)`,
|
|
27
117
|
promptMode,
|
|
118
|
+
environmentVariableNames,
|
|
119
|
+
blockedEnvironmentVariableNames,
|
|
28
120
|
...(promptMode === "file" && promptFilePath ? { promptFilePath } : {}),
|
|
29
121
|
};
|
|
30
122
|
}
|
|
@@ -51,6 +51,8 @@ export interface ChangeArtifacts {
|
|
|
51
51
|
diff: string;
|
|
52
52
|
diff_available: boolean;
|
|
53
53
|
diff_truncated: boolean;
|
|
54
|
+
diff_redacted?: boolean;
|
|
55
|
+
diff_redaction_categories?: string[];
|
|
54
56
|
diff_size_bytes: number;
|
|
55
57
|
additions: number;
|
|
56
58
|
deletions: number;
|
|
@@ -66,10 +68,16 @@ export interface ChangeArtifacts {
|
|
|
66
68
|
unavailable_reason: string | null;
|
|
67
69
|
artifact_hygiene: ArtifactHygiene;
|
|
68
70
|
}
|
|
69
|
-
export declare function captureRepoSnapshot(repoPath: string): Promise<RepoSnapshot>;
|
|
71
|
+
export declare function captureRepoSnapshot(repoPath: string, signal?: AbortSignal): Promise<RepoSnapshot>;
|
|
70
72
|
export declare function writeSnapshot(taskDir: string, filename: string, snapshot: RepoSnapshot): void;
|
|
71
|
-
export declare function buildChangeArtifacts(repoPath: string, before: RepoSnapshot, after: RepoSnapshot): Promise<ChangeArtifacts>;
|
|
72
|
-
export declare function
|
|
73
|
+
export declare function buildChangeArtifacts(repoPath: string, before: RepoSnapshot, after: RepoSnapshot, signal?: AbortSignal): Promise<ChangeArtifacts>;
|
|
74
|
+
export declare function sanitizeDiffEvidence(input: string, maxBytes?: number): {
|
|
75
|
+
content: string;
|
|
76
|
+
truncated: boolean;
|
|
77
|
+
redacted: boolean;
|
|
78
|
+
redaction_categories: string[];
|
|
79
|
+
};
|
|
80
|
+
export declare function compareSnapshots(before: RepoSnapshot, after: RepoSnapshot, platform?: NodeJS.Platform): ChangedFile[];
|
|
73
81
|
export declare function emptyArtifactHygiene(): ArtifactHygiene;
|
|
74
82
|
export interface ExternalDirtyFile {
|
|
75
83
|
path: string;
|
|
@@ -81,13 +89,13 @@ export interface ExternalDirtyFile {
|
|
|
81
89
|
* Extract files that are dirty in the workspace but outside the target repo.
|
|
82
90
|
* Used to establish a baseline before task execution.
|
|
83
91
|
*/
|
|
84
|
-
export declare function extractExternalDirtyFiles(workspaceSnapshot: RepoSnapshot, repoPath: string, workspaceRoot: string): ExternalDirtyFile[];
|
|
92
|
+
export declare function extractExternalDirtyFiles(workspaceSnapshot: RepoSnapshot, repoPath: string, workspaceRoot: string, platform?: NodeJS.Platform): ExternalDirtyFile[];
|
|
85
93
|
/**
|
|
86
94
|
* Compare external dirty files between baseline and post-task snapshots.
|
|
87
95
|
* Returns files that are NEW (not present in baseline) or CHANGED
|
|
88
96
|
* (same path but different sha256, meaning the task modified them).
|
|
89
97
|
*/
|
|
90
|
-
export declare function findNewExternalDirtyFiles(baseline: ExternalDirtyFile[], current: ExternalDirtyFile[]): ExternalDirtyFile[];
|
|
98
|
+
export declare function findNewExternalDirtyFiles(baseline: ExternalDirtyFile[], current: ExternalDirtyFile[], platform?: NodeJS.Platform): ExternalDirtyFile[];
|
|
91
99
|
export interface ArtifactManifestEntry {
|
|
92
100
|
path: string;
|
|
93
101
|
type: string;
|