patchwarden 1.1.0 → 1.5.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/README.en.md +83 -8
- package/README.md +78 -10
- package/dist/assessments/agentAssessor.d.ts +1 -1
- package/dist/assessments/agentAssessor.js +3 -3
- package/dist/assessments/assessmentStore.d.ts +1 -1
- package/dist/assessments/assessmentStore.js +2 -2
- package/dist/assessments/confirmCli.js +5 -4
- package/dist/config.d.ts +7 -0
- package/dist/config.js +34 -0
- package/dist/control/middleware/auth.d.ts +10 -0
- package/dist/control/middleware/auth.js +8 -0
- package/dist/control/middleware/static.d.ts +3 -0
- package/dist/control/middleware/static.js +65 -0
- package/dist/control/routes/audit.d.ts +15 -0
- package/dist/control/routes/audit.js +277 -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 +5 -0
- package/dist/control/routes/process.js +200 -0
- package/dist/control/routes/sessions.d.ts +22 -0
- package/dist/control/routes/sessions.js +224 -0
- package/dist/control/routes/status.d.ts +6 -0
- package/dist/control/routes/status.js +250 -0
- package/dist/control/routes/taskActions.d.ts +21 -0
- package/dist/control/routes/taskActions.js +233 -0
- package/dist/control/routes/tasks.d.ts +20 -0
- package/dist/control/routes/tasks.js +310 -0
- package/dist/control/routes/workspace.d.ts +15 -0
- package/dist/control/routes/workspace.js +193 -0
- package/dist/control/runtime.d.ts +91 -0
- package/dist/control/runtime.js +392 -0
- package/dist/control/server.d.ts +13 -0
- package/dist/control/server.js +479 -0
- package/dist/control/shared.d.ts +35 -0
- package/dist/control/shared.js +288 -0
- package/dist/controlCenter.d.ts +6 -0
- package/dist/controlCenter.js +7 -2001
- package/dist/direct/directGuards.js +30 -8
- package/dist/direct/directSessionStore.d.ts +2 -0
- package/dist/direct/directVerification.js +7 -0
- package/dist/doctor.d.ts +18 -1
- package/dist/doctor.js +579 -348
- package/dist/goal/goalReport.d.ts +54 -0
- package/dist/goal/goalReport.js +204 -0
- package/dist/goal/goalStatus.d.ts +6 -0
- package/dist/goal/specKitImport.d.ts +63 -0
- package/dist/goal/specKitImport.js +220 -0
- package/dist/goal/subgoalSync.js +2 -1
- package/dist/httpServer.js +15 -12
- package/dist/index.js +7 -4
- package/dist/logging.d.ts +7 -1
- package/dist/logging.js +8 -0
- package/dist/policy/projectPolicy.d.ts +55 -0
- package/dist/policy/projectPolicy.js +286 -0
- package/dist/runner/changeCapture.d.ts +3 -3
- package/dist/runner/changeCapture.js +63 -39
- package/dist/runner/cli.js +7 -6
- package/dist/runner/postTaskCleanup.js +26 -2
- package/dist/runner/runTask.js +245 -221
- package/dist/runner/simpleProcess.js +4 -4
- package/dist/runner/watch.js +17 -14
- package/dist/security/contentRedaction.d.ts +6 -0
- package/dist/security/contentRedaction.js +22 -0
- package/dist/smoke-test.js +261 -255
- package/dist/test/unit/apply-patch.test.d.ts +1 -0
- package/dist/test/unit/apply-patch.test.js +225 -0
- package/dist/test/unit/create-task.test.d.ts +1 -0
- package/dist/test/unit/create-task.test.js +197 -0
- package/dist/test/unit/direct-guards.test.js +124 -9
- package/dist/test/unit/evidence-pack.test.d.ts +1 -0
- package/dist/test/unit/evidence-pack.test.js +224 -0
- package/dist/test/unit/get-task-status.test.d.ts +1 -0
- package/dist/test/unit/get-task-status.test.js +174 -0
- package/dist/test/unit/get-task-summary.test.d.ts +1 -0
- package/dist/test/unit/get-task-summary.test.js +146 -0
- package/dist/test/unit/goal-report.test.d.ts +1 -0
- package/dist/test/unit/goal-report.test.js +159 -0
- package/dist/test/unit/goal-subgoal-task.test.js +6 -6
- package/dist/test/unit/goal-tools-registry.test.js +6 -4
- package/dist/test/unit/path-guard.test.js +24 -0
- package/dist/test/unit/project-policy-release-mode.test.d.ts +1 -0
- package/dist/test/unit/project-policy-release-mode.test.js +125 -0
- package/dist/test/unit/run-task-loop.test.d.ts +1 -0
- package/dist/test/unit/run-task-loop.test.js +380 -0
- package/dist/test/unit/schema-drift-check.test.js +10 -9
- package/dist/test/unit/spec-kit-import.test.d.ts +1 -0
- package/dist/test/unit/spec-kit-import.test.js +341 -0
- package/dist/test/unit/wait-for-task.test.d.ts +1 -0
- package/dist/test/unit/wait-for-task.test.js +144 -0
- package/dist/tools/auditTask.d.ts +8 -63
- package/dist/tools/auditTask.js +12 -8
- package/dist/tools/createDirectSession.d.ts +1 -1
- package/dist/tools/createDirectSession.js +2 -2
- package/dist/tools/createTask.d.ts +2 -2
- package/dist/tools/createTask.js +4 -4
- package/dist/tools/dispatch/coreDispatch.d.ts +9 -0
- package/dist/tools/dispatch/coreDispatch.js +282 -0
- package/dist/tools/dispatch/diagnosticDispatch.d.ts +14 -0
- package/dist/tools/dispatch/diagnosticDispatch.js +78 -0
- package/dist/tools/dispatch/directDispatch.d.ts +8 -0
- package/dist/tools/dispatch/directDispatch.js +115 -0
- package/dist/tools/dispatch/goalDispatch.d.ts +8 -0
- package/dist/tools/dispatch/goalDispatch.js +91 -0
- package/dist/tools/dispatch/releaseDispatch.d.ts +8 -0
- package/dist/tools/dispatch/releaseDispatch.js +45 -0
- package/dist/tools/dispatch/types.d.ts +23 -0
- package/dist/tools/dispatch/types.js +15 -0
- package/dist/tools/evidencePack.d.ts +45 -0
- package/dist/tools/evidencePack.js +375 -0
- package/dist/tools/finalizeDirectSession.d.ts +1 -1
- package/dist/tools/finalizeDirectSession.js +3 -3
- package/dist/tools/goalSubgoalTask.d.ts +1 -1
- package/dist/tools/goalSubgoalTask.js +2 -2
- package/dist/tools/healthCheck.js +3 -3
- package/dist/tools/recommendAgentForTask.d.ts +19 -0
- package/dist/tools/recommendAgentForTask.js +56 -0
- package/dist/tools/registry.d.ts +3 -3
- package/dist/tools/registry.js +333 -402
- package/dist/tools/releaseMode.d.ts +50 -0
- package/dist/tools/releaseMode.js +370 -0
- package/dist/tools/retryTask.d.ts +2 -2
- package/dist/tools/retryTask.js +2 -2
- package/dist/tools/runDirectVerificationBundle.d.ts +26 -0
- package/dist/tools/runDirectVerificationBundle.js +64 -0
- package/dist/tools/runTaskLoop.d.ts +57 -0
- package/dist/tools/runTaskLoop.js +417 -0
- package/dist/tools/runVerification.d.ts +4 -0
- package/dist/tools/runVerification.js +4 -0
- package/dist/tools/safeViews.d.ts +8 -2
- package/dist/tools/safeViews.js +4 -2
- package/dist/tools/taskLineage.d.ts +91 -0
- package/dist/tools/taskLineage.js +175 -0
- package/dist/tools/toolCatalog.d.ts +2 -2
- package/dist/tools/toolCatalog.js +6 -0
- package/dist/tools/toolRegistry.js +132 -0
- package/dist/version.d.ts +2 -2
- package/dist/version.js +2 -2
- package/docs/CODE_WIKI.md +983 -0
- package/docs/agentseal-integration.md +150 -0
- package/docs/architecture.md +63 -0
- package/docs/assets/patchwarden-oss-demo.gif +0 -0
- package/docs/chatgpt-usage.md +31 -0
- package/docs/control-center/README.md +9 -0
- package/docs/dashboard-overview.md +86 -0
- package/docs/demo.md +8 -0
- package/docs/direct-session-workflow.md +98 -0
- package/docs/evidence-pack-schema.md +215 -0
- package/docs/execution-plan-2026-07-09.md +315 -0
- package/docs/lineage-evidence-pack-workflow.md +127 -0
- package/docs/mcp-inspector-testing.md +200 -0
- package/docs/open-source-application.md +162 -0
- package/docs/opencode-worker.md +151 -0
- package/docs/openhands-worker.md +181 -0
- package/docs/release-evidence.md +72 -0
- package/docs/roadmap-execution-and-acceptance.md +365 -0
- package/docs/spec-kit-integration.md +131 -0
- package/docs/task-safe-review-workflow.md +98 -0
- package/docs/threat-model.md +79 -0
- package/docs/user-feedback.md +40 -0
- package/docs/why-patchwarden.md +110 -0
- package/package.json +3 -3
- package/scripts/checks/control-center-smoke.js +443 -0
- package/scripts/checks/control-smoke.js +2 -2
- package/scripts/checks/lifecycle-smoke.js +29 -23
- package/scripts/checks/mcp-manifest-check.js +12 -0
- package/scripts/checks/mcp-smoke.js +33 -7
- package/scripts/checks/watcher-supervisor-smoke.js +1 -1
- package/scripts/generate-demo-gif.py +320 -0
- package/src/assessments/agentAssessor.ts +3 -3
- package/src/assessments/assessmentStore.ts +2 -2
- package/src/assessments/confirmCli.ts +5 -4
- package/src/config.ts +37 -0
- package/src/control/middleware/auth.ts +17 -0
- package/src/control/middleware/static.ts +71 -0
- package/src/control/routes/audit.ts +321 -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 +204 -0
- package/src/control/routes/sessions.ts +251 -0
- package/src/control/routes/status.ts +325 -0
- package/src/control/routes/taskActions.ts +248 -0
- package/src/control/routes/tasks.ts +323 -0
- package/src/control/routes/workspace.ts +203 -0
- package/src/control/runtime.ts +472 -0
- package/src/control/server.ts +471 -0
- package/src/control/shared.ts +294 -0
- package/src/controlCenter.ts +7 -2150
- package/src/direct/directGuards.ts +28 -7
- package/src/direct/directSessionStore.ts +2 -0
- package/src/direct/directVerification.ts +7 -0
- package/src/doctor.ts +741 -481
- package/src/goal/goalReport.ts +271 -0
- package/src/goal/goalStatus.ts +6 -0
- package/src/goal/specKitImport.ts +355 -0
- package/src/goal/subgoalSync.ts +4 -2
- package/src/httpServer.ts +17 -14
- package/src/index.ts +7 -4
- package/src/logging.ts +10 -1
- package/src/policy/projectPolicy.ts +344 -0
- package/src/runner/changeCapture.ts +70 -42
- package/src/runner/cli.ts +7 -6
- package/src/runner/postTaskCleanup.ts +26 -2
- package/src/runner/runTask.ts +325 -223
- package/src/runner/simpleProcess.ts +4 -4
- package/src/runner/watch.ts +17 -14
- package/src/security/contentRedaction.ts +29 -0
- package/src/smoke-test.ts +254 -252
- package/src/test/unit/apply-patch.test.ts +293 -0
- package/src/test/unit/create-task.test.ts +255 -0
- package/src/test/unit/direct-guards.test.ts +178 -8
- package/src/test/unit/evidence-pack.test.ts +251 -0
- package/src/test/unit/get-task-status.test.ts +203 -0
- package/src/test/unit/get-task-summary.test.ts +173 -0
- package/src/test/unit/goal-report.test.ts +189 -0
- package/src/test/unit/goal-subgoal-task.test.ts +6 -6
- package/src/test/unit/goal-tools-registry.test.ts +7 -5
- package/src/test/unit/path-guard.test.ts +30 -0
- package/src/test/unit/project-policy-release-mode.test.ts +156 -0
- package/src/test/unit/run-task-loop.test.ts +425 -0
- package/src/test/unit/schema-drift-check.test.ts +11 -9
- package/src/test/unit/spec-kit-import.test.ts +429 -0
- package/src/test/unit/wait-for-task.test.ts +176 -0
- package/src/tools/auditTask.ts +99 -59
- package/src/tools/createDirectSession.ts +3 -3
- package/src/tools/createTask.ts +7 -7
- package/src/tools/dispatch/coreDispatch.ts +374 -0
- package/src/tools/dispatch/diagnosticDispatch.ts +101 -0
- package/src/tools/dispatch/directDispatch.ts +167 -0
- package/src/tools/dispatch/goalDispatch.ts +127 -0
- package/src/tools/dispatch/releaseDispatch.ts +65 -0
- package/src/tools/dispatch/types.ts +24 -0
- package/src/tools/evidencePack.ts +490 -0
- package/src/tools/finalizeDirectSession.ts +4 -4
- package/src/tools/goalSubgoalTask.ts +2 -2
- package/src/tools/healthCheck.ts +3 -3
- package/src/tools/listWorkspace.ts +71 -71
- package/src/tools/recommendAgentForTask.ts +79 -0
- package/src/tools/registry.ts +352 -509
- package/src/tools/releaseMode.ts +450 -0
- package/src/tools/retryTask.ts +2 -2
- package/src/tools/runDirectVerificationBundle.ts +98 -0
- package/src/tools/runTaskLoop.ts +526 -0
- package/src/tools/runVerification.ts +8 -0
- package/src/tools/safeViews.ts +4 -2
- package/src/tools/taskLineage.ts +300 -0
- package/src/tools/toolCatalog.ts +6 -0
- package/src/tools/toolRegistry.ts +132 -0
- package/src/version.ts +2 -2
- package/ui/pages/audit.html +192 -3
- package/ui/pages/dashboard.html +1070 -14
- package/ui/pages/direct-sessions.html +505 -53
- package/ui/pages/task-detail.html +456 -438
- package/ui/pages/tasks.html +598 -61
package/README.en.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
[](https://nodejs.org/)
|
|
9
9
|
[](LICENSE)
|
|
10
10
|
|
|
11
|
-
Current source version: **v1.1
|
|
11
|
+
Current source version: **v1.5.1**. See the
|
|
12
12
|
[CHANGELOG](CHANGELOG.md), [migration guide](docs/migration-from-safe-bifrost.md), and
|
|
13
13
|
[release checklist](docs/release-checklist.md). Verify GitHub Release / npm publication separately before release.
|
|
14
14
|
|
|
@@ -46,6 +46,7 @@ independent verification evidence.
|
|
|
46
46
|
- [HTTP MCP mode](#http-mcp-mode)
|
|
47
47
|
- [Diagnostics and health checks](#diagnostics-and-health-checks)
|
|
48
48
|
- [Lessons learned and troubleshooting](#lessons-learned-and-troubleshooting)
|
|
49
|
+
- [Ecosystem guides](#ecosystem-guides)
|
|
49
50
|
- [Security boundaries and local data](#security-boundaries-and-local-data)
|
|
50
51
|
- [Upgrading and migration](#upgrading-and-migration)
|
|
51
52
|
- [Development and release verification](#development-and-release-verification)
|
|
@@ -493,7 +494,7 @@ PatchWarden.cmd start core
|
|
|
493
494
|
The launcher:
|
|
494
495
|
|
|
495
496
|
- Builds `dist/index.js` if it is missing.
|
|
496
|
-
- Verifies v1.
|
|
497
|
+
- Verifies v1.5.0, the fixed 26-tool `chatgpt_core` catalog, and its schema
|
|
497
498
|
manifest.
|
|
498
499
|
- Reads or prompts for the Tunnel ID.
|
|
499
500
|
- Reads or prompts for the runtime API key.
|
|
@@ -845,6 +846,31 @@ It stops only this project's launchers and Watcher plus `tunnel-client.exe`
|
|
|
845
846
|
processes that exactly match the selected profile. It does not globally
|
|
846
847
|
terminate unrelated PatchWarden, OpenCode, or Codex instances.
|
|
847
848
|
|
|
849
|
+
## Dashboard pages and recommended workflow
|
|
850
|
+
|
|
851
|
+
The PatchWarden Dashboard (Control Center) provides these main pages:
|
|
852
|
+
|
|
853
|
+
- **Dashboard**: System overview, including Repo selector, Health Score, service status, Release card, Project Policy, Lineage, Evidence Pack, stale task hints, recent task list, and system status (with Copy diagnostics).
|
|
854
|
+
- **Tasks**: Task list, filterable by repo_path / status / acceptance_status / warning type / agent / date range. Each row offers safe_result / safe_audit / safe_test_summary / safe_diff_summary quick actions.
|
|
855
|
+
- **Task Detail**: Defaults to a safe summary (safe_result / safe_test_summary / safe_diff_summary / safe_audit). Full result / diff / test log live in a collapsed advanced section and load on demand.
|
|
856
|
+
- **Direct Sessions**: Grouped by active / finalized / audited / expired, with safe_direct_summary / safe_finalize_direct_session / safe_audit_direct_session quick actions.
|
|
857
|
+
- **Audit / Warnings**: Aggregated by warning type, showing affected tasks / severity / recommended action.
|
|
858
|
+
- **Workspace**: First-level workspace directories and project list.
|
|
859
|
+
- **Logs**: Tails of Core / Direct / Watcher / Control Center logs.
|
|
860
|
+
|
|
861
|
+
Recommended workflow:
|
|
862
|
+
|
|
863
|
+
1. Select the target repo at the top of the Dashboard.
|
|
864
|
+
2. Check the Health Score to confirm system health.
|
|
865
|
+
3. Click safe_result on a recent task row to view the task summary.
|
|
866
|
+
4. Open Task Detail for safe-first acceptance; expand the advanced section only when you need the full logs.
|
|
867
|
+
5. Use Lineage Detail to inspect why a run_task_loop succeeded or failed.
|
|
868
|
+
6. Export the Evidence Pack after acceptance.
|
|
869
|
+
7. Use Direct sessions for independent verification, then finalize + audit.
|
|
870
|
+
8. When something goes wrong, click Copy diagnostics and paste the output to ChatGPT / Codex / opencode for triage.
|
|
871
|
+
|
|
872
|
+
> See [docs/dashboard-overview.md](docs/dashboard-overview.md), [docs/task-safe-review-workflow.md](docs/task-safe-review-workflow.md), [docs/lineage-evidence-pack-workflow.md](docs/lineage-evidence-pack-workflow.md), and [docs/direct-session-workflow.md](docs/direct-session-workflow.md) for details.
|
|
873
|
+
|
|
848
874
|
## Lessons learned and troubleshooting
|
|
849
875
|
|
|
850
876
|
### Quick reference
|
|
@@ -930,10 +956,12 @@ names.
|
|
|
930
956
|
|
|
931
957
|
## MCP tools and profiles
|
|
932
958
|
|
|
933
|
-
`chatgpt_core` is the fixed
|
|
959
|
+
`chatgpt_core` is the fixed 26-tool profile used by the ChatGPT tunnel:
|
|
934
960
|
|
|
935
961
|
`health_check`, `list_agents`, `list_workspace`,
|
|
936
|
-
`read_workspace_file`, `save_plan`, `create_task`,
|
|
962
|
+
`read_workspace_file`, `save_plan`, `create_task`, `run_task_loop`,
|
|
963
|
+
`recommend_agent_for_task`, `get_task_lineage`, `export_task_evidence_pack`,
|
|
964
|
+
`get_project_policy`,
|
|
937
965
|
`wait_for_task`, `get_task_summary`, `get_diff`, `get_result`,
|
|
938
966
|
`get_result_json`, `get_test_log`, `get_task_status`, `list_tasks`,
|
|
939
967
|
`cancel_task`, `audit_task`, `safe_status`, `safe_result`, `safe_audit`, `safe_test_summary`, and `safe_diff_summary`.
|
|
@@ -942,6 +970,38 @@ names.
|
|
|
942
970
|
ChatGPT should request `view: "compact"` first; terminal `wait_for_task`
|
|
943
971
|
responses also embed compact acceptance evidence only.
|
|
944
972
|
|
|
973
|
+
`run_task_loop` is the v1.2 safe orchestration entrypoint. It only composes
|
|
974
|
+
existing `create_task`, `wait_for_task`, safe summary, and `audit_task`
|
|
975
|
+
behavior; it does not bypass the Watcher, command allowlist, workspace
|
|
976
|
+
confinement, or local confirmation boundaries. `get_task_lineage` reads the
|
|
977
|
+
bounded `.patchwarden/lineages/<lineage_id>/` summary without returning full
|
|
978
|
+
logs or diffs.
|
|
979
|
+
|
|
980
|
+
`get_project_policy` is the v1.3 read-only policy entrypoint. It returns the
|
|
981
|
+
bounded effective `.patchwarden/project-policy.json` policy and release
|
|
982
|
+
readiness summary without expanding command permissions. The v1.3 release mode
|
|
983
|
+
tools, `release_check`, `release_prepare`, `release_verify`, and
|
|
984
|
+
`release_cleanup`, are full-profile only and never perform publish, push, tag,
|
|
985
|
+
or GitHub Release writes. The Control Center dashboard also shows bounded
|
|
986
|
+
lineage, policy, and release status summaries without full logs, diffs, or
|
|
987
|
+
secret-bearing content.
|
|
988
|
+
|
|
989
|
+
v1.4 adds Direct-assisted loop verification. `run_task_loop` can opt into
|
|
990
|
+
`direct_verify=true`; after the guarded task and audit succeed, PatchWarden
|
|
991
|
+
creates a Direct session, runs only allowlisted verification commands, safe
|
|
992
|
+
finalizes, safe audits, and records bounded Direct evidence in lineage. It does
|
|
993
|
+
not call Direct patching tools, publish, push, tag, create releases, restart
|
|
994
|
+
watchers, or return full stdout/stderr/diffs.
|
|
995
|
+
|
|
996
|
+
v1.5 adds worktree-assisted loop isolation, bounded agent routing, and evidence
|
|
997
|
+
pack export. `run_task_loop(isolation_mode="worktree")` creates an isolated git
|
|
998
|
+
worktree for the task and records the worktree id, path, branch, and next action
|
|
999
|
+
in lineage. It does not auto-merge or auto-delete the worktree. `agent="auto"`
|
|
1000
|
+
uses `recommend_agent_for_task` to select a configured agent before task
|
|
1001
|
+
creation. `export_task_evidence_pack` writes bounded `evidence.json` and
|
|
1002
|
+
`EVIDENCE.md` files under `.patchwarden/evidence-packs/<lineage_id>/` without
|
|
1003
|
+
stdout/stderr tails, full diffs, verification logs, or sensitive file content.
|
|
1004
|
+
|
|
945
1005
|
`full` additionally provides:
|
|
946
1006
|
|
|
947
1007
|
- `get_plan`
|
|
@@ -956,9 +1016,9 @@ to `full`.
|
|
|
956
1016
|
|
|
957
1017
|
### ChatGPT Direct mode
|
|
958
1018
|
|
|
959
|
-
Direct mode exposes
|
|
1019
|
+
Direct mode exposes fourteen guarded tools so ChatGPT can create an editing
|
|
960
1020
|
session, read and search source files, apply hash-bound JSON patches, run
|
|
961
|
-
exactly allowlisted verification commands, finalize the evidence, and audit
|
|
1021
|
+
exactly allowlisted verification commands or a bounded verification bundle, finalize the evidence, and audit
|
|
962
1022
|
the result without a local execution agent.
|
|
963
1023
|
|
|
964
1024
|
Enable it in the trusted local configuration while keeping the ordinary Core
|
|
@@ -980,9 +1040,20 @@ On first use, provide the `tunnel-client.exe` path and a Tunnel ID dedicated
|
|
|
980
1040
|
to the Direct Connector. The launcher uses the `patchwarden-direct` profile,
|
|
981
1041
|
stores runtime state under `%LOCALAPPDATA%\patchwarden\runtime-direct`, skips
|
|
982
1042
|
the Watcher, and retains the existing DPAPI credential handling. In a fresh
|
|
983
|
-
ChatGPT conversation, `health_check` should report `chatgpt_direct`,
|
|
1043
|
+
ChatGPT conversation, `health_check` should report `chatgpt_direct`, fourteen
|
|
984
1044
|
tools, and `direct_profile_enabled=true`.
|
|
985
1045
|
|
|
1046
|
+
## Ecosystem guides
|
|
1047
|
+
|
|
1048
|
+
- [Why PatchWarden](docs/why-patchwarden.md)
|
|
1049
|
+
- [Evidence Pack v2 schema](docs/evidence-pack-schema.md)
|
|
1050
|
+
- [Spec Kit integration](docs/spec-kit-integration.md)
|
|
1051
|
+
- [AgentSeal integration](docs/agentseal-integration.md)
|
|
1052
|
+
- [MCP Inspector testing](docs/mcp-inspector-testing.md)
|
|
1053
|
+
- [OpenCode worker integration](docs/opencode-worker.md)
|
|
1054
|
+
- [OpenHands worker integration](docs/openhands-worker.md)
|
|
1055
|
+
- [Threat model](docs/threat-model.md)
|
|
1056
|
+
|
|
986
1057
|
## Security boundaries and local data
|
|
987
1058
|
|
|
988
1059
|
Primary protections:
|
|
@@ -1088,6 +1159,10 @@ and release-asset checksums independently.
|
|
|
1088
1159
|
- [ChatGPT usage guide](docs/chatgpt-usage.md)
|
|
1089
1160
|
- [Migration guide](docs/migration-from-safe-bifrost.md)
|
|
1090
1161
|
- [ChatGPT Connector demo](docs/demo.md)
|
|
1162
|
+
- [Dashboard overview](docs/dashboard-overview.md)
|
|
1163
|
+
- [Task safe review workflow](docs/task-safe-review-workflow.md)
|
|
1164
|
+
- [Lineage and Evidence Pack workflow](docs/lineage-evidence-pack-workflow.md)
|
|
1165
|
+
- [Direct session workflow](docs/direct-session-workflow.md)
|
|
1091
1166
|
- [OpenAI tunnel examples](examples/openai-tunnel/README.md)
|
|
1092
1167
|
- [ChatGPT test prompt](examples/openai-tunnel/chatgpt-test-prompt.md)
|
|
1093
1168
|
|
|
@@ -1103,7 +1178,7 @@ and release-asset checksums independently.
|
|
|
1103
1178
|
- [x] Release Gate (five-stage pre-release verification)
|
|
1104
1179
|
- [x] Worktree isolation
|
|
1105
1180
|
- [x] Multi-agent routing
|
|
1106
|
-
- [
|
|
1181
|
+
- [x] Local dashboard
|
|
1107
1182
|
|
|
1108
1183
|
## License
|
|
1109
1184
|
|
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
[](https://nodejs.org/)
|
|
9
9
|
[](LICENSE)
|
|
10
10
|
|
|
11
|
-
当前源码版本:**v1.1
|
|
11
|
+
当前源码版本:**v1.5.1**。查看
|
|
12
12
|
[CHANGELOG](CHANGELOG.md)、[迁移指南](docs/migration-from-safe-bifrost.md)和
|
|
13
13
|
[发布检查清单](docs/release-checklist.md)。GitHub Release / npm 发布状态需要在发布前单独核对。
|
|
14
14
|
|
|
@@ -44,6 +44,7 @@ PatchWarden 负责把计划保存成工作区内任务,再由预先配置的
|
|
|
44
44
|
- [诊断与健康检查](#诊断与健康检查)
|
|
45
45
|
- [踩坑记录与故障排查](#踩坑记录与故障排查)
|
|
46
46
|
- [Direct 模式:ChatGPT 直接开发](#direct-模式chatgpt-直接开发)
|
|
47
|
+
- [生态适配](#生态适配)
|
|
47
48
|
- [安全边界与本地数据](#安全边界与本地数据)
|
|
48
49
|
- [升级与旧版本迁移](#升级与旧版本迁移)
|
|
49
50
|
- [开发与发布验证](#开发与发布验证)
|
|
@@ -399,7 +400,7 @@ PatchWarden.cmd start core
|
|
|
399
400
|
启动器会:
|
|
400
401
|
|
|
401
402
|
- 检查 `dist/index.js`,缺失时自动构建。
|
|
402
|
-
- 校验 `chatgpt_core` 的版本、
|
|
403
|
+
- 校验 `chatgpt_core` 的版本、26 个核心工具和 Schema Manifest。
|
|
403
404
|
- 读取或提示输入 Tunnel ID。
|
|
404
405
|
- 读取或提示输入运行时 API Key。
|
|
405
406
|
- 使用 Windows DPAPI 保存凭据到 `%APPDATA%\patchwarden`。
|
|
@@ -751,6 +752,31 @@ powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%CD%\scripts\control\st
|
|
|
751
752
|
`chatgpt_core` / `patchwarden` → `127.0.0.1:8080`,
|
|
752
753
|
`chatgpt_direct` / `patchwarden-direct` → `127.0.0.1:8081`。
|
|
753
754
|
|
|
755
|
+
## Dashboard 主要页面与推荐工作流
|
|
756
|
+
|
|
757
|
+
PatchWarden Dashboard (Control Center) 提供以下主要页面:
|
|
758
|
+
|
|
759
|
+
- **控制台 (Dashboard)**: 系统总览,包含 Repo selector、Health Score、服务状态、Release 卡片、Project Policy、Lineage、Evidence Pack、Stale 任务提示、最近任务列表、系统状态(含 Copy diagnostics)。
|
|
760
|
+
- **任务面板 (Tasks)**: 任务列表,支持按 repo_path / status / acceptance_status / warning type / agent / date range 过滤,每行提供 safe_result / safe_audit / safe_test_summary / safe_diff_summary 快捷操作。
|
|
761
|
+
- **任务详情 (Task Detail)**: 默认展示 safe 摘要(safe_result / safe_test_summary / safe_diff_summary / safe_audit),完整 result / diff / test log 在折叠的高级区按需加载。
|
|
762
|
+
- **Direct 会话 (Direct Sessions)**: 按 active / finalized / audited / expired 分组,提供 safe_direct_summary / safe_finalize_direct_session / safe_audit_direct_session 快捷操作。
|
|
763
|
+
- **审计日志 / Warnings (Audit)**: 按 warning 类型聚合,显示 affected tasks / severity / recommended action。
|
|
764
|
+
- **工作区 (Workspace)**: workspace 一级目录与项目列表。
|
|
765
|
+
- **日志 (Logs)**: Core / Direct / Watcher / Control Center 日志尾部。
|
|
766
|
+
|
|
767
|
+
推荐工作流:
|
|
768
|
+
|
|
769
|
+
1. 在 Dashboard 顶部选择目标 repo。
|
|
770
|
+
2. 查看 Health Score 确认系统健康。
|
|
771
|
+
3. 在最近任务列表点击 safe_result 快捷查看任务摘要。
|
|
772
|
+
4. 打开 Task Detail 进行 safe-first 验收,仅在需要时展开高级区查看完整日志。
|
|
773
|
+
5. 使用 Lineage Detail 查看 run_task_loop 的成功/失败原因。
|
|
774
|
+
6. 验收完成后导出 Evidence Pack。
|
|
775
|
+
7. Direct 会话用于独立验证,完成后 finalize + audit。
|
|
776
|
+
8. 遇到问题时点击 Copy diagnostics 复制诊断信息发给 ChatGPT / Codex / opencode 排查。
|
|
777
|
+
|
|
778
|
+
> 详细说明见 [docs/dashboard-overview.md](docs/dashboard-overview.md)、[docs/task-safe-review-workflow.md](docs/task-safe-review-workflow.md)、[docs/lineage-evidence-pack-workflow.md](docs/lineage-evidence-pack-workflow.md)、[docs/direct-session-workflow.md](docs/direct-session-workflow.md)。
|
|
779
|
+
|
|
754
780
|
## 踩坑记录与故障排查
|
|
755
781
|
|
|
756
782
|
### 快速对照表
|
|
@@ -836,10 +862,11 @@ PatchWarden v0.4.0 不自动读取旧 CLI、旧环境变量、旧 Header、旧
|
|
|
836
862
|
|
|
837
863
|
## MCP 工具与 Profile
|
|
838
864
|
|
|
839
|
-
`chatgpt_core` 是固定的
|
|
865
|
+
`chatgpt_core` 是固定的 26 工具 Profile,适合 ChatGPT Tunnel:
|
|
840
866
|
|
|
841
867
|
`health_check`、`list_agents`、`list_workspace`、
|
|
842
|
-
`read_workspace_file`、`save_plan`、`create_task`、
|
|
868
|
+
`read_workspace_file`、`save_plan`、`create_task`、`run_task_loop`、`recommend_agent_for_task`、
|
|
869
|
+
`get_task_lineage`、`export_task_evidence_pack`、`get_project_policy`、
|
|
843
870
|
`wait_for_task`、`get_task_summary`、`get_diff`、`get_result`、
|
|
844
871
|
`get_result_json`、`get_test_log`、`get_task_status`、`list_tasks`、
|
|
845
872
|
`cancel_task`、`audit_task`、`safe_status`、`safe_result`、`safe_audit`、`safe_test_summary`、`safe_diff_summary`。
|
|
@@ -847,7 +874,33 @@ PatchWarden v0.4.0 不自动读取旧 CLI、旧环境变量、旧 Header、旧
|
|
|
847
874
|
`get_task_summary` 默认保留兼容的 `standard` 视图;ChatGPT 应优先使用
|
|
848
875
|
`view: "compact"`,终态 `wait_for_task` 也只内嵌 compact 验收证据。
|
|
849
876
|
|
|
850
|
-
`
|
|
877
|
+
`run_task_loop` 是 v1.2 的安全编排入口:它只组合现有 `create_task`、`wait_for_task`、safe summary 和
|
|
878
|
+
`audit_task`,不会绕过 Watcher、命令白名单、workspace confinement 或确认边界。`get_task_lineage`
|
|
879
|
+
读取 `.patchwarden/lineages/<lineage_id>/` 中的有界链路摘要,不返回完整日志或 diff。
|
|
880
|
+
|
|
881
|
+
v1.4 adds Direct-assisted loop verification. `run_task_loop(direct_verify=true)`
|
|
882
|
+
will create a Direct session only after the watcher-driven task and normal audit
|
|
883
|
+
succeed, run allowlisted Direct verification commands, safe-finalize, safe-audit,
|
|
884
|
+
and write bounded Direct evidence into lineage. It does not call Direct patching
|
|
885
|
+
tools, publish, push, tag, create releases, restart live services, or return full
|
|
886
|
+
stdout/stderr/diffs.
|
|
887
|
+
|
|
888
|
+
v1.5 adds worktree-assisted loop isolation, bounded agent routing, and evidence
|
|
889
|
+
pack export. `run_task_loop(isolation_mode="worktree")` creates an isolated git
|
|
890
|
+
worktree for the task and records the worktree id, path, branch, and next action
|
|
891
|
+
in lineage. It does not auto-merge or auto-delete the worktree. `agent="auto"`
|
|
892
|
+
uses `recommend_agent_for_task` to select a configured agent before task
|
|
893
|
+
creation. `export_task_evidence_pack` writes bounded `evidence.json` and
|
|
894
|
+
`EVIDENCE.md` files under `.patchwarden/evidence-packs/<lineage_id>/` without
|
|
895
|
+
stdout/stderr tails, full diffs, verification logs, or sensitive file content.
|
|
896
|
+
|
|
897
|
+
`get_project_policy` 是 v1.3 的只读策略入口,返回 `.patchwarden/project-policy.json`
|
|
898
|
+
的有界 effective policy 与 release readiness,不会扩大命令白名单。v1.3 的
|
|
899
|
+
`release_check`、`release_prepare`、`release_verify`、`release_cleanup` 仅在 `full`
|
|
900
|
+
Profile 中可见,不执行 publish、push、tag 或 GitHub Release 写操作。Control Center
|
|
901
|
+
Dashboard 会展示 lineage、policy 和 release status 的有界摘要,不返回完整日志、diff 或密钥内容。
|
|
902
|
+
|
|
903
|
+
`full` 提供完整 64 工具本地开发目录,包含核心工具、管理工具和 Direct
|
|
851
904
|
工具。除 `chatgpt_core` 外,常用额外管理工具包括:
|
|
852
905
|
|
|
853
906
|
- `get_plan`
|
|
@@ -857,15 +910,15 @@ PatchWarden v0.4.0 不自动读取旧 CLI、旧环境变量、旧 Header、旧
|
|
|
857
910
|
- `get_task_stdout_tail`
|
|
858
911
|
- `get_task_log_tail`
|
|
859
912
|
|
|
860
|
-
`chatgpt_direct` 是 v0.6.0 新增的 Direct 直接开发 Profile,v1.
|
|
913
|
+
`chatgpt_direct` 是 v0.6.0 新增的 Direct 直接开发 Profile,v1.4 包含 14 个工具:
|
|
861
914
|
|
|
862
915
|
`health_check`、`list_workspace`、`create_direct_session`、
|
|
863
916
|
`search_workspace`、`read_workspace_file`、`apply_patch`、
|
|
864
|
-
`run_verification`、`finalize_direct_session`、`audit_session`、`safe_direct_summary`、`safe_finalize_direct_session`、`safe_audit_direct_session`、`sync_file`。
|
|
917
|
+
`run_verification`、`run_direct_verification_bundle`、`finalize_direct_session`、`audit_session`、`safe_direct_summary`、`safe_finalize_direct_session`、`safe_audit_direct_session`、`sync_file`。
|
|
865
918
|
|
|
866
919
|
`chatgpt_direct` 默认关闭,需要通过 `enableDirectProfile: true` 或
|
|
867
920
|
`PATCHWARDEN_TOOL_PROFILE=chatgpt_direct` 显式启用。`chatgpt_core` 保持
|
|
868
|
-
|
|
921
|
+
26 工具清单。
|
|
869
922
|
|
|
870
923
|
Tunnel 包装脚本会强制使用 `chatgpt_core`;普通本地开发默认使用 `full`。
|
|
871
924
|
|
|
@@ -920,7 +973,7 @@ Tunnel ID。启动器使用 `patchwarden-direct` Profile、独立的
|
|
|
920
973
|
Tunnel API Key 仍通过现有 Windows DPAPI 缓存处理,不会写入仓库。
|
|
921
974
|
|
|
922
975
|
连接 ChatGPT 后新建对话并先调用 `health_check`。预期
|
|
923
|
-
`tool_profile=chatgpt_direct`、`tool_count=
|
|
976
|
+
`tool_profile=chatgpt_direct`、`tool_count=14`、
|
|
924
977
|
`direct_profile_enabled=true`。已有对话可能缓存旧工具清单,需要重新连接
|
|
925
978
|
Connector 后再新建对话。
|
|
926
979
|
|
|
@@ -950,6 +1003,17 @@ Direct 模式在受控 session 内执行,具有以下硬性限制:
|
|
|
950
1003
|
|
|
951
1004
|
Direct 模式不支持:shell、delete、rename、commit、push、publish、deployment。
|
|
952
1005
|
|
|
1006
|
+
## 生态适配
|
|
1007
|
+
|
|
1008
|
+
- [为什么需要 PatchWarden](docs/why-patchwarden.md)
|
|
1009
|
+
- [Evidence Pack v2 文件结构](docs/evidence-pack-schema.md)
|
|
1010
|
+
- [Spec Kit 集成模式](docs/spec-kit-integration.md)
|
|
1011
|
+
- [AgentSeal 集成模式](docs/agentseal-integration.md)
|
|
1012
|
+
- [MCP Inspector 测试](docs/mcp-inspector-testing.md)
|
|
1013
|
+
- [OpenCode worker 集成](docs/opencode-worker.md)
|
|
1014
|
+
- [OpenHands worker 集成](docs/openhands-worker.md)
|
|
1015
|
+
- [威胁模型](docs/threat-model.md)
|
|
1016
|
+
|
|
953
1017
|
## 安全边界与本地数据
|
|
954
1018
|
|
|
955
1019
|
PatchWarden 的主要保护:
|
|
@@ -1054,6 +1118,10 @@ Release 和发布资产校验值。
|
|
|
1054
1118
|
- [ChatGPT 调用规范](docs/chatgpt-usage.md)
|
|
1055
1119
|
- [旧版本迁移指南](docs/migration-from-safe-bifrost.md)
|
|
1056
1120
|
- [ChatGPT Connector 演示](docs/demo.md)
|
|
1121
|
+
- [Dashboard 概览](docs/dashboard-overview.md)
|
|
1122
|
+
- [任务 safe 验收工作流](docs/task-safe-review-workflow.md)
|
|
1123
|
+
- [Lineage 与 Evidence Pack 工作流](docs/lineage-evidence-pack-workflow.md)
|
|
1124
|
+
- [Direct 会话工作流](docs/direct-session-workflow.md)
|
|
1057
1125
|
- [OpenAI Tunnel 示例](examples/openai-tunnel/README.md)
|
|
1058
1126
|
- [ChatGPT 测试提示词](examples/openai-tunnel/chatgpt-test-prompt.md)
|
|
1059
1127
|
|
|
@@ -1069,7 +1137,7 @@ Release 和发布资产校验值。
|
|
|
1069
1137
|
- [x] Release Gate(发布前五阶段校验)
|
|
1070
1138
|
- [x] Worktree 隔离
|
|
1071
1139
|
- [x] 多 Agent 路由
|
|
1072
|
-
- [
|
|
1140
|
+
- [x] 本地 Dashboard
|
|
1073
1141
|
|
|
1074
1142
|
## License
|
|
1075
1143
|
|
|
@@ -12,4 +12,4 @@ export interface AgentAssessorInput {
|
|
|
12
12
|
maxOutputBytes: number;
|
|
13
13
|
config: PatchWardenConfig;
|
|
14
14
|
}
|
|
15
|
-
export declare function runAgentAssessment(input: AgentAssessorInput): AgentAssessmentSummary
|
|
15
|
+
export declare function runAgentAssessment(input: AgentAssessorInput): Promise<AgentAssessmentSummary>;
|
|
@@ -4,7 +4,7 @@ import { buildAgentInvocation, buildAssessmentPrompt } from "../runner/agentInvo
|
|
|
4
4
|
import { runSimpleProcessSync } from "../runner/simpleProcess.js";
|
|
5
5
|
import { captureRepoSnapshot, compareSnapshots } from "../runner/changeCapture.js";
|
|
6
6
|
const ASSESSMENT_MARKER = "===ASSESSMENT_JSON===";
|
|
7
|
-
export function runAgentAssessment(input) {
|
|
7
|
+
export async function runAgentAssessment(input) {
|
|
8
8
|
const logPaths = {
|
|
9
9
|
stdout: resolve(input.assessmentDir, "agent-assessment-stdout.log"),
|
|
10
10
|
stderr: resolve(input.assessmentDir, "agent-assessment-stderr.log"),
|
|
@@ -33,7 +33,7 @@ export function runAgentAssessment(input) {
|
|
|
33
33
|
// ── 2. Before snapshot (repo-scoped) ──
|
|
34
34
|
let repoBefore;
|
|
35
35
|
try {
|
|
36
|
-
repoBefore = captureRepoSnapshot(input.repoPath);
|
|
36
|
+
repoBefore = await captureRepoSnapshot(input.repoPath);
|
|
37
37
|
}
|
|
38
38
|
catch {
|
|
39
39
|
// If we can't capture before snapshot, conservatively skip agent assessment
|
|
@@ -73,7 +73,7 @@ export function runAgentAssessment(input) {
|
|
|
73
73
|
let readOnlyViolation = false;
|
|
74
74
|
let violationFiles = [];
|
|
75
75
|
try {
|
|
76
|
-
const repoAfter = captureRepoSnapshot(input.repoPath);
|
|
76
|
+
const repoAfter = await captureRepoSnapshot(input.repoPath);
|
|
77
77
|
const changes = compareSnapshots(repoBefore, repoAfter);
|
|
78
78
|
if (changes.length > 0) {
|
|
79
79
|
readOnlyViolation = true;
|
|
@@ -117,7 +117,7 @@ export declare function validateAssessmentFreshness(assessmentId: string, curren
|
|
|
117
117
|
* This is intentionally not registered as an MCP tool: a remote client may
|
|
118
118
|
* request confirmation, but it cannot grant confirmation to itself.
|
|
119
119
|
*/
|
|
120
|
-
export declare function confirmAssessment(assessmentId: string): AssessmentConfirmationResult
|
|
120
|
+
export declare function confirmAssessment(assessmentId: string): Promise<AssessmentConfirmationResult>;
|
|
121
121
|
export declare function computeWorkspaceFingerprint(snapshot: RepoSnapshot): string;
|
|
122
122
|
interface PolicyHashInput {
|
|
123
123
|
change_policy: ChangePolicy;
|
|
@@ -156,7 +156,7 @@ export function validateAssessmentFreshness(assessmentId, currentSnapshot, optio
|
|
|
156
156
|
* This is intentionally not registered as an MCP tool: a remote client may
|
|
157
157
|
* request confirmation, but it cannot grant confirmation to itself.
|
|
158
158
|
*/
|
|
159
|
-
export function confirmAssessment(assessmentId) {
|
|
159
|
+
export async function confirmAssessment(assessmentId) {
|
|
160
160
|
if (!/^assessment_\d{8}_\d{6}_[0-9a-f]{32}$/.test(assessmentId)) {
|
|
161
161
|
throw new PatchWardenError("assessment_id_invalid", "Local confirmation requires the full assessment_id (32 hexadecimal random characters).", "Copy the complete assessment_id from the assess_only response; assessment_short_id is display-only.");
|
|
162
162
|
}
|
|
@@ -166,7 +166,7 @@ export function confirmAssessment(assessmentId) {
|
|
|
166
166
|
? "Fix the hard-rule finding and run assess_only again."
|
|
167
167
|
: "This assessment does not require confirmation; execute it with the minimal assessment_id call.");
|
|
168
168
|
}
|
|
169
|
-
const snapshot = captureRepoSnapshot(assessment.resolved_repo_path);
|
|
169
|
+
const snapshot = await captureRepoSnapshot(assessment.resolved_repo_path);
|
|
170
170
|
const validation = validateAssessmentFreshness(assessmentId, snapshot, {
|
|
171
171
|
allow_unconfirmed: true,
|
|
172
172
|
// A standalone CLI has no active MCP profile snapshot. The execute path
|
|
@@ -9,18 +9,19 @@
|
|
|
9
9
|
import { loadConfig } from "../config.js";
|
|
10
10
|
import { confirmAssessment } from "./assessmentStore.js";
|
|
11
11
|
import { errorPayload } from "../errors.js";
|
|
12
|
+
import { logger } from "../logging.js";
|
|
12
13
|
loadConfig();
|
|
13
14
|
const assessmentId = process.argv[2];
|
|
14
15
|
if (!assessmentId || process.argv.length !== 3) {
|
|
15
|
-
|
|
16
|
-
|
|
16
|
+
logger.info("Usage: patchwarden-confirm <full_assessment_id>");
|
|
17
|
+
logger.info("The display-only assessment_short_id is not accepted.");
|
|
17
18
|
process.exit(1);
|
|
18
19
|
}
|
|
19
20
|
try {
|
|
20
|
-
const result = confirmAssessment(assessmentId);
|
|
21
|
+
const result = await confirmAssessment(assessmentId);
|
|
21
22
|
console.log(JSON.stringify(result, null, 2));
|
|
22
23
|
}
|
|
23
24
|
catch (error) {
|
|
24
|
-
|
|
25
|
+
logger.error("confirm_assessment_failed", { error: errorPayload(error) });
|
|
25
26
|
process.exit(1);
|
|
26
27
|
}
|
package/dist/config.d.ts
CHANGED
|
@@ -17,6 +17,13 @@ export interface PatchWardenConfig {
|
|
|
17
17
|
watcherStaleSeconds: number;
|
|
18
18
|
toolProfile?: "full" | "chatgpt_core" | "chatgpt_direct" | "chatgpt_search";
|
|
19
19
|
repoAliases?: Record<string, string>;
|
|
20
|
+
httpPort?: number;
|
|
21
|
+
http?: {
|
|
22
|
+
port?: number;
|
|
23
|
+
host?: string;
|
|
24
|
+
ownerTokenEnv?: string;
|
|
25
|
+
};
|
|
26
|
+
enableRunTaskTool?: boolean;
|
|
20
27
|
enableAgentAssessment?: boolean;
|
|
21
28
|
agentAssessmentTimeoutSeconds?: number;
|
|
22
29
|
agentAssessmentMaxOutputBytes?: number;
|
package/dist/config.js
CHANGED
|
@@ -182,6 +182,40 @@ function normalizeConfig(config) {
|
|
|
182
182
|
config.toolProfile !== "chatgpt_search") {
|
|
183
183
|
throw new Error('toolProfile must be "full", "chatgpt_core", "chatgpt_direct", or "chatgpt_search"');
|
|
184
184
|
}
|
|
185
|
+
if (config.repoAliases !== undefined) {
|
|
186
|
+
if (typeof config.repoAliases !== "object" || config.repoAliases === null || Array.isArray(config.repoAliases)) {
|
|
187
|
+
throw new Error("repoAliases must be an object mapping alias names to repository paths");
|
|
188
|
+
}
|
|
189
|
+
for (const [alias, target] of Object.entries(config.repoAliases)) {
|
|
190
|
+
if (typeof target !== "string") {
|
|
191
|
+
throw new Error(`repoAliases["${alias}"] must be a string`);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
if (config.httpPort !== undefined) {
|
|
196
|
+
if (typeof config.httpPort !== "number" || !Number.isInteger(config.httpPort) || config.httpPort < 1 || config.httpPort > 65535) {
|
|
197
|
+
throw new Error("httpPort must be an integer from 1 to 65535");
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
if (config.http !== undefined) {
|
|
201
|
+
if (typeof config.http !== "object" || config.http === null || Array.isArray(config.http)) {
|
|
202
|
+
throw new Error("http must be an object");
|
|
203
|
+
}
|
|
204
|
+
if (config.http.port !== undefined) {
|
|
205
|
+
if (typeof config.http.port !== "number" || !Number.isInteger(config.http.port) || config.http.port < 1 || config.http.port > 65535) {
|
|
206
|
+
throw new Error("http.port must be an integer from 1 to 65535");
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
if (config.http.host !== undefined && typeof config.http.host !== "string") {
|
|
210
|
+
throw new Error("http.host must be a string");
|
|
211
|
+
}
|
|
212
|
+
if (config.http.ownerTokenEnv !== undefined && typeof config.http.ownerTokenEnv !== "string") {
|
|
213
|
+
throw new Error("http.ownerTokenEnv must be a string");
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
if (config.enableRunTaskTool !== undefined && typeof config.enableRunTaskTool !== "boolean") {
|
|
217
|
+
throw new Error("enableRunTaskTool must be a boolean");
|
|
218
|
+
}
|
|
185
219
|
if (config.enableAgentAssessment !== undefined && typeof config.enableAgentAssessment !== "boolean") {
|
|
186
220
|
throw new Error("enableAgentAssessment must be a boolean");
|
|
187
221
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Control Center auth middleware — control token validation.
|
|
3
|
+
*
|
|
4
|
+
* POST routes are gated behind an in-memory control token generated at boot.
|
|
5
|
+
* The token is exposed read-only via GET /control-token.json (handled by the
|
|
6
|
+
* server router) so the local dashboard can read it, but every mutating
|
|
7
|
+
* action must pass through `checkControlToken` first.
|
|
8
|
+
*/
|
|
9
|
+
import { type IncomingMessage } from "node:http";
|
|
10
|
+
export declare function checkControlToken(req: IncomingMessage): boolean;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { controlToken } from "../shared.js";
|
|
2
|
+
export function checkControlToken(req) {
|
|
3
|
+
const header = req.headers["x-patchwarden-control-token"];
|
|
4
|
+
const provided = Array.isArray(header) ? header[0] : header;
|
|
5
|
+
if (typeof provided !== "string" || provided.length === 0)
|
|
6
|
+
return false;
|
|
7
|
+
return provided === controlToken;
|
|
8
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Control Center static file middleware.
|
|
3
|
+
*
|
|
4
|
+
* Serves the bundled `ui/` directory (dashboard pages, partials, vendor
|
|
5
|
+
* assets, css) with path-traversal protection, plus the inline SVG favicon.
|
|
6
|
+
* Content types are mapped from `CONTENT_TYPES` in shared.ts.
|
|
7
|
+
*/
|
|
8
|
+
import { existsSync, readFileSync, statSync } from "node:fs";
|
|
9
|
+
import { extname, isAbsolute, relative, resolve } from "node:path";
|
|
10
|
+
import { CONTENT_TYPES, CONTROL_CENTER_FAVICON, errorMessage, sendJson, uiRoot, } from "../shared.js";
|
|
11
|
+
export function serveStatic(res, urlPath) {
|
|
12
|
+
let candidate = "";
|
|
13
|
+
try {
|
|
14
|
+
const normalized = urlPath.startsWith("/") ? urlPath.slice(1) : urlPath;
|
|
15
|
+
let decoded;
|
|
16
|
+
try {
|
|
17
|
+
decoded = decodeURIComponent(normalized);
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
sendJson(res, 400, { error: "Invalid path encoding" });
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
if (decoded.includes("\0")) {
|
|
24
|
+
sendJson(res, 400, { error: "Invalid path" });
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const segments = decoded.split("/").filter(Boolean);
|
|
28
|
+
if (segments.some((s) => s === "..")) {
|
|
29
|
+
sendJson(res, 403, { error: "Forbidden" });
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
candidate = resolve(uiRoot, ...segments);
|
|
33
|
+
const rel = relative(uiRoot, candidate);
|
|
34
|
+
if (rel === "" || rel.startsWith("..") || isAbsolute(rel)) {
|
|
35
|
+
sendJson(res, 403, { error: "Forbidden" });
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
sendJson(res, 500, { error: errorMessage(err) });
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
try {
|
|
44
|
+
if (!existsSync(candidate) || !statSync(candidate).isFile()) {
|
|
45
|
+
sendJson(res, 404, { error: "Not found" });
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const ext = extname(candidate).toLowerCase();
|
|
49
|
+
const contentType = CONTENT_TYPES[ext] || "application/octet-stream";
|
|
50
|
+
const content = readFileSync(candidate);
|
|
51
|
+
res.writeHead(200, { "Content-Type": contentType });
|
|
52
|
+
res.end(content);
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
sendJson(res, 500, { error: errorMessage(err) });
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
export function serveFavicon(res) {
|
|
59
|
+
res.writeHead(200, {
|
|
60
|
+
"Content-Type": "image/svg+xml; charset=utf-8",
|
|
61
|
+
"Cache-Control": "public, max-age=86400",
|
|
62
|
+
"X-Content-Type-Options": "nosniff",
|
|
63
|
+
});
|
|
64
|
+
res.end(CONTROL_CENTER_FAVICON);
|
|
65
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type ServerResponse } from "node:http";
|
|
2
|
+
export type LogCategory = "core" | "direct" | "watcher" | "control-center";
|
|
3
|
+
export declare function handleLogs(res: ServerResponse, category: LogCategory, tailLines: number): void;
|
|
4
|
+
export declare function handleAudit(res: ServerResponse): void;
|
|
5
|
+
/**
|
|
6
|
+
* Aggregate warnings from multiple sources:
|
|
7
|
+
* - audit.json warnings/fail_checks/possible_false_positives/manual_verification_required
|
|
8
|
+
* - stale task classification (heartbeat stale, collecting_artifacts stale, etc.)
|
|
9
|
+
* - task status=failed_verification
|
|
10
|
+
*
|
|
11
|
+
* Each warning type is grouped into a bucket with affected task IDs. The
|
|
12
|
+
* handler is fault-tolerant: any per-task read failure is skipped, and a
|
|
13
|
+
* top-level failure returns an empty warnings array (never 500).
|
|
14
|
+
*/
|
|
15
|
+
export declare function handleWarnings(res: ServerResponse): void;
|