patchwarden 1.5.0 → 1.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/PatchWarden.cmd +32 -2
- package/README.en.md +194 -26
- package/README.md +160 -22
- package/dist/assessments/agentAssessor.d.ts +1 -1
- package/dist/assessments/agentAssessor.js +24 -15
- package/dist/assessments/assessmentStore.d.ts +1 -1
- package/dist/assessments/assessmentStore.js +44 -36
- package/dist/assessments/confirmCli.js +5 -4
- package/dist/config.d.ts +22 -0
- package/dist/config.js +98 -11
- package/dist/control/fileManager.d.ts +2 -0
- package/dist/control/fileManager.js +39 -0
- package/dist/control/middleware/auth.d.ts +16 -0
- package/dist/control/middleware/auth.js +17 -0
- package/dist/control/middleware/static.d.ts +3 -0
- package/dist/control/middleware/static.js +78 -0
- package/dist/control/routeTable.d.ts +24 -0
- package/dist/control/routeTable.js +263 -0
- package/dist/control/routes/audit.d.ts +15 -0
- package/dist/control/routes/audit.js +287 -0
- package/dist/control/routes/evidence.d.ts +4 -0
- package/dist/control/routes/evidence.js +96 -0
- package/dist/control/routes/lineage.d.ts +3 -0
- package/dist/control/routes/lineage.js +71 -0
- package/dist/control/routes/policy.d.ts +3 -0
- package/dist/control/routes/policy.js +81 -0
- package/dist/control/routes/process.d.ts +12 -0
- package/dist/control/routes/process.js +487 -0
- package/dist/control/routes/sessions.d.ts +30 -0
- package/dist/control/routes/sessions.js +287 -0
- package/dist/control/routes/status.d.ts +51 -0
- package/dist/control/routes/status.js +307 -0
- package/dist/control/routes/taskActions.d.ts +21 -0
- package/dist/control/routes/taskActions.js +197 -0
- package/dist/control/routes/tasks.d.ts +24 -0
- package/dist/control/routes/tasks.js +309 -0
- package/dist/control/routes/workspace.d.ts +15 -0
- package/dist/control/routes/workspace.js +220 -0
- package/dist/control/runtime.d.ts +92 -0
- package/dist/control/runtime.js +425 -0
- package/dist/control/server.d.ts +13 -0
- package/dist/control/server.js +150 -0
- package/dist/control/shared.d.ts +59 -0
- package/dist/control/shared.js +341 -0
- package/dist/controlCenter.d.ts +6 -0
- package/dist/controlCenter.js +7 -2197
- package/dist/direct/directAudit.js +234 -225
- package/dist/direct/directGuards.d.ts +2 -1
- package/dist/direct/directGuards.js +72 -37
- package/dist/direct/directPatch.d.ts +6 -1
- package/dist/direct/directPatch.js +55 -8
- package/dist/direct/directSessionStore.d.ts +16 -6
- package/dist/direct/directSessionStore.js +127 -35
- package/dist/direct/directVerification.js +8 -16
- package/dist/doctor.d.ts +18 -1
- package/dist/doctor.js +614 -373
- package/dist/goal/acceptanceEngine.d.ts +1 -1
- package/dist/goal/goalProgress.js +75 -69
- package/dist/goal/goalReport.d.ts +54 -0
- package/dist/goal/goalReport.js +197 -0
- package/dist/goal/goalStatus.d.ts +8 -0
- package/dist/goal/goalStatus.js +10 -3
- package/dist/goal/goalStore.d.ts +9 -2
- package/dist/goal/goalStore.js +152 -45
- package/dist/goal/handoffExport.js +6 -6
- package/dist/goal/specKitImport.d.ts +63 -0
- package/dist/goal/specKitImport.js +221 -0
- package/dist/goal/subgoalSync.js +13 -10
- package/dist/goal/worktreeManager.d.ts +2 -0
- package/dist/goal/worktreeManager.js +209 -136
- package/dist/httpServer.js +126 -44
- package/dist/index.js +7 -4
- package/dist/logging.d.ts +7 -1
- package/dist/logging.js +13 -3
- package/dist/policy/projectPolicy.js +5 -2
- package/dist/release/releaseGate.d.ts +1 -1
- package/dist/release/releaseGate.js +78 -25
- package/dist/runner/agentInvocation.d.ts +14 -0
- package/dist/runner/agentInvocation.js +96 -4
- package/dist/runner/changeCapture.d.ts +14 -6
- package/dist/runner/changeCapture.js +287 -81
- package/dist/runner/cli.js +7 -6
- package/dist/runner/postTaskCleanup.js +60 -7
- package/dist/runner/processSecurity.d.ts +56 -0
- package/dist/runner/processSecurity.js +373 -0
- package/dist/runner/runTask.d.ts +1 -1
- package/dist/runner/runTask.js +339 -287
- package/dist/runner/simpleProcess.d.ts +3 -0
- package/dist/runner/simpleProcess.js +52 -38
- package/dist/{taskProgress.d.ts → runner/taskProgress.d.ts} +1 -1
- package/dist/{taskProgress.js → runner/taskProgress.js} +2 -2
- package/dist/{taskRuntime.d.ts → runner/taskRuntime.d.ts} +1 -1
- package/dist/{taskRuntime.js → runner/taskRuntime.js} +3 -2
- package/dist/runner/taskStatusStore.d.ts +11 -0
- package/dist/runner/taskStatusStore.js +24 -0
- package/dist/runner/watch.d.ts +14 -1
- package/dist/runner/watch.js +265 -54
- package/dist/security/contentRedaction.d.ts +6 -0
- package/dist/security/contentRedaction.js +24 -2
- package/dist/security/discoveryTokenStore.d.ts +3 -2
- package/dist/security/discoveryTokenStore.js +17 -2
- package/dist/security/loopbackHost.d.ts +2 -0
- package/dist/security/loopbackHost.js +16 -0
- package/dist/security/pathGuard.js +32 -17
- package/dist/security/planGuard.js +2 -1
- package/dist/security/runtimeGuard.js +9 -6
- package/dist/security/secretComparison.d.ts +3 -0
- package/dist/security/secretComparison.js +11 -0
- package/dist/security/sensitiveGuard.d.ts +5 -0
- package/dist/security/sensitiveGuard.js +27 -8
- package/dist/security/toolInvocationGuard.d.ts +2 -2
- package/dist/security/toolInvocationGuard.js +1 -1
- package/dist/security/workspaceRootGuard.d.ts +8 -0
- package/dist/security/workspaceRootGuard.js +47 -0
- package/dist/smoke-test.js +280 -273
- package/dist/tools/catalog/index.d.ts +4 -0
- package/dist/tools/catalog/index.js +4 -0
- package/dist/tools/{toolCatalog.js → catalog/toolCatalog.js} +3 -12
- package/dist/tools/{toolRegistry.d.ts → catalog/toolRegistry.d.ts} +3 -3
- package/dist/tools/{toolRegistry.js → catalog/toolRegistry.js} +28 -15
- package/dist/tools/definitions/toolDefs.d.ts +18 -0
- package/dist/tools/definitions/toolDefs.js +1177 -0
- package/dist/tools/{auditSession.d.ts → diagnostics/auditSession.d.ts} +1 -1
- package/dist/tools/{auditSession.js → diagnostics/auditSession.js} +2 -2
- package/dist/tools/{auditTask.d.ts → diagnostics/auditTask.d.ts} +8 -63
- package/dist/tools/{auditTask.js → diagnostics/auditTask.js} +111 -37
- package/dist/tools/{healthCheck.d.ts → diagnostics/healthCheck.d.ts} +6 -6
- package/dist/tools/{healthCheck.js → diagnostics/healthCheck.js} +10 -10
- package/dist/tools/diagnostics/index.d.ts +6 -0
- package/dist/tools/diagnostics/index.js +6 -0
- package/dist/tools/{safeStatus.d.ts → diagnostics/safeStatus.d.ts} +3 -3
- package/dist/tools/{safeStatus.js → diagnostics/safeStatus.js} +6 -6
- package/dist/tools/{safeViews.d.ts → diagnostics/safeViews.d.ts} +14 -10
- package/dist/tools/{safeViews.js → diagnostics/safeViews.js} +25 -15
- package/dist/tools/{schemaDriftCheck.d.ts → diagnostics/schemaDriftCheck.d.ts} +1 -1
- package/dist/tools/{schemaDriftCheck.js → diagnostics/schemaDriftCheck.js} +2 -2
- package/dist/tools/{createDirectSession.d.ts → direct/createDirectSession.d.ts} +1 -1
- package/dist/tools/{createDirectSession.js → direct/createDirectSession.js} +8 -8
- package/dist/tools/{finalizeDirectSession.d.ts → direct/finalizeDirectSession.d.ts} +2 -2
- package/dist/tools/direct/finalizeDirectSession.js +86 -0
- package/dist/tools/direct/index.d.ts +3 -0
- package/dist/tools/direct/index.js +3 -0
- package/dist/tools/{runDirectVerificationBundle.js → direct/runDirectVerificationBundle.js} +2 -2
- package/dist/tools/{discoverTools.d.ts → discovery/discoverTools.d.ts} +2 -2
- package/dist/tools/{discoverTools.js → discovery/discoverTools.js} +5 -5
- package/dist/tools/{explainTool.d.ts → discovery/explainTool.d.ts} +2 -2
- package/dist/tools/{explainTool.js → discovery/explainTool.js} +2 -2
- package/dist/tools/discovery/index.d.ts +3 -0
- package/dist/tools/discovery/index.js +3 -0
- package/dist/tools/{invokeDiscoveredTool.d.ts → discovery/invokeDiscoveredTool.d.ts} +2 -2
- package/dist/tools/{invokeDiscoveredTool.js → discovery/invokeDiscoveredTool.js} +5 -5
- package/dist/tools/dispatch/coreDispatch.d.ts +9 -0
- package/dist/tools/dispatch/coreDispatch.js +283 -0
- package/dist/tools/dispatch/diagnosticDispatch.d.ts +12 -0
- package/dist/tools/dispatch/diagnosticDispatch.js +80 -0
- package/dist/tools/dispatch/directDispatch.d.ts +8 -0
- package/dist/tools/dispatch/directDispatch.js +116 -0
- package/dist/tools/dispatch/goalDispatch.d.ts +8 -0
- package/dist/tools/dispatch/goalDispatch.js +92 -0
- package/dist/tools/dispatch/releaseDispatch.d.ts +8 -0
- package/dist/tools/dispatch/releaseDispatch.js +46 -0
- package/dist/tools/dispatch/types.d.ts +23 -0
- package/dist/tools/dispatch/types.js +15 -0
- package/dist/tools/dispatch/validation.d.ts +7 -0
- package/dist/tools/dispatch/validation.js +71 -0
- package/dist/tools/{getPlan.js → goals/getPlan.js} +4 -4
- package/dist/tools/{goalSubgoalTask.d.ts → goals/goalSubgoalTask.d.ts} +2 -2
- package/dist/tools/goals/goalSubgoalTask.js +118 -0
- package/dist/tools/goals/index.d.ts +3 -0
- package/dist/tools/goals/index.js +3 -0
- package/dist/tools/{savePlan.js → goals/savePlan.js} +28 -8
- package/dist/tools/registry.d.ts +10 -14
- package/dist/tools/registry.js +47 -1651
- package/dist/tools/{checkReleaseGate.d.ts → release/checkReleaseGate.d.ts} +1 -1
- package/dist/tools/{checkReleaseGate.js → release/checkReleaseGate.js} +3 -3
- package/dist/tools/release/index.d.ts +2 -0
- package/dist/tools/release/index.js +2 -0
- package/dist/tools/{releaseMode.d.ts → release/releaseMode.d.ts} +2 -2
- package/dist/tools/{releaseMode.js → release/releaseMode.js} +46 -26
- package/dist/tools/tasks/cancelTask.d.ts +11 -0
- package/dist/tools/tasks/cancelTask.js +85 -0
- package/dist/tools/{createTask.d.ts → tasks/createTask.d.ts} +12 -4
- package/dist/tools/{createTask.js → tasks/createTask.js} +46 -31
- package/dist/tools/{diagnoseTask.d.ts → tasks/diagnoseTask.d.ts} +1 -1
- package/dist/tools/{diagnoseTask.js → tasks/diagnoseTask.js} +8 -8
- package/dist/tools/{evidencePack.d.ts → tasks/evidencePack.d.ts} +6 -0
- package/dist/tools/tasks/evidencePack.js +387 -0
- package/dist/tools/{getTaskFile.js → tasks/getTaskFile.js} +4 -4
- package/dist/tools/{getTaskStatus.d.ts → tasks/getTaskStatus.d.ts} +6 -1
- package/dist/tools/{getTaskStatus.js → tasks/getTaskStatus.js} +5 -5
- package/dist/tools/{getTaskStdoutTail.js → tasks/getTaskStdoutTail.js} +13 -11
- package/dist/tools/{getTaskSummary.js → tasks/getTaskSummary.js} +33 -26
- package/dist/tools/tasks/index.d.ts +18 -0
- package/dist/tools/tasks/index.js +18 -0
- package/dist/tools/tasks/killTask.d.ts +1 -0
- package/dist/tools/{listTasks.d.ts → tasks/listTasks.d.ts} +1 -1
- package/dist/tools/{listTasks.js → tasks/listTasks.js} +3 -3
- package/dist/tools/{reconcileTasks.d.ts → tasks/reconcileTasks.d.ts} +1 -1
- package/dist/tools/{reconcileTasks.js → tasks/reconcileTasks.js} +64 -66
- package/dist/tools/{retryTask.d.ts → tasks/retryTask.d.ts} +2 -2
- package/dist/tools/tasks/retryTask.js +60 -0
- package/dist/tools/{runTaskLoop.d.ts → tasks/runTaskLoop.d.ts} +6 -6
- package/dist/tools/{runTaskLoop.js → tasks/runTaskLoop.js} +59 -31
- package/dist/tools/tasks/runVerification.js +38 -0
- package/dist/tools/{taskLineage.js → tasks/taskLineage.js} +8 -7
- package/dist/tools/{taskOutputs.js → tasks/taskOutputs.js} +17 -16
- package/dist/tools/{androidDoctor.js → workspace/androidDoctor.js} +16 -10
- package/dist/tools/{applyPatch.d.ts → workspace/applyPatch.d.ts} +1 -1
- package/dist/tools/workspace/applyPatch.js +53 -0
- package/dist/tools/{discardWorktree.js → workspace/discardWorktree.js} +3 -3
- package/dist/tools/workspace/index.d.ts +10 -0
- package/dist/tools/workspace/index.js +10 -0
- package/dist/tools/{listAgents.d.ts → workspace/listAgents.d.ts} +5 -0
- package/dist/tools/{listAgents.js → workspace/listAgents.js} +8 -4
- package/dist/tools/{listWorkspace.js → workspace/listWorkspace.js} +3 -3
- package/dist/tools/{mergeWorktree.js → workspace/mergeWorktree.js} +3 -3
- package/dist/tools/{readWorkspaceFile.js → workspace/readWorkspaceFile.js} +8 -8
- package/dist/tools/{recommendAgentForTask.js → workspace/recommendAgentForTask.js} +3 -3
- package/dist/tools/{searchWorkspace.js → workspace/searchWorkspace.js} +5 -5
- package/dist/tools/{syncFile.d.ts → workspace/syncFile.d.ts} +1 -1
- package/dist/tools/workspace/syncFile.js +134 -0
- package/dist/utils/atomicFile.d.ts +7 -0
- package/dist/utils/atomicFile.js +48 -0
- package/dist/utils/boundedFile.d.ts +8 -0
- package/dist/utils/boundedFile.js +93 -0
- package/dist/utils/lockedJsonFile.d.ts +15 -0
- package/dist/utils/lockedJsonFile.js +224 -0
- package/dist/utils/platform.d.ts +11 -0
- package/dist/utils/platform.js +26 -0
- package/dist/utils/stableJson.d.ts +2 -0
- package/dist/utils/stableJson.js +12 -0
- package/dist/version.d.ts +3 -2
- package/dist/version.js +3 -2
- package/dist/watcherStatus.d.ts +2 -2
- package/dist/watcherStatus.js +18 -0
- package/docs/CODE_WIKI.md +1648 -0
- package/docs/agentseal-integration.md +150 -0
- package/docs/architecture.md +23 -0
- package/docs/assets/patchwarden-desktop-onboarding.png +0 -0
- package/docs/assets/patchwarden-oss-demo.gif +0 -0
- package/docs/control-center/README.md +4 -4
- package/docs/dashboard-overview.md +86 -0
- package/docs/demo.md +8 -0
- package/docs/desktop-app.md +175 -0
- package/docs/direct-session-workflow.md +98 -0
- package/docs/evidence-pack-schema.md +215 -0
- package/docs/lineage-evidence-pack-workflow.md +127 -0
- package/docs/mcp-inspector-testing.md +200 -0
- package/docs/open-source-application.md +168 -0
- package/docs/opencode-worker.md +151 -0
- package/docs/openhands-worker.md +181 -0
- package/docs/release-checklist.md +1 -1
- package/docs/release-evidence.md +82 -0
- package/docs/spec-kit-integration.md +131 -0
- package/docs/task-safe-review-workflow.md +98 -0
- package/docs/threat-model.md +97 -0
- package/docs/user-feedback.md +40 -0
- package/docs/why-patchwarden.md +110 -0
- package/examples/config.example.json +4 -2
- package/package.json +28 -11
- package/scripts/README.md +15 -6
- package/scripts/build.js +11 -0
- package/scripts/checks/brand-check.js +3 -0
- package/scripts/checks/build-output-check.js +37 -0
- package/scripts/checks/control-center-smoke.js +447 -6
- package/scripts/checks/control-smoke.js +19 -8
- package/scripts/checks/http-mcp-smoke.js +82 -4
- package/scripts/checks/lifecycle-smoke.js +39 -33
- package/scripts/checks/mcp-manifest-check.js +1 -1
- package/scripts/checks/mcp-smoke.js +30 -4
- package/scripts/checks/package-manifest-check.js +20 -7
- package/scripts/checks/unit-tests.js +3 -5
- package/scripts/checks/watcher-supervisor-smoke.js +9 -0
- package/scripts/control/get-patchwarden-health.ps1 +1 -1
- package/scripts/control/manage-patchwarden.ps1 +69 -4
- package/scripts/control/provision-patchwarden-tunnel.ps1 +127 -0
- package/scripts/control/run-background-supervisor.ps1 +41 -0
- package/scripts/control/start-patchwarden-tunnel.ps1 +126 -32
- package/scripts/generate-demo-gif.py +320 -0
- package/{PatchWarden-Control-Tray.cmd → scripts/launchers/PatchWarden-Control-Tray.cmd} +3 -3
- package/scripts/launchers/PatchWarden-Control.cmd +6 -0
- package/{PatchWarden-Desktop.cmd → scripts/launchers/PatchWarden-Desktop.cmd} +2 -2
- package/scripts/launchers/Restart-PatchWarden-Control.cmd +6 -0
- package/{Stop-PatchWarden.cmd → scripts/launchers/Stop-PatchWarden.cmd} +2 -2
- package/scripts/lib/clean-generated-output.js +11 -0
- package/scripts/lib/file-discovery.js +12 -0
- package/scripts/release/desktop-preflight.js +211 -0
- package/scripts/release/pack-clean.js +59 -14
- package/src/assessments/agentAssessor.ts +29 -15
- package/src/assessments/assessmentStore.ts +55 -43
- package/src/assessments/confirmCli.ts +5 -4
- package/src/config.ts +105 -11
- package/src/control/fileManager.ts +40 -0
- package/src/control/middleware/auth.ts +35 -0
- package/src/control/middleware/static.ts +84 -0
- package/src/control/routeTable.ts +301 -0
- package/src/control/routes/audit.ts +329 -0
- package/src/control/routes/evidence.ts +107 -0
- package/src/control/routes/lineage.ts +92 -0
- package/src/control/routes/policy.ts +81 -0
- package/src/control/routes/process.ts +505 -0
- package/src/control/routes/sessions.ts +314 -0
- package/src/control/routes/status.ts +405 -0
- package/src/control/routes/taskActions.ts +214 -0
- package/src/control/routes/tasks.ts +331 -0
- package/src/control/routes/workspace.ts +234 -0
- package/src/control/runtime.ts +508 -0
- package/src/control/server.ts +165 -0
- package/src/control/shared.ts +360 -0
- package/src/controlCenter.ts +7 -2347
- package/src/direct/directAudit.ts +17 -9
- package/src/direct/directGuards.ts +100 -51
- package/src/direct/directPatch.ts +95 -8
- package/src/direct/directSessionStore.ts +211 -55
- package/src/direct/directVerification.ts +9 -23
- package/src/doctor.ts +766 -492
- package/src/goal/acceptanceEngine.ts +1 -1
- package/src/goal/goalProgress.ts +17 -13
- package/src/goal/goalReport.ts +263 -0
- package/src/goal/goalStatus.ts +25 -3
- package/src/goal/goalStore.ts +241 -54
- package/src/goal/handoffExport.ts +6 -6
- package/src/goal/specKitImport.ts +355 -0
- package/src/goal/subgoalSync.ts +15 -10
- package/src/goal/worktreeManager.ts +139 -22
- package/src/httpServer.ts +130 -44
- package/src/index.ts +7 -4
- package/src/logging.ts +20 -4
- package/src/policy/projectPolicy.ts +5 -2
- package/src/release/releaseGate.ts +74 -27
- package/src/runner/agentInvocation.ts +126 -4
- package/src/runner/changeCapture.ts +342 -80
- package/src/runner/cli.ts +7 -6
- package/src/runner/postTaskCleanup.ts +55 -7
- package/src/runner/processSecurity.ts +433 -0
- package/src/runner/runTask.ts +441 -292
- package/src/runner/simpleProcess.ts +68 -33
- package/src/{taskProgress.ts → runner/taskProgress.ts} +3 -3
- package/src/{taskRuntime.ts → runner/taskRuntime.ts} +4 -3
- package/src/runner/taskStatusStore.ts +54 -0
- package/src/runner/watch.ts +290 -57
- package/src/security/contentRedaction.ts +31 -2
- package/src/security/discoveryTokenStore.ts +18 -4
- package/src/security/loopbackHost.ts +19 -0
- package/src/security/pathGuard.ts +35 -16
- package/src/security/planGuard.ts +2 -1
- package/src/security/runtimeGuard.ts +9 -6
- package/src/security/secretComparison.ts +13 -0
- package/src/security/sensitiveGuard.ts +27 -8
- package/src/security/toolInvocationGuard.ts +2 -2
- package/src/security/workspaceRootGuard.ts +53 -0
- package/src/smoke-test.ts +276 -273
- package/src/tools/catalog/index.ts +4 -0
- package/src/tools/{toolCatalog.ts → catalog/toolCatalog.ts} +3 -12
- package/src/tools/{toolRegistry.ts → catalog/toolRegistry.ts} +29 -16
- package/src/tools/definitions/toolDefs.ts +1264 -0
- package/src/tools/{auditSession.ts → diagnostics/auditSession.ts} +2 -2
- package/src/tools/{auditTask.ts → diagnostics/auditTask.ts} +196 -89
- package/src/tools/{healthCheck.ts → diagnostics/healthCheck.ts} +11 -11
- package/src/tools/diagnostics/index.ts +6 -0
- package/src/tools/{safeStatus.ts → diagnostics/safeStatus.ts} +7 -7
- package/src/tools/{safeViews.ts → diagnostics/safeViews.ts} +29 -19
- package/src/tools/{schemaDriftCheck.ts → diagnostics/schemaDriftCheck.ts} +3 -3
- package/src/tools/{createDirectSession.ts → direct/createDirectSession.ts} +9 -9
- package/src/tools/{finalizeDirectSession.ts → direct/finalizeDirectSession.ts} +11 -9
- package/src/tools/direct/index.ts +3 -0
- package/src/tools/{runDirectVerificationBundle.ts → direct/runDirectVerificationBundle.ts} +2 -2
- package/src/tools/{discoverTools.ts → discovery/discoverTools.ts} +6 -6
- package/src/tools/{explainTool.ts → discovery/explainTool.ts} +3 -3
- package/src/tools/discovery/index.ts +3 -0
- package/src/tools/{invokeDiscoveredTool.ts → discovery/invokeDiscoveredTool.ts} +7 -7
- package/src/tools/dispatch/coreDispatch.ts +379 -0
- package/src/tools/dispatch/diagnosticDispatch.ts +106 -0
- package/src/tools/dispatch/directDispatch.ts +168 -0
- package/src/tools/dispatch/goalDispatch.ts +128 -0
- package/src/tools/dispatch/releaseDispatch.ts +66 -0
- package/src/tools/dispatch/types.ts +24 -0
- package/src/tools/dispatch/validation.ts +78 -0
- package/src/tools/{getPlan.ts → goals/getPlan.ts} +4 -4
- package/src/tools/{goalSubgoalTask.ts → goals/goalSubgoalTask.ts} +43 -28
- package/src/tools/goals/index.ts +3 -0
- package/src/tools/{savePlan.ts → goals/savePlan.ts} +38 -8
- package/src/tools/registry.ts +54 -1858
- package/src/tools/{checkReleaseGate.ts → release/checkReleaseGate.ts} +3 -3
- package/src/tools/release/index.ts +2 -0
- package/src/tools/{releaseMode.ts → release/releaseMode.ts} +42 -24
- package/src/tools/tasks/cancelTask.ts +109 -0
- package/src/tools/{createTask.ts → tasks/createTask.ts} +56 -33
- package/src/tools/{diagnoseTask.ts → tasks/diagnoseTask.ts} +8 -8
- package/src/tools/tasks/evidencePack.ts +504 -0
- package/src/tools/{getTaskFile.ts → tasks/getTaskFile.ts} +4 -4
- package/src/tools/{getTaskStatus.ts → tasks/getTaskStatus.ts} +7 -5
- package/src/tools/{getTaskStdoutTail.ts → tasks/getTaskStdoutTail.ts} +13 -11
- package/src/tools/{getTaskSummary.ts → tasks/getTaskSummary.ts} +44 -33
- package/src/tools/tasks/index.ts +18 -0
- package/src/tools/{listTasks.ts → tasks/listTasks.ts} +4 -4
- package/src/tools/{reconcileTasks.ts → tasks/reconcileTasks.ts} +68 -66
- package/src/tools/tasks/retryTask.ts +69 -0
- package/src/tools/{runTaskLoop.ts → tasks/runTaskLoop.ts} +70 -35
- package/src/tools/{runVerification.ts → tasks/runVerification.ts} +6 -3
- package/src/tools/{taskLineage.ts → tasks/taskLineage.ts} +8 -7
- package/src/tools/{taskOutputs.ts → tasks/taskOutputs.ts} +27 -20
- package/src/tools/{androidDoctor.ts → workspace/androidDoctor.ts} +15 -10
- package/src/tools/{applyPatch.ts → workspace/applyPatch.ts} +38 -16
- package/src/tools/{discardWorktree.ts → workspace/discardWorktree.ts} +3 -3
- package/src/tools/workspace/index.ts +10 -0
- package/src/tools/{listAgents.ts → workspace/listAgents.ts} +11 -4
- package/src/tools/{listWorkspace.ts → workspace/listWorkspace.ts} +3 -3
- package/src/tools/{mergeWorktree.ts → workspace/mergeWorktree.ts} +3 -3
- package/src/tools/{readWorkspaceFile.ts → workspace/readWorkspaceFile.ts} +8 -8
- package/src/tools/{recommendAgentForTask.ts → workspace/recommendAgentForTask.ts} +3 -3
- package/src/tools/{searchWorkspace.ts → workspace/searchWorkspace.ts} +5 -5
- package/src/tools/workspace/syncFile.ts +292 -0
- package/src/utils/atomicFile.ts +58 -0
- package/src/utils/boundedFile.ts +116 -0
- package/src/utils/lockedJsonFile.ts +251 -0
- package/src/utils/platform.ts +31 -0
- package/src/utils/stableJson.ts +12 -0
- package/src/version.ts +3 -2
- package/src/watcherStatus.ts +19 -1
- package/ui/desktop-bootstrap.js +11 -0
- package/ui/desktop-bridge.js +36 -0
- package/ui/desktop.css +160 -0
- package/ui/getting-started.js +93 -0
- package/ui/i18n.js +484 -0
- package/ui/log-parser.js +30 -0
- package/ui/pages/audit.html +204 -3
- package/ui/pages/dashboard.html +937 -79
- package/ui/pages/direct-sessions.html +609 -60
- package/ui/pages/getting-started.html +43 -0
- package/ui/pages/logs.html +105 -22
- package/ui/pages/settings.html +101 -0
- package/ui/pages/task-detail.html +468 -438
- package/ui/pages/tasks.html +648 -65
- package/ui/pages/workspace.html +38 -1
- package/ui/settings.js +245 -0
- package/PatchWarden-Control.cmd +0 -6
- package/Restart-PatchWarden-Control.cmd +0 -6
- package/dist/test/unit/acceptance-engine.test.d.ts +0 -1
- package/dist/test/unit/acceptance-engine.test.js +0 -228
- package/dist/test/unit/agent-router.test.d.ts +0 -1
- package/dist/test/unit/agent-router.test.js +0 -287
- package/dist/test/unit/android-doctor.test.d.ts +0 -1
- package/dist/test/unit/android-doctor.test.js +0 -118
- package/dist/test/unit/audit-checks.test.d.ts +0 -1
- package/dist/test/unit/audit-checks.test.js +0 -350
- package/dist/test/unit/chinese-path.test.d.ts +0 -1
- package/dist/test/unit/chinese-path.test.js +0 -91
- package/dist/test/unit/command-guard.test.d.ts +0 -1
- package/dist/test/unit/command-guard.test.js +0 -160
- package/dist/test/unit/diagnose-task.test.d.ts +0 -1
- package/dist/test/unit/diagnose-task.test.js +0 -457
- package/dist/test/unit/direct-guards.test.d.ts +0 -1
- package/dist/test/unit/direct-guards.test.js +0 -213
- package/dist/test/unit/discovery-token-store.test.d.ts +0 -1
- package/dist/test/unit/discovery-token-store.test.js +0 -139
- package/dist/test/unit/evidence-pack.test.d.ts +0 -1
- package/dist/test/unit/evidence-pack.test.js +0 -130
- package/dist/test/unit/goal-graph.test.d.ts +0 -1
- package/dist/test/unit/goal-graph.test.js +0 -298
- package/dist/test/unit/goal-progress.test.d.ts +0 -1
- package/dist/test/unit/goal-progress.test.js +0 -381
- package/dist/test/unit/goal-status.test.d.ts +0 -1
- package/dist/test/unit/goal-status.test.js +0 -215
- package/dist/test/unit/goal-store.test.d.ts +0 -1
- package/dist/test/unit/goal-store.test.js +0 -253
- package/dist/test/unit/goal-subgoal-task.test.d.ts +0 -1
- package/dist/test/unit/goal-subgoal-task.test.js +0 -55
- package/dist/test/unit/goal-tools-registry.test.d.ts +0 -1
- package/dist/test/unit/goal-tools-registry.test.js +0 -190
- package/dist/test/unit/handoff-export.test.d.ts +0 -1
- package/dist/test/unit/handoff-export.test.js +0 -263
- package/dist/test/unit/invoke-discovered-tool.test.d.ts +0 -1
- package/dist/test/unit/invoke-discovered-tool.test.js +0 -167
- package/dist/test/unit/logging.test.d.ts +0 -1
- package/dist/test/unit/logging.test.js +0 -397
- package/dist/test/unit/path-guard.test.d.ts +0 -1
- package/dist/test/unit/path-guard.test.js +0 -109
- package/dist/test/unit/post-task-cleanup.test.d.ts +0 -1
- package/dist/test/unit/post-task-cleanup.test.js +0 -48
- package/dist/test/unit/project-policy-release-mode.test.d.ts +0 -1
- package/dist/test/unit/project-policy-release-mode.test.js +0 -125
- package/dist/test/unit/reconcile-tasks.test.d.ts +0 -1
- package/dist/test/unit/reconcile-tasks.test.js +0 -456
- package/dist/test/unit/release-gate.test.d.ts +0 -1
- package/dist/test/unit/release-gate.test.js +0 -242
- package/dist/test/unit/run-task-loop.test.d.ts +0 -1
- package/dist/test/unit/run-task-loop.test.js +0 -380
- package/dist/test/unit/safe-status.test.d.ts +0 -1
- package/dist/test/unit/safe-status.test.js +0 -165
- package/dist/test/unit/safe-views.test.d.ts +0 -1
- package/dist/test/unit/safe-views.test.js +0 -171
- package/dist/test/unit/schema-drift-check.test.d.ts +0 -1
- package/dist/test/unit/schema-drift-check.test.js +0 -176
- package/dist/test/unit/sensitive-guard.test.d.ts +0 -1
- package/dist/test/unit/sensitive-guard.test.js +0 -104
- package/dist/test/unit/subgoal-sync.test.d.ts +0 -1
- package/dist/test/unit/subgoal-sync.test.js +0 -183
- package/dist/test/unit/sync-file.test.d.ts +0 -1
- package/dist/test/unit/sync-file.test.js +0 -154
- package/dist/test/unit/tool-invocation-guard.test.d.ts +0 -1
- package/dist/test/unit/tool-invocation-guard.test.js +0 -432
- package/dist/test/unit/tool-usage-stats.test.d.ts +0 -1
- package/dist/test/unit/tool-usage-stats.test.js +0 -300
- package/dist/test/unit/toolSearch.test.d.ts +0 -1
- package/dist/test/unit/toolSearch.test.js +0 -571
- package/dist/test/unit/watcher-status.test.d.ts +0 -1
- package/dist/test/unit/watcher-status.test.js +0 -169
- package/dist/test/unit/worktree-manager.test.d.ts +0 -1
- package/dist/test/unit/worktree-manager.test.js +0 -176
- package/dist/tools/applyPatch.js +0 -41
- package/dist/tools/cancelTask.d.ts +0 -30
- package/dist/tools/cancelTask.js +0 -64
- package/dist/tools/evidencePack.js +0 -168
- package/dist/tools/finalizeDirectSession.js +0 -84
- package/dist/tools/goalSubgoalTask.js +0 -110
- package/dist/tools/killTask.d.ts +0 -15
- package/dist/tools/retryTask.js +0 -45
- package/dist/tools/runVerification.js +0 -36
- package/dist/tools/syncFile.js +0 -65
- package/docs/control-center/control-center-daily-driver.md +0 -211
- package/docs/control-center/control-center-mvp.md +0 -205
- package/docs/control-center/control-center-phase2.md +0 -159
- package/docs/release-v0.6.0.md +0 -71
- package/docs/release-v0.6.1.md +0 -75
- package/docs/release-v0.6.4.md +0 -45
- package/src/test/unit/acceptance-engine.test.ts +0 -261
- package/src/test/unit/agent-router.test.ts +0 -342
- package/src/test/unit/android-doctor.test.ts +0 -158
- package/src/test/unit/audit-checks.test.ts +0 -567
- package/src/test/unit/chinese-path.test.ts +0 -106
- package/src/test/unit/command-guard.test.ts +0 -221
- package/src/test/unit/diagnose-task.test.ts +0 -544
- package/src/test/unit/direct-guards.test.ts +0 -297
- package/src/test/unit/discovery-token-store.test.ts +0 -181
- package/src/test/unit/evidence-pack.test.ts +0 -142
- package/src/test/unit/goal-graph.test.ts +0 -347
- package/src/test/unit/goal-progress.test.ts +0 -538
- package/src/test/unit/goal-status.test.ts +0 -270
- package/src/test/unit/goal-store.test.ts +0 -318
- package/src/test/unit/goal-subgoal-task.test.ts +0 -72
- package/src/test/unit/goal-tools-registry.test.ts +0 -243
- package/src/test/unit/handoff-export.test.ts +0 -295
- package/src/test/unit/invoke-discovered-tool.test.ts +0 -216
- package/src/test/unit/logging.test.ts +0 -497
- package/src/test/unit/path-guard.test.ts +0 -150
- package/src/test/unit/post-task-cleanup.test.ts +0 -53
- package/src/test/unit/project-policy-release-mode.test.ts +0 -156
- package/src/test/unit/reconcile-tasks.test.ts +0 -551
- package/src/test/unit/release-gate.test.ts +0 -314
- package/src/test/unit/run-task-loop.test.ts +0 -425
- package/src/test/unit/safe-status.test.ts +0 -187
- package/src/test/unit/safe-views.test.ts +0 -184
- package/src/test/unit/schema-drift-check.test.ts +0 -260
- package/src/test/unit/sensitive-guard.test.ts +0 -124
- package/src/test/unit/subgoal-sync.test.ts +0 -236
- package/src/test/unit/sync-file.test.ts +0 -231
- package/src/test/unit/tool-invocation-guard.test.ts +0 -542
- package/src/test/unit/tool-usage-stats.test.ts +0 -384
- package/src/test/unit/toolSearch.test.ts +0 -756
- package/src/test/unit/watcher-status.test.ts +0 -190
- package/src/test/unit/worktree-manager.test.ts +0 -247
- package/src/tools/cancelTask.ts +0 -70
- package/src/tools/evidencePack.ts +0 -205
- package/src/tools/retryTask.ts +0 -53
- package/src/tools/syncFile.ts +0 -122
- /package/dist/tools/{toolCatalog.d.ts → catalog/toolCatalog.d.ts} +0 -0
- /package/dist/tools/{toolSearch.d.ts → catalog/toolSearch.d.ts} +0 -0
- /package/dist/tools/{toolSearch.js → catalog/toolSearch.js} +0 -0
- /package/dist/tools/{toolUsageStats.d.ts → catalog/toolUsageStats.d.ts} +0 -0
- /package/dist/tools/{toolUsageStats.js → catalog/toolUsageStats.js} +0 -0
- /package/dist/tools/{runDirectVerificationBundle.d.ts → direct/runDirectVerificationBundle.d.ts} +0 -0
- /package/dist/tools/{getPlan.d.ts → goals/getPlan.d.ts} +0 -0
- /package/dist/tools/{savePlan.d.ts → goals/savePlan.d.ts} +0 -0
- /package/dist/tools/{getTaskFile.d.ts → tasks/getTaskFile.d.ts} +0 -0
- /package/dist/tools/{getTaskProgress.d.ts → tasks/getTaskProgress.d.ts} +0 -0
- /package/dist/tools/{getTaskProgress.js → tasks/getTaskProgress.js} +0 -0
- /package/dist/tools/{getTaskStdoutTail.d.ts → tasks/getTaskStdoutTail.d.ts} +0 -0
- /package/dist/tools/{getTaskSummary.d.ts → tasks/getTaskSummary.d.ts} +0 -0
- /package/dist/tools/{killTask.js → tasks/killTask.js} +0 -0
- /package/dist/tools/{runVerification.d.ts → tasks/runVerification.d.ts} +0 -0
- /package/dist/tools/{taskLineage.d.ts → tasks/taskLineage.d.ts} +0 -0
- /package/dist/tools/{taskOutputs.d.ts → tasks/taskOutputs.d.ts} +0 -0
- /package/dist/tools/{waitForTask.d.ts → tasks/waitForTask.d.ts} +0 -0
- /package/dist/tools/{waitForTask.js → tasks/waitForTask.js} +0 -0
- /package/dist/tools/{androidDoctor.d.ts → workspace/androidDoctor.d.ts} +0 -0
- /package/dist/tools/{discardWorktree.d.ts → workspace/discardWorktree.d.ts} +0 -0
- /package/dist/tools/{listWorkspace.d.ts → workspace/listWorkspace.d.ts} +0 -0
- /package/dist/tools/{mergeWorktree.d.ts → workspace/mergeWorktree.d.ts} +0 -0
- /package/dist/tools/{readWorkspaceFile.d.ts → workspace/readWorkspaceFile.d.ts} +0 -0
- /package/dist/tools/{recommendAgentForTask.d.ts → workspace/recommendAgentForTask.d.ts} +0 -0
- /package/dist/tools/{searchWorkspace.d.ts → workspace/searchWorkspace.d.ts} +0 -0
- /package/src/tools/{toolSearch.ts → catalog/toolSearch.ts} +0 -0
- /package/src/tools/{toolUsageStats.ts → catalog/toolUsageStats.ts} +0 -0
- /package/src/tools/{getTaskProgress.ts → tasks/getTaskProgress.ts} +0 -0
- /package/src/tools/{killTask.ts → tasks/killTask.ts} +0 -0
- /package/src/tools/{waitForTask.ts → tasks/waitForTask.ts} +0 -0
|
@@ -1,6 +1,51 @@
|
|
|
1
1
|
import { execFileSync } from "node:child_process";
|
|
2
|
-
import { existsSync, readdirSync, rmSync
|
|
2
|
+
import { chmodSync, existsSync, lstatSync, readdirSync, rmSync } from "node:fs";
|
|
3
3
|
import { basename, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
4
|
+
import { platform } from "node:os";
|
|
5
|
+
import { buildGitEnvironment, resolveTrustedExecutable } from "./processSecurity.js";
|
|
6
|
+
import { atomicWriteJsonFileSync } from "../utils/atomicFile.js";
|
|
7
|
+
const isWindows = platform() === "win32";
|
|
8
|
+
/**
|
|
9
|
+
* Remove a file or directory, working around Node.js fs.rmSync issues on Windows
|
|
10
|
+
* where recursive directory deletion silently fails (Node v22+).
|
|
11
|
+
* On Windows, clears read-only attributes before one bounded native retry.
|
|
12
|
+
*/
|
|
13
|
+
function safeRemoveSync(targetPath) {
|
|
14
|
+
rmSync(targetPath, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 });
|
|
15
|
+
if (isWindows && existsSync(targetPath)) {
|
|
16
|
+
makeWritableSync(targetPath);
|
|
17
|
+
rmSync(targetPath, { recursive: true, force: true, maxRetries: 5, retryDelay: 150 });
|
|
18
|
+
}
|
|
19
|
+
if (existsSync(targetPath)) {
|
|
20
|
+
throw new Error(`Cleanup path still exists after bounded retries: ${targetPath}`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function makeWritableSync(targetPath) {
|
|
24
|
+
let stat;
|
|
25
|
+
try {
|
|
26
|
+
stat = lstatSync(targetPath);
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
if (stat.isSymbolicLink())
|
|
32
|
+
return;
|
|
33
|
+
try {
|
|
34
|
+
chmodSync(targetPath, stat.isDirectory() ? 0o700 : 0o600);
|
|
35
|
+
}
|
|
36
|
+
catch { /* best effort */ }
|
|
37
|
+
if (!stat.isDirectory())
|
|
38
|
+
return;
|
|
39
|
+
let entries;
|
|
40
|
+
try {
|
|
41
|
+
entries = readdirSync(targetPath);
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
for (const entry of entries)
|
|
47
|
+
makeWritableSync(join(targetPath, entry));
|
|
48
|
+
}
|
|
4
49
|
const EXCLUDED_DIRS = new Set([".git", ".patchwarden", ".venv", "node_modules", "samples", "docs"]);
|
|
5
50
|
const CLEANUP_DIRS = new Set(["__pycache__", "dist", "release_packages", "temp_files"]);
|
|
6
51
|
const CLEANUP_FILES = [/\.pyc$/i];
|
|
@@ -28,7 +73,7 @@ export function runPostTaskCleanup(repoPath, taskDir) {
|
|
|
28
73
|
continue;
|
|
29
74
|
}
|
|
30
75
|
try {
|
|
31
|
-
|
|
76
|
+
safeRemoveSync(candidate.path);
|
|
32
77
|
report.removed.push({ path: rel, reason: candidate.reason });
|
|
33
78
|
}
|
|
34
79
|
catch (error) {
|
|
@@ -39,7 +84,7 @@ export function runPostTaskCleanup(repoPath, taskDir) {
|
|
|
39
84
|
});
|
|
40
85
|
}
|
|
41
86
|
}
|
|
42
|
-
|
|
87
|
+
atomicWriteJsonFileSync(join(taskDir, "post-task-cleanup.json"), report);
|
|
43
88
|
return report;
|
|
44
89
|
}
|
|
45
90
|
function collectCandidates(root) {
|
|
@@ -85,10 +130,12 @@ function hasTrackedGitContent(root, rel) {
|
|
|
85
130
|
if (!isGitWorktree(root))
|
|
86
131
|
return false;
|
|
87
132
|
try {
|
|
88
|
-
const
|
|
133
|
+
const env = buildGitEnvironment(root);
|
|
134
|
+
const output = execFileSync(resolveTrustedExecutable("git", root, { pathValue: env.PATH }), ["ls-files", "--", rel], {
|
|
89
135
|
cwd: root,
|
|
90
136
|
encoding: "utf-8",
|
|
91
137
|
windowsHide: true,
|
|
138
|
+
env,
|
|
92
139
|
});
|
|
93
140
|
return output.trim().length > 0;
|
|
94
141
|
}
|
|
@@ -99,20 +146,24 @@ function hasTrackedGitContent(root, rel) {
|
|
|
99
146
|
function isIgnoredOrUntracked(root, rel) {
|
|
100
147
|
if (!isGitWorktree(root))
|
|
101
148
|
return true;
|
|
149
|
+
const env = buildGitEnvironment(root);
|
|
150
|
+
const git = resolveTrustedExecutable("git", root, { pathValue: env.PATH });
|
|
102
151
|
try {
|
|
103
|
-
execFileSync(
|
|
152
|
+
execFileSync(git, ["check-ignore", "-q", "--", rel], {
|
|
104
153
|
cwd: root,
|
|
105
154
|
stdio: "ignore",
|
|
106
155
|
windowsHide: true,
|
|
156
|
+
env,
|
|
107
157
|
});
|
|
108
158
|
return true;
|
|
109
159
|
}
|
|
110
160
|
catch {
|
|
111
161
|
try {
|
|
112
|
-
const output = execFileSync(
|
|
162
|
+
const output = execFileSync(git, ["ls-files", "--others", "--exclude-standard", "--", rel], {
|
|
113
163
|
cwd: root,
|
|
114
164
|
encoding: "utf-8",
|
|
115
165
|
windowsHide: true,
|
|
166
|
+
env,
|
|
116
167
|
});
|
|
117
168
|
return output.trim().length > 0 || !existsSync(resolve(root, rel));
|
|
118
169
|
}
|
|
@@ -123,10 +174,12 @@ function isIgnoredOrUntracked(root, rel) {
|
|
|
123
174
|
}
|
|
124
175
|
function isGitWorktree(root) {
|
|
125
176
|
try {
|
|
126
|
-
|
|
177
|
+
const env = buildGitEnvironment(root);
|
|
178
|
+
return execFileSync(resolveTrustedExecutable("git", root, { pathValue: env.PATH }), ["rev-parse", "--is-inside-work-tree"], {
|
|
127
179
|
cwd: root,
|
|
128
180
|
encoding: "utf-8",
|
|
129
181
|
windowsHide: true,
|
|
182
|
+
env,
|
|
130
183
|
}).trim() === "true";
|
|
131
184
|
}
|
|
132
185
|
catch {
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
export declare const DEFAULT_MAX_PROCESS_LOG_BYTES: number;
|
|
2
|
+
export interface ChildEnvironmentOptions {
|
|
3
|
+
cwd: string;
|
|
4
|
+
allowedNames?: readonly string[];
|
|
5
|
+
blockedNames?: readonly string[];
|
|
6
|
+
sourceEnvironment?: NodeJS.ProcessEnv;
|
|
7
|
+
platform?: NodeJS.Platform;
|
|
8
|
+
}
|
|
9
|
+
export interface ExecutableResolutionOptions {
|
|
10
|
+
platform?: NodeJS.Platform;
|
|
11
|
+
pathValue?: string;
|
|
12
|
+
pathExtValue?: string;
|
|
13
|
+
fileExists?: (path: string) => boolean;
|
|
14
|
+
}
|
|
15
|
+
export interface ResolvedProcessCommand {
|
|
16
|
+
command: string;
|
|
17
|
+
argsPrefix: string[];
|
|
18
|
+
}
|
|
19
|
+
export interface PreparedProcessCommand {
|
|
20
|
+
command: string;
|
|
21
|
+
args: string[];
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Build the environment for a task-owned child. Provider credentials are not
|
|
25
|
+
* ambient capability: an agent receives them only when their variable names
|
|
26
|
+
* are explicitly allow-listed in trusted local configuration.
|
|
27
|
+
*/
|
|
28
|
+
export declare function buildChildEnvironment(options: ChildEnvironmentOptions): NodeJS.ProcessEnv;
|
|
29
|
+
/** Build a non-interactive Git environment that disables repo-defined hooks and fsmonitor. */
|
|
30
|
+
export declare function buildGitEnvironment(cwd: string): NodeJS.ProcessEnv;
|
|
31
|
+
/** Resolve a Windows bare command before spawn so CreateProcess never searches cwd. */
|
|
32
|
+
export declare function resolveTrustedExecutable(command: string, cwd: string, options?: ExecutableResolutionOptions): string;
|
|
33
|
+
/**
|
|
34
|
+
* Resolve Windows package-manager shims to their JavaScript CLI entry point.
|
|
35
|
+
* This keeps npm/npx/pnpm execution shell-free while still supporting their
|
|
36
|
+
* normal .cmd installations.
|
|
37
|
+
*/
|
|
38
|
+
export declare function resolvePackageManagerInvocation(managerCommand: string, cwd: string, options?: ExecutableResolutionOptions): ResolvedProcessCommand;
|
|
39
|
+
/** Replace the one supported Windows cmd wrapper with a native Node CLI. */
|
|
40
|
+
export declare function prepareShellFreeCommand(command: string, args: readonly string[], cwd: string, options?: ExecutableResolutionOptions): PreparedProcessCommand;
|
|
41
|
+
/** Parse the intentionally simple allow-listed command grammar without a shell. */
|
|
42
|
+
export declare function resolveTrustedCommandLine(commandLine: string, cwd: string, options?: ExecutableResolutionOptions): ResolvedProcessCommand;
|
|
43
|
+
export declare function sanitizeTrustedPath(pathValue: string, cwd: string, platform?: NodeJS.Platform): string;
|
|
44
|
+
export declare function allowedEnvironmentValues(names: readonly string[] | undefined, sourceEnvironment?: NodeJS.ProcessEnv, platform?: NodeJS.Platform): string[];
|
|
45
|
+
export declare function redactProcessOutput(input: string, exactValues?: readonly string[]): string;
|
|
46
|
+
/** Captures complete process logs up to one auditable, redacted byte budget. */
|
|
47
|
+
export declare class SecureProcessLogCapture {
|
|
48
|
+
private readonly chunks;
|
|
49
|
+
private readonly maxBytes;
|
|
50
|
+
private readonly existingBytes;
|
|
51
|
+
private capturedBytes;
|
|
52
|
+
private truncatedPath;
|
|
53
|
+
constructor(paths: Array<string | undefined>, maxBytes?: number);
|
|
54
|
+
append(path: string | undefined, chunk: Buffer | string): void;
|
|
55
|
+
flush(exactValues?: readonly string[]): void;
|
|
56
|
+
}
|
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
import { appendFileSync, existsSync, statSync } from "node:fs";
|
|
2
|
+
import { delimiter, isAbsolute, relative, resolve, sep, win32 } from "node:path";
|
|
3
|
+
import { redactSensitiveContent } from "../security/contentRedaction.js";
|
|
4
|
+
const WINDOWS_BASE_ENVIRONMENT = [
|
|
5
|
+
"SystemRoot",
|
|
6
|
+
"WINDIR",
|
|
7
|
+
"ComSpec",
|
|
8
|
+
"PATHEXT",
|
|
9
|
+
"PATH",
|
|
10
|
+
"TEMP",
|
|
11
|
+
"TMP",
|
|
12
|
+
"USERPROFILE",
|
|
13
|
+
"HOMEDRIVE",
|
|
14
|
+
"HOMEPATH",
|
|
15
|
+
"APPDATA",
|
|
16
|
+
"LOCALAPPDATA",
|
|
17
|
+
"PROGRAMDATA",
|
|
18
|
+
"ProgramFiles",
|
|
19
|
+
"ProgramFiles(x86)",
|
|
20
|
+
"ProgramW6432",
|
|
21
|
+
"HOME",
|
|
22
|
+
"XDG_CONFIG_HOME",
|
|
23
|
+
"XDG_CACHE_HOME",
|
|
24
|
+
"XDG_DATA_HOME",
|
|
25
|
+
"JAVA_HOME",
|
|
26
|
+
"ANDROID_HOME",
|
|
27
|
+
"ANDROID_SDK_ROOT",
|
|
28
|
+
"CARGO_HOME",
|
|
29
|
+
"RUSTUP_HOME",
|
|
30
|
+
"GOPATH",
|
|
31
|
+
"GOROOT",
|
|
32
|
+
"PYTHONHOME",
|
|
33
|
+
"VIRTUAL_ENV",
|
|
34
|
+
];
|
|
35
|
+
const POSIX_BASE_ENVIRONMENT = [
|
|
36
|
+
"PATH",
|
|
37
|
+
"HOME",
|
|
38
|
+
"TMPDIR",
|
|
39
|
+
"USER",
|
|
40
|
+
"LOGNAME",
|
|
41
|
+
"SHELL",
|
|
42
|
+
"LANG",
|
|
43
|
+
"LC_ALL",
|
|
44
|
+
"LC_CTYPE",
|
|
45
|
+
"TERM",
|
|
46
|
+
"COLORTERM",
|
|
47
|
+
"NO_COLOR",
|
|
48
|
+
"FORCE_COLOR",
|
|
49
|
+
"XDG_CONFIG_HOME",
|
|
50
|
+
"XDG_CACHE_HOME",
|
|
51
|
+
"XDG_DATA_HOME",
|
|
52
|
+
];
|
|
53
|
+
const ALWAYS_BLOCKED_ENVIRONMENT = new Set([
|
|
54
|
+
"CONTROL_PLANE_API_KEY",
|
|
55
|
+
"PATCHWARDEN_OWNER_TOKEN",
|
|
56
|
+
]);
|
|
57
|
+
const WINDOWS_EXECUTABLE_EXTENSIONS = [".COM", ".EXE", ".BAT", ".CMD"];
|
|
58
|
+
const LOG_TRUNCATION_MARKER = "\n[PATCHWARDEN LOG TRUNCATED]\n";
|
|
59
|
+
export const DEFAULT_MAX_PROCESS_LOG_BYTES = 2 * 1024 * 1024;
|
|
60
|
+
/**
|
|
61
|
+
* Build the environment for a task-owned child. Provider credentials are not
|
|
62
|
+
* ambient capability: an agent receives them only when their variable names
|
|
63
|
+
* are explicitly allow-listed in trusted local configuration.
|
|
64
|
+
*/
|
|
65
|
+
export function buildChildEnvironment(options) {
|
|
66
|
+
const source = options.sourceEnvironment ?? process.env;
|
|
67
|
+
const platform = options.platform ?? process.platform;
|
|
68
|
+
const blocked = new Set([
|
|
69
|
+
...ALWAYS_BLOCKED_ENVIRONMENT,
|
|
70
|
+
...(options.blockedNames ?? []).map((name) => name.toUpperCase()),
|
|
71
|
+
]);
|
|
72
|
+
const requested = [
|
|
73
|
+
...(platform === "win32" ? WINDOWS_BASE_ENVIRONMENT : POSIX_BASE_ENVIRONMENT),
|
|
74
|
+
...(options.allowedNames ?? []),
|
|
75
|
+
];
|
|
76
|
+
const environment = {};
|
|
77
|
+
for (const name of requested) {
|
|
78
|
+
if (!isEnvironmentVariableName(name)) {
|
|
79
|
+
throw new Error(`Invalid child environment variable name: "${name}"`);
|
|
80
|
+
}
|
|
81
|
+
if (blocked.has(name.toUpperCase()))
|
|
82
|
+
continue;
|
|
83
|
+
const entry = findEnvironmentEntry(source, name, platform);
|
|
84
|
+
if (entry && entry[1] !== undefined)
|
|
85
|
+
environment[entry[0]] = entry[1];
|
|
86
|
+
}
|
|
87
|
+
if (platform === "win32") {
|
|
88
|
+
// The MCP SDK's safe default environment includes SystemRoot and PATH but
|
|
89
|
+
// intentionally omits ComSpec and PATHEXT. npm 10 can start in that
|
|
90
|
+
// environment, but its lifecycle shell then exits before running even a
|
|
91
|
+
// simple Node command. Reconstruct only the standard Windows process
|
|
92
|
+
// plumbing from the already inherited OS root; never copy extra ambient
|
|
93
|
+
// variables or task-controlled values.
|
|
94
|
+
const systemRoot = findEnvironmentEntry(environment, "SystemRoot", platform)?.[1]
|
|
95
|
+
?? findEnvironmentEntry(environment, "WINDIR", platform)?.[1];
|
|
96
|
+
if (!findEnvironmentEntry(environment, "ComSpec", platform) && systemRoot && win32.isAbsolute(systemRoot)) {
|
|
97
|
+
environment.ComSpec = win32.join(systemRoot, "System32", "cmd.exe");
|
|
98
|
+
}
|
|
99
|
+
if (!findEnvironmentEntry(environment, "PATHEXT", platform)) {
|
|
100
|
+
environment.PATHEXT = ".COM;.EXE;.BAT;.CMD";
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
const pathEntry = findEnvironmentEntry(environment, "PATH", platform);
|
|
104
|
+
if (pathEntry) {
|
|
105
|
+
environment[pathEntry[0]] = sanitizeTrustedPath(pathEntry[1] || "", options.cwd, platform);
|
|
106
|
+
}
|
|
107
|
+
return environment;
|
|
108
|
+
}
|
|
109
|
+
/** Build a non-interactive Git environment that disables repo-defined hooks and fsmonitor. */
|
|
110
|
+
export function buildGitEnvironment(cwd) {
|
|
111
|
+
const environment = buildChildEnvironment({ cwd });
|
|
112
|
+
environment.GIT_OPTIONAL_LOCKS = "0";
|
|
113
|
+
environment.GIT_TERMINAL_PROMPT = "0";
|
|
114
|
+
environment.GCM_INTERACTIVE = "Never";
|
|
115
|
+
environment.GIT_CONFIG_COUNT = "2";
|
|
116
|
+
environment.GIT_CONFIG_KEY_0 = "core.fsmonitor";
|
|
117
|
+
environment.GIT_CONFIG_VALUE_0 = "false";
|
|
118
|
+
environment.GIT_CONFIG_KEY_1 = "core.hooksPath";
|
|
119
|
+
environment.GIT_CONFIG_VALUE_1 = "/dev/null";
|
|
120
|
+
return environment;
|
|
121
|
+
}
|
|
122
|
+
/** Resolve a Windows bare command before spawn so CreateProcess never searches cwd. */
|
|
123
|
+
export function resolveTrustedExecutable(command, cwd, options = {}) {
|
|
124
|
+
const platform = options.platform ?? process.platform;
|
|
125
|
+
if (platform !== "win32" || win32.isAbsolute(command))
|
|
126
|
+
return command;
|
|
127
|
+
if (!command || /[\\/]/.test(command)) {
|
|
128
|
+
throw new Error(`Executable must be an absolute path or bare command name: "${command}"`);
|
|
129
|
+
}
|
|
130
|
+
const trustedPath = sanitizeTrustedPath(options.pathValue ?? process.env.PATH ?? "", cwd, platform);
|
|
131
|
+
const roots = trustedPath.split(win32.delimiter).filter(Boolean);
|
|
132
|
+
const extension = win32.extname(command);
|
|
133
|
+
const configuredExtensions = (options.pathExtValue ?? process.env.PATHEXT ?? "")
|
|
134
|
+
.split(win32.delimiter)
|
|
135
|
+
.map((value) => value.trim().toUpperCase())
|
|
136
|
+
.filter((value) => WINDOWS_EXECUTABLE_EXTENSIONS.includes(value));
|
|
137
|
+
const extensions = extension
|
|
138
|
+
? [""]
|
|
139
|
+
: [...new Set([...configuredExtensions, ...WINDOWS_EXECUTABLE_EXTENSIONS])];
|
|
140
|
+
const fileExists = options.fileExists ?? existsSync;
|
|
141
|
+
for (const root of roots) {
|
|
142
|
+
for (const suffix of extensions) {
|
|
143
|
+
const candidate = win32.resolve(root, `${command}${suffix}`);
|
|
144
|
+
if (isPathInside(candidate, cwd, "win32"))
|
|
145
|
+
continue;
|
|
146
|
+
if (fileExists(candidate))
|
|
147
|
+
return candidate;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
throw new Error(`Executable not found in trusted PATH: "${command}"`);
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Resolve Windows package-manager shims to their JavaScript CLI entry point.
|
|
154
|
+
* This keeps npm/npx/pnpm execution shell-free while still supporting their
|
|
155
|
+
* normal .cmd installations.
|
|
156
|
+
*/
|
|
157
|
+
export function resolvePackageManagerInvocation(managerCommand, cwd, options = {}) {
|
|
158
|
+
const platform = options.platform ?? process.platform;
|
|
159
|
+
if (platform !== "win32")
|
|
160
|
+
return { command: managerCommand, argsPrefix: [] };
|
|
161
|
+
const manager = win32.basename(managerCommand).replace(/\.(?:cmd|bat|exe|com)$/i, "").toLowerCase();
|
|
162
|
+
if (!new Set(["npm", "npx", "pnpm"]).has(manager)) {
|
|
163
|
+
throw new Error(`Unsupported package manager command: "${managerCommand}"`);
|
|
164
|
+
}
|
|
165
|
+
const resolved = resolveTrustedExecutable(managerCommand, cwd, options);
|
|
166
|
+
if (/\.(?:exe|com)$/i.test(resolved))
|
|
167
|
+
return { command: resolved, argsPrefix: [] };
|
|
168
|
+
const fileExists = options.fileExists ?? existsSync;
|
|
169
|
+
const roots = [];
|
|
170
|
+
let current = win32.dirname(resolved);
|
|
171
|
+
for (let depth = 0; depth < 5; depth++) {
|
|
172
|
+
roots.push(current);
|
|
173
|
+
const parent = win32.dirname(current);
|
|
174
|
+
if (parent === current)
|
|
175
|
+
break;
|
|
176
|
+
current = parent;
|
|
177
|
+
}
|
|
178
|
+
const relativeCliPaths = manager === "npm"
|
|
179
|
+
? ["node_modules\\npm\\bin\\npm-cli.js"]
|
|
180
|
+
: manager === "npx"
|
|
181
|
+
? ["node_modules\\npm\\bin\\npx-cli.js"]
|
|
182
|
+
: [
|
|
183
|
+
"node_modules\\pnpm\\bin\\pnpm.cjs",
|
|
184
|
+
"node_modules\\pnpm\\bin\\pnpm.mjs",
|
|
185
|
+
"node\\node_modules\\pnpm\\bin\\pnpm.cjs",
|
|
186
|
+
"node\\node_modules\\pnpm\\bin\\pnpm.mjs",
|
|
187
|
+
];
|
|
188
|
+
for (const root of roots) {
|
|
189
|
+
for (const relativeCli of relativeCliPaths) {
|
|
190
|
+
const cliPath = win32.join(root, relativeCli);
|
|
191
|
+
if (fileExists(cliPath))
|
|
192
|
+
return { command: process.execPath, argsPrefix: [cliPath] };
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
throw new Error(`Native CLI entry point not found for trusted package-manager shim: "${resolved}"`);
|
|
196
|
+
}
|
|
197
|
+
/** Replace the one supported Windows cmd wrapper with a native Node CLI. */
|
|
198
|
+
export function prepareShellFreeCommand(command, args, cwd, options = {}) {
|
|
199
|
+
const platform = options.platform ?? process.platform;
|
|
200
|
+
if (platform !== "win32") {
|
|
201
|
+
return { command, args: [...args] };
|
|
202
|
+
}
|
|
203
|
+
// Node cannot reliably execute a .cmd shim with shell:false on Windows.
|
|
204
|
+
// Resolve direct package-manager invocations to their JavaScript CLI too,
|
|
205
|
+
// so callers do not need to manufacture a cmd.exe /c wrapper.
|
|
206
|
+
if (/^(?:npm|npx|pnpm)(?:\.cmd)?$/i.test(win32.basename(command))) {
|
|
207
|
+
const resolved = resolvePackageManagerInvocation(command, cwd, options);
|
|
208
|
+
return { command: resolved.command, args: [...resolved.argsPrefix, ...args] };
|
|
209
|
+
}
|
|
210
|
+
if (!/^cmd(?:\.exe)?$/i.test(win32.basename(command))) {
|
|
211
|
+
return { command, args: [...args] };
|
|
212
|
+
}
|
|
213
|
+
const commandIndex = args.findIndex((arg) => /^\/c$/i.test(arg));
|
|
214
|
+
const prefix = commandIndex >= 0 ? args.slice(0, commandIndex) : [];
|
|
215
|
+
const manager = commandIndex >= 0 ? args[commandIndex + 1] : undefined;
|
|
216
|
+
if (commandIndex < 0
|
|
217
|
+
|| prefix.some((arg) => !/^\/(?:d|s)$/i.test(arg))
|
|
218
|
+
|| !manager
|
|
219
|
+
|| !/^(?:npm|npx|pnpm)(?:\.cmd)?$/i.test(manager)) {
|
|
220
|
+
throw new Error("Windows command shells are not allowed for task-owned child processes");
|
|
221
|
+
}
|
|
222
|
+
const resolved = resolvePackageManagerInvocation(manager, cwd, options);
|
|
223
|
+
return {
|
|
224
|
+
command: resolved.command,
|
|
225
|
+
args: [...resolved.argsPrefix, ...args.slice(commandIndex + 2)],
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
/** Parse the intentionally simple allow-listed command grammar without a shell. */
|
|
229
|
+
export function resolveTrustedCommandLine(commandLine, cwd, options = {}) {
|
|
230
|
+
const parts = commandLine.trim().split(/\s+/).filter(Boolean);
|
|
231
|
+
if (parts.length === 0)
|
|
232
|
+
throw new Error("Command must not be empty");
|
|
233
|
+
if (parts.some((part) => /[\x00-\x1f"'|&;<>()`$]/.test(part))) {
|
|
234
|
+
throw new Error(`Command contains unsupported shell syntax: "${commandLine}"`);
|
|
235
|
+
}
|
|
236
|
+
if (/^(?:npm|npx|pnpm)(?:\.cmd)?$/i.test(parts[0])) {
|
|
237
|
+
const manager = resolvePackageManagerInvocation(parts[0], cwd, options);
|
|
238
|
+
return { command: manager.command, argsPrefix: [...manager.argsPrefix, ...parts.slice(1)] };
|
|
239
|
+
}
|
|
240
|
+
return {
|
|
241
|
+
command: resolveTrustedExecutable(parts[0], cwd, options),
|
|
242
|
+
argsPrefix: parts.slice(1),
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
export function sanitizeTrustedPath(pathValue, cwd, platform = process.platform) {
|
|
246
|
+
const pathApi = platform === "win32" ? win32 : { delimiter, isAbsolute, relative, resolve, sep };
|
|
247
|
+
const seen = new Set();
|
|
248
|
+
const entries = [];
|
|
249
|
+
for (const rawEntry of pathValue.split(pathApi.delimiter)) {
|
|
250
|
+
const unquoted = rawEntry.trim().replace(/^"|"$/g, "");
|
|
251
|
+
if (!unquoted || !pathApi.isAbsolute(unquoted))
|
|
252
|
+
continue;
|
|
253
|
+
const absolute = pathApi.resolve(unquoted);
|
|
254
|
+
if (isPathInside(absolute, cwd, platform))
|
|
255
|
+
continue;
|
|
256
|
+
const comparable = platform === "win32" ? absolute.toLowerCase() : absolute;
|
|
257
|
+
if (seen.has(comparable))
|
|
258
|
+
continue;
|
|
259
|
+
seen.add(comparable);
|
|
260
|
+
entries.push(absolute);
|
|
261
|
+
}
|
|
262
|
+
return entries.join(pathApi.delimiter);
|
|
263
|
+
}
|
|
264
|
+
export function allowedEnvironmentValues(names, sourceEnvironment = process.env, platform = process.platform) {
|
|
265
|
+
const values = new Set();
|
|
266
|
+
for (const name of names ?? []) {
|
|
267
|
+
if (ALWAYS_BLOCKED_ENVIRONMENT.has(name.toUpperCase()))
|
|
268
|
+
continue;
|
|
269
|
+
const value = findEnvironmentEntry(sourceEnvironment, name, platform)?.[1];
|
|
270
|
+
if (value && Buffer.byteLength(value, "utf-8") >= 8)
|
|
271
|
+
values.add(value);
|
|
272
|
+
}
|
|
273
|
+
return [...values].sort((left, right) => right.length - left.length);
|
|
274
|
+
}
|
|
275
|
+
export function redactProcessOutput(input, exactValues = []) {
|
|
276
|
+
let content = redactSensitiveContent(input).content;
|
|
277
|
+
for (const value of exactValues) {
|
|
278
|
+
if (value)
|
|
279
|
+
content = content.split(value).join("[REDACTED ENV VALUE]");
|
|
280
|
+
}
|
|
281
|
+
return content;
|
|
282
|
+
}
|
|
283
|
+
/** Captures complete process logs up to one auditable, redacted byte budget. */
|
|
284
|
+
export class SecureProcessLogCapture {
|
|
285
|
+
chunks = new Map();
|
|
286
|
+
maxBytes;
|
|
287
|
+
existingBytes;
|
|
288
|
+
capturedBytes = 0;
|
|
289
|
+
truncatedPath = null;
|
|
290
|
+
constructor(paths, maxBytes = DEFAULT_MAX_PROCESS_LOG_BYTES) {
|
|
291
|
+
if (!Number.isInteger(maxBytes) || maxBytes <= 0) {
|
|
292
|
+
throw new Error("maxLogBytes must be a positive integer");
|
|
293
|
+
}
|
|
294
|
+
this.maxBytes = maxBytes;
|
|
295
|
+
const uniquePaths = [...new Set(paths.filter((path) => Boolean(path)))];
|
|
296
|
+
this.existingBytes = uniquePaths.reduce((total, path) => total + fileSize(path), 0);
|
|
297
|
+
}
|
|
298
|
+
append(path, chunk) {
|
|
299
|
+
if (!path)
|
|
300
|
+
return;
|
|
301
|
+
const data = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk, "utf-8");
|
|
302
|
+
const remaining = Math.max(0, this.maxBytes - this.existingBytes - this.capturedBytes);
|
|
303
|
+
const accepted = data.subarray(0, remaining);
|
|
304
|
+
if (accepted.length > 0) {
|
|
305
|
+
const chunks = this.chunks.get(path) ?? [];
|
|
306
|
+
chunks.push(accepted);
|
|
307
|
+
this.chunks.set(path, chunks);
|
|
308
|
+
this.capturedBytes += accepted.length;
|
|
309
|
+
}
|
|
310
|
+
if (accepted.length < data.length)
|
|
311
|
+
this.truncatedPath = path;
|
|
312
|
+
}
|
|
313
|
+
flush(exactValues = []) {
|
|
314
|
+
if (this.chunks.size === 0 && !this.truncatedPath)
|
|
315
|
+
return;
|
|
316
|
+
const remaining = Math.max(0, this.maxBytes - this.existingBytes);
|
|
317
|
+
const entries = [...this.chunks.entries()];
|
|
318
|
+
if (this.truncatedPath && !this.chunks.has(this.truncatedPath)) {
|
|
319
|
+
entries.push([this.truncatedPath, []]);
|
|
320
|
+
}
|
|
321
|
+
const markerBudget = this.truncatedPath
|
|
322
|
+
? Math.min(remaining, Buffer.byteLength(LOG_TRUNCATION_MARKER, "utf-8"))
|
|
323
|
+
: 0;
|
|
324
|
+
let contentRemaining = remaining - markerBudget;
|
|
325
|
+
for (const [path, chunks] of entries) {
|
|
326
|
+
const redacted = redactProcessOutput(Buffer.concat(chunks).toString("utf-8"), exactValues);
|
|
327
|
+
const content = utf8Prefix(redacted, contentRemaining);
|
|
328
|
+
contentRemaining -= Buffer.byteLength(content, "utf-8");
|
|
329
|
+
const marker = path === this.truncatedPath
|
|
330
|
+
? utf8Prefix(LOG_TRUNCATION_MARKER, markerBudget)
|
|
331
|
+
: "";
|
|
332
|
+
const output = content + marker;
|
|
333
|
+
if (output) {
|
|
334
|
+
try {
|
|
335
|
+
appendFileSync(path, output, "utf-8");
|
|
336
|
+
}
|
|
337
|
+
catch { /* evidence logging is best effort */ }
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
function findEnvironmentEntry(environment, name, platform) {
|
|
343
|
+
if (platform !== "win32") {
|
|
344
|
+
return Object.prototype.hasOwnProperty.call(environment, name) ? [name, environment[name]] : undefined;
|
|
345
|
+
}
|
|
346
|
+
const match = Object.keys(environment).find((key) => key.toUpperCase() === name.toUpperCase());
|
|
347
|
+
return match ? [match, environment[match]] : undefined;
|
|
348
|
+
}
|
|
349
|
+
function isEnvironmentVariableName(name) {
|
|
350
|
+
return typeof name === "string" && name.length > 0 && !/[=\x00]/.test(name);
|
|
351
|
+
}
|
|
352
|
+
function isPathInside(candidate, parent, platform) {
|
|
353
|
+
const pathApi = platform === "win32" ? win32 : { relative, isAbsolute, sep };
|
|
354
|
+
const rel = pathApi.relative(parent, candidate);
|
|
355
|
+
return rel === "" || (rel !== ".." && !rel.startsWith(`..${pathApi.sep}`) && !pathApi.isAbsolute(rel));
|
|
356
|
+
}
|
|
357
|
+
function fileSize(path) {
|
|
358
|
+
try {
|
|
359
|
+
return statSync(path).size;
|
|
360
|
+
}
|
|
361
|
+
catch {
|
|
362
|
+
return 0;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
function utf8Prefix(value, maxBytes) {
|
|
366
|
+
const encoded = Buffer.from(value, "utf-8");
|
|
367
|
+
if (encoded.length <= maxBytes)
|
|
368
|
+
return value;
|
|
369
|
+
let prefix = encoded.subarray(0, maxBytes).toString("utf-8").replace(/\uFFFD$/u, "");
|
|
370
|
+
while (Buffer.byteLength(prefix, "utf-8") > maxBytes)
|
|
371
|
+
prefix = prefix.slice(0, -1);
|
|
372
|
+
return prefix;
|
|
373
|
+
}
|
package/dist/runner/runTask.d.ts
CHANGED