patchwarden 0.4.0 → 0.6.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.
Files changed (139) hide show
  1. package/PatchWarden.cmd +51 -0
  2. package/README.en.md +1022 -0
  3. package/README.md +897 -358
  4. package/dist/assessments/agentAssessor.d.ts +15 -0
  5. package/dist/assessments/agentAssessor.js +293 -0
  6. package/dist/assessments/assessmentStore.d.ts +133 -0
  7. package/dist/assessments/assessmentStore.js +238 -0
  8. package/dist/assessments/confirmCli.d.ts +9 -0
  9. package/dist/assessments/confirmCli.js +26 -0
  10. package/dist/config.d.ts +22 -1
  11. package/dist/config.js +156 -3
  12. package/dist/direct/directAudit.d.ts +23 -0
  13. package/dist/direct/directAudit.js +309 -0
  14. package/dist/direct/directGuards.d.ts +20 -0
  15. package/dist/direct/directGuards.js +137 -0
  16. package/dist/direct/directPatch.d.ts +17 -0
  17. package/dist/direct/directPatch.js +113 -0
  18. package/dist/direct/directSessionStore.d.ts +63 -0
  19. package/dist/direct/directSessionStore.js +192 -0
  20. package/dist/direct/directVerification.d.ts +12 -0
  21. package/dist/direct/directVerification.js +96 -0
  22. package/dist/doctor.js +73 -5
  23. package/dist/runner/agentInvocation.d.ts +23 -0
  24. package/dist/runner/agentInvocation.js +106 -0
  25. package/dist/runner/changeCapture.d.ts +29 -0
  26. package/dist/runner/changeCapture.js +107 -5
  27. package/dist/runner/runTask.js +70 -44
  28. package/dist/runner/simpleProcess.d.ts +21 -0
  29. package/dist/runner/simpleProcess.js +206 -0
  30. package/dist/runner/watch.js +17 -2
  31. package/dist/security/commandGuard.d.ts +2 -1
  32. package/dist/security/commandGuard.js +25 -3
  33. package/dist/security/riskEngine.d.ts +27 -0
  34. package/dist/security/riskEngine.js +118 -0
  35. package/dist/security/runtimeGuard.d.ts +6 -0
  36. package/dist/security/runtimeGuard.js +28 -0
  37. package/dist/smoke-test.js +1353 -7
  38. package/dist/tools/applyPatch.d.ts +16 -0
  39. package/dist/tools/applyPatch.js +41 -0
  40. package/dist/tools/auditSession.d.ts +5 -0
  41. package/dist/tools/auditSession.js +12 -0
  42. package/dist/tools/auditTask.d.ts +7 -0
  43. package/dist/tools/auditTask.js +94 -2
  44. package/dist/tools/createDirectSession.d.ts +14 -0
  45. package/dist/tools/createDirectSession.js +54 -0
  46. package/dist/tools/createTask.d.ts +48 -1
  47. package/dist/tools/createTask.js +298 -47
  48. package/dist/tools/finalizeDirectSession.d.ts +19 -0
  49. package/dist/tools/finalizeDirectSession.js +84 -0
  50. package/dist/tools/getTaskSummary.d.ts +47 -0
  51. package/dist/tools/getTaskSummary.js +64 -1
  52. package/dist/tools/healthCheck.d.ts +22 -12
  53. package/dist/tools/healthCheck.js +23 -6
  54. package/dist/tools/readWorkspaceFile.d.ts +7 -1
  55. package/dist/tools/readWorkspaceFile.js +48 -2
  56. package/dist/tools/registry.js +217 -19
  57. package/dist/tools/runVerification.d.ts +16 -0
  58. package/dist/tools/runVerification.js +32 -0
  59. package/dist/tools/savePlan.d.ts +1 -0
  60. package/dist/tools/savePlan.js +38 -7
  61. package/dist/tools/searchWorkspace.d.ts +19 -0
  62. package/dist/tools/searchWorkspace.js +205 -0
  63. package/dist/tools/taskTemplates.js +2 -1
  64. package/dist/tools/toolCatalog.d.ts +3 -2
  65. package/dist/tools/toolCatalog.js +32 -5
  66. package/dist/tools/waitForTask.d.ts +2 -2
  67. package/dist/tools/waitForTask.js +1 -1
  68. package/dist/version.d.ts +2 -2
  69. package/dist/version.js +2 -2
  70. package/docs/chatgpt-usage.md +101 -0
  71. package/docs/release-checklist.md +14 -0
  72. package/docs/release-v0.6.0.md +71 -0
  73. package/examples/config.example.json +5 -0
  74. package/examples/openai-tunnel/README.md +11 -4
  75. package/examples/openai-tunnel/chatgpt-test-prompt.md +18 -14
  76. package/examples/openai-tunnel/tunnel-client.example.yaml +8 -0
  77. package/package.json +12 -8
  78. package/scripts/brand-check.js +58 -12
  79. package/scripts/control-smoke.js +206 -0
  80. package/scripts/launchers/Check-PatchWarden-Health.cmd +6 -0
  81. package/scripts/launchers/Reset-PatchWarden-Tunnel-Key.cmd +6 -0
  82. package/scripts/launchers/Restart-PatchWarden.cmd +6 -0
  83. package/scripts/launchers/Start-PatchWarden-Direct-Tunnel.cmd +7 -0
  84. package/scripts/launchers/Start-PatchWarden-Tunnel.cmd +7 -0
  85. package/scripts/lifecycle-smoke.js +66 -6
  86. package/scripts/manage-patchwarden.ps1 +639 -0
  87. package/scripts/mcp-manifest-check.js +100 -58
  88. package/scripts/mcp-smoke.js +157 -2
  89. package/scripts/pack-clean.js +3 -4
  90. package/scripts/package-manifest-check.js +78 -0
  91. package/scripts/patchwarden-mcp-direct.cmd +7 -0
  92. package/scripts/patchwarden-mcp-stdio.cmd +1 -1
  93. package/scripts/restart-patchwarden.ps1 +5 -4
  94. package/scripts/start-patchwarden-tunnel.ps1 +261 -30
  95. package/scripts/tunnel-supervisor-smoke.js +36 -4
  96. package/scripts/watcher-supervisor-smoke.js +10 -6
  97. package/src/assessments/agentAssessor.ts +324 -0
  98. package/src/assessments/assessmentStore.ts +426 -0
  99. package/src/assessments/confirmCli.ts +29 -0
  100. package/src/config.ts +178 -4
  101. package/src/direct/directAudit.ts +400 -0
  102. package/src/direct/directGuards.ts +279 -0
  103. package/src/direct/directPatch.ts +258 -0
  104. package/src/direct/directSessionStore.ts +345 -0
  105. package/src/direct/directVerification.ts +138 -0
  106. package/src/doctor.ts +103 -7
  107. package/src/runner/agentInvocation.ts +125 -0
  108. package/src/runner/changeCapture.ts +140 -5
  109. package/src/runner/runTask.ts +61 -43
  110. package/src/runner/simpleProcess.ts +223 -0
  111. package/src/runner/watch.ts +18 -2
  112. package/src/security/commandGuard.ts +46 -4
  113. package/src/security/riskEngine.ts +160 -0
  114. package/src/security/runtimeGuard.ts +41 -0
  115. package/src/smoke-test.ts +1291 -4
  116. package/src/tools/applyPatch.ts +86 -0
  117. package/src/tools/auditSession.ts +28 -0
  118. package/src/tools/auditTask.ts +100 -2
  119. package/src/tools/createDirectSession.ts +113 -0
  120. package/src/tools/createTask.ts +405 -55
  121. package/src/tools/finalizeDirectSession.ts +144 -0
  122. package/src/tools/getTaskSummary.ts +111 -1
  123. package/src/tools/healthCheck.ts +23 -6
  124. package/src/tools/readWorkspaceFile.ts +85 -2
  125. package/src/tools/registry.ts +242 -19
  126. package/src/tools/runVerification.ts +58 -0
  127. package/src/tools/savePlan.ts +57 -7
  128. package/src/tools/searchWorkspace.ts +275 -0
  129. package/src/tools/taskTemplates.ts +2 -1
  130. package/src/tools/toolCatalog.ts +35 -6
  131. package/src/tools/waitForTask.ts +3 -3
  132. package/src/version.ts +2 -2
  133. package/tsconfig.json +18 -17
  134. package/Check-PatchWarden-Health.cmd +0 -6
  135. package/Reset-PatchWarden-Tunnel-Key.cmd +0 -6
  136. package/Restart-PatchWarden.cmd +0 -19
  137. package/Start-PatchWarden-Tunnel.cmd +0 -7
  138. package/docs/release-v0.3.0.md +0 -43
  139. package/docs/release-v0.4.0.md +0 -74
