progmune-runtime 2.0.4 → 2.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/.mcp.json +11 -0
- package/.progmune_allowlist +50 -0
- package/.test_report/test_report.md +87 -0
- package/Dockerfile +2 -10
- package/FAQ.md +167 -0
- package/demo-project/auth.ts +55 -0
- package/demo-project/tsconfig.json +8 -0
- package/dist/ab-stats.js +11 -0
- package/dist/acl-breakdown.js +13 -0
- package/dist/all-sessions.js +11 -0
- package/dist/antibody-stats.js +11 -0
- package/dist/audit.js +218 -0
- package/dist/benchmark-count.js +7 -0
- package/dist/benchmark-full.js +17 -0
- package/dist/benchmark-pass-rate.js +54 -0
- package/dist/benchmark-report.js +67 -0
- package/dist/benchmark-save.js +62 -0
- package/dist/benchmark-status.js +15 -0
- package/dist/branch-ledger.js +365 -0
- package/dist/branch-tree-count.js +14 -0
- package/dist/check.js +506 -0
- package/dist/common-fixpath.js +12 -0
- package/dist/constraint-types.js +12 -0
- package/dist/deterministic-replay.js +277 -0
- package/dist/emitter.js +112 -12
- package/dist/exec-metrics.js +11 -0
- package/dist/execute.js +242 -0
- package/dist/extract-ir.js +550 -5
- package/dist/failure-collector.js +143 -0
- package/dist/failure-corpus.js +481 -35
- package/dist/failure-report.js +11 -0
- package/dist/failures.js +11 -0
- package/dist/fast-path-hits.js +13 -0
- package/dist/feedback.js +6 -3
- package/dist/file-lock.js +82 -0
- package/dist/find-session.js +10 -0
- package/dist/fingerprint-list.js +15 -0
- package/dist/gen-history-log.js +13 -0
- package/dist/generate.js +2 -1
- package/dist/generate_500.js +4 -2
- package/dist/genome.js +11 -0
- package/dist/heatmap-data.js +11 -0
- package/dist/heatmap.js +11 -0
- package/dist/immune-reporter.js +33 -22
- package/dist/learned.js +11 -0
- package/dist/ledger-registry.js +241 -0
- package/dist/llm.js +43 -2
- package/dist/load-benchmarks.js +47 -0
- package/dist/main.js +2 -1
- package/dist/mcp-server.mjs +445 -43
- package/dist/memory-layer.js +51 -13
- package/dist/metrics.js +11 -0
- package/dist/obs-web.js +561 -0
- package/dist/p0_ssg_demo.js +255 -40
- package/dist/planner.js +905 -80
- package/dist/protocol-registry.js +105 -0
- package/dist/recent-session.js +12 -0
- package/dist/repair-proposal.js +353 -0
- package/dist/runtime-invariants.js +161 -0
- package/dist/runtime-types.js +117 -0
- package/dist/search-planner.js +38 -9
- package/dist/semantic-snapshot.js +155 -0
- package/dist/semantic-trace.js +1497 -0
- package/dist/semantic-validator.js +3 -2
- package/dist/semantic_guard_test.js +2 -1
- package/dist/sessions.js +11 -0
- package/dist/ssg-validator.js +658 -20
- package/dist/svl-distribution.js +11 -0
- package/dist/terminal-status.js +11 -0
- package/dist/test_failure_corpus.js +3 -1
- package/dist/token-savings.js +11 -0
- package/dist/total-repairs.js +12 -0
- package/dist/unresolved-count.js +12 -0
- package/dist/valid-fingerprints.js +13 -0
- package/dist/validator.js +116 -60
- package/dist/verify-fps.js +11 -0
- package/dist/verify-ledgers.js +11 -0
- package/docs/whitepaper-style.css +77 -0
- package/docs/whitepaper-v2.1.md +609 -0
- package/docs/whitepaper-v2.2.md +1064 -0
- package/docs/whitepaper-v2.2.pdf +0 -0
- package/fly.toml +1 -1
- package/package.json +13 -4
- package/protocols.json +131 -11
- package/public/dashboard.html +119 -0
- package/readme.md +829 -0
- package/server/hub.js +84 -12
- package/test/replay-golden/sess_1780063202050_mgeld.json +9 -0
- package/test/replay-golden/sess_1780064032560_gocld.json +354 -0
- package/test/replay-golden/sess_1780064413331_s2709.json +606 -0
- package/test/replay-golden/sess_1780064792710_y3avo.json +614 -0
- package/test/replay-golden.ts +84 -0
- package/test_benchmark.js +165 -0
- package/test_comprehensive.mjs +638 -0
- package/test_concurrency.js +129 -0
- package/test_ir_robustness.js +85 -0
- package/test_semantic_contracts.js +269 -0
- package/test_ssg_stress.js +156 -0
- package/test_svl3.js +58 -0
- package/tsconfig.json +1 -1
- package/.env.example +0 -3
- package/.progmune_memory/episodic.json +0 -186
- package/.progmune_memory/fingerprints.json +0 -7
- package/.progmune_memory/opt_in.json +0 -4
- package/README.md +0 -118
- package/immune_hub_data/2026-05-14.json +0 -50
package/.mcp.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Progmune Allowlist — files exempt from @progmune-generated requirement
|
|
2
|
+
# Add patterns (one per line) for files that don't need the marker.
|
|
3
|
+
# Lines starting with # are comments.
|
|
4
|
+
|
|
5
|
+
# Configuration files
|
|
6
|
+
\\.json$
|
|
7
|
+
\\.md$
|
|
8
|
+
\\.sh$
|
|
9
|
+
\\.css$
|
|
10
|
+
\\.html$
|
|
11
|
+
|
|
12
|
+
# Test files
|
|
13
|
+
test-.*
|
|
14
|
+
.*\\.test\\.ts$
|
|
15
|
+
.*\\.spec\\.ts$
|
|
16
|
+
test_.*\\.ts$
|
|
17
|
+
test_.*\\.mjs$
|
|
18
|
+
test_.*\\.js$
|
|
19
|
+
|
|
20
|
+
# Build artifacts
|
|
21
|
+
dist/
|
|
22
|
+
node_modules/
|
|
23
|
+
|
|
24
|
+
# Progmune's own infrastructure (core files that predate Phase 4.5)
|
|
25
|
+
src/runtime-types\\.ts$
|
|
26
|
+
src/runtime-invariants\\.ts$
|
|
27
|
+
src/ssg-validator\\.ts$
|
|
28
|
+
src/failure-corpus\\.ts$
|
|
29
|
+
src/memory-layer\\.ts$
|
|
30
|
+
src/planner\\.ts$
|
|
31
|
+
src/emitter\\.ts$
|
|
32
|
+
src/extract-ir.*\\.ts$
|
|
33
|
+
src/validator\\.ts$
|
|
34
|
+
src/semantic-validator\\.ts$
|
|
35
|
+
src/action-runtime\\.ts$
|
|
36
|
+
src/actions\\.ts$
|
|
37
|
+
src/llm\\.ts$
|
|
38
|
+
src/utils\\.ts$
|
|
39
|
+
src/feedback\\.ts$
|
|
40
|
+
src/immune-reporter\\.ts$
|
|
41
|
+
src/report\\.ts$
|
|
42
|
+
src/file-lock\\.ts$
|
|
43
|
+
src/consolidate\\.ts$
|
|
44
|
+
src/mcp-server\\.ts$
|
|
45
|
+
src/check\\.ts$
|
|
46
|
+
src/semantic-trace\\.ts$
|
|
47
|
+
src/semantic-snapshot\\.ts$
|
|
48
|
+
src/obs-web\\.ts$
|
|
49
|
+
src/p0_ssg_demo\\.ts$
|
|
50
|
+
src/main\\.ts$
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# Progmune Runtime 综合测试报告
|
|
2
|
+
|
|
3
|
+
**测试时间**: 2026-05-23 14:15:09
|
|
4
|
+
**运行时长**: 3171ms
|
|
5
|
+
**测试版本**: 2.0.5
|
|
6
|
+
**LLM 后端**: DeepSeek Chat (deepseek-chat)
|
|
7
|
+
**Node 版本**: v20.11.1
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## 测试结果摘要
|
|
12
|
+
|
|
13
|
+
| 指标 | 数值 |
|
|
14
|
+
|------|------|
|
|
15
|
+
| 总用例 | 29 |
|
|
16
|
+
| 通过 | 29 |
|
|
17
|
+
| 失败 | 0 |
|
|
18
|
+
| 通过率 | 100.0% |
|
|
19
|
+
|
|
20
|
+
## 逐项测试详情
|
|
21
|
+
|
|
22
|
+
| # | 测试项 | 状态 | 说明 |
|
|
23
|
+
|---|--------|------|------|
|
|
24
|
+
| 1 | MCP tools/list 返回工具列表 | ✅ PASS | 返回 2 个工具 |
|
|
25
|
+
| 2 | MCP 暴露 progmune_generate 工具 | ✅ PASS | 工具名: progmune_generate |
|
|
26
|
+
| 3 | 工具包含 intent 参数 | ✅ PASS | |
|
|
27
|
+
| 4 | 工具包含 projectPath 参数 | ✅ PASS | |
|
|
28
|
+
| 5 | SVL-1: 调用存在的函数通过 | ✅ PASS | |
|
|
29
|
+
| 6 | SVL-1: 拦截不存在的函数 | ✅ PASS | 错误: 函数 'nonexistent_func' 不存在 |
|
|
30
|
+
| 7 | SVL-1: 错误消息包含"不存在" | ✅ PASS | 函数 'nonexistent_func' 不存在 |
|
|
31
|
+
| 8 | SVL-2: 参数数量匹配通过 | ✅ PASS | |
|
|
32
|
+
| 9 | SVL-2: 拦截参数数量不匹配 | ✅ PASS | 错误: 参数数量不匹配: 期望 2, 实际 1 |
|
|
33
|
+
| 10 | SVL-2: 错误消息包含"参数数量" | ✅ PASS | 参数数量不匹配: 期望 2, 实际 1 |
|
|
34
|
+
| 11 | SVL-3: 变量先声明后使用通过 | ✅ PASS | |
|
|
35
|
+
| 12 | SVL-3: 拦截未声明变量 | ✅ PASS | 错误: 变量 'undeclaredVar' 在赋值前未声明 |
|
|
36
|
+
| 13 | SVL-3: 拦截条件中未声明变量 | ✅ PASS | 错误: 条件中引用了未声明的变量 'undefinedVar' |
|
|
37
|
+
| 14 | SVL-3: 复杂嵌套变量流通过 | ✅ PASS | |
|
|
38
|
+
| 15 | SVL-4: 认证动作合法 | ✅ PASS | 状态: UNAUTHENTICATED -> AUTHENTICATED |
|
|
39
|
+
| 16 | SVL-4: 认证后签发令牌合法 | ✅ PASS | 状态: AUTHENTICATED -> TOKEN_ISSUED |
|
|
40
|
+
| 17 | SVL-4: 拦截未认证直接签发令牌 | ✅ PASS | 错误: [PROGMUNE] L4 协议违规:issue_token
|
|
41
|
+
当前状态:UNAUTHENTICATED
|
|
42
|
+
期望前置状态:AUTHENTICATED
|
|
43
|
+
缺失步骤:authenticate → AUTHENTICATED |
|
|
44
|
+
| 18 | Failure Corpus: 记录失败案例 | ✅ PASS | 共 17 条 |
|
|
45
|
+
| 19 | Failure Corpus: 按 SVL-1 过滤 | ✅ PASS | 找到 2 条 |
|
|
46
|
+
| 20 | Failure Corpus: 生成失败模式统计 | ✅ PASS | [{"pattern":"SVL-4:protocol","count":11},{"pattern":"SVL-1:symbol_existence","count":2},{"pattern":"SVL-2:type_mismatch","count":2}] |
|
|
47
|
+
| 21 | 记忆系统: 记录情景记忆 | ✅ PASS | 共 5 条 |
|
|
48
|
+
| 22 | 记忆系统: 过滤成功情景 | ✅ PASS | 共 5 条 |
|
|
49
|
+
| 23 | 记忆系统: 语义模板巩固与匹配 | ✅ PASS | 模板: tmpl_1779545707638, 成功率: 1 |
|
|
50
|
+
| 24 | 边界: 空动作序列通过 | ✅ PASS | |
|
|
51
|
+
| 25 | 边界: 拦截未知动作类型 | ✅ PASS | 无效动作类型: 'invalid_kind' |
|
|
52
|
+
| 26 | 边界: 多层嵌套通过 | ✅ PASS | |
|
|
53
|
+
| 27 | 白名单: 内置函数通过校验 | ✅ PASS | console.log, JSON.stringify |
|
|
54
|
+
| 28 | 端到端: 生成动作序列 | ✅ PASS | 共 2 个动作 |
|
|
55
|
+
| 29 | 端到端: 生成 Python 代码 | ✅ PASS | 代码长度: 144 字符 |
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## SVL 层级覆盖矩阵
|
|
60
|
+
|
|
61
|
+
| SVL 级别 | 名称 | 测试覆盖 | 状态 |
|
|
62
|
+
|:---------:|:----|:---------|:----:|
|
|
63
|
+
| SVL-1 | 符号存在性 | 调用存在/不存在函数校验 | ✅ |
|
|
64
|
+
| SVL-2 | 类型有效性 | 参数数量匹配校验 | ✅ |
|
|
65
|
+
| SVL-3 | 数据流正确性 | 变量声明/使用、嵌套作用域 | ✅ |
|
|
66
|
+
| SVL-4 | 协议合法性 | SSG 状态机、非法跃迁拦截 | ✅ |
|
|
67
|
+
|
|
68
|
+
## 系统组件覆盖
|
|
69
|
+
|
|
70
|
+
| 组件 | 测试覆盖 | 状态 |
|
|
71
|
+
|:-----|:---------|:----:|
|
|
72
|
+
| MCP 协议层 | tools/list、tools/call | ✅ |
|
|
73
|
+
| 校验引擎 (Validator) | SVL-1~3 校验 | ✅ |
|
|
74
|
+
| SSG 状态机 | 协议跃迁校验 | ✅ |
|
|
75
|
+
| Failure Corpus | 记录/查询/模式统计 | ✅ |
|
|
76
|
+
| 三层记忆系统 | 情景记忆/语义模板 | ✅ |
|
|
77
|
+
| 代码生成器 | 动作序列 → Python | ✅ |
|
|
78
|
+
| 内置白名单 | console.log / fetch 等 | ✅ |
|
|
79
|
+
| 边界情况 | 空序列/嵌套/非法类型 | ✅ |
|
|
80
|
+
|
|
81
|
+
## 结论
|
|
82
|
+
|
|
83
|
+
**全部测试通过。** Progmune Runtime 各核心组件运行正常,约束引擎、SSG 协议校验、记忆系统和 Failure Corpus 均按预期工作。
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
*报告由 Progmune Runtime 综合测试套件自动生成*
|
package/Dockerfile
CHANGED
|
@@ -1,17 +1,9 @@
|
|
|
1
1
|
FROM node:18-alpine
|
|
2
|
-
|
|
3
2
|
WORKDIR /app
|
|
4
|
-
|
|
5
|
-
# 只复制运行时需要的文件
|
|
6
3
|
COPY server/ ./server/
|
|
7
4
|
COPY dist/ ./dist/
|
|
5
|
+
COPY public/ ./public/
|
|
8
6
|
COPY package.json package-lock.json* ./
|
|
9
|
-
|
|
10
|
-
# 安装生产依赖
|
|
11
7
|
RUN npm install --production
|
|
12
|
-
|
|
13
|
-
# 暴露端口
|
|
14
|
-
EXPOSE 3000
|
|
15
|
-
|
|
16
|
-
# 启动中央免疫服务器
|
|
8
|
+
EXPOSE 8080
|
|
17
9
|
CMD ["node", "server/hub.js"]
|
package/FAQ.md
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# Progmune Runtime 常见问题 (FAQ)
|
|
2
|
+
|
|
3
|
+
## 安装与配置
|
|
4
|
+
|
|
5
|
+
### 如何获取 LLM API 密钥?
|
|
6
|
+
|
|
7
|
+
Progmune 需要 LLM API 密钥来生成代码。目前支持 DeepSeek 和 OpenAI 兼容接口。
|
|
8
|
+
|
|
9
|
+
**DeepSeek:**
|
|
10
|
+
1. 访问 https://platform.deepseek.com/api_keys
|
|
11
|
+
2. 注册账号并创建 API 密钥
|
|
12
|
+
3. 密钥格式:`sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`
|
|
13
|
+
|
|
14
|
+
**OpenAI:**
|
|
15
|
+
1. 访问 https://platform.openai.com/api-keys
|
|
16
|
+
2. 创建 API 密钥
|
|
17
|
+
3. 设置环境变量 `LLM_BASE_URL=https://api.openai.com/v1` 和 `LLM_MODEL=gpt-4`
|
|
18
|
+
|
|
19
|
+
### 如何配置 API 密钥?
|
|
20
|
+
|
|
21
|
+
**方式一:MCP 客户端配置(推荐)**
|
|
22
|
+
在 `~/.claude/settings.json` 中:
|
|
23
|
+
```json
|
|
24
|
+
{
|
|
25
|
+
"mcpServers": {
|
|
26
|
+
"progmune": {
|
|
27
|
+
"command": "npx",
|
|
28
|
+
"args": ["progmune-runtime"],
|
|
29
|
+
"env": {
|
|
30
|
+
"LLM_API_KEY": "你的密钥",
|
|
31
|
+
"LLM_BASE_URL": "https://api.deepseek.com/v1"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**方式二:环境变量**
|
|
39
|
+
```bash
|
|
40
|
+
export LLM_API_KEY="你的密钥"
|
|
41
|
+
npx progmune-runtime
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
**方式三:快速配置命令**
|
|
45
|
+
```bash
|
|
46
|
+
npx progmune-runtime setup 你的密钥
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### 如何验证安装是否成功?
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
# 检查版本
|
|
53
|
+
npx progmune-runtime --version
|
|
54
|
+
|
|
55
|
+
# 检查 MCP 工具列表(需在 MCP 客户端中)
|
|
56
|
+
# 应看到 progmune_generate 和 progmune_status 两个工具
|
|
57
|
+
|
|
58
|
+
# 运行内置测试
|
|
59
|
+
npx progmune-runtime test
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### 为什么浏览器打不开仪表板?
|
|
63
|
+
|
|
64
|
+
如果运行 `open http://localhost:8080/` 无效:
|
|
65
|
+
|
|
66
|
+
1. **确认 Hub 服务器正在运行:**
|
|
67
|
+
```bash
|
|
68
|
+
curl http://localhost:8080/api/dashboard
|
|
69
|
+
```
|
|
70
|
+
如果返回 JSON 数据,说明服务器运行正常。
|
|
71
|
+
|
|
72
|
+
2. **手动在浏览器打开:**
|
|
73
|
+
- 在地址栏输入 `http://localhost:8080/`
|
|
74
|
+
- 注意使用 `http://` 而非 `https://`(本地服务器不支持 HTTPS)
|
|
75
|
+
|
|
76
|
+
3. **端口冲突:**
|
|
77
|
+
- 默认端口 8080,可通过 `PORT` 环境变量修改
|
|
78
|
+
- 检查是否有其他程序占用:`lsof -i :8080`
|
|
79
|
+
|
|
80
|
+
## 使用问题
|
|
81
|
+
|
|
82
|
+
### MCP 配置失败怎么办?
|
|
83
|
+
|
|
84
|
+
**症状:** Claude Code 提示 "MCP server progmune not found"
|
|
85
|
+
|
|
86
|
+
**排查步骤:**
|
|
87
|
+
1. 确认 `~/.claude/settings.json` 中配置格式正确
|
|
88
|
+
2. 确认 Node.js >= 18 已安装:`node --version`
|
|
89
|
+
3. 尝试手动启动验证:`npx progmune-runtime`
|
|
90
|
+
4. 检查 Claude Code 日志中是否有错误信息
|
|
91
|
+
|
|
92
|
+
**症状:** 调用 `progmune_generate` 返回 "未设置 LLM_API_KEY"
|
|
93
|
+
|
|
94
|
+
即使已在终端 `export` 了密钥,MCP 子进程也可能无法继承。必须在 `settings.json` 的 `env` 字段中显式配置。
|
|
95
|
+
|
|
96
|
+
### 如何开启免疫网络上报?
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
# 开启(推荐)
|
|
100
|
+
npx progmune-runtime opt-in enable
|
|
101
|
+
|
|
102
|
+
# 关闭
|
|
103
|
+
npx progmune-runtime opt-in disable
|
|
104
|
+
|
|
105
|
+
# 查看状态
|
|
106
|
+
npx progmune-runtime opt-in status
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
开启后,每次代码生成的脱敏错误指纹会自动上报到中央免疫服务器。
|
|
110
|
+
|
|
111
|
+
### 如何部署中央免疫服务器?
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
# 启动本地 Hub
|
|
115
|
+
cd progmune-runtime
|
|
116
|
+
node server/hub.js
|
|
117
|
+
|
|
118
|
+
# 设置环境变量让 MCP 服务器自动上报
|
|
119
|
+
export PROGMUNE_HUB=http://localhost:8080/report
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
仪表板访问:`http://localhost:8080/`
|
|
123
|
+
|
|
124
|
+
## 错误与调试
|
|
125
|
+
|
|
126
|
+
### "无法生成满足约束的代码"
|
|
127
|
+
|
|
128
|
+
这意味着 LLM 生成的代码未能通过 Progmune 的约束校验(SVL-1~4)。常见原因:
|
|
129
|
+
|
|
130
|
+
1. **IR 为空:** 项目目录中没有提取到函数定义。确认 `projectPath` 指向包含 `.py` 文件的目录。
|
|
131
|
+
2. **LLM 输出不符合格式:** DeepSeek/OpenAI 返回了非预期的格式。重试通常可以解决。
|
|
132
|
+
3. **SSG 协议违规:** 生成的代码跳过了必要的业务步骤。错误信息会提示缺失的步骤。
|
|
133
|
+
|
|
134
|
+
### "函数 'xxx' 不存在"
|
|
135
|
+
|
|
136
|
+
这是 SVL-1 符号存在性校验的拦截。说明 LLM 幻觉调用了一个项目中不存在的函数。这是 Progmune 的正常保护行为。
|
|
137
|
+
|
|
138
|
+
### 如何查看运行状态?
|
|
139
|
+
|
|
140
|
+
通过 MCP 调用 `progmune_status` 工具,返回 JSON 格式的运行状态,包括:
|
|
141
|
+
- LLM 模型和调用次数
|
|
142
|
+
- 免疫网络状态
|
|
143
|
+
- Failure Corpus 统计
|
|
144
|
+
- 记忆系统状态
|
|
145
|
+
|
|
146
|
+
## 技术细节
|
|
147
|
+
|
|
148
|
+
### Progmune 支持哪些语言?
|
|
149
|
+
|
|
150
|
+
目前代码生成支持 **Python**。IR 提取支持 Python 项目(通过 `extract-ir-python.ts`)。
|
|
151
|
+
|
|
152
|
+
### 数据隐私如何保障?
|
|
153
|
+
|
|
154
|
+
上报到中央免疫服务器的数据**只包含**:
|
|
155
|
+
- 函数名序列(如 `verify_password → generate_jwt`)
|
|
156
|
+
- SVL 违规级别
|
|
157
|
+
- 约束类型
|
|
158
|
+
|
|
159
|
+
**绝不包含**:
|
|
160
|
+
- 代码片段
|
|
161
|
+
- 变量值
|
|
162
|
+
- 文件内容
|
|
163
|
+
- 用户数据
|
|
164
|
+
|
|
165
|
+
### 如何贡献?
|
|
166
|
+
|
|
167
|
+
欢迎通过 GitHub Issues 提交"看似合法但实际危险"的生成案例,帮助我们完善语义状态图(SSG)协议。
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Demo 项目: 用户认证系统
|
|
3
|
+
* 用于展示 SSG (Semantic State Graph) 协议验证
|
|
4
|
+
*
|
|
5
|
+
* 每个函数通过 JSDoc @protocol 注解声明其状态转换规则。
|
|
6
|
+
* 这些注解在 IR 提取时被解析,驱动 SSG 状态机。
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* 验证用户密码
|
|
11
|
+
* @protocol pre_states=["UNAUTHENTICATED"] post_states=["PASSWORD_VERIFIED"]
|
|
12
|
+
*/
|
|
13
|
+
export function verify_password(username: string, password: string): boolean {
|
|
14
|
+
return password === "correct";
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* 签发 JWT 令牌
|
|
19
|
+
* @protocol pre_states=["PASSWORD_VERIFIED"] post_states=["TOKEN_ISSUED"] invalidate=["PASSWORD_VERIFIED"]
|
|
20
|
+
*/
|
|
21
|
+
export function generate_jwt(userId: string, expiresIn: number): string {
|
|
22
|
+
return "eyJhbGciOi...";
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* 创建用户会话
|
|
27
|
+
* @protocol pre_states=["TOKEN_ISSUED"] post_states=["SESSION_ACTIVE"] invalidate=["TOKEN_ISSUED"]
|
|
28
|
+
*/
|
|
29
|
+
export function create_session(token: string): { sessionId: string } {
|
|
30
|
+
return { sessionId: "sess_abc123" };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* 撤销令牌
|
|
35
|
+
* @protocol pre_states=["TOKEN_ISSUED"] post_states=["UNAUTHENTICATED"] invalidate=["TOKEN_ISSUED"]
|
|
36
|
+
*/
|
|
37
|
+
export function revoke_token(token: string): void {
|
|
38
|
+
// 将 token 加入黑名单
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* 登出
|
|
43
|
+
* @protocol pre_states=["SESSION_ACTIVE"] post_states=["UNAUTHENTICATED"] invalidate=["SESSION_ACTIVE"]
|
|
44
|
+
*/
|
|
45
|
+
export function logout(sessionId: string): void {
|
|
46
|
+
// 销毁会话
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* 获取用户资料(无协议约束)
|
|
51
|
+
* @protocol pre_states=[] post_states=[]
|
|
52
|
+
*/
|
|
53
|
+
export function get_user_profile(userId: string): { name: string; email: string } {
|
|
54
|
+
return { name: "Alice", email: "alice@example.com" };
|
|
55
|
+
}
|
package/dist/ab-stats.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.main = main;
|
|
4
|
+
// @progmune-generated session=sess_1780345600422_aexmh timestamp=2026-06-01T20:26:42.334Z ruleHash=9dec68bc2995e92a
|
|
5
|
+
// Generated with IR constraint: 384 functions, 17 protocol rules
|
|
6
|
+
const failure_corpus_1 = require("./failure-corpus");
|
|
7
|
+
function main() {
|
|
8
|
+
const stats = (0, failure_corpus_1.getAntibodyStats)();
|
|
9
|
+
return stats;
|
|
10
|
+
}
|
|
11
|
+
main();
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.main = main;
|
|
4
|
+
// @progmune-generated session=sess_1780343994721_xgc40 timestamp=2026-06-01T19:59:59.184Z ruleHash=9dec68bc2995e92a
|
|
5
|
+
// Generated with IR constraint: 400 functions, 17 protocol rules
|
|
6
|
+
const failure_corpus_1 = require("./failure-corpus");
|
|
7
|
+
const semantic_trace_1 = require("./semantic-trace");
|
|
8
|
+
function main() {
|
|
9
|
+
const stats = (0, failure_corpus_1.getAntibodyStats)();
|
|
10
|
+
const formatted = (0, semantic_trace_1.formatAntibodyStats)();
|
|
11
|
+
return formatted;
|
|
12
|
+
}
|
|
13
|
+
main();
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.main = main;
|
|
4
|
+
// @progmune-generated session=sess_1780343397192_jd8hw timestamp=2026-06-01T19:49:58.982Z ruleHash=9dec68bc2995e92a
|
|
5
|
+
// Generated with IR constraint: 383 functions, 17 protocol rules
|
|
6
|
+
const failure_corpus_1 = require("./failure-corpus");
|
|
7
|
+
function main() {
|
|
8
|
+
const sessions = (0, failure_corpus_1.getAllSessions)();
|
|
9
|
+
return sessions;
|
|
10
|
+
}
|
|
11
|
+
main();
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.main = main;
|
|
4
|
+
// @progmune-generated session=sess_1780343418638_31zut timestamp=2026-06-01T19:50:19.661Z ruleHash=9dec68bc2995e92a
|
|
5
|
+
// Generated with IR constraint: 384 functions, 17 protocol rules
|
|
6
|
+
const failure_corpus_1 = require("./failure-corpus");
|
|
7
|
+
function main() {
|
|
8
|
+
const stats = (0, failure_corpus_1.getAntibodyStats)();
|
|
9
|
+
return stats;
|
|
10
|
+
}
|
|
11
|
+
main();
|
package/dist/audit.js
ADDED
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Phase 4.5: Progmune Audit — 扫描代码库中的 @progmune-generated 标记,统计覆盖率
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* npx ts-node src/audit.ts <directory>
|
|
7
|
+
* npx ts-node src/audit.ts src/
|
|
8
|
+
*/
|
|
9
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
12
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
13
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
14
|
+
}
|
|
15
|
+
Object.defineProperty(o, k2, desc);
|
|
16
|
+
}) : (function(o, m, k, k2) {
|
|
17
|
+
if (k2 === undefined) k2 = k;
|
|
18
|
+
o[k2] = m[k];
|
|
19
|
+
}));
|
|
20
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
21
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
22
|
+
}) : function(o, v) {
|
|
23
|
+
o["default"] = v;
|
|
24
|
+
});
|
|
25
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
26
|
+
var ownKeys = function(o) {
|
|
27
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
28
|
+
var ar = [];
|
|
29
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
30
|
+
return ar;
|
|
31
|
+
};
|
|
32
|
+
return ownKeys(o);
|
|
33
|
+
};
|
|
34
|
+
return function (mod) {
|
|
35
|
+
if (mod && mod.__esModule) return mod;
|
|
36
|
+
var result = {};
|
|
37
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
38
|
+
__setModuleDefault(result, mod);
|
|
39
|
+
return result;
|
|
40
|
+
};
|
|
41
|
+
})();
|
|
42
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
43
|
+
exports.auditDirectory = auditDirectory;
|
|
44
|
+
exports.formatAuditResult = formatAuditResult;
|
|
45
|
+
const fs = __importStar(require("fs"));
|
|
46
|
+
const path = __importStar(require("path"));
|
|
47
|
+
/** Scan a directory recursively for TypeScript files and check for @progmune-generated markers. */
|
|
48
|
+
const DEFAULT_THRESHOLD = 0.8;
|
|
49
|
+
function auditDirectory(dir, threshold = DEFAULT_THRESHOLD) {
|
|
50
|
+
const result = {
|
|
51
|
+
directory: dir,
|
|
52
|
+
totalFiles: 0,
|
|
53
|
+
progmuneFiles: 0,
|
|
54
|
+
coverage: 0,
|
|
55
|
+
threshold,
|
|
56
|
+
warning: null,
|
|
57
|
+
nonProgmuneFiles: [],
|
|
58
|
+
sessions: [],
|
|
59
|
+
};
|
|
60
|
+
if (!fs.existsSync(dir)) {
|
|
61
|
+
return result;
|
|
62
|
+
}
|
|
63
|
+
const stat = fs.statSync(dir);
|
|
64
|
+
if (!stat.isDirectory()) {
|
|
65
|
+
return result;
|
|
66
|
+
}
|
|
67
|
+
scanDir(dir, dir, result);
|
|
68
|
+
result.coverage = result.totalFiles > 0
|
|
69
|
+
? result.progmuneFiles / result.totalFiles
|
|
70
|
+
: 0;
|
|
71
|
+
if (result.coverage < result.threshold && result.totalFiles > 0) {
|
|
72
|
+
const pct = (result.coverage * 100).toFixed(0);
|
|
73
|
+
const target = (result.threshold * 100).toFixed(0);
|
|
74
|
+
result.warning = `Coverage ${pct}% below ${target}% threshold. ${result.nonProgmuneFiles.length} file(s) are not @progmune-generated.`;
|
|
75
|
+
}
|
|
76
|
+
// Sort sessions by timestamp (most recent first)
|
|
77
|
+
result.sessions.sort((a, b) => (b.timestamp || "").localeCompare(a.timestamp || ""));
|
|
78
|
+
if (result.sessions.length > 0) {
|
|
79
|
+
result.lastGeneration = result.sessions[0].timestamp;
|
|
80
|
+
}
|
|
81
|
+
return result;
|
|
82
|
+
}
|
|
83
|
+
const MARKER_REGEX = /@progmune-generated\s+session=(\S+)(?:\s+timestamp=(\S+))?(?:\s+ruleHash=(\S+))?/;
|
|
84
|
+
const EXCLUDED_DIRS = new Set(["node_modules", ".git", "dist", ".progmune_corpus", ".progmune_memory"]);
|
|
85
|
+
function scanDir(rootDir, currentDir, result) {
|
|
86
|
+
let entries;
|
|
87
|
+
try {
|
|
88
|
+
entries = fs.readdirSync(currentDir, { withFileTypes: true });
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
for (const entry of entries) {
|
|
94
|
+
const fullPath = path.join(currentDir, entry.name);
|
|
95
|
+
if (entry.isDirectory()) {
|
|
96
|
+
if (!EXCLUDED_DIRS.has(entry.name) && !entry.name.startsWith(".")) {
|
|
97
|
+
scanDir(rootDir, fullPath, result);
|
|
98
|
+
}
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
// Only check TypeScript source files
|
|
102
|
+
if (!entry.name.endsWith(".ts") && !entry.name.endsWith(".tsx") && !entry.name.endsWith(".mjs")) {
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
result.totalFiles++;
|
|
106
|
+
try {
|
|
107
|
+
const content = fs.readFileSync(fullPath, "utf-8");
|
|
108
|
+
// Only check first 5 lines for the marker (performance)
|
|
109
|
+
const head = content.split("\n").slice(0, 5).join("\n");
|
|
110
|
+
const match = head.match(MARKER_REGEX);
|
|
111
|
+
if (match) {
|
|
112
|
+
result.progmuneFiles++;
|
|
113
|
+
result.sessions.push({
|
|
114
|
+
sessionId: match[1],
|
|
115
|
+
file: path.relative(rootDir, fullPath),
|
|
116
|
+
timestamp: match[2],
|
|
117
|
+
ruleHash: match[3],
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
result.nonProgmuneFiles.push(path.relative(rootDir, fullPath));
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
// Skip unreadable files
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/** Format audit result as human-readable text. */
|
|
130
|
+
function formatAuditResult(result) {
|
|
131
|
+
const pct = (result.coverage * 100).toFixed(1);
|
|
132
|
+
const lines = [];
|
|
133
|
+
lines.push(`Progmune Audit: ${result.directory}`);
|
|
134
|
+
lines.push("═".repeat(56));
|
|
135
|
+
lines.push(` Total source files: ${result.totalFiles}`);
|
|
136
|
+
lines.push(` @progmune-generated: ${result.progmuneFiles} (${pct}%)`);
|
|
137
|
+
lines.push(` Threshold: ${(result.threshold * 100).toFixed(0)}%`);
|
|
138
|
+
if (result.warning) {
|
|
139
|
+
lines.push(` ⚠️ ${result.warning}`);
|
|
140
|
+
}
|
|
141
|
+
lines.push(` Not covered: ${result.nonProgmuneFiles.length}`);
|
|
142
|
+
lines.push("");
|
|
143
|
+
// Phase 7: Execution metrics
|
|
144
|
+
try {
|
|
145
|
+
const { getExecutionMetrics } = require("./execute");
|
|
146
|
+
const m = getExecutionMetrics();
|
|
147
|
+
if (m.generated > 0) {
|
|
148
|
+
const repairRate = m.repaired > 0 ? ` | Repaired: ${m.repaired}` : "";
|
|
149
|
+
lines.push(` Executions: ${m.generated} total${repairRate}`);
|
|
150
|
+
if (m.lastGeneration) {
|
|
151
|
+
lines.push(` Last: ${m.lastGeneration}`);
|
|
152
|
+
}
|
|
153
|
+
if (m.history.length >= 2) {
|
|
154
|
+
const recent = m.history.slice(-5);
|
|
155
|
+
lines.push(` Recent: ${recent.map((r) => r.repaired ? '🔧' : '✅').join(' ')}`);
|
|
156
|
+
}
|
|
157
|
+
lines.push("");
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
catch { }
|
|
161
|
+
// Phase 7: Violation Analytics
|
|
162
|
+
try {
|
|
163
|
+
const repairDir = ".progmune_corpus/repairs";
|
|
164
|
+
if (fs.existsSync(repairDir)) {
|
|
165
|
+
const repairs = fs.readdirSync(repairDir).filter((f) => f.endsWith(".json"));
|
|
166
|
+
if (repairs.length > 0) {
|
|
167
|
+
const bySvl = {};
|
|
168
|
+
const byConstraint = {};
|
|
169
|
+
for (const f of repairs) {
|
|
170
|
+
try {
|
|
171
|
+
const r = JSON.parse(fs.readFileSync(`${repairDir}/${f}`, "utf-8"));
|
|
172
|
+
bySvl[r.violation] = (bySvl[r.violation] || 0) + 1;
|
|
173
|
+
byConstraint[r.constraint] = (byConstraint[r.constraint] || 0) + 1;
|
|
174
|
+
}
|
|
175
|
+
catch { }
|
|
176
|
+
}
|
|
177
|
+
lines.push(` Repairs recorded: ${repairs.length}`);
|
|
178
|
+
const svlSummary = Object.entries(bySvl).map(([k, v]) => `${k}: ${v}`).join(" | ");
|
|
179
|
+
lines.push(` By SVL: ${svlSummary}`);
|
|
180
|
+
if (Object.keys(byConstraint).length > 1) {
|
|
181
|
+
const cSummary = Object.entries(byConstraint).map(([k, v]) => `${k}: ${v}`).join(" | ");
|
|
182
|
+
lines.push(` By constraint: ${cSummary}`);
|
|
183
|
+
}
|
|
184
|
+
lines.push("");
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
catch { }
|
|
189
|
+
if (result.sessions.length > 0) {
|
|
190
|
+
lines.push(` Last generation: ${result.lastGeneration || "unknown"}`);
|
|
191
|
+
lines.push(` Unique sessions: ${new Set(result.sessions.map(s => s.sessionId)).size}`);
|
|
192
|
+
lines.push("");
|
|
193
|
+
lines.push(" Generated files:");
|
|
194
|
+
for (const s of result.sessions.slice(0, 10)) {
|
|
195
|
+
lines.push(` ${s.file}`);
|
|
196
|
+
}
|
|
197
|
+
if (result.sessions.length > 10) {
|
|
198
|
+
lines.push(` ... and ${result.sessions.length - 10} more`);
|
|
199
|
+
}
|
|
200
|
+
lines.push("");
|
|
201
|
+
}
|
|
202
|
+
if (result.nonProgmuneFiles.length > 0) {
|
|
203
|
+
lines.push(` Files without Progmune marker (${result.nonProgmuneFiles.length}):`);
|
|
204
|
+
for (const f of result.nonProgmuneFiles.slice(0, 20)) {
|
|
205
|
+
lines.push(` ${f}`);
|
|
206
|
+
}
|
|
207
|
+
if (result.nonProgmuneFiles.length > 20) {
|
|
208
|
+
lines.push(` ... and ${result.nonProgmuneFiles.length - 20} more`);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
return lines.join("\n");
|
|
212
|
+
}
|
|
213
|
+
// CLI entry
|
|
214
|
+
if (require.main === module) {
|
|
215
|
+
const dir = process.argv[2] || "src";
|
|
216
|
+
const result = auditDirectory(dir);
|
|
217
|
+
console.log(formatAuditResult(result));
|
|
218
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.benchmarkCount = benchmarkCount;
|
|
4
|
+
const load_benchmarks_1 = require("./load-benchmarks");
|
|
5
|
+
function benchmarkCount() {
|
|
6
|
+
return (0, load_benchmarks_1.loadBenchmarks)().length;
|
|
7
|
+
}
|