patchwarden 1.5.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.
Files changed (217) hide show
  1. package/README.en.md +43 -2
  2. package/README.md +43 -2
  3. package/dist/assessments/agentAssessor.d.ts +1 -1
  4. package/dist/assessments/agentAssessor.js +3 -3
  5. package/dist/assessments/assessmentStore.d.ts +1 -1
  6. package/dist/assessments/assessmentStore.js +2 -2
  7. package/dist/assessments/confirmCli.js +5 -4
  8. package/dist/config.d.ts +7 -0
  9. package/dist/config.js +34 -0
  10. package/dist/control/middleware/auth.d.ts +10 -0
  11. package/dist/control/middleware/auth.js +8 -0
  12. package/dist/control/middleware/static.d.ts +3 -0
  13. package/dist/control/middleware/static.js +65 -0
  14. package/dist/control/routes/audit.d.ts +15 -0
  15. package/dist/control/routes/audit.js +277 -0
  16. package/dist/control/routes/evidence.d.ts +4 -0
  17. package/dist/control/routes/evidence.js +96 -0
  18. package/dist/control/routes/lineage.d.ts +3 -0
  19. package/dist/control/routes/lineage.js +71 -0
  20. package/dist/control/routes/policy.d.ts +3 -0
  21. package/dist/control/routes/policy.js +81 -0
  22. package/dist/control/routes/process.d.ts +5 -0
  23. package/dist/control/routes/process.js +200 -0
  24. package/dist/control/routes/sessions.d.ts +22 -0
  25. package/dist/control/routes/sessions.js +224 -0
  26. package/dist/control/routes/status.d.ts +6 -0
  27. package/dist/control/routes/status.js +250 -0
  28. package/dist/control/routes/taskActions.d.ts +21 -0
  29. package/dist/control/routes/taskActions.js +233 -0
  30. package/dist/control/routes/tasks.d.ts +20 -0
  31. package/dist/control/routes/tasks.js +310 -0
  32. package/dist/control/routes/workspace.d.ts +15 -0
  33. package/dist/control/routes/workspace.js +193 -0
  34. package/dist/control/runtime.d.ts +91 -0
  35. package/dist/control/runtime.js +392 -0
  36. package/dist/control/server.d.ts +13 -0
  37. package/dist/control/server.js +479 -0
  38. package/dist/control/shared.d.ts +35 -0
  39. package/dist/control/shared.js +288 -0
  40. package/dist/controlCenter.d.ts +6 -0
  41. package/dist/controlCenter.js +7 -2197
  42. package/dist/direct/directGuards.js +30 -8
  43. package/dist/doctor.d.ts +18 -1
  44. package/dist/doctor.js +579 -348
  45. package/dist/goal/goalReport.d.ts +54 -0
  46. package/dist/goal/goalReport.js +204 -0
  47. package/dist/goal/goalStatus.d.ts +6 -0
  48. package/dist/goal/specKitImport.d.ts +63 -0
  49. package/dist/goal/specKitImport.js +220 -0
  50. package/dist/goal/subgoalSync.js +2 -1
  51. package/dist/httpServer.js +15 -12
  52. package/dist/index.js +7 -4
  53. package/dist/logging.d.ts +7 -1
  54. package/dist/logging.js +8 -0
  55. package/dist/runner/changeCapture.d.ts +3 -3
  56. package/dist/runner/changeCapture.js +63 -39
  57. package/dist/runner/cli.js +7 -6
  58. package/dist/runner/postTaskCleanup.js +26 -2
  59. package/dist/runner/runTask.js +245 -221
  60. package/dist/runner/simpleProcess.js +4 -4
  61. package/dist/runner/watch.js +17 -14
  62. package/dist/security/contentRedaction.d.ts +6 -0
  63. package/dist/security/contentRedaction.js +22 -0
  64. package/dist/smoke-test.js +257 -251
  65. package/dist/test/unit/apply-patch.test.d.ts +1 -0
  66. package/dist/test/unit/apply-patch.test.js +225 -0
  67. package/dist/test/unit/create-task.test.d.ts +1 -0
  68. package/dist/test/unit/create-task.test.js +197 -0
  69. package/dist/test/unit/direct-guards.test.js +124 -9
  70. package/dist/test/unit/evidence-pack.test.js +95 -1
  71. package/dist/test/unit/get-task-status.test.d.ts +1 -0
  72. package/dist/test/unit/get-task-status.test.js +174 -0
  73. package/dist/test/unit/get-task-summary.test.d.ts +1 -0
  74. package/dist/test/unit/get-task-summary.test.js +146 -0
  75. package/dist/test/unit/goal-report.test.d.ts +1 -0
  76. package/dist/test/unit/goal-report.test.js +159 -0
  77. package/dist/test/unit/goal-subgoal-task.test.js +6 -6
  78. package/dist/test/unit/goal-tools-registry.test.js +6 -4
  79. package/dist/test/unit/path-guard.test.js +24 -0
  80. package/dist/test/unit/spec-kit-import.test.d.ts +1 -0
  81. package/dist/test/unit/spec-kit-import.test.js +341 -0
  82. package/dist/test/unit/wait-for-task.test.d.ts +1 -0
  83. package/dist/test/unit/wait-for-task.test.js +144 -0
  84. package/dist/tools/auditTask.d.ts +8 -63
  85. package/dist/tools/auditTask.js +12 -8
  86. package/dist/tools/createDirectSession.d.ts +1 -1
  87. package/dist/tools/createDirectSession.js +2 -2
  88. package/dist/tools/createTask.d.ts +2 -2
  89. package/dist/tools/createTask.js +4 -4
  90. package/dist/tools/dispatch/coreDispatch.d.ts +9 -0
  91. package/dist/tools/dispatch/coreDispatch.js +282 -0
  92. package/dist/tools/dispatch/diagnosticDispatch.d.ts +14 -0
  93. package/dist/tools/dispatch/diagnosticDispatch.js +78 -0
  94. package/dist/tools/dispatch/directDispatch.d.ts +8 -0
  95. package/dist/tools/dispatch/directDispatch.js +115 -0
  96. package/dist/tools/dispatch/goalDispatch.d.ts +8 -0
  97. package/dist/tools/dispatch/goalDispatch.js +91 -0
  98. package/dist/tools/dispatch/releaseDispatch.d.ts +8 -0
  99. package/dist/tools/dispatch/releaseDispatch.js +45 -0
  100. package/dist/tools/dispatch/types.d.ts +23 -0
  101. package/dist/tools/dispatch/types.js +15 -0
  102. package/dist/tools/evidencePack.d.ts +6 -0
  103. package/dist/tools/evidencePack.js +213 -6
  104. package/dist/tools/finalizeDirectSession.d.ts +1 -1
  105. package/dist/tools/finalizeDirectSession.js +3 -3
  106. package/dist/tools/goalSubgoalTask.d.ts +1 -1
  107. package/dist/tools/goalSubgoalTask.js +2 -2
  108. package/dist/tools/healthCheck.js +3 -3
  109. package/dist/tools/registry.d.ts +3 -3
  110. package/dist/tools/registry.js +60 -503
  111. package/dist/tools/retryTask.d.ts +2 -2
  112. package/dist/tools/retryTask.js +2 -2
  113. package/dist/tools/runTaskLoop.js +4 -4
  114. package/dist/tools/safeViews.d.ts +2 -2
  115. package/dist/tools/safeViews.js +2 -2
  116. package/dist/tools/toolRegistry.js +22 -0
  117. package/dist/version.d.ts +1 -1
  118. package/dist/version.js +1 -1
  119. package/docs/CODE_WIKI.md +983 -0
  120. package/docs/agentseal-integration.md +150 -0
  121. package/docs/architecture.md +63 -0
  122. package/docs/assets/patchwarden-oss-demo.gif +0 -0
  123. package/docs/dashboard-overview.md +86 -0
  124. package/docs/demo.md +8 -0
  125. package/docs/direct-session-workflow.md +98 -0
  126. package/docs/evidence-pack-schema.md +215 -0
  127. package/docs/execution-plan-2026-07-09.md +315 -0
  128. package/docs/lineage-evidence-pack-workflow.md +127 -0
  129. package/docs/mcp-inspector-testing.md +200 -0
  130. package/docs/open-source-application.md +162 -0
  131. package/docs/opencode-worker.md +151 -0
  132. package/docs/openhands-worker.md +181 -0
  133. package/docs/release-evidence.md +72 -0
  134. package/docs/roadmap-execution-and-acceptance.md +365 -0
  135. package/docs/spec-kit-integration.md +131 -0
  136. package/docs/task-safe-review-workflow.md +98 -0
  137. package/docs/threat-model.md +79 -0
  138. package/docs/user-feedback.md +40 -0
  139. package/docs/why-patchwarden.md +110 -0
  140. package/package.json +2 -2
  141. package/scripts/checks/control-center-smoke.js +356 -0
  142. package/scripts/checks/lifecycle-smoke.js +29 -23
  143. package/scripts/checks/mcp-smoke.js +3 -1
  144. package/scripts/generate-demo-gif.py +320 -0
  145. package/src/assessments/agentAssessor.ts +3 -3
  146. package/src/assessments/assessmentStore.ts +2 -2
  147. package/src/assessments/confirmCli.ts +5 -4
  148. package/src/config.ts +37 -0
  149. package/src/control/middleware/auth.ts +17 -0
  150. package/src/control/middleware/static.ts +71 -0
  151. package/src/control/routes/audit.ts +321 -0
  152. package/src/control/routes/evidence.ts +107 -0
  153. package/src/control/routes/lineage.ts +92 -0
  154. package/src/control/routes/policy.ts +81 -0
  155. package/src/control/routes/process.ts +204 -0
  156. package/src/control/routes/sessions.ts +251 -0
  157. package/src/control/routes/status.ts +325 -0
  158. package/src/control/routes/taskActions.ts +248 -0
  159. package/src/control/routes/tasks.ts +323 -0
  160. package/src/control/routes/workspace.ts +203 -0
  161. package/src/control/runtime.ts +472 -0
  162. package/src/control/server.ts +471 -0
  163. package/src/control/shared.ts +294 -0
  164. package/src/controlCenter.ts +7 -2347
  165. package/src/direct/directGuards.ts +28 -7
  166. package/src/doctor.ts +741 -481
  167. package/src/goal/goalReport.ts +271 -0
  168. package/src/goal/goalStatus.ts +6 -0
  169. package/src/goal/specKitImport.ts +355 -0
  170. package/src/goal/subgoalSync.ts +4 -2
  171. package/src/httpServer.ts +17 -14
  172. package/src/index.ts +7 -4
  173. package/src/logging.ts +10 -1
  174. package/src/runner/changeCapture.ts +70 -42
  175. package/src/runner/cli.ts +7 -6
  176. package/src/runner/postTaskCleanup.ts +26 -2
  177. package/src/runner/runTask.ts +325 -223
  178. package/src/runner/simpleProcess.ts +4 -4
  179. package/src/runner/watch.ts +17 -14
  180. package/src/security/contentRedaction.ts +29 -0
  181. package/src/smoke-test.ts +252 -250
  182. package/src/test/unit/apply-patch.test.ts +293 -0
  183. package/src/test/unit/create-task.test.ts +255 -0
  184. package/src/test/unit/direct-guards.test.ts +178 -8
  185. package/src/test/unit/evidence-pack.test.ts +110 -1
  186. package/src/test/unit/get-task-status.test.ts +203 -0
  187. package/src/test/unit/get-task-summary.test.ts +173 -0
  188. package/src/test/unit/goal-report.test.ts +189 -0
  189. package/src/test/unit/goal-subgoal-task.test.ts +6 -6
  190. package/src/test/unit/goal-tools-registry.test.ts +7 -5
  191. package/src/test/unit/path-guard.test.ts +30 -0
  192. package/src/test/unit/spec-kit-import.test.ts +429 -0
  193. package/src/test/unit/wait-for-task.test.ts +176 -0
  194. package/src/tools/auditTask.ts +99 -59
  195. package/src/tools/createDirectSession.ts +3 -3
  196. package/src/tools/createTask.ts +7 -7
  197. package/src/tools/dispatch/coreDispatch.ts +374 -0
  198. package/src/tools/dispatch/diagnosticDispatch.ts +101 -0
  199. package/src/tools/dispatch/directDispatch.ts +167 -0
  200. package/src/tools/dispatch/goalDispatch.ts +127 -0
  201. package/src/tools/dispatch/releaseDispatch.ts +65 -0
  202. package/src/tools/dispatch/types.ts +24 -0
  203. package/src/tools/evidencePack.ts +291 -6
  204. package/src/tools/finalizeDirectSession.ts +4 -4
  205. package/src/tools/goalSubgoalTask.ts +2 -2
  206. package/src/tools/healthCheck.ts +3 -3
  207. package/src/tools/registry.ts +68 -628
  208. package/src/tools/retryTask.ts +2 -2
  209. package/src/tools/runTaskLoop.ts +4 -4
  210. package/src/tools/safeViews.ts +2 -2
  211. package/src/tools/toolRegistry.ts +22 -0
  212. package/src/version.ts +1 -1
  213. package/ui/pages/audit.html +192 -3
  214. package/ui/pages/dashboard.html +959 -44
  215. package/ui/pages/direct-sessions.html +505 -53
  216. package/ui/pages/task-detail.html +456 -438
  217. package/ui/pages/tasks.html +598 -61
