patchwarden 0.6.1 → 1.1.0
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-Control-Tray.cmd +11 -0
- package/PatchWarden-Control.cmd +6 -0
- package/PatchWarden-Desktop.cmd +5 -0
- package/PatchWarden.cmd +1 -1
- package/README.en.md +112 -24
- package/README.md +36 -25
- package/Restart-PatchWarden-Control.cmd +6 -0
- package/Stop-PatchWarden.cmd +11 -0
- package/dist/agents/agentRouter.d.ts +40 -0
- package/dist/agents/agentRouter.js +95 -0
- package/dist/config.d.ts +1 -1
- package/dist/config.js +6 -2
- package/dist/controlCenter.d.ts +14 -0
- package/dist/controlCenter.js +2015 -0
- package/dist/doctor.js +35 -4
- package/dist/goal/acceptanceEngine.d.ts +62 -0
- package/dist/goal/acceptanceEngine.js +103 -0
- package/dist/goal/acceptanceTemplate.d.ts +10 -0
- package/dist/goal/acceptanceTemplate.js +104 -0
- package/dist/goal/goalGraph.d.ts +58 -0
- package/dist/goal/goalGraph.js +189 -0
- package/dist/goal/goalProgress.d.ts +81 -0
- package/dist/goal/goalProgress.js +216 -0
- package/dist/goal/goalStatus.d.ts +60 -0
- package/dist/goal/goalStatus.js +137 -0
- package/dist/goal/goalStore.d.ts +79 -0
- package/dist/goal/goalStore.js +211 -0
- package/dist/goal/handoffExport.d.ts +34 -0
- package/dist/goal/handoffExport.js +183 -0
- package/dist/goal/subgoalSync.d.ts +40 -0
- package/dist/goal/subgoalSync.js +72 -0
- package/dist/goal/worktreeManager.d.ts +96 -0
- package/dist/goal/worktreeManager.js +292 -0
- package/dist/logging.d.ts +44 -0
- package/dist/logging.js +68 -0
- package/dist/release/releaseGate.d.ts +99 -0
- package/dist/release/releaseGate.js +475 -0
- package/dist/runner/postTaskCleanup.d.ts +13 -0
- package/dist/runner/postTaskCleanup.js +147 -0
- package/dist/runner/runTask.js +50 -10
- package/dist/security/discoveryTokenStore.d.ts +62 -0
- package/dist/security/discoveryTokenStore.js +100 -0
- package/dist/security/toolInvocationGuard.d.ts +35 -0
- package/dist/security/toolInvocationGuard.js +153 -0
- package/dist/smoke-test.js +18 -10
- package/dist/taskRuntime.d.ts +17 -0
- package/dist/test/unit/acceptance-engine.test.d.ts +1 -0
- package/dist/test/unit/acceptance-engine.test.js +228 -0
- package/dist/test/unit/agent-router.test.d.ts +1 -0
- package/dist/test/unit/agent-router.test.js +287 -0
- package/dist/test/unit/audit-checks.test.d.ts +1 -0
- package/dist/test/unit/audit-checks.test.js +350 -0
- package/dist/test/unit/diagnose-task.test.d.ts +1 -0
- package/dist/test/unit/diagnose-task.test.js +457 -0
- package/dist/test/unit/discovery-token-store.test.d.ts +1 -0
- package/dist/test/unit/discovery-token-store.test.js +139 -0
- package/dist/test/unit/goal-graph.test.d.ts +1 -0
- package/dist/test/unit/goal-graph.test.js +298 -0
- package/dist/test/unit/goal-progress.test.d.ts +1 -0
- package/dist/test/unit/goal-progress.test.js +381 -0
- package/dist/test/unit/goal-status.test.d.ts +1 -0
- package/dist/test/unit/goal-status.test.js +215 -0
- package/dist/test/unit/goal-store.test.d.ts +1 -0
- package/dist/test/unit/goal-store.test.js +253 -0
- package/dist/test/unit/goal-subgoal-task.test.d.ts +1 -0
- package/dist/test/unit/goal-subgoal-task.test.js +55 -0
- package/dist/test/unit/goal-tools-registry.test.d.ts +1 -0
- package/dist/test/unit/goal-tools-registry.test.js +190 -0
- package/dist/test/unit/handoff-export.test.d.ts +1 -0
- package/dist/test/unit/handoff-export.test.js +263 -0
- package/dist/test/unit/invoke-discovered-tool.test.d.ts +1 -0
- package/dist/test/unit/invoke-discovered-tool.test.js +167 -0
- package/dist/test/unit/logging.test.js +127 -5
- package/dist/test/unit/post-task-cleanup.test.d.ts +1 -0
- package/dist/test/unit/post-task-cleanup.test.js +48 -0
- package/dist/test/unit/reconcile-tasks.test.d.ts +1 -0
- package/dist/test/unit/reconcile-tasks.test.js +456 -0
- package/dist/test/unit/release-gate.test.d.ts +1 -0
- package/dist/test/unit/release-gate.test.js +242 -0
- package/dist/test/unit/safe-views.test.d.ts +1 -0
- package/dist/test/unit/safe-views.test.js +171 -0
- package/dist/test/unit/schema-drift-check.test.d.ts +1 -0
- package/dist/test/unit/schema-drift-check.test.js +175 -0
- package/dist/test/unit/subgoal-sync.test.d.ts +1 -0
- package/dist/test/unit/subgoal-sync.test.js +183 -0
- package/dist/test/unit/tool-invocation-guard.test.d.ts +1 -0
- package/dist/test/unit/tool-invocation-guard.test.js +432 -0
- package/dist/test/unit/tool-usage-stats.test.d.ts +1 -0
- package/dist/test/unit/tool-usage-stats.test.js +300 -0
- package/dist/test/unit/toolSearch.test.d.ts +1 -0
- package/dist/test/unit/toolSearch.test.js +571 -0
- package/dist/test/unit/worktree-manager.test.d.ts +1 -0
- package/dist/test/unit/worktree-manager.test.js +176 -0
- package/dist/tools/auditTask.d.ts +103 -1
- package/dist/tools/auditTask.js +461 -8
- package/dist/tools/cancelTask.js +1 -1
- package/dist/tools/checkReleaseGate.d.ts +21 -0
- package/dist/tools/checkReleaseGate.js +22 -0
- package/dist/tools/createTask.d.ts +18 -2
- package/dist/tools/createTask.js +29 -1
- package/dist/tools/diagnoseTask.d.ts +45 -0
- package/dist/tools/diagnoseTask.js +347 -0
- package/dist/tools/discardWorktree.d.ts +24 -0
- package/dist/tools/discardWorktree.js +27 -0
- package/dist/tools/discoverTools.d.ts +11 -0
- package/dist/tools/discoverTools.js +39 -0
- package/dist/tools/explainTool.d.ts +11 -0
- package/dist/tools/explainTool.js +21 -0
- package/dist/tools/getTaskSummary.js +2 -1
- package/dist/tools/goalSubgoalTask.d.ts +51 -0
- package/dist/tools/goalSubgoalTask.js +110 -0
- package/dist/tools/healthCheck.d.ts +1 -0
- package/dist/tools/healthCheck.js +5 -1
- package/dist/tools/invokeDiscoveredTool.d.ts +37 -0
- package/dist/tools/invokeDiscoveredTool.js +112 -0
- package/dist/tools/listTasks.d.ts +3 -1
- package/dist/tools/listTasks.js +14 -1
- package/dist/tools/mergeWorktree.d.ts +24 -0
- package/dist/tools/mergeWorktree.js +27 -0
- package/dist/tools/reconcileTasks.d.ts +41 -0
- package/dist/tools/reconcileTasks.js +352 -0
- package/dist/tools/registry.js +550 -0
- package/dist/tools/safeStatus.d.ts +31 -1
- package/dist/tools/safeStatus.js +43 -1
- package/dist/tools/safeViews.d.ts +256 -0
- package/dist/tools/safeViews.js +250 -0
- package/dist/tools/schemaDriftCheck.d.ts +46 -0
- package/dist/tools/schemaDriftCheck.js +80 -0
- package/dist/tools/toolCatalog.d.ts +4 -3
- package/dist/tools/toolCatalog.js +33 -11
- package/dist/tools/toolRegistry.d.ts +61 -0
- package/dist/tools/toolRegistry.js +724 -0
- package/dist/tools/toolSearch.d.ts +110 -0
- package/dist/tools/toolSearch.js +331 -0
- package/dist/tools/toolUsageStats.d.ts +41 -0
- package/dist/tools/toolUsageStats.js +116 -0
- package/dist/tools/waitForTask.js +1 -0
- package/dist/version.d.ts +2 -2
- package/dist/version.js +2 -2
- package/dist/watcherStatus.d.ts +29 -0
- package/dist/watcherStatus.js +92 -1
- package/docs/control-center/README.md +33 -0
- package/docs/control-center/control-center-daily-driver.md +211 -0
- package/docs/control-center/control-center-mvp.md +205 -0
- package/docs/control-center/control-center-phase2.md +159 -0
- package/docs/demo.md +3 -0
- package/docs/release-v0.6.4.md +45 -0
- package/examples/openai-tunnel/README.md +5 -5
- package/examples/openai-tunnel/tunnel-client.example.yaml +3 -3
- package/package.json +25 -16
- package/scripts/README.md +47 -0
- package/scripts/{brand-check.js → checks/brand-check.js} +2 -2
- package/scripts/checks/control-center-smoke.js +1098 -0
- package/scripts/{control-smoke.js → checks/control-smoke.js} +19 -5
- package/scripts/{doctor-smoke.js → checks/doctor-smoke.js} +2 -1
- package/scripts/{http-mcp-smoke.js → checks/http-mcp-smoke.js} +2 -2
- package/scripts/{lifecycle-smoke.js → checks/lifecycle-smoke.js} +25 -21
- package/scripts/{mcp-manifest-check.js → checks/mcp-manifest-check.js} +54 -7
- package/scripts/{mcp-smoke.js → checks/mcp-smoke.js} +40 -11
- package/scripts/{package-manifest-check.js → checks/package-manifest-check.js} +2 -1
- package/scripts/{tunnel-supervisor-smoke.js → checks/tunnel-supervisor-smoke.js} +2 -2
- package/scripts/{unit-tests.js → checks/unit-tests.js} +1 -1
- package/scripts/{watcher-supervisor-smoke.js → checks/watcher-supervisor-smoke.js} +13 -7
- package/scripts/control/control-center-tray.ps1 +281 -0
- package/scripts/{get-patchwarden-health.ps1 → control/get-patchwarden-health.ps1} +3 -3
- package/scripts/{manage-patchwarden.ps1 → control/manage-patchwarden.ps1} +30 -4
- package/scripts/control/restart-control-center.ps1 +173 -0
- package/scripts/{restart-patchwarden.ps1 → control/restart-patchwarden.ps1} +1 -1
- package/scripts/control/start-control-center.ps1 +263 -0
- package/scripts/{start-patchwarden-tunnel.ps1 → control/start-patchwarden-tunnel.ps1} +48 -6
- package/scripts/control/stop-patchwarden.ps1 +114 -0
- package/scripts/launchers/Check-PatchWarden-Health.cmd +1 -1
- package/scripts/launchers/Reset-PatchWarden-Tunnel-Key.cmd +1 -1
- package/scripts/launchers/Restart-PatchWarden.cmd +1 -1
- package/scripts/launchers/Start-PatchWarden-Direct-Tunnel.cmd +1 -1
- package/scripts/launchers/Start-PatchWarden-Tunnel.cmd +1 -1
- package/scripts/{patchwarden-mcp-direct.cmd → mcp/patchwarden-mcp-direct.cmd} +1 -1
- package/scripts/{patchwarden-mcp-stdio.cmd → mcp/patchwarden-mcp-stdio.cmd} +1 -1
- package/scripts/{pack-clean.js → release/pack-clean.js} +9 -1
- package/src/agents/agentRouter.ts +149 -0
- package/src/config.ts +9 -3
- package/src/controlCenter.ts +2166 -0
- package/src/doctor.ts +40 -5
- package/src/goal/acceptanceEngine.ts +160 -0
- package/src/goal/acceptanceTemplate.ts +121 -0
- package/src/goal/goalGraph.ts +225 -0
- package/src/goal/goalProgress.ts +301 -0
- package/src/goal/goalStatus.ts +234 -0
- package/src/goal/goalStore.ts +306 -0
- package/src/goal/handoffExport.ts +211 -0
- package/src/goal/subgoalSync.ts +82 -0
- package/src/goal/worktreeManager.ts +404 -0
- package/src/logging.ts +91 -0
- package/src/release/releaseGate.ts +567 -0
- package/src/runner/postTaskCleanup.ts +154 -0
- package/src/runner/runTask.ts +49 -10
- package/src/security/discoveryTokenStore.ts +157 -0
- package/src/security/toolInvocationGuard.ts +251 -0
- package/src/smoke-test.ts +15 -7
- package/src/taskRuntime.ts +17 -0
- package/src/test/unit/acceptance-engine.test.ts +261 -0
- package/src/test/unit/agent-router.test.ts +342 -0
- package/src/test/unit/audit-checks.test.ts +567 -0
- package/src/test/unit/diagnose-task.test.ts +544 -0
- package/src/test/unit/discovery-token-store.test.ts +181 -0
- package/src/test/unit/goal-graph.test.ts +347 -0
- package/src/test/unit/goal-progress.test.ts +538 -0
- package/src/test/unit/goal-status.test.ts +270 -0
- package/src/test/unit/goal-store.test.ts +318 -0
- package/src/test/unit/goal-subgoal-task.test.ts +72 -0
- package/src/test/unit/goal-tools-registry.test.ts +243 -0
- package/src/test/unit/handoff-export.test.ts +295 -0
- package/src/test/unit/invoke-discovered-tool.test.ts +216 -0
- package/src/test/unit/logging.test.ts +177 -5
- package/src/test/unit/post-task-cleanup.test.ts +53 -0
- package/src/test/unit/reconcile-tasks.test.ts +551 -0
- package/src/test/unit/release-gate.test.ts +314 -0
- package/src/test/unit/safe-views.test.ts +184 -0
- package/src/test/unit/schema-drift-check.test.ts +258 -0
- package/src/test/unit/subgoal-sync.test.ts +236 -0
- package/src/test/unit/tool-invocation-guard.test.ts +542 -0
- package/src/test/unit/tool-usage-stats.test.ts +384 -0
- package/src/test/unit/toolSearch.test.ts +756 -0
- package/src/test/unit/worktree-manager.test.ts +247 -0
- package/src/tools/auditTask.ts +831 -402
- package/src/tools/cancelTask.ts +1 -1
- package/src/tools/checkReleaseGate.ts +45 -0
- package/src/tools/createTask.ts +64 -6
- package/src/tools/diagnoseTask.ts +460 -0
- package/src/tools/discardWorktree.ts +42 -0
- package/src/tools/discoverTools.ts +51 -0
- package/src/tools/explainTool.ts +26 -0
- package/src/tools/getTaskSummary.ts +2 -1
- package/src/tools/goalSubgoalTask.ts +170 -0
- package/src/tools/healthCheck.ts +4 -1
- package/src/tools/invokeDiscoveredTool.ts +163 -0
- package/src/tools/listTasks.ts +16 -2
- package/src/tools/mergeWorktree.ts +42 -0
- package/src/tools/reconcileTasks.ts +464 -0
- package/src/tools/registry.ts +618 -1
- package/src/tools/safeStatus.ts +73 -2
- package/src/tools/safeViews.ts +271 -0
- package/src/tools/schemaDriftCheck.ts +120 -0
- package/src/tools/toolCatalog.ts +34 -11
- package/src/tools/toolRegistry.ts +786 -0
- package/src/tools/toolSearch.ts +464 -0
- package/src/tools/toolUsageStats.ts +151 -0
- package/src/tools/waitForTask.ts +1 -0
- package/src/version.ts +2 -2
- package/src/watcherStatus.ts +97 -1
- package/ui/colors_and_type.css +141 -0
- package/ui/pages/audit.html +743 -0
- package/ui/pages/dashboard.html +1154 -0
- package/ui/pages/direct-sessions.html +652 -0
- package/ui/pages/logs.html +502 -0
- package/ui/pages/task-detail.html +1229 -0
- package/ui/pages/tasks.html +702 -0
- package/ui/pages/workspace.html +947 -0
- package/ui/partials/project-shell.html +362 -0
- package/ui/vendor/lucide.js +12 -0
- package/ui/vendor/tailwindcss-browser.js +947 -0
|
@@ -11,8 +11,8 @@ if (process.platform !== "win32") {
|
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
const scriptDir = resolve(fileURLToPath(new URL(".", import.meta.url)));
|
|
14
|
-
const root = resolve(scriptDir, "..");
|
|
15
|
-
const manager = join(
|
|
14
|
+
const root = resolve(scriptDir, "..", "..");
|
|
15
|
+
const manager = join(root, "scripts", "control", "manage-patchwarden.ps1");
|
|
16
16
|
const temp = mkdtempSync(join(tmpdir(), "patchwarden-control-smoke-"));
|
|
17
17
|
const mockConfig = join(temp, "patchwarden.config.json");
|
|
18
18
|
writeFileSync(mockConfig, JSON.stringify({
|
|
@@ -76,7 +76,7 @@ try {
|
|
|
76
76
|
ready: false,
|
|
77
77
|
pid: null,
|
|
78
78
|
tool_profile: "chatgpt_direct",
|
|
79
|
-
tool_count:
|
|
79
|
+
tool_count: 13,
|
|
80
80
|
tools_ready: true,
|
|
81
81
|
}), "utf8");
|
|
82
82
|
writeFileSync(join(directRuntime, "tunnel-client.pid"), String(fakeTunnel.pid), "utf8");
|
|
@@ -114,7 +114,7 @@ try {
|
|
|
114
114
|
reason_code: "stale_fixture",
|
|
115
115
|
last_error: "stale failure",
|
|
116
116
|
tool_profile: "chatgpt_core",
|
|
117
|
-
tool_count:
|
|
117
|
+
tool_count: 21,
|
|
118
118
|
tools_ready: true,
|
|
119
119
|
}), "utf8");
|
|
120
120
|
healthServer = spawn(
|
|
@@ -139,7 +139,13 @@ try {
|
|
|
139
139
|
|
|
140
140
|
const expectedFiles = [
|
|
141
141
|
"PatchWarden.cmd",
|
|
142
|
-
"
|
|
142
|
+
"PatchWarden-Control.cmd",
|
|
143
|
+
"PatchWarden-Control-Tray.cmd",
|
|
144
|
+
"PatchWarden-Desktop.cmd",
|
|
145
|
+
"Restart-PatchWarden-Control.cmd",
|
|
146
|
+
"Stop-PatchWarden.cmd",
|
|
147
|
+
"scripts/control/manage-patchwarden.ps1",
|
|
148
|
+
"scripts/control/stop-patchwarden.ps1",
|
|
143
149
|
"scripts/launchers/Start-PatchWarden-Tunnel.cmd",
|
|
144
150
|
"scripts/launchers/Start-PatchWarden-Direct-Tunnel.cmd",
|
|
145
151
|
];
|
|
@@ -152,6 +158,14 @@ try {
|
|
|
152
158
|
if (!rootEntry.includes("manage-patchwarden.ps1")) {
|
|
153
159
|
throw new Error("PatchWarden.cmd does not invoke the consolidated manager");
|
|
154
160
|
}
|
|
161
|
+
const stopEntry = readFileSync(join(root, "Stop-PatchWarden.cmd"), "utf8");
|
|
162
|
+
if (!stopEntry.includes("scripts\\control\\stop-patchwarden.ps1")) {
|
|
163
|
+
throw new Error("Stop-PatchWarden.cmd does not invoke the one-click shutdown script");
|
|
164
|
+
}
|
|
165
|
+
const desktopEntry = readFileSync(join(root, "PatchWarden-Desktop.cmd"), "utf8");
|
|
166
|
+
if (!desktopEntry.includes("control-center-tray.ps1") || !desktopEntry.includes("WindowStyle Hidden")) {
|
|
167
|
+
throw new Error("PatchWarden-Desktop.cmd must launch the tray hidden as the daily desktop entry");
|
|
168
|
+
}
|
|
155
169
|
console.log("ok - control handles orphan cleanup, scoped kill, port conflicts, health fallback, and Core/Direct lifecycle actions");
|
|
156
170
|
} finally {
|
|
157
171
|
if (fakeTunnel?.exitCode === null) fakeTunnel.kill();
|
|
@@ -5,7 +5,7 @@ import { tmpdir } from "node:os";
|
|
|
5
5
|
import { join, resolve } from "node:path";
|
|
6
6
|
import { fileURLToPath } from "node:url";
|
|
7
7
|
|
|
8
|
-
const root = resolve(fileURLToPath(new URL("
|
|
8
|
+
const root = resolve(fileURLToPath(new URL("../..", import.meta.url)));
|
|
9
9
|
const tempRoot = mkdtempSync(join(tmpdir(), "patchwarden-doctor-"));
|
|
10
10
|
const workspaceRoot = join(tempRoot, "workspace");
|
|
11
11
|
const configPath = join(tempRoot, "patchwarden.config.json");
|
|
@@ -42,6 +42,7 @@ try {
|
|
|
42
42
|
"[OK] Task directory writable",
|
|
43
43
|
"[OK] Example task directory read/write",
|
|
44
44
|
"[OK] allowedTestCommands is non-empty",
|
|
45
|
+
"[OK] Release gate module loadable",
|
|
45
46
|
];
|
|
46
47
|
for (const line of requiredLines) {
|
|
47
48
|
if (!result.stdout.includes(line)) throw new Error(`doctor output missing stable line: ${line}`);
|
|
@@ -11,10 +11,10 @@ import { tmpdir } from "node:os";
|
|
|
11
11
|
import { dirname, join, resolve } from "node:path";
|
|
12
12
|
import { fileURLToPath } from "node:url";
|
|
13
13
|
import { setTimeout as sleep } from "node:timers/promises";
|
|
14
|
-
import { CHATGPT_CORE_TOOL_NAMES } from "
|
|
14
|
+
import { CHATGPT_CORE_TOOL_NAMES } from "../../dist/tools/toolCatalog.js";
|
|
15
15
|
|
|
16
16
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
17
|
-
const root = resolve(__dirname, "..");
|
|
17
|
+
const root = resolve(__dirname, "..", "..");
|
|
18
18
|
const serverPath = resolve(root, "dist", "httpServer.js");
|
|
19
19
|
|
|
20
20
|
const host = "127.0.0.1";
|
|
@@ -12,6 +12,10 @@ import { tmpdir } from "node:os";
|
|
|
12
12
|
import { join } from "node:path";
|
|
13
13
|
import { setTimeout as sleep } from "node:timers/promises";
|
|
14
14
|
|
|
15
|
+
// v0.7.2: tasks complete with "done_by_agent" (pending acceptance) instead of "done".
|
|
16
|
+
// Both are valid successful completion statuses for lifecycle smoke tests.
|
|
17
|
+
const isDoneStatus = (s) => s === "done" || s === "done_by_agent";
|
|
18
|
+
|
|
15
19
|
const tempRoot = mkdtempSync(join(tmpdir(), "patchwarden-lifecycle-"));
|
|
16
20
|
const workspaceRoot = join(tempRoot, "workspace");
|
|
17
21
|
const repoPath = join(workspaceRoot, "repo");
|
|
@@ -148,18 +152,18 @@ try {
|
|
|
148
152
|
);
|
|
149
153
|
process.env.PATCHWARDEN_CONFIG = configPath;
|
|
150
154
|
|
|
151
|
-
const { savePlan } = await import("
|
|
152
|
-
const { createTask } = await import("
|
|
153
|
-
const { getTaskStatus } = await import("
|
|
154
|
-
const { cancelTask } = await import("
|
|
155
|
-
const { killTask } = await import("
|
|
156
|
-
const { getDiff } = await import("
|
|
157
|
-
const { listAgents } = await import("
|
|
158
|
-
const { getTaskSummary } = await import("
|
|
159
|
-
const { auditTask } = await import("
|
|
160
|
-
const { waitForTask } = await import("
|
|
161
|
-
const { runTask } = await import("
|
|
162
|
-
const { reloadConfig } = await import("
|
|
155
|
+
const { savePlan } = await import("../../dist/tools/savePlan.js");
|
|
156
|
+
const { createTask } = await import("../../dist/tools/createTask.js");
|
|
157
|
+
const { getTaskStatus } = await import("../../dist/tools/getTaskStatus.js");
|
|
158
|
+
const { cancelTask } = await import("../../dist/tools/cancelTask.js");
|
|
159
|
+
const { killTask } = await import("../../dist/tools/killTask.js");
|
|
160
|
+
const { getDiff } = await import("../../dist/tools/taskOutputs.js");
|
|
161
|
+
const { listAgents } = await import("../../dist/tools/listAgents.js");
|
|
162
|
+
const { getTaskSummary } = await import("../../dist/tools/getTaskSummary.js");
|
|
163
|
+
const { auditTask } = await import("../../dist/tools/auditTask.js");
|
|
164
|
+
const { waitForTask } = await import("../../dist/tools/waitForTask.js");
|
|
165
|
+
const { runTask } = await import("../../dist/runner/runTask.js");
|
|
166
|
+
const { reloadConfig } = await import("../../dist/config.js");
|
|
163
167
|
|
|
164
168
|
await test("list_agents reports configured executables", async () => {
|
|
165
169
|
const result = listAgents();
|
|
@@ -178,7 +182,7 @@ try {
|
|
|
178
182
|
verify_commands: ["node --check main.js", "node --check second.js"],
|
|
179
183
|
});
|
|
180
184
|
const result = await runTask(task.task_id);
|
|
181
|
-
if (result.status
|
|
185
|
+
if (!isDoneStatus(result.status)) throw new Error(`Writer task ended ${result.status}: ${result.error}`);
|
|
182
186
|
const status = getTaskStatus(task.task_id);
|
|
183
187
|
const changed = status.changed_files || [];
|
|
184
188
|
if (!changed.some((file) => file.path === "README.md" && file.change === "modified")) {
|
|
@@ -253,7 +257,7 @@ try {
|
|
|
253
257
|
});
|
|
254
258
|
const result = await runTask(task.task_id);
|
|
255
259
|
const verify = JSON.parse(readFileSync(join(task.path, "verify.json"), "utf-8"));
|
|
256
|
-
if (result.status
|
|
260
|
+
if (!isDoneStatus(result.status) || verify.status !== "passed" || verify.commands.length !== 1) {
|
|
257
261
|
throw new Error(`Legacy verification mismatch: ${JSON.stringify({ result, verify })}`);
|
|
258
262
|
}
|
|
259
263
|
if (verify.commands[0].cwd !== repoPath || !("stdout_tail" in verify.commands[0]) || !("stderr_tail" in verify.commands[0])) {
|
|
@@ -265,7 +269,7 @@ try {
|
|
|
265
269
|
const plan = savePlan({ title: "No diff", content: "Do not change files." });
|
|
266
270
|
const task = createTask({ plan_id: plan.plan_id, agent: "noop", repo_path: "repo" });
|
|
267
271
|
const result = await runTask(task.task_id);
|
|
268
|
-
if (result.status
|
|
272
|
+
if (!isDoneStatus(result.status)) throw new Error(`No-op task failed: ${JSON.stringify(result)}`);
|
|
269
273
|
const diff = getDiff(task.task_id);
|
|
270
274
|
const verify = JSON.parse(readFileSync(join(task.path, "verify.json"), "utf-8"));
|
|
271
275
|
if (verify.status !== "skipped") throw new Error(`Expected skipped verification: ${JSON.stringify(verify)}`);
|
|
@@ -286,7 +290,7 @@ try {
|
|
|
286
290
|
const plan = savePlan({ title: "Large diff", content: "Create a large text file." });
|
|
287
291
|
const task = createTask({ plan_id: plan.plan_id, agent: "largewriter", repo_path: "repo" });
|
|
288
292
|
const result = await runTask(task.task_id);
|
|
289
|
-
if (result.status
|
|
293
|
+
if (!isDoneStatus(result.status)) throw new Error(`Large task failed: ${JSON.stringify(result)}`);
|
|
290
294
|
const diff = getDiff(task.task_id);
|
|
291
295
|
const patchSize = readFileSync(join(task.path, "diff.patch"), "utf-8").length;
|
|
292
296
|
if (!diff.truncated || !diff.patch_head || !diff.diff_patch_path || patchSize <= diff.content.length) {
|
|
@@ -298,7 +302,7 @@ try {
|
|
|
298
302
|
const plan = savePlan({ title: "Non-Git evidence", content: "Modify files in a non-Git repository." });
|
|
299
303
|
const task = createTask({ plan_id: plan.plan_id, agent: "writer", repo_path: "plain-repo" });
|
|
300
304
|
const result = await runTask(task.task_id);
|
|
301
|
-
if (result.status
|
|
305
|
+
if (!isDoneStatus(result.status)) throw new Error(`Non-Git task failed: ${JSON.stringify(result)}`);
|
|
302
306
|
const diff = getDiff(task.task_id);
|
|
303
307
|
if (
|
|
304
308
|
diff.patch_mode !== "hash_only" ||
|
|
@@ -313,7 +317,7 @@ try {
|
|
|
313
317
|
const plan = savePlan({ title: "Binary evidence", content: "Create a binary fixture." });
|
|
314
318
|
const task = createTask({ plan_id: plan.plan_id, agent: "binarywriter", repo_path: "repo" });
|
|
315
319
|
const result = await runTask(task.task_id);
|
|
316
|
-
if (result.status
|
|
320
|
+
if (!isDoneStatus(result.status)) throw new Error(`Binary task failed: ${JSON.stringify(result)}`);
|
|
317
321
|
const diff = getDiff(task.task_id);
|
|
318
322
|
if (diff.patch_mode !== "textual" || !diff.content.includes("GIT binary patch")) {
|
|
319
323
|
throw new Error(`Binary patch evidence mismatch: ${JSON.stringify(diff)}`);
|
|
@@ -324,7 +328,7 @@ try {
|
|
|
324
328
|
const plan = savePlan({ title: "Artifact hygiene", content: "Generate representative task outputs." });
|
|
325
329
|
const task = createTask({ plan_id: plan.plan_id, agent: "artifactwriter", repo_path: "repo" });
|
|
326
330
|
const result = await runTask(task.task_id);
|
|
327
|
-
if (result.status
|
|
331
|
+
if (!isDoneStatus(result.status)) throw new Error(`Artifact task failed: ${JSON.stringify(result)}`);
|
|
328
332
|
const standard = getTaskSummary(task.task_id);
|
|
329
333
|
const compact = getTaskSummary(task.task_id, { view: "compact", max_items: 1 });
|
|
330
334
|
const counts = standard.artifact_hygiene?.counts || {};
|
|
@@ -353,7 +357,7 @@ try {
|
|
|
353
357
|
const plan = savePlan({ title: "Delete fixture", content: "Delete the designated fixture file." });
|
|
354
358
|
const task = createTask({ plan_id: plan.plan_id, agent: "deleter", repo_path: "repo" });
|
|
355
359
|
const result = await runTask(task.task_id);
|
|
356
|
-
if (result.status
|
|
360
|
+
if (!isDoneStatus(result.status)) throw new Error(`Delete task failed: ${JSON.stringify(result)}`);
|
|
357
361
|
const diff = getDiff(task.task_id);
|
|
358
362
|
if (!diff.file_stats?.some((file) => file.path === "delete-me.txt" && file.status === "deleted")) {
|
|
359
363
|
throw new Error(`Deleted file stats missing: ${JSON.stringify(diff.file_stats)}`);
|
|
@@ -504,7 +508,7 @@ try {
|
|
|
504
508
|
const task = createTask({ plan_id: plan.plan_id, agent: "noop", repo_path: "repo", verify_commands: ["node --check main.js"] });
|
|
505
509
|
const result = await runTask(task.task_id);
|
|
506
510
|
|
|
507
|
-
if (result.status
|
|
511
|
+
if (!isDoneStatus(result.status)) {
|
|
508
512
|
throw new Error(`Expected done, got: ${JSON.stringify(result)}`);
|
|
509
513
|
}
|
|
510
514
|
const structured = JSON.parse(readFileSync(join(task.path, "result.json"), "utf-8"));
|
|
@@ -4,18 +4,20 @@ import { resolve } from "node:path";
|
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
6
6
|
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
7
|
-
import { CHATGPT_CORE_TOOL_NAMES, CHATGPT_DIRECT_TOOL_NAMES } from "
|
|
7
|
+
import { CHATGPT_CORE_TOOL_NAMES, CHATGPT_DIRECT_TOOL_NAMES, CHATGPT_SEARCH_TOOL_NAMES } from "../../dist/tools/toolCatalog.js";
|
|
8
8
|
|
|
9
|
-
const root = resolve(fileURLToPath(new URL("
|
|
9
|
+
const root = resolve(fileURLToPath(new URL("../..", import.meta.url)));
|
|
10
10
|
const jsonOnly = process.argv.includes("--json");
|
|
11
11
|
const profileIndex = process.argv.indexOf("--profile");
|
|
12
12
|
const profile = profileIndex >= 0 ? process.argv[profileIndex + 1] : "chatgpt_core";
|
|
13
|
-
if (profile !== "chatgpt_core" && profile !== "chatgpt_direct") {
|
|
13
|
+
if (profile !== "chatgpt_core" && profile !== "chatgpt_direct" && profile !== "chatgpt_search") {
|
|
14
14
|
throw new Error(`Unsupported manifest profile "${profile}".`);
|
|
15
15
|
}
|
|
16
16
|
const expectedTools = profile === "chatgpt_direct"
|
|
17
17
|
? [...CHATGPT_DIRECT_TOOL_NAMES]
|
|
18
|
-
:
|
|
18
|
+
: profile === "chatgpt_search"
|
|
19
|
+
? [...CHATGPT_SEARCH_TOOL_NAMES]
|
|
20
|
+
: [...CHATGPT_CORE_TOOL_NAMES];
|
|
19
21
|
const defaultConfigPath = resolve(root, "patchwarden.config.json");
|
|
20
22
|
const transportEnv = {
|
|
21
23
|
...process.env,
|
|
@@ -102,13 +104,31 @@ try {
|
|
|
102
104
|
if (!summaryProperties.includes("view") || !summaryProperties.includes("max_items")) {
|
|
103
105
|
throw new Error("get_task_summary schema must expose view and max_items");
|
|
104
106
|
}
|
|
105
|
-
|
|
107
|
+
const safeRequirements = {
|
|
108
|
+
safe_result: ["task_id"],
|
|
109
|
+
safe_audit: ["task_id"],
|
|
110
|
+
safe_test_summary: ["task_id"],
|
|
111
|
+
safe_diff_summary: ["task_id"],
|
|
112
|
+
};
|
|
113
|
+
for (const [toolName, requiredProperties] of Object.entries(safeRequirements)) {
|
|
114
|
+
const tool = listed.tools.find((entry) => entry.name === toolName);
|
|
115
|
+
const properties = Object.keys(tool?.inputSchema?.properties || {});
|
|
116
|
+
for (const property of requiredProperties) {
|
|
117
|
+
if (!properties.includes(property)) {
|
|
118
|
+
throw new Error(`${toolName} schema is missing ${property}`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
} else if (profile === "chatgpt_direct") {
|
|
106
123
|
const directRequirements = {
|
|
107
124
|
create_direct_session: ["repo_path"],
|
|
108
125
|
apply_patch: ["session_id", "path", "expected_sha256", "operations"],
|
|
109
126
|
run_verification: ["session_id", "command"],
|
|
110
127
|
finalize_direct_session: ["session_id"],
|
|
111
128
|
audit_session: ["session_id"],
|
|
129
|
+
safe_direct_summary: ["session_id"],
|
|
130
|
+
safe_finalize_direct_session: ["session_id"],
|
|
131
|
+
safe_audit_direct_session: ["session_id"],
|
|
112
132
|
};
|
|
113
133
|
for (const [toolName, requiredProperties] of Object.entries(directRequirements)) {
|
|
114
134
|
const tool = listed.tools.find((entry) => entry.name === toolName);
|
|
@@ -119,6 +139,21 @@ try {
|
|
|
119
139
|
}
|
|
120
140
|
}
|
|
121
141
|
}
|
|
142
|
+
} else {
|
|
143
|
+
const searchRequirements = {
|
|
144
|
+
discover_tools: ["query"],
|
|
145
|
+
explain_tool: ["name"],
|
|
146
|
+
invoke_discovered_tool: ["toolName", "arguments", "discoveryToken"],
|
|
147
|
+
};
|
|
148
|
+
for (const [toolName, requiredProperties] of Object.entries(searchRequirements)) {
|
|
149
|
+
const tool = listed.tools.find((entry) => entry.name === toolName);
|
|
150
|
+
const properties = Object.keys(tool?.inputSchema?.properties || {});
|
|
151
|
+
for (const property of requiredProperties) {
|
|
152
|
+
if (!properties.includes(property)) {
|
|
153
|
+
throw new Error(`${toolName} schema is missing ${property}`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
122
157
|
}
|
|
123
158
|
const healthResult = await client.callTool({ name: "health_check", arguments: {} });
|
|
124
159
|
if (healthResult.isError) throw new Error(String(healthResult.content?.[0]?.text || "health_check failed"));
|
|
@@ -127,7 +162,8 @@ try {
|
|
|
127
162
|
health.tool_profile !== profile ||
|
|
128
163
|
health.tool_count !== expectedTools.length ||
|
|
129
164
|
!health.tool_manifest_sha256 ||
|
|
130
|
-
(profile === "chatgpt_direct" && health.direct_profile_enabled !== true)
|
|
165
|
+
(profile === "chatgpt_direct" && health.direct_profile_enabled !== true) ||
|
|
166
|
+
(profile === "chatgpt_search" && health.search_tool_count !== expectedTools.length)
|
|
131
167
|
) {
|
|
132
168
|
throw new Error(`health_check catalog mismatch: ${JSON.stringify(health)}`);
|
|
133
169
|
}
|
|
@@ -164,12 +200,23 @@ try {
|
|
|
164
200
|
health_check: ["detail"],
|
|
165
201
|
list_tasks: ["repo_path", "active_only"],
|
|
166
202
|
get_task_summary: ["view", "max_items"],
|
|
167
|
-
|
|
203
|
+
safe_result: ["task_id"],
|
|
204
|
+
safe_audit: ["task_id"],
|
|
205
|
+
safe_test_summary: ["task_id"],
|
|
206
|
+
safe_diff_summary: ["task_id"],
|
|
207
|
+
} : profile === "chatgpt_direct" ? {
|
|
168
208
|
create_direct_session: ["repo_path"],
|
|
169
209
|
apply_patch: ["session_id", "path", "expected_sha256", "operations"],
|
|
170
210
|
run_verification: ["session_id", "command"],
|
|
171
211
|
finalize_direct_session: ["session_id"],
|
|
172
212
|
audit_session: ["session_id"],
|
|
213
|
+
safe_direct_summary: ["session_id"],
|
|
214
|
+
safe_finalize_direct_session: ["session_id"],
|
|
215
|
+
safe_audit_direct_session: ["session_id"],
|
|
216
|
+
} : {
|
|
217
|
+
discover_tools: ["query"],
|
|
218
|
+
explain_tool: ["name"],
|
|
219
|
+
invoke_discovered_tool: ["toolName", "arguments", "discoveryToken"],
|
|
173
220
|
},
|
|
174
221
|
};
|
|
175
222
|
console.log(jsonOnly ? JSON.stringify(output) : JSON.stringify(output, null, 2));
|
|
@@ -14,7 +14,9 @@ import { fileURLToPath } from "node:url";
|
|
|
14
14
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
15
15
|
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
16
16
|
|
|
17
|
-
const root = resolve(fileURLToPath(new URL("
|
|
17
|
+
const root = resolve(fileURLToPath(new URL("../..", import.meta.url)));
|
|
18
|
+
const packageJson = JSON.parse(readFileSync(join(root, "package.json"), "utf-8"));
|
|
19
|
+
const expectedServerVersion = packageJson.version;
|
|
18
20
|
const tempRoot = mkdtempSync(join(tmpdir(), "patchwarden-mcp-"));
|
|
19
21
|
const workspaceRoot = join(tempRoot, "workspace");
|
|
20
22
|
const configPath = join(tempRoot, "patchwarden.config.json");
|
|
@@ -101,12 +103,21 @@ try {
|
|
|
101
103
|
const tools = await client.listTools();
|
|
102
104
|
const names = tools.tools.map((tool) => tool.name).sort();
|
|
103
105
|
const expected = [
|
|
106
|
+
"accept_subgoal",
|
|
104
107
|
"apply_patch",
|
|
105
108
|
"audit_session",
|
|
106
109
|
"audit_task",
|
|
107
110
|
"cancel_task",
|
|
111
|
+
"check_release_gate",
|
|
108
112
|
"create_direct_session",
|
|
113
|
+
"create_goal",
|
|
114
|
+
"create_subgoal_task",
|
|
109
115
|
"create_task",
|
|
116
|
+
"diagnose_task",
|
|
117
|
+
"discard_worktree",
|
|
118
|
+
"discover_tools",
|
|
119
|
+
"explain_tool",
|
|
120
|
+
"export_handoff",
|
|
110
121
|
"finalize_direct_session",
|
|
111
122
|
"get_diff",
|
|
112
123
|
"get_plan",
|
|
@@ -119,16 +130,31 @@ try {
|
|
|
119
130
|
"get_task_summary",
|
|
120
131
|
"get_test_log",
|
|
121
132
|
"health_check",
|
|
133
|
+
"invoke_discovered_tool",
|
|
122
134
|
"kill_task",
|
|
123
135
|
"list_agents",
|
|
136
|
+
"list_goals",
|
|
124
137
|
"list_tasks",
|
|
125
138
|
"list_workspace",
|
|
139
|
+
"merge_worktree",
|
|
140
|
+
"read_goal",
|
|
126
141
|
"read_workspace_file",
|
|
142
|
+
"reconcile_tasks",
|
|
143
|
+
"reject_subgoal",
|
|
127
144
|
"retry_task",
|
|
128
145
|
"run_verification",
|
|
146
|
+
"safe_audit",
|
|
147
|
+
"safe_audit_direct_session",
|
|
148
|
+
"safe_diff_summary",
|
|
149
|
+
"safe_direct_summary",
|
|
150
|
+
"safe_finalize_direct_session",
|
|
151
|
+
"safe_result",
|
|
129
152
|
"safe_status",
|
|
153
|
+
"safe_test_summary",
|
|
130
154
|
"save_plan",
|
|
131
155
|
"search_workspace",
|
|
156
|
+
"suggest_next_subgoal",
|
|
157
|
+
"summarize_goal_progress",
|
|
132
158
|
"sync_file",
|
|
133
159
|
"wait_for_task",
|
|
134
160
|
];
|
|
@@ -141,7 +167,7 @@ try {
|
|
|
141
167
|
if (!tools._meta || typeof tools._meta.tool_manifest_sha256 !== "string" || tools._meta.tool_manifest_sha256.length !== 64) {
|
|
142
168
|
throw new Error(`tools/list _meta missing manifest hash: ${JSON.stringify(tools._meta || null)}`);
|
|
143
169
|
}
|
|
144
|
-
if (tools._meta.tool_profile !== "full" || tools._meta.tool_count !==
|
|
170
|
+
if (tools._meta.tool_profile !== "full" || tools._meta.tool_count !== 54) {
|
|
145
171
|
throw new Error(`tools/list _meta profile/count mismatch: ${JSON.stringify(tools._meta)}`);
|
|
146
172
|
}
|
|
147
173
|
if (typeof tools._meta.schema_epoch !== "string" || typeof tools._meta.server_version !== "string") {
|
|
@@ -212,7 +238,7 @@ try {
|
|
|
212
238
|
test_command: "npm test",
|
|
213
239
|
});
|
|
214
240
|
if (
|
|
215
|
-
task.server_version !==
|
|
241
|
+
task.server_version !== expectedServerVersion ||
|
|
216
242
|
!/^[a-f0-9]{64}$/.test(task.tool_manifest_sha256 || "") ||
|
|
217
243
|
task.next_tool_call?.name !== "wait_for_task" ||
|
|
218
244
|
task.next_tool_call?.arguments?.timeout_seconds !== 25
|
|
@@ -294,8 +320,8 @@ try {
|
|
|
294
320
|
|
|
295
321
|
const statusPath = join(task.path, "status.json");
|
|
296
322
|
const statusAfter = JSON.parse(readFileSync(statusPath, "utf-8"));
|
|
297
|
-
if (statusAfter.status !== "done") {
|
|
298
|
-
throw new Error(`runner status should be done, got ${statusAfter.status}`);
|
|
323
|
+
if (statusAfter.status !== "done" && statusAfter.status !== "done_by_agent") {
|
|
324
|
+
throw new Error(`runner status should be done or done_by_agent, got ${statusAfter.status}`);
|
|
299
325
|
}
|
|
300
326
|
for (const fileName of ["result.md", "result.json", "diff.patch", "git.diff", "file-stats.json", "test.log", "verify.json", "verify.log"]) {
|
|
301
327
|
if (!existsSync(join(task.path, fileName))) {
|
|
@@ -391,7 +417,7 @@ try {
|
|
|
391
417
|
await disabledClient.close();
|
|
392
418
|
ok("chatgpt_direct disabled exposes only health_check with diagnostic");
|
|
393
419
|
|
|
394
|
-
// 2. chatgpt_direct enabled:
|
|
420
|
+
// 2. chatgpt_direct enabled: 13 tools + minimal create_direct_session
|
|
395
421
|
const enabledConfigPath = join(tempRoot, "direct-enabled.json");
|
|
396
422
|
const directRepo = join(workspaceRoot, "direct-fixture");
|
|
397
423
|
mkdirSync(join(directRepo, "src"), { recursive: true });
|
|
@@ -448,14 +474,17 @@ try {
|
|
|
448
474
|
"list_workspace",
|
|
449
475
|
"read_workspace_file",
|
|
450
476
|
"run_verification",
|
|
477
|
+
"safe_audit_direct_session",
|
|
478
|
+
"safe_direct_summary",
|
|
479
|
+
"safe_finalize_direct_session",
|
|
451
480
|
"search_workspace",
|
|
452
481
|
"sync_file",
|
|
453
482
|
];
|
|
454
483
|
if (JSON.stringify(enabledNames) !== JSON.stringify(expectedDirect)) {
|
|
455
484
|
throw new Error(`chatgpt_direct enabled tools mismatch: ${enabledNames.join(", ")}`);
|
|
456
485
|
}
|
|
457
|
-
if (enabledTools._meta.tool_count !==
|
|
458
|
-
throw new Error(`chatgpt_direct enabled tool_count should be
|
|
486
|
+
if (enabledTools._meta.tool_count !== 13) {
|
|
487
|
+
throw new Error(`chatgpt_direct enabled tool_count should be 13, got ${enabledTools._meta.tool_count}`);
|
|
459
488
|
}
|
|
460
489
|
|
|
461
490
|
// Minimal create_direct_session
|
|
@@ -475,12 +504,12 @@ try {
|
|
|
475
504
|
if (enabledHealth.direct_profile_enabled !== true) {
|
|
476
505
|
throw new Error(`direct_profile_enabled should be true, got ${enabledHealth.direct_profile_enabled}`);
|
|
477
506
|
}
|
|
478
|
-
if (enabledHealth.direct_tool_count !==
|
|
479
|
-
throw new Error(`direct_tool_count should be
|
|
507
|
+
if (enabledHealth.direct_tool_count !== 13) {
|
|
508
|
+
throw new Error(`direct_tool_count should be 13, got ${enabledHealth.direct_tool_count}`);
|
|
480
509
|
}
|
|
481
510
|
|
|
482
511
|
await enabledClient.close();
|
|
483
|
-
ok("chatgpt_direct enabled exposes
|
|
512
|
+
ok("chatgpt_direct enabled exposes 13 tools and create_direct_session works");
|
|
484
513
|
} catch (error) {
|
|
485
514
|
fail("MCP smoke test", error);
|
|
486
515
|
} finally {
|
|
@@ -45,7 +45,8 @@ if (leaked.length > 0) {
|
|
|
45
45
|
|
|
46
46
|
const required = [
|
|
47
47
|
"PatchWarden.cmd",
|
|
48
|
-
"
|
|
48
|
+
"PatchWarden-Desktop.cmd",
|
|
49
|
+
"scripts/control/manage-patchwarden.ps1",
|
|
49
50
|
"scripts/launchers/Start-PatchWarden-Tunnel.cmd",
|
|
50
51
|
"scripts/launchers/Start-PatchWarden-Direct-Tunnel.cmd",
|
|
51
52
|
];
|
|
@@ -10,7 +10,7 @@ if (process.platform !== "win32") {
|
|
|
10
10
|
process.exit(0);
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
const root = resolve(fileURLToPath(new URL("
|
|
13
|
+
const root = resolve(fileURLToPath(new URL("../..", import.meta.url)));
|
|
14
14
|
const temp = mkdtempSync(join(tmpdir(), "patchwarden-tunnel-smoke-"));
|
|
15
15
|
const mockJs = join(temp, "mock-tunnel-client.js");
|
|
16
16
|
const mockCmd = join(temp, "mock-tunnel-client.cmd");
|
|
@@ -57,7 +57,7 @@ if(command==='run'){
|
|
|
57
57
|
MOCK_TUNNEL_STATE: stateFile,
|
|
58
58
|
};
|
|
59
59
|
const result = spawnSync("powershell.exe", [
|
|
60
|
-
"-NoProfile", "-ExecutionPolicy", "Bypass", "-File", join(root, "scripts", "start-patchwarden-tunnel.ps1"),
|
|
60
|
+
"-NoProfile", "-ExecutionPolicy", "Bypass", "-File", join(root, "scripts", "control", "start-patchwarden-tunnel.ps1"),
|
|
61
61
|
"-TunnelId", "tunnel_smoke_fixture",
|
|
62
62
|
"-TunnelClientExe", mockCmd,
|
|
63
63
|
"-ConfigPath", mockConfig,
|
|
@@ -5,7 +5,7 @@ import { resolve } from "node:path";
|
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
6
|
|
|
7
7
|
const scriptDir = resolve(fileURLToPath(new URL(".", import.meta.url)));
|
|
8
|
-
const root = resolve(scriptDir, "..");
|
|
8
|
+
const root = resolve(scriptDir, "..", "..");
|
|
9
9
|
const unitDir = resolve(root, "dist", "test", "unit");
|
|
10
10
|
|
|
11
11
|
if (!existsSync(unitDir)) {
|
|
@@ -19,7 +19,7 @@ if (process.platform !== "win32") {
|
|
|
19
19
|
process.exit(0);
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
const root = resolve(fileURLToPath(new URL("
|
|
22
|
+
const root = resolve(fileURLToPath(new URL("../..", import.meta.url)));
|
|
23
23
|
const temp = mkdtempSync(join(tmpdir(), "patchwarden-watcher-supervisor-"));
|
|
24
24
|
const children = [];
|
|
25
25
|
|
|
@@ -87,23 +87,29 @@ async function runExternalScenario() {
|
|
|
87
87
|
function createFixture(name) {
|
|
88
88
|
const project = join(temp, name, "patchwarden-fixture");
|
|
89
89
|
const scripts = join(project, "scripts");
|
|
90
|
+
const controlScripts = join(scripts, "control");
|
|
91
|
+
const mcpScripts = join(scripts, "mcp");
|
|
92
|
+
const checkScripts = join(scripts, "checks");
|
|
90
93
|
const runner = join(project, "dist", "runner");
|
|
91
94
|
const workspace = join(project, "workspace");
|
|
92
95
|
mkdirSync(scripts, { recursive: true });
|
|
96
|
+
mkdirSync(controlScripts, { recursive: true });
|
|
97
|
+
mkdirSync(mcpScripts, { recursive: true });
|
|
98
|
+
mkdirSync(checkScripts, { recursive: true });
|
|
93
99
|
mkdirSync(runner, { recursive: true });
|
|
94
100
|
mkdirSync(workspace, { recursive: true });
|
|
95
|
-
cpSync(join(root, "scripts", "start-patchwarden-tunnel.ps1"), join(
|
|
96
|
-
writeFileSync(join(
|
|
101
|
+
cpSync(join(root, "scripts", "control", "start-patchwarden-tunnel.ps1"), join(controlScripts, "start-patchwarden-tunnel.ps1"));
|
|
102
|
+
writeFileSync(join(mcpScripts, "patchwarden-mcp-stdio.cmd"), "@echo off\r\nexit /b 0\r\n", "utf-8");
|
|
97
103
|
const manifestFixture = JSON.stringify({
|
|
98
104
|
ok: true,
|
|
99
105
|
server_version: "0.6.0",
|
|
100
106
|
schema_epoch: "2026-06-22-v6",
|
|
101
107
|
tool_profile: "chatgpt_core",
|
|
102
|
-
tool_count:
|
|
108
|
+
tool_count: 21,
|
|
103
109
|
tool_names: [],
|
|
104
110
|
tool_manifest_sha256: "a".repeat(64),
|
|
105
111
|
});
|
|
106
|
-
writeFileSync(join(
|
|
112
|
+
writeFileSync(join(checkScripts, "mcp-manifest-check.js"), `process.stdout.write(${JSON.stringify(manifestFixture)});\n`, "utf-8");
|
|
107
113
|
writeFileSync(join(project, "dist", "index.js"), "", "utf-8");
|
|
108
114
|
const watcherAttemptPath = join(project, "watcher-attempt.txt");
|
|
109
115
|
const watcherPath = join(runner, "watch.js");
|
|
@@ -140,7 +146,7 @@ function createFixture(name) {
|
|
|
140
146
|
|
|
141
147
|
function runLauncher(fixture, mode, maxRestarts, lifetimeMs) {
|
|
142
148
|
return spawnSync("powershell.exe", [
|
|
143
|
-
"-NoProfile", "-ExecutionPolicy", "Bypass", "-File", join(fixture.project, "scripts", "start-patchwarden-tunnel.ps1"),
|
|
149
|
+
"-NoProfile", "-ExecutionPolicy", "Bypass", "-File", join(fixture.project, "scripts", "control", "start-patchwarden-tunnel.ps1"),
|
|
144
150
|
"-TunnelId", "tunnel_watcher_fixture",
|
|
145
151
|
"-TunnelClientExe", fixture.mockCmd,
|
|
146
152
|
"-ProxyUrl", "http://127.0.0.1:1",
|
|
@@ -161,7 +167,7 @@ function fixtureEnv(fixture, mode, lifetimeMs) {
|
|
|
161
167
|
...process.env,
|
|
162
168
|
APPDATA: fixture.appData,
|
|
163
169
|
LOCALAPPDATA: fixture.localAppData,
|
|
164
|
-
CONTROL_PLANE_API_KEY: "
|
|
170
|
+
CONTROL_PLANE_API_KEY: "test-key",
|
|
165
171
|
WATCHER_FIXTURE_MODE: mode,
|
|
166
172
|
TUNNEL_FIXTURE_LIFETIME_MS: String(lifetimeMs),
|
|
167
173
|
};
|