@@ -0,0 +1,118 @@
1
+ import { existsSync, statSync, } from "node:fs";
2
+ import { resolve } from "node:path";
3
+ import { guardWorkspacePath } from "./pathGuard.js";
4
+ import { guardPlanContent } from "./planGuard.js";
5
+ import { guardTestCommand } from "./commandGuard.js";
6
+ import { isSensitivePath } from "./sensitiveGuard.js";
7
+ import { guardRuntimeSelfModification } from "./runtimeGuard.js";
8
+ import { PatchWardenError } from "../errors.js";
9
+ const DIST_COMMANDS = new Set(["npm run dist", "npm run pack"]);
10
+ export function assessRisk(input) {
11
+ const hardRuleHits = [];
12
+ const reasonCodes = [];
13
+ // ── Hard rules (guard functions). A hit means high → blocked. ──
14
+ let resolvedRepoPath = input.resolvedRepoPath;
15
+ try {
16
+ resolvedRepoPath = guardWorkspacePath(input.repoPath, input.config.workspaceRoot);
17
+ }
18
+ catch (e) {
19
+ hardRuleHits.push(extractReason(e));
20
+ return finalize("high", "blocked", reasonCodes, hardRuleHits, input);
21
+ }
22
+ if (!existsSync(resolvedRepoPath)) {
23
+ hardRuleHits.push("repo_path_not_found");
24
+ return finalize("high", "blocked", reasonCodes, hardRuleHits, input);
25
+ }
26
+ if (!statSync(resolvedRepoPath).isDirectory()) {
27
+ hardRuleHits.push("repo_path_not_directory");
28
+ return finalize("high", "blocked", reasonCodes, hardRuleHits, input);
29
+ }
30
+ try {
31
+ guardRuntimeSelfModification(resolvedRepoPath);
32
+ }
33
+ catch (e) {
34
+ hardRuleHits.push(extractReason(e));
35
+ return finalize("high", "blocked", reasonCodes, hardRuleHits, input);
36
+ }
37
+ if (!input.config.agents[input.agent]) {
38
+ hardRuleHits.push("agent_not_configured");
39
+ return finalize("high", "blocked", reasonCodes, hardRuleHits, input);
40
+ }
41
+ try {
42
+ guardPlanContent(input.planTitle, input.planContent);
43
+ }
44
+ catch (e) {
45
+ hardRuleHits.push(extractReason(e));
46
+ return finalize("high", "blocked", reasonCodes, hardRuleHits, input);
47
+ }
48
+ for (const cmd of [input.testCommand, ...input.verifyCommands]) {
49
+ if (!cmd || cmd.trim() === "")
50
+ continue;
51
+ try {
52
+ guardTestCommand(cmd, input.config, resolvedRepoPath);
53
+ }
54
+ catch (e) {
55
+ hardRuleHits.push(extractReason(e));
56
+ return finalize("high", "blocked", reasonCodes, hardRuleHits, input);
57
+ }
58
+ }
59
+ if (input.goal) {
60
+ const goalPath = resolve(resolvedRepoPath, input.goal);
61
+ if (isSensitivePath(input.goal) || isSensitivePath(goalPath)) {
62
+ hardRuleHits.push("sensitive_path_in_goal");
63
+ return finalize("high", "blocked", reasonCodes, hardRuleHits, input);
64
+ }
65
+ }
66
+ // ── Hard rules passed. Reason codes for passing. ──
67
+ reasonCodes.push("repo_scoped", "no_sensitive_paths", "allowlisted_commands");
68
+ // ── Snapshot truncation (微调 #2): force needs_confirm. ──
69
+ if (input.snapshotTruncated) {
70
+ reasonCodes.push("snapshot_truncated");
71
+ return finalize("medium", "needs_confirm", reasonCodes, hardRuleHits, input);
72
+ }
73
+ // ── Medium-risk policy decisions. ──
74
+ if (input.template === "release_check") {
75
+ reasonCodes.push("release_template_needs_confirm");
76
+ return finalize("medium", "needs_confirm", reasonCodes, hardRuleHits, input);
77
+ }
78
+ if (input.verifyCommands.some((c) => DIST_COMMANDS.has(c.trim()))) {
79
+ reasonCodes.push("dist_command_needs_confirm");
80
+ return finalize("medium", "needs_confirm", reasonCodes, hardRuleHits, input);
81
+ }
82
+ // ── Low risk. ──
83
+ if (input.template === "inspect_only")
84
+ reasonCodes.push("inspect_only_no_changes");
85
+ else if (input.template === "feature_small")
86
+ reasonCodes.push("feature_small_scoped");
87
+ else if (input.template === "fix_tests")
88
+ reasonCodes.push("fix_tests_scoped");
89
+ return finalize("low", "allow", reasonCodes, hardRuleHits, input);
90
+ }
91
+ /** Risk hints — keyword detection only, never affects risk_level (收缩 #4). */
92
+ export function collectRiskHints(input) {
93
+ const hints = [];
94
+ const text = `${input.goal || ""} ${input.planContent || ""}`.toLowerCase();
95
+ if (/\bpackage-lock\b/.test(text))
96
+ hints.push("mentions_package_lock");
97
+ if (/\brelease\b|\bdist\b/.test(text))
98
+ hints.push("mentions_artifact_dir");
99
+ if (/\bsync\b|\bbackup\b|\bpayload\b|\bpersistence\b/.test(text))
100
+ hints.push("mentions_dev_vocab");
101
+ return hints;
102
+ }
103
+ function finalize(risk_level, decision, reason_codes, hard_rule_hits, input) {
104
+ return {
105
+ risk_level,
106
+ decision,
107
+ reason_codes,
108
+ risk_hints: collectRiskHints(input),
109
+ hard_rule_hits,
110
+ };
111
+ }
112
+ function extractReason(error) {
113
+ if (error instanceof PatchWardenError)
114
+ return error.reason;
115
+ if (error instanceof Error)
116
+ return error.message.slice(0, 80);
117
+ return String(error).slice(0, 80);
118
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Refuse operations against the active PatchWarden runtime directory or its
3
+ * critical subdirectories. Extracted from createTask.ts so assess-only flows
4
+ * and direct-session flows share the same protection.
5
+ */
6
+ export declare function guardRuntimeSelfModification(resolvedRepoPath: string): void;
@@ -0,0 +1,28 @@
1
+ import { resolve, join, dirname } from "node:path";
2
+ import { fileURLToPath } from "node:url";
3
+ import { PatchWardenError } from "../errors.js";
4
+ const CRITICAL_RUNTIME_DIRS = ["dist", "src", "scripts", "release"];
5
+ /**
6
+ * Refuse operations against the active PatchWarden runtime directory or its
7
+ * critical subdirectories. Extracted from createTask.ts so assess-only flows
8
+ * and direct-session flows share the same protection.
9
+ */
10
+ export function guardRuntimeSelfModification(resolvedRepoPath) {
11
+ const runtimeRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
12
+ if (resolvedRepoPath === runtimeRoot ||
13
+ resolvedRepoPath.startsWith(runtimeRoot + resolve("/")[0])) {
14
+ const isCritical = CRITICAL_RUNTIME_DIRS.some((dir) => {
15
+ const full = join(runtimeRoot, dir);
16
+ return (resolvedRepoPath === full ||
17
+ resolvedRepoPath.startsWith(full + resolve("/")[0]));
18
+ });
19
+ if (resolvedRepoPath === runtimeRoot || isCritical) {
20
+ throw new PatchWardenError("runtime_self_modification_blocked", `repo_path points to the active PatchWarden runtime or its critical subdirectories.`, "Use a dev copy or git worktree for PatchWarden development. The running MCP server must not be modified by a task.", true, {
21
+ operation: "runtime_guard",
22
+ path: resolvedRepoPath,
23
+ runtime_root: runtimeRoot,
24
+ safe_alternative: "Clone or copy PatchWarden to a separate directory for development tasks.",
25
+ });
26
+ }
27
+ }
28
+ }