@@ -37,13 +37,13 @@ export function runSimpleProcessSync(options) {
37
37
  try {
38
38
  writeFileSyncAppend(options.stdoutPath, stdout);
39
39
  }
40
- catch { }
40
+ catch { } // best-effort log write; failure doesn't affect result
41
41
  }
42
42
  if (options.stderrPath && stderr) {
43
43
  try {
44
44
  writeFileSyncAppend(options.stderrPath, stderr);
45
45
  }
46
- catch { }
46
+ catch { } // best-effort log write; failure doesn't affect result
47
47
  }
48
48
  return {
49
49
  exitCode: result.status,
@@ -174,7 +174,7 @@ function gracefulKill(child) {
174
174
  else
175
175
  child.kill("SIGTERM");
176
176
  }
177
- catch { }
177
+ catch { } // cleanup failure is safe to ignore
178
178
  }
179
179
  function forceKill(child) {
180
180
  if (!child.pid)
@@ -197,7 +197,7 @@ function forceKill(child) {
197
197
  try {
198
198
  child.kill("SIGKILL");
199
199
  }
200
- catch { }
200
+ catch { } // cleanup failure is safe to ignore
201
201
  }
202
202
  }
203
203
  function writeFileSyncAppend(path, content) {
@@ -24,6 +24,7 @@ import { guardAgentCommand, guardTestCommand } from "../security/commandGuard.js
24
24
  import { validateAssessmentFreshness } from "../assessments/assessmentStore.js";
25
25
  import { captureRepoSnapshot } from "./changeCapture.js";
26
26
  import { runTask } from "./runTask.js";
27
+ import { logger } from "../logging.js";
27
28
  // ── Bootstrap ─────────────────────────────────────────────────────
28
29
  loadConfig();
29
30
  const config = getConfig();
@@ -37,10 +38,10 @@ const WATCHER_LAUNCHER_PID = Number.isInteger(Number(process.env.PATCHWARDEN_WAT
37
38
  ? Number(process.env.PATCHWARDEN_WATCHER_LAUNCHER_PID)
38
39
  : null;
39
40
  mkdirSync(dirname(WATCHER_HEARTBEAT_FILE), { recursive: true });
40
- console.error(`[watcher] Workspace: ${wsRoot}`);
41
- console.error(`[watcher] Tasks: ${tasksDir}`);
42
- console.error(`[watcher] Polling every ${POLL_INTERVAL_MS / 1000}s`);
43
- console.error(`[watcher] Press Ctrl+C to stop`);
41
+ logger.info(`[watcher] Workspace: ${wsRoot}`);
42
+ logger.info(`[watcher] Tasks: ${tasksDir}`);
43
+ logger.info(`[watcher] Polling every ${POLL_INTERVAL_MS / 1000}s`);
44
+ logger.info(`[watcher] Press Ctrl+C to stop`);
44
45
  // Track executed tasks to prevent re-execution
45
46
  const executedTasks = new Set();
46
47
  // ── Main loop ─────────────────────────────────────────────────────
@@ -96,7 +97,7 @@ async function tick() {
96
97
  }
97
98
  // Assessment freshness revalidation
98
99
  if (statusData.assessment_id) {
99
- const preExecSnapshot = captureRepoSnapshot(resolvedRepoPath);
100
+ const preExecSnapshot = await captureRepoSnapshot(resolvedRepoPath);
100
101
  const validation = validateAssessmentFreshness(String(statusData.assessment_id), preExecSnapshot);
101
102
  if (!validation.valid) {
102
103
  throw new Error(`assessment validation failed: ${validation.failure_reason}`);
@@ -105,7 +106,7 @@ async function tick() {
105
106
  }
106
107
  catch (err) {
107
108
  const errMsg = `[watcher] Safety check failed for ${taskId}: ${err instanceof Error ? err.message : String(err)}`;
108
- console.error(errMsg);
109
+ logger.error(errMsg);
109
110
  // Write error and mark as failed so it doesn't get re-picked
110
111
  try {
111
112
  writeFileSync(join(taskDir, "error.log"), errMsg, "utf-8");
@@ -115,37 +116,39 @@ async function tick() {
115
116
  data.updated_at = new Date().toISOString();
116
117
  writeFileSync(statusFile, JSON.stringify(data, null, 2), "utf-8");
117
118
  }
118
- catch { }
119
+ catch (err) {
120
+ logger.warn("watcher error-log write failed", { error: err instanceof Error ? err.message : String(err) });
121
+ }
119
122
  executedTasks.add(taskId);
120
123
  continue;
121
124
  }
122
125
  // ── Execute ──
123
- console.error(`[watcher] Executing: ${taskId}`);
126
+ logger.info(`[watcher] Executing: ${taskId}`);
124
127
  executedTasks.add(taskId);
125
128
  try {
126
129
  const result = await runTask(taskId);
127
- console.error(`[watcher] ${taskId} → ${result.status}`);
130
+ logger.info(`[watcher] ${taskId} → ${result.status}`);
128
131
  }
129
132
  catch (err) {
130
- console.error(`[watcher] ${taskId} → error: ${err instanceof Error ? err.message : String(err)}`);
133
+ logger.error(`[watcher] ${taskId} → error: ${err instanceof Error ? err.message : String(err)}`);
131
134
  }
132
135
  }
133
136
  }
134
137
  catch (err) {
135
- console.error(`[watcher] Tick error: ${err instanceof Error ? err.message : String(err)}`);
138
+ logger.error(`[watcher] Tick error: ${err instanceof Error ? err.message : String(err)}`);
136
139
  }
137
140
  }
138
141
  // ── Start ─────────────────────────────────────────────────────────
139
- console.error("[watcher] Started");
142
+ logger.info("[watcher] Started");
140
143
  setInterval(tick, POLL_INTERVAL_MS);
141
144
  // Run first tick immediately
142
145
  tick();
143
146
  // Graceful shutdown
144
147
  process.on("SIGINT", () => {
145
- console.error("[watcher] Stopped");
148
+ logger.info("[watcher] Stopped");
146
149
  process.exit(0);
147
150
  });
148
151
  process.on("SIGTERM", () => {
149
- console.error("[watcher] Stopped");
152
+ logger.info("[watcher] Stopped");
150
153
  process.exit(0);
151
154
  });
@@ -8,5 +8,11 @@ export interface StructuredRedactionResult<T> {
8
8
  redacted: boolean;
9
9
  redaction_categories: string[];
10
10
  }
11
+ export interface RedactionCategoryCount {
12
+ category: string;
13
+ reason: string;
14
+ count: number;
15
+ }
16
+ export declare function countRedactionsByCategory(input: string): RedactionCategoryCount[];
11
17
  export declare function redactSensitiveContent(input: string): RedactionResult;
12
18
  export declare function redactSensitiveValue<T>(input: T): StructuredRedactionResult<T>;
@@ -1,30 +1,52 @@
1
1
  const RULES = [
2
2
  {
3
3
  category: "private_key",
4
+ reason: "matched private key block",
4
5
  pattern: /-----BEGIN [^-\r\n]*PRIVATE KEY-----[\s\S]*?-----END [^-\r\n]*PRIVATE KEY-----/gi,
5
6
  replace: "[REDACTED PRIVATE KEY]",
6
7
  },
7
8
  {
8
9
  category: "bearer_token",
10
+ reason: "matched bearer token",
9
11
  pattern: /\bBearer\s+[A-Za-z0-9._~+\/-]{12,}={0,2}/gi,
10
12
  replace: "Bearer [REDACTED]",
11
13
  },
12
14
  {
13
15
  category: "npm_token",
16
+ reason: "matched npm auth token",
14
17
  pattern: /(\b_?authToken\s*=\s*)[^\s\r\n]+/gi,
15
18
  replace: "$1[REDACTED]",
16
19
  },
17
20
  {
18
21
  category: "credential_assignment",
22
+ reason: "matched credential assignment",
19
23
  pattern: /\b((?:access[_ -]?token|api[_ -]?key|secret|password|credential|token)\s*[:=]\s*)(["']?)([^\s,"'\]}]{8,})(["']?)/gi,
20
24
  replace: "$1$2[REDACTED]$4",
21
25
  },
22
26
  {
23
27
  category: "known_token_format",
28
+ reason: "matched known token format",
24
29
  pattern: /\b(?:sk|ghp|github_pat)_[A-Za-z0-9_-]{16,}\b/g,
25
30
  replace: "[REDACTED TOKEN]",
26
31
  },
27
32
  ];
33
+ export function countRedactionsByCategory(input) {
34
+ const counts = new Map();
35
+ for (const rule of RULES) {
36
+ rule.pattern.lastIndex = 0;
37
+ const matches = input.match(rule.pattern);
38
+ if (matches && matches.length > 0) {
39
+ counts.set(rule.category, (counts.get(rule.category) || 0) + matches.length);
40
+ }
41
+ }
42
+ const result = [];
43
+ for (const rule of RULES) {
44
+ const count = counts.get(rule.category);
45
+ if (count)
46
+ result.push({ category: rule.category, reason: rule.reason, count });
47
+ }
48
+ return result;
49
+ }
28
50
  export function redactSensitiveContent(input) {
29
51
  let content = input;
30
52
  const categories = [];