progmune-runtime 3.3.8 → 3.4.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/CHANGELOG.md ADDED
@@ -0,0 +1,50 @@
1
+ # Changelog
2
+
3
+ ## [3.4.1] — 2026-08-22
4
+
5
+ ### 修复:`npm run check` 四项失败根因
6
+
7
+ - protocol-registry:protocols.json 解析加包目录回退——在无协议文件的项目目录下运行时,命名空间初始状态不再退化为仅 `_global`(session 记录与 check 重建的世界一致)
8
+ - checkLedgerConsistency:只比较 ledger 中记录过的非空快照命名空间(早期 session 的空数组/部分命名空间不参与比较)
9
+ - check:历史约定兼容——早期 session 的 `INIT` 初始状态按当前约定(`UNAUTHENTICATED`)规范化比较(只比较、不改盘)
10
+ - audit:`.progmune_allowlist` 祖父条款——存量手写代码一次入册,新文件仍受覆盖率约束
11
+ - 结果:check 从 4 失败 → 0 失败(免疫状态正常),1313/1313 Ledger 全过
12
+
13
+ ### 新增:P5 操作级安全层 v1
14
+
15
+ - 权限决策引擎(auto / sandbox / approve / deny 四级)+ patrol / agent 预设
16
+ - FsSandbox 白名单(巡逻报告等产品文件);shell 执行审批门(`--yes` 或交互确认)
17
+ - **commit 恒拒绝且不可被 `--yes` 绕过**(修复信任悖论:自动修复/自动合并永不)
18
+
19
+ ## [3.4.0] — 2026-08-21
20
+
21
+ ### 新增:Agent 化 P1–P4.5
22
+
23
+ - `npm run agent "意图"` — 免疫门在环内的自主实现循环:目标分解 → 8 门验证 → SSG 确定性修复 → 写盘+指纹 → 编译/指纹/测试验证门 → 失败反馈重试(≤3)→ 审计轨迹 + 带指纹 diff
24
+ - `npm run patrol -- --project X [--watch]` — 免疫巡逻:trust_check → 违规报告 + 建议补丁(**绝不自动合并**,修复需人工审批)
25
+ - 感知层:Git 仓库上下文注入、IR 增量差集、文件变更监听(RepoWatcher)
26
+ - 自监督层:项目测试门(npm test / pytest 自动探测,失败摘要注入重试反馈)
27
+
28
+ ### 行为变化:Trust 引擎协议验证语义(P4.5)
29
+
30
+ - 协议违规收集从「正则扫描文件声明序列」改为「IR 函数体调用序列」:
31
+ - 函数声明顺序不再被当作执行链(消除 auth.ts 类声明误报)
32
+ - 单调用违规文件不再被 `≥4` 阈值跳过(修复 bad_flow 类漏报)
33
+ - 合并项目 `@protocol` 注解(IR 优先、缺 namespace 继承内置 JSON,对齐 planner 语义)——项目级前置约束现在生效
34
+ - **升级后 trust 检查结果可能与 3.3.x 不同:误报减少、真违规命中增多**
35
+
36
+ ### 修复
37
+
38
+ - `verifyCompiles` 绝对路径漏匹配——编译验证门静默漏报
39
+ - `@protocol` 注解解析早退——文件首函数协议丢失,SSG 误拦正确调用链
40
+ - 语义 marker(`__progmune_*`)泄漏进 LLM 可见函数表,被生成为真实调用
41
+ - LLM 调用异常静默吞没——改为可见日志(铁律:不许静默绕过)
42
+ - `git status --porcelain` 首字符状态列被整串 trim 截断
43
+
44
+ ### 已知问题
45
+
46
+ - `npm run check` 的 Ledger 不变量 / 回放 / 覆盖率失败为历史遗留(基线核查确认与本次改动无关),待单独排期
47
+
48
+ ## [3.3.8] — 2026-08-18
49
+
50
+ - README 链接跨平台修复(npm 页面语言切换链接)
@@ -0,0 +1,215 @@
1
+ "use strict";
2
+ /**
3
+ * Phase 12: Progmune Agent CLI — `progmune agent "意图"`
4
+ *
5
+ * P1 最小 agent loop 的命令行入口。免疫门在环内:意图 → 目标分解 →
6
+ * execute()(plan→8门验证→SSG修复→emit→写盘+指纹)→ 编译/指纹验证门 →
7
+ * 失败反馈重试 → 带指纹 diff 输出。
8
+ *
9
+ * Usage:
10
+ * npx ts-node src/agent-cli.ts "实现 XX" [options]
11
+ * npm run agent -- "实现 XX" [options] (构建后)
12
+ *
13
+ * Options:
14
+ * --file <path> 输出文件(相对 project 目录)
15
+ * --project <dir> 目标项目目录(默认 CWD)
16
+ * --iterations <n> 最大迭代轮数(默认 5)
17
+ * --retries <n> 每轮最大重试(默认 3)
18
+ * --timeout <ms> 单次执行超时毫秒(默认 120000)
19
+ * --context 注入 git 仓库上下文(默认开启)
20
+ * --no-context 关闭 git 上下文注入
21
+ * --test 编译/指纹通过后追加项目测试门(shell 执行需审批)
22
+ * --yes 预批准审批门(配合 --test;无此参数时交互确认)
23
+ * --json JSON 输出
24
+ * --help, -h 显示帮助
25
+ */
26
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
27
+ if (k2 === undefined) k2 = k;
28
+ var desc = Object.getOwnPropertyDescriptor(m, k);
29
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
30
+ desc = { enumerable: true, get: function() { return m[k]; } };
31
+ }
32
+ Object.defineProperty(o, k2, desc);
33
+ }) : (function(o, m, k, k2) {
34
+ if (k2 === undefined) k2 = k;
35
+ o[k2] = m[k];
36
+ }));
37
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
38
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
39
+ }) : function(o, v) {
40
+ o["default"] = v;
41
+ });
42
+ var __importStar = (this && this.__importStar) || (function () {
43
+ var ownKeys = function(o) {
44
+ ownKeys = Object.getOwnPropertyNames || function (o) {
45
+ var ar = [];
46
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
47
+ return ar;
48
+ };
49
+ return ownKeys(o);
50
+ };
51
+ return function (mod) {
52
+ if (mod && mod.__esModule) return mod;
53
+ var result = {};
54
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
55
+ __setModuleDefault(result, mod);
56
+ return result;
57
+ };
58
+ })();
59
+ Object.defineProperty(exports, "__esModule", { value: true });
60
+ const path = __importStar(require("path"));
61
+ const agent_loop_1 = require("./agent-loop");
62
+ const args = process.argv.slice(2);
63
+ // ── Help ──
64
+ if (args.includes("--help") || args.includes("-h")) {
65
+ console.log(`
66
+ Progmune Agent — 免疫门在环内的自主实现循环 (P1)
67
+
68
+ Usage:
69
+ npx ts-node src/agent-cli.ts "实现 XX" [options]
70
+ npm run agent -- "实现 XX" [options]
71
+
72
+ Options:
73
+ --file <path> 输出文件(相对 project 目录)
74
+ --project <dir> 目标项目目录(默认当前目录)
75
+ --iterations <n> 最大迭代轮数(默认 5)
76
+ --retries <n> 每轮最大重试(默认 3)
77
+ --timeout <ms> 单次执行超时毫秒(默认 120000)
78
+ --context 注入 git 仓库上下文(默认开启)
79
+ --no-context 关闭 git 上下文注入
80
+ --test 编译/指纹通过后追加项目测试门
81
+ --json JSON 输出
82
+ --help, -h 显示帮助
83
+
84
+ Example:
85
+ npm run agent -- "实现会话刷新函数" --project demo-project --file refresh_session.ts
86
+ `);
87
+ process.exit(0);
88
+ }
89
+ // ── Arg parsing ──
90
+ function parseArgs(argv) {
91
+ const intentParts = [];
92
+ let file;
93
+ let project = process.cwd();
94
+ let iterations = 5;
95
+ let retries = 3;
96
+ let timeout = 120000;
97
+ let context = true;
98
+ let test = false;
99
+ let yes = false;
100
+ let json = false;
101
+ for (let i = 0; i < argv.length; i++) {
102
+ const a = argv[i];
103
+ if (a === "--file") {
104
+ file = argv[++i];
105
+ }
106
+ else if (a === "--project") {
107
+ project = argv[++i];
108
+ }
109
+ else if (a === "--iterations") {
110
+ iterations = parseInt(argv[++i], 10) || 5;
111
+ }
112
+ else if (a === "--retries") {
113
+ retries = parseInt(argv[++i], 10) || 3;
114
+ }
115
+ else if (a === "--timeout") {
116
+ timeout = parseInt(argv[++i], 10) || 120000;
117
+ }
118
+ else if (a === "--context") {
119
+ context = true;
120
+ }
121
+ else if (a === "--no-context") {
122
+ context = false;
123
+ }
124
+ else if (a === "--test") {
125
+ test = true;
126
+ }
127
+ else if (a === "--yes") {
128
+ yes = true;
129
+ }
130
+ else if (a === "--json") {
131
+ json = true;
132
+ }
133
+ else {
134
+ intentParts.push(a);
135
+ }
136
+ }
137
+ const intent = intentParts.join(" ").trim();
138
+ if (!intent) {
139
+ console.error("❌ 缺少意图参数。用法: progmune agent \"实现 XX\" [--file path] [--project dir]");
140
+ process.exit(2);
141
+ }
142
+ return { intent, file, project, iterations, retries, timeout, context, test, yes, json };
143
+ }
144
+ // ── Formatting ──
145
+ function printAttempt(i, r) {
146
+ const a = r.attempts[i];
147
+ const mark = a.success ? "✅" : "❌";
148
+ const testGate = a.testRan ? ` test=${a.testPass ? "pass" : "FAIL"}` : "";
149
+ const gates = a.success
150
+ ? `compile=${a.compilePass} marker=${a.markerPass}${testGate}`
151
+ : `compile=${a.compilePass} marker=${a.markerPass}${testGate}${a.error ? ` err=${a.error.slice(0, 80)}` : ""}`;
152
+ console.log(`[#${a.attempt}] iter ${a.iteration} retry ${a.attempt - 1 - (a.iteration - 1) * 3} ${mark} ` +
153
+ `session=${a.sessionId || "-"} fp=${a.fingerprint || "-"} repair=${a.repairCount} ${gates}`);
154
+ }
155
+ function printResult(r, opts) {
156
+ console.log("");
157
+ if (r.success) {
158
+ console.log(`✅ 完成: intent="${opts.intent}"`);
159
+ if (r.filePath)
160
+ console.log(` 文件: ${r.filePath}`);
161
+ console.log(` 指纹: ${r.fingerprint}`);
162
+ console.log(` 迭代: ${r.iterations} 轮 / 重试: ${r.retries} 次${r.degraded ? " / ⚠️ 降级(LLM 回退)" : ""}`);
163
+ if (r.irDelta) {
164
+ console.log(` IR 增量: +${r.irDelta.added.length} -${r.irDelta.removed.length}` +
165
+ (r.irDelta.added.length > 0 ? ` 新增: ${r.irDelta.added.join(", ")}` : ""));
166
+ }
167
+ console.log(` 审计事件: ${r.auditTrail.length} 条(含 ${r.attempts.length} 次尝试记录)`);
168
+ console.log("");
169
+ console.log("── diff ──");
170
+ console.log(r.diff.slice(0, 2000) || "(空)");
171
+ }
172
+ else {
173
+ console.log(`❌ 失败: intent="${opts.intent}" 共 ${r.attempts.length} 次尝试`);
174
+ console.log(` 最后错误: ${r.attempts[r.attempts.length - 1]?.error || "迭代耗尽"}`);
175
+ console.log(` 审计轨迹 ${r.auditTrail.length} 条事件(可回放)`);
176
+ }
177
+ }
178
+ // ── Main ──
179
+ async function main() {
180
+ const opts = parseArgs(args);
181
+ const projectPath = path.resolve(opts.project);
182
+ // 切到项目目录:execute 写 ir.json 到 CWD,verifyCompiles 跑项目 tsconfig,
183
+ // git diff 也相对项目。dotenv/.env 在模块加载时已按启动 CWD 读取。
184
+ process.chdir(projectPath);
185
+ console.log(`⚙️ Progmune Agent (P2+P3) — 免疫门在环内`);
186
+ console.log(` 意图: ${opts.intent}`);
187
+ console.log(` 项目: ${projectPath}`);
188
+ console.log(` 输出: ${opts.file ? path.resolve(opts.file) : "(未指定)"}`);
189
+ console.log(` 感知: git上下文=${opts.context ? "开" : "关"} 测试门=${opts.test ? "开" : "关"}`);
190
+ console.log("");
191
+ const result = await (0, agent_loop_1.runAgentLoop)({
192
+ projectPath,
193
+ intent: opts.intent,
194
+ filePath: opts.file,
195
+ maxIterations: opts.iterations,
196
+ maxRetries: opts.retries,
197
+ timeoutMs: opts.timeout,
198
+ includeContext: opts.context,
199
+ runTests: opts.test,
200
+ approveExec: opts.yes,
201
+ });
202
+ if (opts.json) {
203
+ console.log(JSON.stringify(result, null, 2));
204
+ }
205
+ else {
206
+ console.log(` 目标分解: ${result.subgoals.length > 0 ? result.subgoals.join(" → ") : "无模板命中"}`);
207
+ result.attempts.forEach((_, i) => printAttempt(i, result));
208
+ printResult(result, { intent: opts.intent, file: opts.file });
209
+ }
210
+ process.exit(result.success ? 0 : 1);
211
+ }
212
+ main().catch((e) => {
213
+ console.error(`❌ Agent CLI 异常: ${e?.message || e}`);
214
+ process.exit(1);
215
+ });
@@ -0,0 +1,333 @@
1
+ "use strict";
2
+ /**
3
+ * Phase 12: Agent Loop Controller (P1)
4
+ *
5
+ * Progmune Agent 最小闭环 —— 免疫门在环内的自主实现循环。
6
+ *
7
+ * Loop:
8
+ * intent → 目标分解(GoalPlanner) → execute()(plan→8门验证→SSG修复→emit→写盘+指纹)
9
+ * → verifyCompiles / verifyFileMarker(写盘后验证门)
10
+ * → 失败反馈注入 → 重试(≤maxRetries) → 迭代(≤maxIterations)
11
+ * → 成功输出带指纹 diff + 完整审计轨迹
12
+ *
13
+ * 铁律(Agent 化设计文档 v1.1):
14
+ * 1. 验证门必须在环内 —— 写盘前已过 plan/emit 内验证,写盘后再过编译+指纹门;
15
+ * 2. 违规优先确定性修复(execute 内 SSG 修复),其次 LLM 重试,最后明确降级;
16
+ * 3. 失败反馈必须注入下一次尝试 —— 不静默重试同一输入。
17
+ *
18
+ * 设计文档里程碑 M1 验收:
19
+ * progmune agent "实现 XX" → 全程过验证门 → 编译通过 → 输出带指纹 diff;
20
+ * 失败注入重试 ≤3;审计轨迹完整。
21
+ */
22
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
23
+ if (k2 === undefined) k2 = k;
24
+ var desc = Object.getOwnPropertyDescriptor(m, k);
25
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
26
+ desc = { enumerable: true, get: function() { return m[k]; } };
27
+ }
28
+ Object.defineProperty(o, k2, desc);
29
+ }) : (function(o, m, k, k2) {
30
+ if (k2 === undefined) k2 = k;
31
+ o[k2] = m[k];
32
+ }));
33
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
34
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
35
+ }) : function(o, v) {
36
+ o["default"] = v;
37
+ });
38
+ var __importStar = (this && this.__importStar) || (function () {
39
+ var ownKeys = function(o) {
40
+ ownKeys = Object.getOwnPropertyNames || function (o) {
41
+ var ar = [];
42
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
43
+ return ar;
44
+ };
45
+ return ownKeys(o);
46
+ };
47
+ return function (mod) {
48
+ if (mod && mod.__esModule) return mod;
49
+ var result = {};
50
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
51
+ __setModuleDefault(result, mod);
52
+ return result;
53
+ };
54
+ })();
55
+ Object.defineProperty(exports, "__esModule", { value: true });
56
+ exports.computeDiff = computeDiff;
57
+ exports.runAgentLoop = runAgentLoop;
58
+ const child_process_1 = require("child_process");
59
+ const fs = __importStar(require("fs"));
60
+ const path = __importStar(require("path"));
61
+ const execute_1 = require("./execute");
62
+ const goal_planner_1 = require("./goal-planner");
63
+ const agent_perception_1 = require("./agent-perception");
64
+ const agent_supervision_1 = require("./agent-supervision");
65
+ const agent_permissions_1 = require("./agent-permissions");
66
+ // ── Helpers ──
67
+ /** 单次执行超时包装。超时后底层 promise 继续运行(P1 已知限制,文档化即可)。 */
68
+ function withTimeout(p, ms, label) {
69
+ return new Promise((resolve, reject) => {
70
+ const timer = setTimeout(() => reject(new Error(`${label} 超时(${ms}ms)`)), ms);
71
+ p.then((v) => { clearTimeout(timer); resolve(v); }, (e) => { clearTimeout(timer); reject(e); });
72
+ });
73
+ }
74
+ /** 构造失败的 ExecuteResult(execute 抛异常时的兜底) */
75
+ function failedExecuteResult(error) {
76
+ return {
77
+ success: false,
78
+ code: "",
79
+ sessionId: "",
80
+ hash: "",
81
+ ruleHash: "",
82
+ irFunctionCount: 0,
83
+ protocolRuleCount: 0,
84
+ violations: 0,
85
+ degraded: false,
86
+ repairApplied: false,
87
+ repairCount: 0,
88
+ repairBranchIds: [],
89
+ error,
90
+ };
91
+ }
92
+ /** 计算目标文件的 git diff;新文件/非 git 仓库时回退为摘要。 */
93
+ function computeDiff(projectPath, filePath) {
94
+ const abs = path.isAbsolute(filePath) ? filePath : path.resolve(projectPath, filePath);
95
+ try {
96
+ const out = (0, child_process_1.execSync)(`git -C "${projectPath}" diff -- "${abs}"`, {
97
+ encoding: "utf-8",
98
+ timeout: 10000,
99
+ stdio: "pipe",
100
+ }).trim();
101
+ if (out)
102
+ return out;
103
+ const status = (0, child_process_1.execSync)(`git -C "${projectPath}" status --porcelain -- "${abs}"`, {
104
+ encoding: "utf-8",
105
+ timeout: 10000,
106
+ stdio: "pipe",
107
+ }).trim();
108
+ if (status)
109
+ return `(新文件,未跟踪)\n${status}`;
110
+ return "(无 git 变更)";
111
+ }
112
+ catch (e) {
113
+ // 非 git 仓库或文件不存在 → 回退为文件内容摘要
114
+ try {
115
+ const content = fs.readFileSync(abs, "utf-8");
116
+ return `(git diff 不可用: ${e.message})\n${content.slice(0, 500)}`;
117
+ }
118
+ catch {
119
+ return `(git diff 不可用: ${e.message})`;
120
+ }
121
+ }
122
+ }
123
+ // ── Main Loop ──
124
+ /**
125
+ * 运行 P1 最小 agent loop。
126
+ *
127
+ * @requires INTENT @produces AGENT_LOOP_RESULT
128
+ */
129
+ async function runAgentLoop(opts) {
130
+ const projectPath = path.resolve(opts.projectPath);
131
+ const maxIterations = opts.maxIterations ?? 5;
132
+ const maxRetries = opts.maxRetries ?? 3;
133
+ const timeoutMs = opts.timeoutMs ?? 120000;
134
+ const includeContext = opts.includeContext ?? false;
135
+ const runTestsGate = opts.runTests ?? false;
136
+ const attempts = [];
137
+ const auditTrail = [];
138
+ const audit = (event, detail) => auditTrail.push({ timestamp: new Date().toISOString(), event, detail });
139
+ audit("loop:start", `intent="${opts.intent}" project=${projectPath} file=${opts.filePath || "(未指定)"} ` +
140
+ `maxIterations=${maxIterations} maxRetries=${maxRetries} timeoutMs=${timeoutMs} ` +
141
+ `context=${includeContext} tests=${runTestsGate}`);
142
+ // ── P2 感知:git 上下文(best-effort) ──
143
+ let gitContext;
144
+ let contextHint = "";
145
+ if (includeContext) {
146
+ gitContext = (0, agent_perception_1.collectGitContext)(projectPath);
147
+ audit("perception:git", gitContext.available
148
+ ? `branch=${gitContext.branch} commits=${gitContext.recentCommits.length} ` +
149
+ `changed=${gitContext.changedFiles.length} files=${gitContext.sourceFiles.length}`
150
+ : `不可用: ${gitContext.error}`);
151
+ if (gitContext.available) {
152
+ contextHint =
153
+ `\n[项目上下文:分支 ${gitContext.branch};` +
154
+ `最近提交: ${gitContext.recentCommits.slice(0, 2).join(" / ") || "(无)"};` +
155
+ `变更文件: ${gitContext.changedFiles.slice(0, 5).join(", ") || "(无)"}]`;
156
+ }
157
+ }
158
+ // ── P2 感知:初始 IR 函数名集合(成功时算增量) ──
159
+ let prevIRNames;
160
+ try {
161
+ const { ir } = (0, agent_perception_1.extractIRWithDelta)(projectPath);
162
+ prevIRNames = new Set(ir.map((f) => String(f.name || "")).filter(Boolean));
163
+ audit("perception:ir", `初始 IR ${prevIRNames.size} 个函数`);
164
+ }
165
+ catch (e) {
166
+ audit("perception:ir", `初始 IR 提取失败(忽略): ${e.message}`);
167
+ }
168
+ // ── 目标分解(best-effort,不阻塞主循环) ──
169
+ let subgoals = [];
170
+ try {
171
+ subgoals = (0, goal_planner_1.expandGoalActions)(opts.intent);
172
+ audit("goal:decompose", subgoals.length > 0 ? `子目标: ${subgoals.join(" → ")}` : "无模板命中,单目标直行");
173
+ }
174
+ catch (e) {
175
+ audit("goal:decompose", `目标分解失败(忽略): ${e.message}`);
176
+ }
177
+ let attemptNo = 0;
178
+ const baseIntent = `${opts.intent}${contextHint}`;
179
+ let currentIntent = baseIntent;
180
+ for (let iteration = 1; iteration <= maxIterations; iteration++) {
181
+ audit("iteration:start", `第 ${iteration}/${maxIterations} 轮`);
182
+ for (let retry = 0; retry < maxRetries; retry++) {
183
+ attemptNo++;
184
+ const startedAt = new Date().toISOString();
185
+ audit("attempt:start", `#${attemptNo} (iter ${iteration}, retry ${retry}) intent="${currentIntent.slice(0, 120)}"`);
186
+ // ── 执行(内部含 plan → 8 门验证 → SSG 修复 → emit → 写盘+指纹) ──
187
+ let result;
188
+ try {
189
+ result = await withTimeout((0, execute_1.execute)(currentIntent, projectPath, opts.filePath), timeoutMs, `execute #${attemptNo}`);
190
+ }
191
+ catch (e) {
192
+ result = failedExecuteResult(`execute 抛出异常: ${e.message}`);
193
+ }
194
+ // ── 写盘后验证门(编译 + 指纹标记) ──
195
+ let compilePass = false;
196
+ let markerPass = false;
197
+ let filePath = opts.filePath || result.filePath;
198
+ if (result.success && filePath) {
199
+ const resolved = path.isAbsolute(filePath) ? filePath : path.resolve(projectPath, filePath);
200
+ try {
201
+ const compile = (0, execute_1.verifyCompiles)(resolved);
202
+ compilePass = compile.pass;
203
+ const marker = (0, execute_1.verifyFileMarker)(resolved);
204
+ markerPass = marker.marked;
205
+ }
206
+ catch (e) {
207
+ audit("verify:error", `写盘后验证门异常: ${e.message}`);
208
+ }
209
+ }
210
+ else if (result.success) {
211
+ // 产码模式(未指定输出文件):编译门不适用;指纹门改为检查代码头部标记
212
+ compilePass = true;
213
+ markerPass = result.code.includes("@progmune-generated");
214
+ }
215
+ // ── P3 自监督:项目测试门(可选,编译/指纹通过后才跑) ──
216
+ let testRan = false;
217
+ let testPass = true;
218
+ let testFailureSummary = "";
219
+ if (result.success && compilePass && markerPass && runTestsGate && filePath) {
220
+ // ── P5 安全层:跑测试 = shell 执行 → 审批门 ──
221
+ const execDecision = (0, agent_permissions_1.decidePermission)("agent", { level: "exec", target: "项目测试(npm test / pytest)", projectPath, preApproved: opts.approveExec }, agent_permissions_1.interactiveConfirm);
222
+ audit(execDecision.audit.event, execDecision.audit.detail);
223
+ if (!execDecision.allowed) {
224
+ audit("verify:test", "测试门被审批门拒绝,跳过(--yes 可预批准)");
225
+ }
226
+ else {
227
+ try {
228
+ const t = (0, agent_supervision_1.runProjectTests)(projectPath);
229
+ testRan = t.ran;
230
+ testPass = t.pass;
231
+ if (t.ran) {
232
+ audit("verify:test", t.pass ? `测试通过 (${t.command})` : `测试失败: ${t.failures.slice(0, 3).join(" | ")}`);
233
+ if (!t.pass)
234
+ testFailureSummary = `项目测试失败: ${t.failures.slice(0, 3).join(";")}`;
235
+ }
236
+ }
237
+ catch (e) {
238
+ audit("verify:test", `测试门异常(忽略): ${e.message}`);
239
+ }
240
+ }
241
+ }
242
+ const attempt = {
243
+ attempt: attemptNo,
244
+ iteration,
245
+ intent: currentIntent,
246
+ feedback: attemptNo > 1 ? currentIntent.slice(opts.intent.length) || undefined : undefined,
247
+ startedAt,
248
+ success: result.success && compilePass && markerPass && (!testRan || testPass),
249
+ degraded: result.degraded || false,
250
+ sessionId: result.sessionId || "",
251
+ filePath,
252
+ fingerprint: result.hash || "",
253
+ ruleHash: result.ruleHash || "",
254
+ irFunctionCount: result.irFunctionCount,
255
+ violations: result.violations,
256
+ repairApplied: result.repairApplied,
257
+ repairCount: result.repairCount,
258
+ compilePass,
259
+ markerPass,
260
+ testRan,
261
+ testPass,
262
+ error: result.error,
263
+ };
264
+ attempts.push(attempt);
265
+ // ── 成功出口 ──
266
+ if (attempt.success) {
267
+ const diff = filePath ? computeDiff(projectPath, filePath) : "(未指定输出文件,无 diff)";
268
+ audit("attempt:ok", `#${attemptNo} 验证门全通过: sessionId=${result.sessionId} fingerprint=${result.hash} ` +
269
+ `compile=${compilePass} marker=${markerPass} test=${testRan ? testPass : "(未跑)"} ` +
270
+ `repairApplied=${result.repairApplied}`);
271
+ audit("loop:success", `fingerprint=${result.hash} 迭代=${iteration} 重试=${attemptNo - 1}`);
272
+ // ── P2 感知:成功时 IR 增量(agent 写盘后 IR 变化观测) ──
273
+ let irDelta;
274
+ try {
275
+ const { delta } = (0, agent_perception_1.extractIRWithDelta)(projectPath, prevIRNames);
276
+ irDelta = delta;
277
+ audit("perception:ir", `IR 增量: +${delta.added.length} -${delta.removed.length} (共 ${delta.functionCount} 函数)` +
278
+ (delta.added.length > 0 ? ` 新增: ${delta.added.join(", ")}` : ""));
279
+ }
280
+ catch (e) {
281
+ audit("perception:ir", `成功时 IR 增量提取失败(忽略): ${e.message}`);
282
+ }
283
+ return {
284
+ success: true,
285
+ attempts,
286
+ iterations: iteration,
287
+ retries: attemptNo - 1,
288
+ subgoals,
289
+ filePath,
290
+ fingerprint: result.hash,
291
+ diff,
292
+ auditTrail,
293
+ degraded: result.degraded || false,
294
+ irDelta,
295
+ gitContext,
296
+ };
297
+ }
298
+ // ── 失败反馈注入(不静默重试同一输入) ──
299
+ const reasons = [];
300
+ if (!result.success)
301
+ reasons.push(result.error || "执行失败");
302
+ if (result.success && !compilePass)
303
+ reasons.push("编译验证未通过");
304
+ if (result.success && !markerPass)
305
+ reasons.push("指纹标记缺失");
306
+ if (testFailureSummary)
307
+ reasons.push(testFailureSummary);
308
+ const feedback = reasons.join(";");
309
+ audit("attempt:fail", `#${attemptNo} ${feedback || "未知原因"}`);
310
+ if (retry < maxRetries - 1) {
311
+ currentIntent = `${baseIntent}\n[上一次尝试失败:${feedback}。请修复后重新实现。]`;
312
+ audit("retry", `注入反馈后重试 #${retry + 2}/${maxRetries}`);
313
+ }
314
+ else {
315
+ currentIntent = baseIntent; // 进入下一迭代前复位意图
316
+ }
317
+ }
318
+ audit("iteration:end", `第 ${iteration} 轮耗尽 ${maxRetries} 次重试`);
319
+ }
320
+ audit("loop:exhausted", `迭代上限 ${maxIterations} 轮后仍未成功,共 ${attemptNo} 次尝试`);
321
+ return {
322
+ success: false,
323
+ attempts,
324
+ iterations: maxIterations,
325
+ retries: attemptNo,
326
+ subgoals,
327
+ fingerprint: "",
328
+ diff: "",
329
+ auditTrail,
330
+ degraded: attempts.some((a) => a.degraded),
331
+ gitContext,
332
+ };
333
+ }