apphx 2.0.1 → 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/README.md +10 -8
- package/dist/cli.js +41 -11
- package/dist/cli.js.map +1 -1
- package/dist/config.js +4 -2
- package/dist/config.js.map +1 -1
- package/dist/integrations.js +154 -95
- package/dist/integrations.js.map +1 -1
- package/dist/notify.js +267 -0
- package/dist/notify.js.map +1 -0
- package/dist/runner.js +119 -20
- package/dist/runner.js.map +1 -1
- package/dist/schemas.js +57 -2
- package/dist/schemas.js.map +1 -1
- package/dist/vendor/obfuscator/dist/config.js +119 -6
- package/dist/vendor/obfuscator/dist/config.js.map +1 -1
- package/dist/vendor/obfuscator/dist/dfa.js +528 -0
- package/dist/vendor/obfuscator/dist/dfa.js.map +1 -0
- package/dist/vendor/obfuscator/dist/flutter.js +3266 -0
- package/dist/vendor/obfuscator/dist/flutter.js.map +1 -0
- package/dist/vendor/obfuscator/dist/image-utils.js +335 -0
- package/dist/vendor/obfuscator/dist/image-utils.js.map +1 -0
- package/dist/vendor/obfuscator/dist/junk.js +1501 -0
- package/dist/vendor/obfuscator/dist/junk.js.map +1 -0
- package/dist/vendor/obfuscator/dist/lexicon-data.js +972 -0
- package/dist/vendor/obfuscator/dist/lexicon-data.js.map +1 -0
- package/dist/vendor/obfuscator/dist/obfuscate.js +51 -2
- package/dist/vendor/obfuscator/dist/obfuscate.js.map +1 -1
- package/dist/vendor/obfuscator/dist/objc-symbols.js +1819 -0
- package/dist/vendor/obfuscator/dist/objc-symbols.js.map +1 -0
- package/dist/vendor/obfuscator/dist/project-identity.js +852 -0
- package/dist/vendor/obfuscator/dist/project-identity.js.map +1 -0
- package/dist/vendor/obfuscator/dist/string-encrypt.js +330 -0
- package/dist/vendor/obfuscator/dist/string-encrypt.js.map +1 -0
- package/examples/android-java.factory.json +40 -5
- package/examples/expo.factory.json +68 -5
- package/examples/flutter.factory.json +40 -4
- package/examples/luggage.json +1 -0
- package/examples/multi-role-agents.md +129 -0
- package/examples/mygo.factory.json +54 -4
- package/examples/queue-loop-demo.md +146 -0
- package/examples/react-native.factory.json +58 -5
- package/examples/roles.example.json +31 -0
- package/examples/swift.factory.json +60 -5
- package/examples/uni-app.factory.json +58 -5
- package/package.json +1 -1
- package/skills/apphx/SKILL.md +39 -4
- package/skills/apphx/resources/requirement.json +1 -0
- package/skills/apphx-obfuscator/LICENSE +21 -0
- package/skills/apphx-obfuscator/SKILL.md +72 -0
|
@@ -4,15 +4,78 @@
|
|
|
4
4
|
"allowLocalExecution": false,
|
|
5
5
|
"allowCloudBuild": false,
|
|
6
6
|
"packageTarget": "aab",
|
|
7
|
-
"
|
|
7
|
+
"obfuscation": {
|
|
8
|
+
"options": {
|
|
9
|
+
"code": {
|
|
10
|
+
"removeComments": true
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"executionEnv": [
|
|
15
|
+
"ANDROID_HOME",
|
|
16
|
+
"ANDROID_DEVICE_ID"
|
|
17
|
+
],
|
|
8
18
|
"verification": {
|
|
9
|
-
"prerequisites": [
|
|
10
|
-
|
|
11
|
-
|
|
19
|
+
"prerequisites": [
|
|
20
|
+
[
|
|
21
|
+
"node",
|
|
22
|
+
"--version"
|
|
23
|
+
],
|
|
24
|
+
[
|
|
25
|
+
"eas",
|
|
26
|
+
"--version"
|
|
27
|
+
],
|
|
28
|
+
[
|
|
29
|
+
"java",
|
|
30
|
+
"-version"
|
|
31
|
+
],
|
|
32
|
+
[
|
|
33
|
+
"adb",
|
|
34
|
+
"version"
|
|
35
|
+
]
|
|
36
|
+
],
|
|
37
|
+
"checks": [
|
|
38
|
+
[
|
|
39
|
+
"npm",
|
|
40
|
+
"run",
|
|
41
|
+
"lint"
|
|
42
|
+
],
|
|
43
|
+
[
|
|
44
|
+
"npm",
|
|
45
|
+
"test",
|
|
46
|
+
"--",
|
|
47
|
+
"--runInBand"
|
|
48
|
+
]
|
|
49
|
+
],
|
|
50
|
+
"runtime": [
|
|
51
|
+
[
|
|
52
|
+
"npm",
|
|
53
|
+
"run",
|
|
54
|
+
"test:e2e",
|
|
55
|
+
"--",
|
|
56
|
+
"--platform",
|
|
57
|
+
"android",
|
|
58
|
+
"--device",
|
|
59
|
+
"${ANDROID_DEVICE_ID}"
|
|
60
|
+
]
|
|
61
|
+
]
|
|
12
62
|
},
|
|
13
63
|
"packaging": {
|
|
14
64
|
"provider": "local",
|
|
15
|
-
"commands": [
|
|
65
|
+
"commands": [
|
|
66
|
+
[
|
|
67
|
+
"eas",
|
|
68
|
+
"build",
|
|
69
|
+
"--platform",
|
|
70
|
+
"android",
|
|
71
|
+
"--profile",
|
|
72
|
+
"production",
|
|
73
|
+
"--local",
|
|
74
|
+
"--non-interactive",
|
|
75
|
+
"--output",
|
|
76
|
+
"build/app.aab"
|
|
77
|
+
]
|
|
78
|
+
],
|
|
16
79
|
"artifactPath": "build/app.aab"
|
|
17
80
|
}
|
|
18
81
|
}
|
|
@@ -4,10 +4,46 @@
|
|
|
4
4
|
"allowLocalExecution": false,
|
|
5
5
|
"allowCloudBuild": false,
|
|
6
6
|
"packageTarget": "simulator",
|
|
7
|
-
"
|
|
7
|
+
"obfuscation": {
|
|
8
|
+
"options": {
|
|
9
|
+
"code": {
|
|
10
|
+
"removeComments": true
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"executionEnv": [
|
|
15
|
+
"IOS_DEVICE_ID"
|
|
16
|
+
],
|
|
8
17
|
"verification": {
|
|
9
|
-
"prerequisites": [
|
|
10
|
-
|
|
11
|
-
|
|
18
|
+
"prerequisites": [
|
|
19
|
+
[
|
|
20
|
+
"xcodebuild",
|
|
21
|
+
"-version"
|
|
22
|
+
]
|
|
23
|
+
],
|
|
24
|
+
"checks": [
|
|
25
|
+
[
|
|
26
|
+
"flutter",
|
|
27
|
+
"analyze",
|
|
28
|
+
"--fatal-infos"
|
|
29
|
+
],
|
|
30
|
+
[
|
|
31
|
+
"flutter",
|
|
32
|
+
"test"
|
|
33
|
+
]
|
|
34
|
+
],
|
|
35
|
+
"runtime": [
|
|
36
|
+
[
|
|
37
|
+
"flutter",
|
|
38
|
+
"drive",
|
|
39
|
+
"--driver",
|
|
40
|
+
"test_driver/integration_test.dart",
|
|
41
|
+
"--target",
|
|
42
|
+
"integration_test/app_test.dart",
|
|
43
|
+
"-d",
|
|
44
|
+
"${IOS_DEVICE_ID}",
|
|
45
|
+
"--no-pub"
|
|
46
|
+
]
|
|
47
|
+
]
|
|
12
48
|
}
|
|
13
49
|
}
|
package/examples/luggage.json
CHANGED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# 多角色 Agent 团队设计(apphx 宿主式)
|
|
2
|
+
|
|
3
|
+
apphx 不启动自己的 coding agent,角色全部由**宿主会话**执行;apphx 只做三件事:命名角色、
|
|
4
|
+
把角色随回合发给宿主、用确定性控制面分配工作。本文档是角色到流水线的完整映射、自动分配
|
|
5
|
+
算法、模型矩阵与验收 agent 定义。
|
|
6
|
+
|
|
7
|
+
## 1. 角色 ↔ 流水线映射
|
|
8
|
+
|
|
9
|
+
| 角色 | 流水线位置 | 职责 | 输出 / 关卡 |
|
|
10
|
+
| --- | --- | --- | --- |
|
|
11
|
+
| 产品 / 需求分析 agent | `research` 回合(宿主) | 需求整理、可行性、诚实差异化、隐私、实施计划 | 类型化 research 结论(viable/distinctness/plan) |
|
|
12
|
+
| 架构设计 agents ×N | `build` 回合第一步 | N 份独立方案 → 互相 critique → 合成决定 | 工作区内 `docs/architecture.md` |
|
|
13
|
+
| 开发 agents ×N | `build` 回合 | 按合成设计并行实现模块切片 | 源码 |
|
|
14
|
+
| 测试 agent | `build`(编写测试)+ `verify`(确定性执行) | 测试编写;checks + 设备真实验收 | 验证通过 + 源码/依赖摘要前后一致 |
|
|
15
|
+
| 架构师 review | `review` 回合 | 对照设计文档审查实现与模块边界 | findings(可阻断) |
|
|
16
|
+
| 质量工程师 agent | `review` 回合 | 空态/错误态、可访问性、边界、质量 | findings(可阻断) |
|
|
17
|
+
| 验收 agent | `review` 回合(逐条验收证据)+ `package` 产物校验 | 每条 acceptance 给出具体证据;产物非空且摘要记录 | approved + artifact |
|
|
18
|
+
| 项目管理 agent | 控制面(无回合) | 队列排序、预算、重试、repair、通知、终局审计 | 队列状态与事件日志 |
|
|
19
|
+
| 补充角色(自由命名) | 任意回合 | `roles` 配置加名字即可 | 宿主按 role 数组执行 |
|
|
20
|
+
|
|
21
|
+
`roles` 配置(factory.json,可选;默认如上表):
|
|
22
|
+
|
|
23
|
+
```jsonc
|
|
24
|
+
{ "roles": {
|
|
25
|
+
"research": ["product-analyst", "requirement-groomer"],
|
|
26
|
+
"build": ["developer", "security-aware-developer"],
|
|
27
|
+
"review": ["architect-review", "qa-engineer", "acceptance-reviewer", "performance-analyst"]
|
|
28
|
+
} }
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
每个回合的 `next` 返回负载带 `turn.role` 数组([runner.ts](src/runner.ts) hostAction),
|
|
32
|
+
提示词尾部也会写明本回合角色;宿主按顺序或按其原生 delegation 并行采用。
|
|
33
|
+
|
|
34
|
+
## 2. AI 自动分配:确定性算法,不用模型
|
|
35
|
+
|
|
36
|
+
分配发生在控制面,与模型无关(loopx 同款原则:Kernel 检查 authority/frontier/quota,
|
|
37
|
+
Capability 才做领域判断)。`apphx next --any` 的分配顺序:
|
|
38
|
+
|
|
39
|
+
1. **priority 泳道**:P0 → P1 → P2(同泳道才比较到期时间);
|
|
40
|
+
2. **到期时间**:`nextAt` 最早的先做;
|
|
41
|
+
3. **入队序**:稳定排序兜底;
|
|
42
|
+
4. **资格过滤**:过期/预算耗尽/有活动回合/命令组恢复中/被另一 worker 持有的任务一律跳过,
|
|
43
|
+
继续取下一个 safe action。
|
|
44
|
+
|
|
45
|
+
为什么不用 LLM 分配:
|
|
46
|
+
|
|
47
|
+
- 可审计可重放:同样的队列状态永远得到同样的分配;
|
|
48
|
+
- 无幻觉:LLM 不会"记错"到期时间或预算;
|
|
49
|
+
- 幂等安全:分配本身不改状态,claim 由事务完成(turn token / worker 锁)。
|
|
50
|
+
|
|
51
|
+
模型只出现在**需要判断的环节**:research、设计讨论、实现、三类 review。分配动作零模型。
|
|
52
|
+
|
|
53
|
+
## 3. 模型矩阵(以宿主为准)
|
|
54
|
+
|
|
55
|
+
apphx 不管理模型凭据;`roles` 只声明角色名,角色→模型的绑定写在宿主的 role 配置里。
|
|
56
|
+
矩阵按角色类别给出建议(型号以宿主实际可用为准):
|
|
57
|
+
|
|
58
|
+
| 角色 | 模型类别 | 建议 | 独立性要求 |
|
|
59
|
+
| --- | --- | --- | --- |
|
|
60
|
+
| 产品 / 需求分析 | 长上下文强推理 | o3/Opus/R1 类推理模型 | 与开发不同上下文 |
|
|
61
|
+
| 架构设计 ×N | 强推理 | N 份方案尽量不同厂商/模型,最大化多样性 | 相互独立会话 |
|
|
62
|
+
| 开发 | 编码模型 | Sonnet/Opus/Codex 类编码模型 | 按模块切片可并行 |
|
|
63
|
+
| 测试编写 | 编码 + 推理 | 编码模型即可 | 与开发不同上下文更佳 |
|
|
64
|
+
| 架构师 review | 强推理 | **与开发者不同厂商**的推理模型 | 未参与实现的新会话 |
|
|
65
|
+
| 质量工程师 | 编码 + 推理 | 与架构师可相同、与开发者不同 | 未参与实现的新会话 |
|
|
66
|
+
| 验收 agent | 推理 | 与实现者不同模型/厂商 | 未参与实现的新会话 |
|
|
67
|
+
| 项目管理 / 分配 | **无模型** | 确定性队列(见上节) | — |
|
|
68
|
+
|
|
69
|
+
独立性规则(skill 已强制):实现者不能自审;验收证据由 harness 门禁(typed 结果 +
|
|
70
|
+
未变摘要),reviewer 只能 approve/reject,不能改证据、不能替跑 verify。
|
|
71
|
+
|
|
72
|
+
## 4. 验收 agent 定义
|
|
73
|
+
|
|
74
|
+
"验收"不是单个 agent 的一句话,而是三层门禁 + 一个独立评审:
|
|
75
|
+
|
|
76
|
+
1. **verify(确定性)**:配置的 checks + runtime 真实验收全过,且验证前后源码/依赖摘要
|
|
77
|
+
完全一致,截图目录摘要一致;
|
|
78
|
+
2. **review(acceptance-reviewer)**:逐条 acceptance 给出"文件/符号 + 实际观察到的命令或
|
|
79
|
+
设备场景"证据,覆盖全部条目才可能 approved;
|
|
80
|
+
3. **package(确定性)**:非空常规产物、摘要落盘;built 之后 `notify` 通知作者。
|
|
81
|
+
|
|
82
|
+
验收 agent 无法"自证":它只产出 typed 结论,harness 用摘要门禁决定是否采信。
|
|
83
|
+
|
|
84
|
+
## 5. 扩展新角色
|
|
85
|
+
|
|
86
|
+
需要新 agent(如 security-review)时只改两处:
|
|
87
|
+
|
|
88
|
+
1. `factory.json` 的 `roles.<stage>` 数组加名字;
|
|
89
|
+
2. 宿主的角色提示词库加对应定义(skill 的 turn.role 会把它随回合带来)。
|
|
90
|
+
|
|
91
|
+
不需要改 CLI、状态机或队列。
|
|
92
|
+
|
|
93
|
+
## 6. 宿主能力与降级规则(所有 AI agent 是否都支持)
|
|
94
|
+
|
|
95
|
+
多角色不需要宿主支持"子代理"——**独立上下文是会话级属性**,任何宿主都能做到;只是
|
|
96
|
+
执行形态不同。`apphx hosts` 输出里每行带 `delegation` 说明(以宿主版本为准):
|
|
97
|
+
|
|
98
|
+
| 宿主 | 原生 subagents | 多角色执行形态 |
|
|
99
|
+
| --- | --- | --- |
|
|
100
|
+
| Codex | ✓(agents/tasks) | 单会话并行/串行 fresh contexts |
|
|
101
|
+
| Claude Code | ✓(subagents) | 单会话并行/串行 fresh contexts |
|
|
102
|
+
| Hermes | ✓(subagents + cron) | 单会话并行 + cron 无人唤醒 |
|
|
103
|
+
| DeepSeek Harness | 视 provider | 有则单会话,无则多会话 |
|
|
104
|
+
| Cursor | 视版本 | 无则每个角色独立 fresh 会话 |
|
|
105
|
+
| OpenCode | 视版本 | 无则每个角色独立 fresh 会话 |
|
|
106
|
+
| Pi(stock) | ✗(仓库已记录) | 每个角色人工启动独立会话 |
|
|
107
|
+
| Gemini CLI | ✗(未记录子代理) | 顺序 fresh 会话 |
|
|
108
|
+
|
|
109
|
+
降级规则(skill 强制,任何宿主都不允许静默降级独立性):
|
|
110
|
+
|
|
111
|
+
1. **review 三角色**必须各自 fresh、非实现者上下文;宿主无子代理时顺序开独立会话,
|
|
112
|
+
由控制会话收集 typed 结论,**恰好一个会话**完成 token。
|
|
113
|
+
2. **verdict 聚合**:findings 取并集;acceptanceEvidence 逐条覆盖且注明"哪个角色观察
|
|
114
|
+
到什么证据";任一角色有阻断 finding 即不通过;**某角色零证据 = 该角色缺席**,不算通过。
|
|
115
|
+
3. **设计讨论**(build 内):多样性而非独立性——无子代理时同一会话顺序产出 N 份方案
|
|
116
|
+
也可接受,但记录"同会话、同模型"的局限性。
|
|
117
|
+
4. 角色→模型绑定是宿主侧配置(参考 [roles.example.json](roles.example.json) 的
|
|
118
|
+
fresh/independentOf 约定);apphx 只命名角色、随回合下发,不管理模型凭据。
|
|
119
|
+
|
|
120
|
+
## 7. 为什么不把 review 拆成多个 token
|
|
121
|
+
|
|
122
|
+
review 三角色共用一个 token、由单个 completing 会话聚合,而不是拆成三段独立 token:
|
|
123
|
+
|
|
124
|
+
- 独立性已由"fresh 会话"规则保证(对无子代理宿主更通用);
|
|
125
|
+
- 聚合 verdict 仍受 harness 门禁(typed 结果 + 未变摘要),不会因聚合而放宽;
|
|
126
|
+
- 拆 token 要改阶段状态机与迁移,收益只是把"会话边界"搬到"token 边界",不新增保证。
|
|
127
|
+
|
|
128
|
+
若某宿主连多会话都做不到(例如只能单进程单会话),stock Pi 规则已覆盖:暂停并请
|
|
129
|
+
所有者人工开启独立会话完成 review。
|
|
@@ -4,15 +4,65 @@
|
|
|
4
4
|
"allowLocalExecution": false,
|
|
5
5
|
"allowCloudBuild": false,
|
|
6
6
|
"packageTarget": "app",
|
|
7
|
+
"obfuscation": {
|
|
8
|
+
"options": {
|
|
9
|
+
"code": {
|
|
10
|
+
"removeComments": true
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
},
|
|
7
14
|
"executionEnv": [],
|
|
8
15
|
"verification": {
|
|
9
|
-
"prerequisites": [
|
|
10
|
-
|
|
11
|
-
|
|
16
|
+
"prerequisites": [
|
|
17
|
+
[
|
|
18
|
+
"go",
|
|
19
|
+
"version"
|
|
20
|
+
],
|
|
21
|
+
[
|
|
22
|
+
"go",
|
|
23
|
+
"tool",
|
|
24
|
+
"mygo",
|
|
25
|
+
"version"
|
|
26
|
+
]
|
|
27
|
+
],
|
|
28
|
+
"checks": [
|
|
29
|
+
[
|
|
30
|
+
"go",
|
|
31
|
+
"vet",
|
|
32
|
+
"./..."
|
|
33
|
+
],
|
|
34
|
+
[
|
|
35
|
+
"go",
|
|
36
|
+
"test",
|
|
37
|
+
"./..."
|
|
38
|
+
]
|
|
39
|
+
],
|
|
40
|
+
"runtime": [
|
|
41
|
+
[
|
|
42
|
+
"go",
|
|
43
|
+
"run",
|
|
44
|
+
"./cmd/acceptance"
|
|
45
|
+
]
|
|
46
|
+
]
|
|
12
47
|
},
|
|
13
48
|
"packaging": {
|
|
14
49
|
"provider": "local",
|
|
15
|
-
"commands": [
|
|
50
|
+
"commands": [
|
|
51
|
+
[
|
|
52
|
+
"go",
|
|
53
|
+
"tool",
|
|
54
|
+
"mygo",
|
|
55
|
+
"build",
|
|
56
|
+
"-platform",
|
|
57
|
+
"darwin/arm64",
|
|
58
|
+
"-sign",
|
|
59
|
+
"-",
|
|
60
|
+
"-skip-notarize",
|
|
61
|
+
"-skip-dmg",
|
|
62
|
+
"-o",
|
|
63
|
+
"build"
|
|
64
|
+
]
|
|
65
|
+
],
|
|
16
66
|
"artifactPath": "build/darwin-arm64/MyGo App.app"
|
|
17
67
|
}
|
|
18
68
|
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# 队列循环演示:三个需求从 enqueue 到 built
|
|
2
|
+
|
|
3
|
+
loopx 风格的 agent loop 在 apphx 中的完整走法:一个宿主会话(或每次定时唤醒)用
|
|
4
|
+
`apphx next --any` 逐轮消费队列,直到 `idle` 且 `summary` 显示全部 `built`/`failed`。
|
|
5
|
+
|
|
6
|
+
本文档是工作流示例;JSON 输出为**缩略示意**(真实 job id、turn id、digest 与逐字
|
|
7
|
+
输出不同),不作为任何运行证据。真实验收需要 macOS、完整 Xcode 与模拟器/设备,
|
|
8
|
+
商店提交始终是工具之外的人工工作。
|
|
9
|
+
|
|
10
|
+
## 1. 控制项目与三个需求
|
|
11
|
+
|
|
12
|
+
```sh
|
|
13
|
+
apphx init --framework flutter --platform ios --package-target simulator
|
|
14
|
+
# 按项目校准 factory.json:真实验收命令、allowLocalExecution 等(见 Skill/README)
|
|
15
|
+
apphx doctor
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
三个需求文件放在控制目录(此处只展示决定循环行为的关键字段):
|
|
19
|
+
|
|
20
|
+
```jsonc
|
|
21
|
+
// requirements/checklist-p0.json —— 高优先级修复
|
|
22
|
+
{ "id": "pack-checklist", "name": "行李核对", "framework": "flutter",
|
|
23
|
+
"platform": "ios", "channel": "local", "version": "1.0.0",
|
|
24
|
+
"priority": "P0", // P0 优先扫描;不改变验收门槛
|
|
25
|
+
"differentiators": ["离线核对清单"], "acceptance": ["重启后清单完整"] }
|
|
26
|
+
|
|
27
|
+
// requirements/timer-p1.json —— 常规新应用
|
|
28
|
+
{ "id": "pomodoro-timer", "priority": "P1", "acceptance": ["计时结束有可及性提示"] }
|
|
29
|
+
|
|
30
|
+
// requirements/notes-p2.json —— 后台补量
|
|
31
|
+
{ "id": "daily-notes", "priority": "P2", "acceptance": ["导出恢复一致"] }
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
```sh
|
|
35
|
+
apphx enqueue requirements/checklist-p0.json --config factory.json
|
|
36
|
+
apphx enqueue requirements/timer-p1.json --config factory.json
|
|
37
|
+
apphx enqueue requirements/notes-p2.json --config factory.json
|
|
38
|
+
# 或走 inbox:apphx submit ... 三份后 apphx scan --config factory.json
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## 2. Agent 循环(每一轮都是同一步)
|
|
42
|
+
|
|
43
|
+
```text
|
|
44
|
+
loop:
|
|
45
|
+
r = apphx next --any --config factory.json --build-only
|
|
46
|
+
action host → 按 turn.prompt 完成该回合 → apphx complete <id> <turn> [result.json]
|
|
47
|
+
action step → apphx step <id> --config factory.json --build-only(一次)
|
|
48
|
+
built 出现 → apphx notify <id>(或收尾时统一 notify --any)给作者发邮件
|
|
49
|
+
重复,直到 idle → 读 summary 做终局审计 → 按 nextAt 汇报并退出
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## 3. 逐轮示意
|
|
53
|
+
|
|
54
|
+
```text
|
|
55
|
+
#1 next --any → { "action": "host", "job": { "id": "…01", "product": "pack-checklist" },
|
|
56
|
+
"turn": { "stage": "research", "prompt": "…" } }
|
|
57
|
+
宿主完成 research → apphx complete …01 <turn> research-result.json
|
|
58
|
+
|
|
59
|
+
#2 next --any → host(…01, stage=build)→ 实现 → apphx complete …01 <turn>(无 result)
|
|
60
|
+
注意:P0 未完工前不会被跳过,但它的 build 回合结束后下一轮会先跑它的确定性阶段。
|
|
61
|
+
|
|
62
|
+
#3 next --any → { "action": "step", "job": { "id": "…01", "stage": "verify" } }
|
|
63
|
+
apphx step …01 → verify 通过 → 任务进入 review
|
|
64
|
+
|
|
65
|
+
#4 next --any → host(…01, stage=review)→ 独立评审返回 approved + 逐条证据
|
|
66
|
+
apphx complete …01 <turn> review-result.json
|
|
67
|
+
|
|
68
|
+
#5 next --any → { "action": "step", "job": { "id": "…01", "stage": "package" } }
|
|
69
|
+
apphx step …01 → status=built,artifact 记录 kind/path/digest
|
|
70
|
+
# 通过门禁(verify+review 全过才可能 built)→ 发邮件给作者
|
|
71
|
+
apphx notify …01 → { "id": "…01", "notifiedTo": "author@example.org",
|
|
72
|
+
"messageId": "…", "error": null }
|
|
73
|
+
# 失败会记 notifyError,重跑 notify 只补发未成功的,不会重复发
|
|
74
|
+
|
|
75
|
+
#6 next --any → host(…02 pomodoro-timer, P1, research)… 同 #1-#5 走完 → built
|
|
76
|
+
|
|
77
|
+
#7 next --any → host(…03 daily-notes, P2, research)… → built
|
|
78
|
+
|
|
79
|
+
#8 next --any → { "action": "idle",
|
|
80
|
+
"summary": { "total": 3, "built": 3, "failed": 0, "blocked": 0,
|
|
81
|
+
"waiting": 0, "queued": 0, "running": 0 },
|
|
82
|
+
"nextAt": null, "pendingErrors": [] }
|
|
83
|
+
终局审计:全部 built → 队列真正结束,汇报三个产物。
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## 4. 循环中常见的三种分支
|
|
87
|
+
|
|
88
|
+
**评审拒绝(repair 自动回到 build)**
|
|
89
|
+
|
|
90
|
+
```text
|
|
91
|
+
next --any → host(review)→ 评审返回 approved=false + findings
|
|
92
|
+
apphx complete …02 <turn> review-result.json → 任务自动回到 stage=build、status=waiting
|
|
93
|
+
# 下一轮 next --any 仍返回 …02 的 build 回合;不新建任务、不问用户
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
**验证失败(verify → repair → build,attempts 扣减)**
|
|
97
|
+
|
|
98
|
+
```text
|
|
99
|
+
apphx step …02 → Verification failed (1) … → status=waiting, stage=build, attempts={verify:1}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
**P0 阻塞不冻结队列(next safe action)**
|
|
103
|
+
|
|
104
|
+
```text
|
|
105
|
+
…01 (P0) 处于 waiting(等待 retryDelayMs)且 nextAt 在未来 → next --any 跳过它
|
|
106
|
+
→ 返回 …02 (P1) 的 host 回合;P0 到期后重新被扫描到。
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## 5. 定时唤醒的固定 re-entry 指令
|
|
110
|
+
|
|
111
|
+
cron/Hermes 每次唤醒只注入这一段,不带任何任务细节(job id、prompt、结论都
|
|
112
|
+
由 CLI 在唤醒时重新给出):
|
|
113
|
+
|
|
114
|
+
```text
|
|
115
|
+
在控制项目目录用 apphx status 查看队列,然后循环执行
|
|
116
|
+
apphx next --any --config factory.json --build-only:
|
|
117
|
+
host → 执行该回合并用 apphx complete <id> <turn> [result] 收尾;
|
|
118
|
+
step → apphx step <id> 一次;built → apphx notify --any;
|
|
119
|
+
重复直到 idle。
|
|
120
|
+
idle 时读 summary:全部 built/failed 才是队列结束,存在 blocked/waiting 只是暂停;
|
|
121
|
+
按 nextAt 安排下次唤醒,汇报状态后退出。一个唤醒内不超过所有者设定的动作上限。
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
`factory.json` 中的邮件配置(密码只在发送时从环境变量读取,不落盘、不打日志):
|
|
125
|
+
|
|
126
|
+
```jsonc
|
|
127
|
+
{
|
|
128
|
+
"notify": {
|
|
129
|
+
"email": {
|
|
130
|
+
"from": "factory@example.org",
|
|
131
|
+
"to": "author@example.org", // 默认收件人;需求里 authorEmail 可覆盖
|
|
132
|
+
"smtpHost": "smtp.example.org",
|
|
133
|
+
"smtpPort": 465,
|
|
134
|
+
"secure": true,
|
|
135
|
+
"user": "factory@example.org",
|
|
136
|
+
"passwordEnv": "SMTP_PASSWORD" // 环境变量名,不是密码本身
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## 6. 边界
|
|
143
|
+
|
|
144
|
+
- 一个 session 同一时间只应拥有一个队列;worker 锁和 turn token 防确定性阶段重叠。
|
|
145
|
+
- `next --any` 每轮重读持久化状态,任何一轮的结论都不能靠"记得上一轮"。
|
|
146
|
+
- 商店上传、提交、审核不在本工具内;`built` ≠ 上架/过审。
|
|
@@ -4,15 +4,68 @@
|
|
|
4
4
|
"allowLocalExecution": false,
|
|
5
5
|
"allowCloudBuild": false,
|
|
6
6
|
"packageTarget": "aab",
|
|
7
|
-
"
|
|
7
|
+
"obfuscation": {
|
|
8
|
+
"options": {
|
|
9
|
+
"code": {
|
|
10
|
+
"removeComments": true
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"executionEnv": [
|
|
15
|
+
"ANDROID_HOME",
|
|
16
|
+
"ANDROID_DEVICE_ID"
|
|
17
|
+
],
|
|
8
18
|
"verification": {
|
|
9
|
-
"prerequisites": [
|
|
10
|
-
|
|
11
|
-
|
|
19
|
+
"prerequisites": [
|
|
20
|
+
[
|
|
21
|
+
"node",
|
|
22
|
+
"--version"
|
|
23
|
+
],
|
|
24
|
+
[
|
|
25
|
+
"java",
|
|
26
|
+
"-version"
|
|
27
|
+
],
|
|
28
|
+
[
|
|
29
|
+
"adb",
|
|
30
|
+
"version"
|
|
31
|
+
]
|
|
32
|
+
],
|
|
33
|
+
"checks": [
|
|
34
|
+
[
|
|
35
|
+
"npm",
|
|
36
|
+
"run",
|
|
37
|
+
"lint"
|
|
38
|
+
],
|
|
39
|
+
[
|
|
40
|
+
"npm",
|
|
41
|
+
"test",
|
|
42
|
+
"--",
|
|
43
|
+
"--runInBand"
|
|
44
|
+
]
|
|
45
|
+
],
|
|
46
|
+
"runtime": [
|
|
47
|
+
[
|
|
48
|
+
"npm",
|
|
49
|
+
"run",
|
|
50
|
+
"test:e2e",
|
|
51
|
+
"--",
|
|
52
|
+
"--platform",
|
|
53
|
+
"android",
|
|
54
|
+
"--device",
|
|
55
|
+
"${ANDROID_DEVICE_ID}"
|
|
56
|
+
]
|
|
57
|
+
]
|
|
12
58
|
},
|
|
13
59
|
"packaging": {
|
|
14
60
|
"provider": "local",
|
|
15
|
-
"commands": [
|
|
61
|
+
"commands": [
|
|
62
|
+
[
|
|
63
|
+
"./android/gradlew",
|
|
64
|
+
"-p",
|
|
65
|
+
"android",
|
|
66
|
+
":app:bundleRelease"
|
|
67
|
+
]
|
|
68
|
+
],
|
|
16
69
|
"artifactPath": "android/app/build/outputs/bundle/release/app-release.aab"
|
|
17
70
|
}
|
|
18
71
|
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$comment": "宿主侧角色→模型约定样例。apphx 不读取此文件;把每个角色绑定到你的宿主实际可用的模型/会话策略。model 填宿主模型 id(或类别占位),fresh=true 表示必须新会话,independentOf 表示该角色不能由这些角色的同一会话/同一模型执行。",
|
|
3
|
+
"product-analyst": {
|
|
4
|
+
"model": "reasoning-large",
|
|
5
|
+
"fresh": true,
|
|
6
|
+
"independentOf": []
|
|
7
|
+
},
|
|
8
|
+
"architect-proposal-1": { "model": "reasoning-a", "fresh": true, "independentOf": [] },
|
|
9
|
+
"architect-proposal-2": { "model": "reasoning-b", "fresh": true, "independentOf": [] },
|
|
10
|
+
"architect-proposal-3": { "model": "reasoning-c", "fresh": true, "independentOf": [] },
|
|
11
|
+
"developer": {
|
|
12
|
+
"model": "coding",
|
|
13
|
+
"fresh": false,
|
|
14
|
+
"parallel": "module slices under the synthesized design in docs/architecture.md"
|
|
15
|
+
},
|
|
16
|
+
"architect-review": {
|
|
17
|
+
"model": "reasoning-b",
|
|
18
|
+
"fresh": true,
|
|
19
|
+
"independentOf": ["developer"]
|
|
20
|
+
},
|
|
21
|
+
"qa-engineer": {
|
|
22
|
+
"model": "coding",
|
|
23
|
+
"fresh": true,
|
|
24
|
+
"independentOf": ["developer"]
|
|
25
|
+
},
|
|
26
|
+
"acceptance-reviewer": {
|
|
27
|
+
"model": "reasoning",
|
|
28
|
+
"fresh": true,
|
|
29
|
+
"independentOf": ["developer", "architect-review", "qa-engineer"]
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -4,15 +4,70 @@
|
|
|
4
4
|
"allowLocalExecution": false,
|
|
5
5
|
"allowCloudBuild": false,
|
|
6
6
|
"packageTarget": "simulator",
|
|
7
|
-
"
|
|
7
|
+
"obfuscation": {
|
|
8
|
+
"options": {
|
|
9
|
+
"code": {
|
|
10
|
+
"removeComments": true
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"executionEnv": [
|
|
15
|
+
"IOS_DEVICE_ID"
|
|
16
|
+
],
|
|
8
17
|
"verification": {
|
|
9
|
-
"prerequisites": [
|
|
10
|
-
|
|
11
|
-
|
|
18
|
+
"prerequisites": [
|
|
19
|
+
[
|
|
20
|
+
"xcodebuild",
|
|
21
|
+
"-version"
|
|
22
|
+
]
|
|
23
|
+
],
|
|
24
|
+
"checks": [
|
|
25
|
+
[
|
|
26
|
+
"xcodebuild",
|
|
27
|
+
"-project",
|
|
28
|
+
"App.xcodeproj",
|
|
29
|
+
"-scheme",
|
|
30
|
+
"App",
|
|
31
|
+
"build-for-testing",
|
|
32
|
+
"-destination",
|
|
33
|
+
"generic/platform=iOS Simulator",
|
|
34
|
+
"-derivedDataPath",
|
|
35
|
+
"build/DerivedData"
|
|
36
|
+
]
|
|
37
|
+
],
|
|
38
|
+
"runtime": [
|
|
39
|
+
[
|
|
40
|
+
"xcodebuild",
|
|
41
|
+
"-project",
|
|
42
|
+
"App.xcodeproj",
|
|
43
|
+
"-scheme",
|
|
44
|
+
"App",
|
|
45
|
+
"test",
|
|
46
|
+
"-destination",
|
|
47
|
+
"id=${IOS_DEVICE_ID}",
|
|
48
|
+
"-derivedDataPath",
|
|
49
|
+
"build/DerivedData"
|
|
50
|
+
]
|
|
51
|
+
]
|
|
12
52
|
},
|
|
13
53
|
"packaging": {
|
|
14
54
|
"provider": "local",
|
|
15
|
-
"commands": [
|
|
55
|
+
"commands": [
|
|
56
|
+
[
|
|
57
|
+
"xcodebuild",
|
|
58
|
+
"-project",
|
|
59
|
+
"App.xcodeproj",
|
|
60
|
+
"-scheme",
|
|
61
|
+
"App",
|
|
62
|
+
"build",
|
|
63
|
+
"-configuration",
|
|
64
|
+
"Debug",
|
|
65
|
+
"-destination",
|
|
66
|
+
"generic/platform=iOS Simulator",
|
|
67
|
+
"-derivedDataPath",
|
|
68
|
+
"build/DerivedData"
|
|
69
|
+
]
|
|
70
|
+
],
|
|
16
71
|
"artifactPath": "build/DerivedData/Build/Products/Debug-iphonesimulator/App.app"
|
|
17
72
|
}
|
|
18
73
|
}
|