helloloop 0.1.0 → 0.1.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/.codex-plugin/plugin.json +4 -5
- package/README.md +129 -200
- package/package.json +4 -9
- package/skills/helloloop/SKILL.md +8 -10
- package/src/cli.mjs +12 -3
- package/src/config.mjs +2 -2
- package/src/context.mjs +3 -23
- package/src/process.mjs +55 -4
- package/src/runner.mjs +1 -1
- package/templates/STATE.template.md +1 -1
- package/templates/status.template.json +1 -1
- /package/bin/{helloloop.mjs → helloloop.js} +0 -0
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "helloloop",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Backlog-driven continuous repository execution for Codex with verification loops and explicit skill and CLI entrypoints.",
|
|
5
5
|
"author": {
|
|
6
|
-
"name": "
|
|
7
|
-
"url": "https://github.com/hellowind777"
|
|
6
|
+
"name": "HelloLoop"
|
|
8
7
|
},
|
|
9
8
|
"license": "MIT",
|
|
10
9
|
"keywords": [
|
|
@@ -18,8 +17,8 @@
|
|
|
18
17
|
"interface": {
|
|
19
18
|
"displayName": "HelloLoop",
|
|
20
19
|
"shortDescription": "Continuous repo execution with backlog and Ralph Loop guards",
|
|
21
|
-
"longDescription": "HelloLoop packages backlog-driven continuous development for Codex as
|
|
22
|
-
"developerName": "
|
|
20
|
+
"longDescription": "HelloLoop packages backlog-driven continuous development for Codex as an official plugin bundle with explicit skill and CLI entrypoints.",
|
|
21
|
+
"developerName": "HelloLoop",
|
|
23
22
|
"category": "Coding",
|
|
24
23
|
"capabilities": [
|
|
25
24
|
"Interactive",
|
package/README.md
CHANGED
|
@@ -1,100 +1,91 @@
|
|
|
1
1
|
# HelloLoop
|
|
2
2
|
|
|
3
|
-
`HelloLoop` 是一个面向 Codex
|
|
3
|
+
`HelloLoop` 是一个面向 Codex 的独立插件,用来把“按 backlog 持续推进仓库开发”这件事标准化、可追踪、可验证地跑起来。
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
它不只是在单轮对话里改一段代码,而是把任务队列、必读文档、执行约束、验证命令和运行记录统一放进目标仓库的 `.helloloop/` 目录,让 Codex 可以按明确流程持续接续开发。
|
|
6
|
+
|
|
7
|
+
命令入口按 `Node.js 20+` 设计,支持 Windows、macOS 和 Linux。
|
|
6
8
|
|
|
7
9
|
## 目录
|
|
8
10
|
|
|
9
11
|
- [HelloLoop 是什么](#helloloop-是什么)
|
|
10
12
|
- [核心能力](#核心能力)
|
|
11
13
|
- [适用场景](#适用场景)
|
|
12
|
-
- [项目结构](#项目结构)
|
|
13
14
|
- [安装](#安装)
|
|
14
15
|
- [快速开始](#快速开始)
|
|
15
|
-
- [
|
|
16
|
+
- [命令速查](#命令速查)
|
|
16
17
|
- [状态目录](#状态目录)
|
|
17
|
-
- [
|
|
18
|
-
- [
|
|
19
|
-
- [验证](#验证)
|
|
18
|
+
- [工作机制](#工作机制)
|
|
19
|
+
- [仓库结构](#仓库结构)
|
|
20
20
|
- [相关文档](#相关文档)
|
|
21
21
|
|
|
22
22
|
## HelloLoop 是什么
|
|
23
23
|
|
|
24
|
-
`HelloLoop`
|
|
24
|
+
`HelloLoop` 解决的是以下问题:
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
- 你的仓库里已经有开发文档、任务拆解或 backlog
|
|
27
|
+
- 你希望 Codex 能按顺序接着做,而不是每次都从头解释背景
|
|
28
|
+
- 你希望每一轮执行前都自动带上项目状态、必读文档和实现约束
|
|
29
|
+
- 你希望每次运行后都留下状态记录、验证结果和运行痕迹
|
|
27
30
|
|
|
28
|
-
|
|
29
|
-
- 根据项目状态、必读文档和约束生成执行提示
|
|
30
|
-
- 调用 Codex 完成实现
|
|
31
|
-
- 运行验证命令确认结果
|
|
32
|
-
- 失败时按 Ralph Loop 思路重试或换路
|
|
33
|
-
- 把状态、结果和运行产物写回目标仓库
|
|
31
|
+
围绕这个目标,`HelloLoop` 提供了一套明确的仓库内执行模型:
|
|
34
32
|
|
|
35
|
-
|
|
33
|
+
1. 从 backlog 中选择当前可执行任务
|
|
34
|
+
2. 汇总项目上下文、任务目标和约束
|
|
35
|
+
3. 生成面向 Codex 的执行提示
|
|
36
|
+
4. 调用 Codex 完成实现
|
|
37
|
+
5. 执行验证命令
|
|
38
|
+
6. 回写状态、日志和运行记录
|
|
36
39
|
|
|
37
40
|
## 核心能力
|
|
38
41
|
|
|
39
|
-
-
|
|
40
|
-
-
|
|
41
|
-
-
|
|
42
|
-
-
|
|
43
|
-
-
|
|
44
|
-
-
|
|
45
|
-
-
|
|
46
|
-
-
|
|
42
|
+
- **插件安装**:安装到 Codex Home,作为独立插件使用
|
|
43
|
+
- **仓库初始化**:在目标仓库生成 `.helloloop/` 状态目录
|
|
44
|
+
- **任务调度**:基于优先级、依赖、风险等级挑选下一任务
|
|
45
|
+
- **干跑预览**:先看下一任务、提示词和验证命令,再决定是否执行
|
|
46
|
+
- **单轮执行**:执行一个任务并回写结果
|
|
47
|
+
- **循环执行**:连续执行多个任务,直到完成、阻塞或达到上限
|
|
48
|
+
- **验证联动**:优先使用任务级验证命令,缺省时读取仓库验证配置
|
|
49
|
+
- **运行留痕**:把提示词、stdout、stderr、验证输出沉淀到 `runs/`
|
|
47
50
|
|
|
48
51
|
## 适用场景
|
|
49
52
|
|
|
50
|
-
-
|
|
51
|
-
-
|
|
52
|
-
-
|
|
53
|
-
-
|
|
54
|
-
-
|
|
55
|
-
|
|
56
|
-
## 项目结构
|
|
57
|
-
|
|
58
|
-
```text
|
|
59
|
-
helloloop/
|
|
60
|
-
├── .codex-plugin/ # Codex 插件 manifest
|
|
61
|
-
├── bin/ # npm bin 入口
|
|
62
|
-
├── docs/ # 说明文档
|
|
63
|
-
├── scripts/ # CLI 安装脚本与入口
|
|
64
|
-
├── skills/ # 插件技能
|
|
65
|
-
├── src/ # 核心实现
|
|
66
|
-
├── templates/ # 初始化模板
|
|
67
|
-
└── tests/ # 回归测试
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
源码仓库包含 `docs/` 和 `tests/`,但安装到 Codex Home 时只会复制运行时必需文件。
|
|
53
|
+
- 你有一套开发文档,希望 Codex 接续完成后续开发
|
|
54
|
+
- 你有清晰 backlog,希望 AI 按队列逐项推进
|
|
55
|
+
- 你希望把“任务、约束、验证、结果”都放在仓库里长期维护
|
|
56
|
+
- 你希望执行失败后不是停住,而是能按既定策略继续推进
|
|
57
|
+
- 你希望多人协作时,每个人都能快速看懂当前任务状态
|
|
71
58
|
|
|
72
59
|
## 安装
|
|
73
60
|
|
|
74
|
-
###
|
|
61
|
+
### 通过 npm / npx 安装
|
|
75
62
|
|
|
76
63
|
```powershell
|
|
77
|
-
npx helloloop install --codex-home
|
|
64
|
+
npx helloloop install --codex-home <CODEX_HOME>
|
|
78
65
|
```
|
|
79
66
|
|
|
80
|
-
###
|
|
67
|
+
### 从源码仓库安装
|
|
81
68
|
|
|
82
69
|
```powershell
|
|
83
|
-
|
|
70
|
+
node ./scripts/helloloop.mjs install --codex-home <CODEX_HOME>
|
|
84
71
|
```
|
|
85
72
|
|
|
86
|
-
|
|
73
|
+
如果你在 Windows 上更习惯 PowerShell,也可以使用:
|
|
74
|
+
|
|
75
|
+
```powershell
|
|
76
|
+
pwsh -NoLogo -NoProfile -File .\scripts\install-home-plugin.ps1 -CodexHome <CODEX_HOME>
|
|
77
|
+
```
|
|
87
78
|
|
|
88
|
-
|
|
79
|
+
安装完成后,插件会被放到:
|
|
89
80
|
|
|
90
81
|
```text
|
|
91
|
-
|
|
82
|
+
<CODEX_HOME>\plugins\helloloop
|
|
92
83
|
```
|
|
93
84
|
|
|
94
|
-
|
|
85
|
+
同时会更新:
|
|
95
86
|
|
|
96
87
|
```text
|
|
97
|
-
|
|
88
|
+
<CODEX_HOME>\.agents\plugins\marketplace.json
|
|
98
89
|
```
|
|
99
90
|
|
|
100
91
|
## 快速开始
|
|
@@ -102,44 +93,60 @@ C:\Users\hellowind\.codex\.agents\plugins\marketplace.json
|
|
|
102
93
|
### 1. 安装插件
|
|
103
94
|
|
|
104
95
|
```powershell
|
|
105
|
-
npx helloloop install --codex-home
|
|
96
|
+
npx helloloop install --codex-home <CODEX_HOME>
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
之后的日常命令推荐直接使用:
|
|
100
|
+
|
|
101
|
+
```powershell
|
|
102
|
+
npx helloloop <command> [options]
|
|
106
103
|
```
|
|
107
104
|
|
|
108
|
-
|
|
105
|
+
如果你已经全局安装过:
|
|
109
106
|
|
|
110
107
|
```powershell
|
|
111
|
-
|
|
108
|
+
helloloop <command> [options]
|
|
112
109
|
```
|
|
113
110
|
|
|
111
|
+
在 Codex 当前会话里,也可以直接运行同样的 `npx helloloop ...` 命令,不需要重开终端。
|
|
112
|
+
|
|
113
|
+
### 2. 在目标仓库初始化 `.helloloop/`
|
|
114
|
+
|
|
115
|
+
```powershell
|
|
116
|
+
npx helloloop init --repo <REPO_ROOT>
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
初始化完成后,模板会落在目标仓库根目录下的 `.helloloop/`,而不是插件目录本身。
|
|
120
|
+
|
|
114
121
|
### 3. 检查运行条件
|
|
115
122
|
|
|
116
123
|
```powershell
|
|
117
|
-
|
|
124
|
+
npx helloloop doctor --repo <REPO_ROOT>
|
|
118
125
|
```
|
|
119
126
|
|
|
120
|
-
### 4.
|
|
127
|
+
### 4. 查看状态与下一任务
|
|
121
128
|
|
|
122
129
|
```powershell
|
|
123
|
-
|
|
124
|
-
|
|
130
|
+
npx helloloop status --repo <REPO_ROOT>
|
|
131
|
+
npx helloloop next --repo <REPO_ROOT>
|
|
125
132
|
```
|
|
126
133
|
|
|
127
134
|
### 5. 执行一个任务或连续执行
|
|
128
135
|
|
|
129
136
|
```powershell
|
|
130
|
-
|
|
131
|
-
|
|
137
|
+
npx helloloop run-once --repo <REPO_ROOT>
|
|
138
|
+
npx helloloop run-loop --repo <REPO_ROOT> --max-tasks 2
|
|
132
139
|
```
|
|
133
140
|
|
|
134
|
-
##
|
|
141
|
+
## 命令速查
|
|
135
142
|
|
|
136
143
|
| 命令 | 作用 |
|
|
137
144
|
| --- | --- |
|
|
138
|
-
| `install` | 安装插件到 Codex Home
|
|
139
|
-
| `init` |
|
|
140
|
-
| `doctor` | 检查 Codex
|
|
141
|
-
| `status` | 查看 backlog
|
|
142
|
-
| `next` |
|
|
145
|
+
| `install` | 安装插件到 Codex Home,并更新插件 marketplace |
|
|
146
|
+
| `init` | 初始化目标仓库的 `.helloloop/` |
|
|
147
|
+
| `doctor` | 检查 Codex、插件文件和目标仓库配置是否齐备 |
|
|
148
|
+
| `status` | 查看 backlog 汇总、当前状态和下一任务 |
|
|
149
|
+
| `next` | 生成下一任务预览,不真正调用 Codex |
|
|
143
150
|
| `run-once` | 执行一个任务 |
|
|
144
151
|
| `run-loop` | 连续执行多个任务 |
|
|
145
152
|
|
|
@@ -147,22 +154,22 @@ node C:\Users\hellowind\.codex\plugins\helloloop\scripts\helloloop.mjs run-loop
|
|
|
147
154
|
|
|
148
155
|
| 选项 | 说明 |
|
|
149
156
|
| --- | --- |
|
|
150
|
-
| `--repo <dir>` |
|
|
157
|
+
| `--repo <dir>` | 目标仓库根目录,默认当前目录 |
|
|
151
158
|
| `--codex-home <dir>` | 指定 Codex Home |
|
|
152
|
-
| `--config-dir <dir>` |
|
|
159
|
+
| `--config-dir <dir>` | 指定状态目录名,默认 `.helloloop` |
|
|
153
160
|
| `--dry-run` | 只生成提示词和预览,不真正调用 Codex |
|
|
154
161
|
| `--task-id <id>` | 指定执行某个任务 |
|
|
155
|
-
| `--max-tasks <n>` | `run-loop`
|
|
156
|
-
| `--max-attempts <n>` |
|
|
162
|
+
| `--max-tasks <n>` | `run-loop` 最多执行的任务数 |
|
|
163
|
+
| `--max-attempts <n>` | 每种策略的最大重试次数 |
|
|
157
164
|
| `--max-strategies <n>` | 单任务最大换路次数 |
|
|
158
|
-
| `--allow-high-risk` | 允许执行 `medium`
|
|
165
|
+
| `--allow-high-risk` | 允许执行 `medium` 及以上风险任务 |
|
|
159
166
|
| `--required-doc <path>` | 追加全局必读文档 |
|
|
160
167
|
| `--constraint <text>` | 追加全局实现约束 |
|
|
161
|
-
| `--force` |
|
|
168
|
+
| `--force` | 覆盖已有安装目录 |
|
|
162
169
|
|
|
163
170
|
### Skill 名称
|
|
164
171
|
|
|
165
|
-
安装为 Codex
|
|
172
|
+
安装为 Codex 插件后,推荐显式使用:
|
|
166
173
|
|
|
167
174
|
```text
|
|
168
175
|
helloloop:helloloop
|
|
@@ -170,7 +177,7 @@ helloloop:helloloop
|
|
|
170
177
|
|
|
171
178
|
## 状态目录
|
|
172
179
|
|
|
173
|
-
`HelloLoop`
|
|
180
|
+
`HelloLoop` 默认在目标仓库根目录创建 `.helloloop/`,用来保存 backlog、策略配置、运行状态和执行留痕。
|
|
174
181
|
|
|
175
182
|
典型结构如下:
|
|
176
183
|
|
|
@@ -184,151 +191,73 @@ helloloop:helloloop
|
|
|
184
191
|
└── runs/
|
|
185
192
|
```
|
|
186
193
|
|
|
187
|
-
|
|
194
|
+
各文件作用如下:
|
|
188
195
|
|
|
189
|
-
- `backlog.json
|
|
190
|
-
- `policy.json
|
|
191
|
-
- `project.json
|
|
192
|
-
- `status.json
|
|
193
|
-
- `STATE.md
|
|
194
|
-
- `runs
|
|
196
|
+
- `backlog.json`:任务列表、优先级、风险、依赖、验收条件
|
|
197
|
+
- `policy.json`:循环上限、重试策略、Codex 执行参数
|
|
198
|
+
- `project.json`:全局必读文档、实现约束、任务规划提示
|
|
199
|
+
- `status.json`:最近一次运行的机器可读状态
|
|
200
|
+
- `STATE.md`:面向人的当前进展摘要
|
|
201
|
+
- `runs/`:每次执行的提示词、日志和验证输出
|
|
195
202
|
|
|
196
|
-
|
|
203
|
+
## 工作机制
|
|
197
204
|
|
|
198
|
-
|
|
205
|
+
### 任务模型
|
|
199
206
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
`backlog.json` 中的任务通常包含这些字段:
|
|
207
|
+
`backlog.json` 中的任务通常包含以下字段:
|
|
203
208
|
|
|
204
209
|
- `id`:任务唯一标识
|
|
205
210
|
- `title`:任务标题
|
|
206
|
-
- `status`:`pending
|
|
211
|
+
- `status`:`pending`、`in_progress`、`done`、`failed`、`blocked`
|
|
207
212
|
- `priority`:`P0` 到 `P3`
|
|
208
|
-
- `risk`:`low
|
|
209
|
-
- `goal
|
|
210
|
-
- `docs
|
|
211
|
-
- `paths
|
|
213
|
+
- `risk`:`low`、`medium`、`high`、`critical`
|
|
214
|
+
- `goal`:本任务要达成的目标
|
|
215
|
+
- `docs`:执行前必须阅读的文档
|
|
216
|
+
- `paths`:本任务主要涉及的目录
|
|
212
217
|
- `acceptance`:验收条件
|
|
213
218
|
- `dependsOn`:依赖的上游任务
|
|
214
|
-
- `verify
|
|
219
|
+
- `verify`:任务专属验证命令
|
|
215
220
|
|
|
216
221
|
### 执行流程
|
|
217
222
|
|
|
218
|
-
`HelloLoop`
|
|
219
|
-
|
|
220
|
-
1. 从 backlog 中筛出可执行任务
|
|
221
|
-
2. 按优先级和依赖关系选择下一任务
|
|
222
|
-
3. 读取仓库状态、必读文档和实现约束
|
|
223
|
-
4. 生成 Codex 执行提示词
|
|
224
|
-
5. 调用 `codex exec`
|
|
225
|
-
6. 运行验证命令
|
|
226
|
-
7. 成功则把任务标记为完成
|
|
227
|
-
8. 失败则按 Ralph Loop 记录失败历史并继续重试或换路
|
|
223
|
+
`HelloLoop` 在每一轮执行中会完成这些事情:
|
|
228
224
|
|
|
229
|
-
|
|
225
|
+
1. 找出当前可执行任务
|
|
226
|
+
2. 读取仓库状态、任务描述和必读文档
|
|
227
|
+
3. 生成清晰的 Codex 执行提示
|
|
228
|
+
4. 运行 Codex 完成开发
|
|
229
|
+
5. 执行验证命令
|
|
230
|
+
6. 更新任务状态和运行记录
|
|
230
231
|
|
|
231
|
-
|
|
232
|
-
- `medium` 及以上风险任务需要显式传入 `--allow-high-risk`
|
|
233
|
-
- 如果存在未收束的 `in_progress` 任务,新的自动执行会被阻塞
|
|
234
|
-
- 如果存在 `failed` 或 `blocked` 任务,执行会停下来等待处理
|
|
235
|
-
- 如果依赖任务未完成,相关任务不会被挑选执行
|
|
232
|
+
### 风险控制
|
|
236
233
|
|
|
237
|
-
|
|
234
|
+
- 默认优先自动执行 `low` 风险任务
|
|
235
|
+
- 较高风险任务需要显式允许
|
|
236
|
+
- 存在未完成依赖时,任务不会被挑选执行
|
|
237
|
+
- 存在未收束的执行状态时,循环会停止并等待处理
|
|
238
238
|
|
|
239
|
-
|
|
239
|
+
## 仓库结构
|
|
240
240
|
|
|
241
241
|
```text
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
- 自动发布到 npm
|
|
252
|
-
- 自动创建 GitHub Release
|
|
253
|
-
|
|
254
|
-
### 推荐发布方式
|
|
255
|
-
|
|
256
|
-
#### 正式版
|
|
257
|
-
|
|
258
|
-
1. 修改 `package.json` 中的 `version`
|
|
259
|
-
2. 提交并推送代码
|
|
260
|
-
3. 创建同版本 Tag
|
|
261
|
-
|
|
262
|
-
示例:
|
|
263
|
-
|
|
264
|
-
```powershell
|
|
265
|
-
npm version patch --no-git-tag-version
|
|
266
|
-
git add package.json
|
|
267
|
-
git commit -m "chore: release v0.1.1"
|
|
268
|
-
git push origin main
|
|
269
|
-
git tag v0.1.1
|
|
270
|
-
git push origin v0.1.1
|
|
271
|
-
```
|
|
272
|
-
|
|
273
|
-
推送 `v0.1.1` 后,Action 会把 `0.1.1` 发布到 npm 的 `latest` 通道。
|
|
274
|
-
|
|
275
|
-
#### Beta 版
|
|
276
|
-
|
|
277
|
-
Beta Tag 采用:
|
|
278
|
-
|
|
279
|
-
```text
|
|
280
|
-
v0.2.0-beta.1
|
|
281
|
-
```
|
|
282
|
-
|
|
283
|
-
这类 Tag 会发布到 npm 的 `beta` 通道。工作流会要求:
|
|
284
|
-
|
|
285
|
-
- `package.json` 中的基础版本为 `0.2.0`
|
|
286
|
-
- 实际发布版本为 `0.2.0-beta.1`
|
|
287
|
-
|
|
288
|
-
### npm Trusted Publishing 配置
|
|
289
|
-
|
|
290
|
-
为了让 GitHub Actions 无需 `NPM_TOKEN` 直接发布到 npm,建议使用 npm Trusted Publishing。
|
|
291
|
-
|
|
292
|
-
在 npm 包设置中把以下信息绑定为 Trusted Publisher:
|
|
293
|
-
|
|
294
|
-
- GitHub 仓库:`hellowind777/helloloop`
|
|
295
|
-
- Workflow 文件:`publish.yml`
|
|
296
|
-
- 触发来源:GitHub-hosted runner
|
|
297
|
-
|
|
298
|
-
发布工作流已经按 Trusted Publishing 方式准备好:
|
|
299
|
-
|
|
300
|
-
- `id-token: write`
|
|
301
|
-
- Node 24
|
|
302
|
-
- 升级到最新 npm CLI
|
|
303
|
-
- 直接执行 `npm publish`
|
|
304
|
-
|
|
305
|
-
### 工作流触发规则
|
|
306
|
-
|
|
307
|
-
- `push tags: v*`:标准自动发布入口
|
|
308
|
-
- `workflow_dispatch`:手动输入 Tag 重新发布某个版本
|
|
309
|
-
|
|
310
|
-
## 验证
|
|
311
|
-
|
|
312
|
-
### 本地回归
|
|
313
|
-
|
|
314
|
-
```powershell
|
|
315
|
-
npm test
|
|
316
|
-
```
|
|
317
|
-
|
|
318
|
-
### 打包预检
|
|
319
|
-
|
|
320
|
-
```powershell
|
|
321
|
-
npm pack --dry-run
|
|
242
|
+
helloloop/
|
|
243
|
+
├── .codex-plugin/ # Codex 插件 manifest 与展示元数据
|
|
244
|
+
├── bin/ # npm 命令入口
|
|
245
|
+
├── docs/ # 补充说明文档
|
|
246
|
+
├── scripts/ # 安装脚本与 CLI 入口
|
|
247
|
+
├── skills/ # 插件技能
|
|
248
|
+
├── src/ # 核心实现
|
|
249
|
+
├── templates/ # 初始化时写入 .helloloop/ 的模板
|
|
250
|
+
└── tests/ # 回归测试
|
|
322
251
|
```
|
|
323
252
|
|
|
324
|
-
|
|
253
|
+
其中:
|
|
325
254
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
255
|
+
- `src/` 用来放 `HelloLoop` 的实际实现逻辑,例如任务选择、状态加载、执行流程、提示词生成和安装流程
|
|
256
|
+
- `tests/` 用来做回归验证,确保 CLI、模板、插件 bundle 和执行流程没有被改坏
|
|
257
|
+
- `templates/` 是初始化目标仓库时写入 `.helloloop/` 的模板来源
|
|
329
258
|
|
|
330
259
|
## 相关文档
|
|
331
260
|
|
|
332
|
-
-
|
|
333
|
-
-
|
|
334
|
-
-
|
|
261
|
+
- `docs/README.md`:插件 bundle 结构补充说明
|
|
262
|
+
- `docs/install.md`:安装说明
|
|
263
|
+
- `docs/plugin-standard.md`:官方插件结构与标准对照
|
package/package.json
CHANGED
|
@@ -1,21 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "helloloop",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Standalone Codex plugin bundle for backlog-driven repository execution with Ralph Loop guards",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
|
-
"url": "https://github.com/hellowind777/helloloop.git"
|
|
9
|
-
},
|
|
10
|
-
"homepage": "https://github.com/hellowind777/helloloop#readme",
|
|
11
|
-
"bugs": {
|
|
12
|
-
"url": "https://github.com/hellowind777/helloloop/issues"
|
|
8
|
+
"url": "git+https://github.com/hellowind777/helloloop.git"
|
|
13
9
|
},
|
|
14
10
|
"publishConfig": {
|
|
15
11
|
"access": "public"
|
|
16
12
|
},
|
|
17
13
|
"bin": {
|
|
18
|
-
"helloloop": "
|
|
14
|
+
"helloloop": "bin/helloloop.js"
|
|
19
15
|
},
|
|
20
16
|
"files": [
|
|
21
17
|
".codex-plugin",
|
|
@@ -28,10 +24,9 @@
|
|
|
28
24
|
"templates"
|
|
29
25
|
],
|
|
30
26
|
"scripts": {
|
|
31
|
-
"test": "node --test tests/cli_surface.test.mjs tests/install_script.test.mjs tests/ralph_loop.test.mjs tests/plugin_bundle.test.mjs"
|
|
27
|
+
"test": "node --test tests/cli_surface.test.mjs tests/install_script.test.mjs tests/process_shell.test.mjs tests/ralph_loop.test.mjs tests/plugin_bundle.test.mjs"
|
|
32
28
|
},
|
|
33
29
|
"engines": {
|
|
34
30
|
"node": ">=20"
|
|
35
31
|
}
|
|
36
32
|
}
|
|
37
|
-
|
|
@@ -11,18 +11,17 @@ Use this plugin when the task is continuous repository execution rather than a s
|
|
|
11
11
|
|
|
12
12
|
- This bundle root is the official plugin surface for HelloLoop.
|
|
13
13
|
- It ships standard Codex plugin metadata through `.codex-plugin/plugin.json` and a plugin skill through `skills/`.
|
|
14
|
-
-
|
|
15
|
-
- This plugin therefore does not support `~helloloop` or automatic Stop-hook continuation.
|
|
14
|
+
- This plugin is designed around explicit skill and CLI entrypoints.
|
|
16
15
|
|
|
17
16
|
## Setup
|
|
18
17
|
|
|
19
18
|
1. Install with `npx helloloop install --codex-home <CODEX_HOME>` or use `scripts/install-home-plugin.ps1`.
|
|
20
|
-
2. From the target repository, run `
|
|
21
|
-
3. From the target repository, run `
|
|
19
|
+
2. From the target repository, run `npx helloloop doctor --repo <repo-root>`.
|
|
20
|
+
3. From the target repository, run `npx helloloop init --repo <repo-root>`.
|
|
22
21
|
|
|
23
22
|
## Operating Model
|
|
24
23
|
|
|
25
|
-
- `.helloloop/` is the CLI and backlog state directory.
|
|
24
|
+
- `.helloloop/` is the default CLI and backlog state directory.
|
|
26
25
|
- The installed plugin bundle keeps runtime files such as `src/`, `templates/`, `bin/`, `scripts/`, and `skills/`.
|
|
27
26
|
- Source-only materials such as `docs/` and `tests/` stay in the development repository.
|
|
28
27
|
|
|
@@ -35,15 +34,14 @@ Use this plugin when the task is continuous repository execution rather than a s
|
|
|
35
34
|
|
|
36
35
|
## Primary Commands
|
|
37
36
|
|
|
38
|
-
- `
|
|
39
|
-
- `
|
|
40
|
-
- `
|
|
41
|
-
- `
|
|
37
|
+
- `npx helloloop status --repo <repo-root>`
|
|
38
|
+
- `npx helloloop next --repo <repo-root>`
|
|
39
|
+
- `npx helloloop run-once --repo <repo-root>`
|
|
40
|
+
- `npx helloloop run-loop --repo <repo-root>`
|
|
42
41
|
|
|
43
42
|
## Reporting Rules
|
|
44
43
|
|
|
45
44
|
- State explicitly that the plugin runs in pure official plugin mode.
|
|
46
|
-
- Call out any request that depends on Hook-only behavior such as `UserPromptSubmit` or `Stop`, because those are intentionally unsupported here.
|
|
47
45
|
- Keep Ralph Loop guardrails and repo verification intact.
|
|
48
46
|
|
|
49
47
|
## Docs
|
package/src/cli.mjs
CHANGED
|
@@ -7,6 +7,8 @@ import { scaffoldIfMissing } from "./config.mjs";
|
|
|
7
7
|
import { installPluginBundle } from "./install.mjs";
|
|
8
8
|
import { runLoop, runOnce, renderStatusText } from "./runner.mjs";
|
|
9
9
|
|
|
10
|
+
const REPO_ROOT_PLACEHOLDER = "<REPO_ROOT>";
|
|
11
|
+
|
|
10
12
|
function parseArgs(argv) {
|
|
11
13
|
const [command = "status", ...rest] = argv;
|
|
12
14
|
const options = {
|
|
@@ -68,6 +70,14 @@ function printHelp() {
|
|
|
68
70
|
console.log(helpText());
|
|
69
71
|
}
|
|
70
72
|
|
|
73
|
+
function renderFollowupExamples() {
|
|
74
|
+
return [
|
|
75
|
+
"下一步示例:",
|
|
76
|
+
`npx helloloop doctor --repo ${REPO_ROOT_PLACEHOLDER}`,
|
|
77
|
+
`如已全局安装,也可直接运行:helloloop doctor --repo ${REPO_ROOT_PLACEHOLDER}`,
|
|
78
|
+
].join("\n");
|
|
79
|
+
}
|
|
80
|
+
|
|
71
81
|
function probeCodexVersion() {
|
|
72
82
|
const codexVersion = process.platform === "win32"
|
|
73
83
|
? spawnSync("codex --version", {
|
|
@@ -171,8 +181,7 @@ export async function runCli(argv) {
|
|
|
171
181
|
console.log(`HelloLoop 已安装到:${result.targetPluginRoot}`);
|
|
172
182
|
console.log(`Marketplace 已更新:${result.marketplaceFile}`);
|
|
173
183
|
console.log("");
|
|
174
|
-
console.log(
|
|
175
|
-
console.log(`node ${path.join(result.targetPluginRoot, "scripts", "helloloop.mjs")} doctor --repo D:\\GitHub\\dev\\your-repo`);
|
|
184
|
+
console.log(renderFollowupExamples());
|
|
176
185
|
return;
|
|
177
186
|
}
|
|
178
187
|
|
|
@@ -259,4 +268,4 @@ export async function runCli(argv) {
|
|
|
259
268
|
|
|
260
269
|
throw new Error(`未知命令:${command}`);
|
|
261
270
|
}
|
|
262
|
-
|
|
271
|
+
|
package/src/config.mjs
CHANGED
|
@@ -98,7 +98,7 @@ export function loadVerifyCommands(context) {
|
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
export function loadRepoStateText(context) {
|
|
101
|
-
return readTextIfExists(context.
|
|
101
|
+
return readTextIfExists(context.stateFile, "").trim();
|
|
102
102
|
}
|
|
103
103
|
|
|
104
104
|
export function writeStatus(context, status) {
|
|
@@ -138,4 +138,4 @@ export function scaffoldIfMissing(context) {
|
|
|
138
138
|
|
|
139
139
|
return created;
|
|
140
140
|
}
|
|
141
|
-
|
|
141
|
+
|
package/src/context.mjs
CHANGED
|
@@ -1,35 +1,16 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { fileURLToPath } from "node:url";
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import { resolveFrom } from "./common.mjs";
|
|
5
5
|
|
|
6
6
|
const __filename = fileURLToPath(import.meta.url);
|
|
7
7
|
const __dirname = path.dirname(__filename);
|
|
8
8
|
const toolRoot = path.resolve(__dirname, "..");
|
|
9
9
|
const defaultConfigDirName = ".helloloop";
|
|
10
|
-
const legacyConfigDirName = ".helloagents/helloloop";
|
|
11
|
-
|
|
12
|
-
function resolveConfigDirName(repoRoot, explicitConfigDirName) {
|
|
13
|
-
if (explicitConfigDirName) {
|
|
14
|
-
return explicitConfigDirName;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const defaultConfigRoot = resolveFrom(repoRoot, ...defaultConfigDirName.split("/"));
|
|
18
|
-
if (fileExists(defaultConfigRoot)) {
|
|
19
|
-
return defaultConfigDirName;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
const legacyConfigRoot = resolveFrom(repoRoot, ...legacyConfigDirName.split("/"));
|
|
23
|
-
if (fileExists(legacyConfigRoot)) {
|
|
24
|
-
return legacyConfigDirName;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
return defaultConfigDirName;
|
|
28
|
-
}
|
|
29
10
|
|
|
30
11
|
export function createContext(options = {}) {
|
|
31
12
|
const repoRoot = path.resolve(options.repoRoot || process.cwd());
|
|
32
|
-
const configDirName =
|
|
13
|
+
const configDirName = options.configDirName || defaultConfigDirName;
|
|
33
14
|
const configRoot = resolveFrom(repoRoot, ...configDirName.split("/"));
|
|
34
15
|
|
|
35
16
|
return {
|
|
@@ -49,8 +30,7 @@ export function createContext(options = {}) {
|
|
|
49
30
|
statusFile: resolveFrom(configRoot, "status.json"),
|
|
50
31
|
stateFile: resolveFrom(configRoot, "STATE.md"),
|
|
51
32
|
runsDir: resolveFrom(configRoot, "runs"),
|
|
52
|
-
repoStateFile: resolveFrom(repoRoot, ".helloagents", "STATE.md"),
|
|
53
33
|
repoVerifyFile: resolveFrom(repoRoot, ".helloagents", "verify.yaml"),
|
|
54
34
|
};
|
|
55
35
|
}
|
|
56
|
-
|
|
36
|
+
|
package/src/process.mjs
CHANGED
|
@@ -66,6 +66,57 @@ function buildCmdCommandLine(executable, args) {
|
|
|
66
66
|
return [quoteForCmd(executable), ...args.map((item) => quoteForCmd(item))].join(" ");
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
+
function hasCommand(command, platform = process.platform) {
|
|
70
|
+
if (platform === "win32") {
|
|
71
|
+
const result = spawnSync("where.exe", [command], {
|
|
72
|
+
encoding: "utf8",
|
|
73
|
+
shell: false,
|
|
74
|
+
});
|
|
75
|
+
return result.status === 0;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const result = spawnSync("sh", ["-lc", `command -v ${command}`], {
|
|
79
|
+
encoding: "utf8",
|
|
80
|
+
shell: false,
|
|
81
|
+
});
|
|
82
|
+
return result.status === 0;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function resolveVerifyShellInvocation(options = {}) {
|
|
86
|
+
const platform = options.platform || process.platform;
|
|
87
|
+
const commandExists = options.commandExists || ((command) => hasCommand(command, platform));
|
|
88
|
+
|
|
89
|
+
if (platform === "win32") {
|
|
90
|
+
if (commandExists("pwsh")) {
|
|
91
|
+
return {
|
|
92
|
+
command: "pwsh",
|
|
93
|
+
argsPrefix: ["-NoLogo", "-NoProfile", "-Command"],
|
|
94
|
+
shell: false,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (commandExists("powershell")) {
|
|
99
|
+
return {
|
|
100
|
+
command: "powershell",
|
|
101
|
+
argsPrefix: ["-NoLogo", "-NoProfile", "-Command"],
|
|
102
|
+
shell: false,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return {
|
|
107
|
+
command: "cmd.exe",
|
|
108
|
+
argsPrefix: ["/d", "/s", "/c"],
|
|
109
|
+
shell: false,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return {
|
|
114
|
+
command: "sh",
|
|
115
|
+
argsPrefix: ["-lc"],
|
|
116
|
+
shell: false,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
69
120
|
function resolveCodexExecutable(explicitExecutable = "") {
|
|
70
121
|
if (explicitExecutable) {
|
|
71
122
|
return explicitExecutable;
|
|
@@ -214,13 +265,13 @@ export async function runCodexExec({ context, prompt, runDir, policy }) {
|
|
|
214
265
|
}
|
|
215
266
|
|
|
216
267
|
export async function runShellCommand(context, commandLine, runDir, index) {
|
|
217
|
-
const
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
"-Command",
|
|
268
|
+
const shellInvocation = resolveVerifyShellInvocation();
|
|
269
|
+
const result = await runChild(shellInvocation.command, [
|
|
270
|
+
...shellInvocation.argsPrefix,
|
|
221
271
|
commandLine,
|
|
222
272
|
], {
|
|
223
273
|
cwd: context.repoRoot,
|
|
274
|
+
shell: shellInvocation.shell,
|
|
224
275
|
});
|
|
225
276
|
|
|
226
277
|
const prefix = String(index + 1).padStart(2, "0");
|
package/src/runner.mjs
CHANGED
|
File without changes
|