@fkqfkq123/opencode-autopilot 0.1.3 → 0.1.6
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/GUIDE.zh-CN.md +120 -0
- package/README.md +50 -390
- package/dist/packages/runtime/src/bootstrap/create-harness.d.ts +1 -0
- package/dist/packages/runtime/src/bootstrap/create-harness.js +5 -1
- package/dist/packages/runtime/src/config/workflow-config.d.ts +5 -0
- package/dist/packages/runtime/src/config/workflow-config.js +95 -6
- package/dist/packages/runtime/src/diagnostics/workflow-diagnostics-format.js +2 -1
- package/dist/packages/runtime/src/diagnostics/workflow-doctor.d.ts +3 -1
- package/dist/packages/runtime/src/diagnostics/workflow-doctor.js +7 -6
- package/dist/packages/runtime/src/install/workflow-installer.js +6 -22
- package/dist/packages/runtime/src/plugin/workflow-plugin-entry.js +7 -12
- package/dist/packages/runtime/src/shared/json-file.d.ts +1 -0
- package/dist/packages/runtime/src/shared/json-file.js +10 -1
- package/dist/packages/runtime/src/workspace/workflow-workspace.js +5 -1
- package/package.json +3 -2
package/GUIDE.zh-CN.md
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# Autopilot
|
|
2
|
+
|
|
3
|
+
[English](./README.md) | 中文说明
|
|
4
|
+
|
|
5
|
+
Autopilot 是一个 OpenCode 插件,可以把自然语言需求推进成一套完整流程:需求精炼、计划、实现、评审和测试。
|
|
6
|
+
|
|
7
|
+
## 安装
|
|
8
|
+
|
|
9
|
+
在 OpenCode 配置里加入插件:
|
|
10
|
+
|
|
11
|
+
```json
|
|
12
|
+
{
|
|
13
|
+
"plugin": ["@fkqfkq123/opencode-autopilot"]
|
|
14
|
+
}
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
然后重启 `opencode`。
|
|
18
|
+
|
|
19
|
+
如果加载成功,你应该看到类似日志:
|
|
20
|
+
|
|
21
|
+
```txt
|
|
22
|
+
[autopilot] Autopilot plugin loaded (... commands)
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## 使用
|
|
26
|
+
|
|
27
|
+
直接输入自然语言需求,例如:
|
|
28
|
+
|
|
29
|
+
```txt
|
|
30
|
+
给商品列表页增加排序能力,并注意回归风险。
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Autopilot 会通过这些工具推进流程:
|
|
34
|
+
|
|
35
|
+
- `workflow_open`
|
|
36
|
+
- `workflow_attach`
|
|
37
|
+
- `workflow_status`
|
|
38
|
+
- `workflow_answer`
|
|
39
|
+
- `workflow_approve`
|
|
40
|
+
- `workflow_resume`
|
|
41
|
+
|
|
42
|
+
通常你只需要按照 workflow 输出里提示的下一步工具继续即可。
|
|
43
|
+
|
|
44
|
+
## 配置
|
|
45
|
+
|
|
46
|
+
Autopilot 会在需要时自动创建:
|
|
47
|
+
|
|
48
|
+
```txt
|
|
49
|
+
.workflow-harness/autopilot.json
|
|
50
|
+
~/.config/opencode/autopilot.json
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
如果配置保持空值,就使用默认行为。
|
|
54
|
+
|
|
55
|
+
### `autopilot.json`
|
|
56
|
+
|
|
57
|
+
最小示例:
|
|
58
|
+
|
|
59
|
+
```json
|
|
60
|
+
{
|
|
61
|
+
"skillRoots": ["~/.claude/skills", "~/.config/opencode/skills"],
|
|
62
|
+
"phases": {
|
|
63
|
+
"spec_refinement": { "requiredSkills": [] },
|
|
64
|
+
"plan": { "requiredSkills": [] },
|
|
65
|
+
"develop": { "requiredSkills": [] },
|
|
66
|
+
"review": { "requiredSkills": [] },
|
|
67
|
+
"test": { "requiredSkills": [] }
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
字段说明:
|
|
73
|
+
|
|
74
|
+
- `skillRoots`:要扫描的 skill 目录
|
|
75
|
+
- `phases.<phase>.requiredSkills`:该阶段需要注入的 skill
|
|
76
|
+
|
|
77
|
+
支持的 phase:
|
|
78
|
+
|
|
79
|
+
- `spec_refinement`
|
|
80
|
+
- `plan`
|
|
81
|
+
- `develop`
|
|
82
|
+
- `review`
|
|
83
|
+
- `test`
|
|
84
|
+
|
|
85
|
+
如果旧的 `workflow.json` 存在而新的 `autopilot.json` 不存在,Autopilot 会复用旧文件,并提示你后续迁移。
|
|
86
|
+
|
|
87
|
+
## 备用安装方式
|
|
88
|
+
|
|
89
|
+
如果你更想走本地文件安装:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
curl -fsSL https://raw.githubusercontent.com/juhuaxia/Autopilot/main/install.sh | bash
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## 常见问题
|
|
96
|
+
|
|
97
|
+
### OpenCode 启动失败
|
|
98
|
+
|
|
99
|
+
先临时从 `opencode.json` 中移除这个插件,确认 OpenCode 能正常启动,再检查配置后重新启用。
|
|
100
|
+
|
|
101
|
+
### 插件加载了,但看不到 workflow 命令
|
|
102
|
+
|
|
103
|
+
通常是宿主没有正确注册导出的 workflow tools。
|
|
104
|
+
|
|
105
|
+
### 某个 workflow 状态坏掉了
|
|
106
|
+
|
|
107
|
+
删除当前项目的运行时目录后重新开始:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
rm -rf .workflow-harness
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## 如果你要开发这个插件
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
bun install
|
|
117
|
+
bun run typecheck
|
|
118
|
+
bun test
|
|
119
|
+
bun run build
|
|
120
|
+
```
|
package/README.md
CHANGED
|
@@ -2,223 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
English | [中文说明](./GUIDE.zh-CN.md)
|
|
4
4
|
|
|
5
|
-
Autopilot is an OpenCode
|
|
5
|
+
Autopilot is an OpenCode plugin that turns a natural-language request into a structured workflow: refinement, plan, implementation, review, and testing.
|
|
6
6
|
|
|
7
|
-
##
|
|
7
|
+
## Install
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
- OpenCode-facing workflow commands such as `workflow_open`, `workflow_attach`, `workflow_status`, `workflow_answer`, `workflow_approve`, `workflow_resume`, and `workflow_back`
|
|
11
|
-
- Plugin loading and native primary workflow agent registration for OpenCode-style hosts
|
|
12
|
-
- `install` and `doctor` flows for bootstrapping configuration and validating setup
|
|
13
|
-
- Review/test loop-back semantics, human breakpoints, event storage, attach/re-attach support
|
|
14
|
-
|
|
15
|
-
## 2. Who this is for
|
|
16
|
-
|
|
17
|
-
Autopilot is a good fit if you want to:
|
|
18
|
-
|
|
19
|
-
- add a workflow primary agent to an OpenCode-style host,
|
|
20
|
-
- structure engineering work into explicit workflow phases,
|
|
21
|
-
- validate a workflow runtime and command surface through a plugin.
|
|
22
|
-
|
|
23
|
-
## 3. Prerequisites
|
|
24
|
-
|
|
25
|
-
Recommended environment:
|
|
26
|
-
|
|
27
|
-
- macOS / Linux / Windows
|
|
28
|
-
- [Bun](https://bun.sh/) `1.3.5` or a compatible version
|
|
29
|
-
- OpenCode installed if you want to actually load and verify the plugin
|
|
30
|
-
|
|
31
|
-
Check Bun:
|
|
32
|
-
|
|
33
|
-
```bash
|
|
34
|
-
bun --version
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
If Bun is not installed yet:
|
|
38
|
-
|
|
39
|
-
```bash
|
|
40
|
-
curl -fsSL https://bun.sh/install | bash
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
Then restart your terminal and verify again:
|
|
44
|
-
|
|
45
|
-
```bash
|
|
46
|
-
bun --version
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
## 4. Installation
|
|
50
|
-
|
|
51
|
-
### 4.1 Recommended: install as an npm plugin package
|
|
52
|
-
|
|
53
|
-
OpenCode supports npm-based plugins directly. Once this package is published, the simplest configuration is:
|
|
54
|
-
|
|
55
|
-
```json
|
|
56
|
-
{
|
|
57
|
-
"plugin": ["@fkqfkq123/opencode-autopilot"]
|
|
58
|
-
}
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
You can also pin a version:
|
|
62
|
-
|
|
63
|
-
```json
|
|
64
|
-
{
|
|
65
|
-
"plugin": ["@fkqfkq123/opencode-autopilot@0.1.2"]
|
|
66
|
-
}
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
In this mode, OpenCode installs and caches the npm package automatically. No manual `git clone`, local `plugin.js`, or extra install script is required.
|
|
70
|
-
|
|
71
|
-
### 4.2 Fallback: install from GitHub Releases
|
|
72
|
-
|
|
73
|
-
If you prefer a local-file installation path or need a fallback distribution mode, use the one-line installer from GitHub Releases:
|
|
74
|
-
|
|
75
|
-
```bash
|
|
76
|
-
curl -fsSL https://raw.githubusercontent.com/juhuaxia/Autopilot/main/install.sh | bash
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
Install a specific version:
|
|
80
|
-
|
|
81
|
-
```bash
|
|
82
|
-
curl -fsSL https://raw.githubusercontent.com/juhuaxia/Autopilot/main/install.sh | bash -s -- --version v0.1.2
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
The fallback installer will:
|
|
86
|
-
|
|
87
|
-
- download the prebuilt release package from GitHub Releases,
|
|
88
|
-
- install it into `~/.config/opencode/plugins/autopilot/`,
|
|
89
|
-
- update `~/.config/opencode/opencode.json`.
|
|
90
|
-
|
|
91
|
-
Release requirement:
|
|
92
|
-
|
|
93
|
-
- Each GitHub Release must include `autopilot-release.tar.gz`
|
|
94
|
-
- The repository includes `.github/workflows/release.yml`, which builds and uploads that file automatically on `v*` tags
|
|
95
|
-
|
|
96
|
-
If you want to modify the codebase or work from source, continue with the source setup below.
|
|
97
|
-
|
|
98
|
-
### 4.3 Clone the repository
|
|
99
|
-
|
|
100
|
-
```bash
|
|
101
|
-
git clone https://github.com/juhuaxia/Autopilot.git
|
|
102
|
-
cd Autopilot
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
### 4.4 Install dependencies
|
|
106
|
-
|
|
107
|
-
```bash
|
|
108
|
-
bun install
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
The project uses `bun.lock`, so dependencies are expected to stay reproducible.
|
|
112
|
-
|
|
113
|
-
## 5. Recommended first-run commands
|
|
114
|
-
|
|
115
|
-
Run these from the project root:
|
|
116
|
-
|
|
117
|
-
```bash
|
|
118
|
-
bun run src/cli.ts install
|
|
119
|
-
bun run src/cli.ts doctor
|
|
120
|
-
bun run build
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
What they do:
|
|
124
|
-
|
|
125
|
-
1. `install`
|
|
126
|
-
- creates project-level `.workflow-harness/workflow.json`
|
|
127
|
-
- tries to safely update `~/.config/opencode/opencode.json`
|
|
128
|
-
- normalizes `opencode.jsonc` into `opencode.json` when safe
|
|
129
|
-
2. `doctor`
|
|
130
|
-
- checks `workflow.json`
|
|
131
|
-
- checks `skillRoots`
|
|
132
|
-
- checks phase-level `requiredSkills`
|
|
133
|
-
- reports warnings and missing pieces
|
|
134
|
-
3. `build`
|
|
135
|
-
- compiles TypeScript
|
|
136
|
-
- produces `dist/plugin.js`
|
|
137
|
-
|
|
138
|
-
After that, confirm:
|
|
139
|
-
|
|
140
|
-
- `.workflow-harness/workflow.json` exists
|
|
141
|
-
- `doctor` shows no blocking configuration issue
|
|
142
|
-
- `dist/plugin.js` exists
|
|
143
|
-
|
|
144
|
-
## 6. Common development commands
|
|
145
|
-
|
|
146
|
-
### 6.1 Build
|
|
147
|
-
|
|
148
|
-
```bash
|
|
149
|
-
bun run build
|
|
150
|
-
```
|
|
151
|
-
|
|
152
|
-
### 6.2 Typecheck
|
|
153
|
-
|
|
154
|
-
```bash
|
|
155
|
-
bun run typecheck
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
### 6.3 Run tests
|
|
159
|
-
|
|
160
|
-
```bash
|
|
161
|
-
bun test
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
### 6.4 Run plugin smoke tests
|
|
165
|
-
|
|
166
|
-
```bash
|
|
167
|
-
bun run smoke:plugin
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
### 6.5 Run CLI commands directly
|
|
171
|
-
|
|
172
|
-
```bash
|
|
173
|
-
bun run src/cli.ts doctor
|
|
174
|
-
bun run src/cli.ts install
|
|
175
|
-
```
|
|
176
|
-
|
|
177
|
-
Or through the script alias:
|
|
178
|
-
|
|
179
|
-
```bash
|
|
180
|
-
bun run cli --help
|
|
181
|
-
```
|
|
182
|
-
|
|
183
|
-
> The CLI mainly provides workflow initialization, attach/status flows, and install/doctor actions.
|
|
184
|
-
|
|
185
|
-
## 7. CLI quick usage
|
|
186
|
-
|
|
187
|
-
### 7.1 Initialize config
|
|
188
|
-
|
|
189
|
-
```bash
|
|
190
|
-
bun run src/cli.ts install
|
|
191
|
-
```
|
|
192
|
-
|
|
193
|
-
### 7.2 Run a self-check
|
|
194
|
-
|
|
195
|
-
```bash
|
|
196
|
-
bun run src/cli.ts doctor
|
|
197
|
-
```
|
|
198
|
-
|
|
199
|
-
### 7.3 Create a workflow
|
|
200
|
-
|
|
201
|
-
```bash
|
|
202
|
-
bun run src/cli.ts workflow-open wf-1
|
|
203
|
-
```
|
|
204
|
-
|
|
205
|
-
### 7.4 Check workflow status
|
|
206
|
-
|
|
207
|
-
```bash
|
|
208
|
-
bun run src/cli.ts workflow-status wf-1
|
|
209
|
-
```
|
|
210
|
-
|
|
211
|
-
### 7.5 Re-attach to the workflow channel
|
|
212
|
-
|
|
213
|
-
```bash
|
|
214
|
-
bun run src/cli.ts workflow-attach wf-1
|
|
215
|
-
```
|
|
216
|
-
|
|
217
|
-
## 8. Loading the plugin into OpenCode
|
|
218
|
-
|
|
219
|
-
### 8.0 Recommended npm plugin path
|
|
220
|
-
|
|
221
|
-
Recommended OpenCode config:
|
|
9
|
+
Add the plugin to your OpenCode config:
|
|
222
10
|
|
|
223
11
|
```json
|
|
224
12
|
{
|
|
@@ -226,237 +14,109 @@ Recommended OpenCode config:
|
|
|
226
14
|
}
|
|
227
15
|
```
|
|
228
16
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
If you prefer a local installed fallback plugin, use:
|
|
232
|
-
|
|
233
|
-
```bash
|
|
234
|
-
curl -fsSL https://raw.githubusercontent.com/juhuaxia/Autopilot/main/install.sh | bash
|
|
235
|
-
```
|
|
236
|
-
|
|
237
|
-
Default install location:
|
|
238
|
-
|
|
239
|
-
```txt
|
|
240
|
-
~/.config/opencode/plugins/autopilot/
|
|
241
|
-
```
|
|
17
|
+
Restart `opencode`.
|
|
242
18
|
|
|
243
|
-
|
|
19
|
+
If the plugin loads correctly, you should see a log like:
|
|
244
20
|
|
|
245
21
|
```txt
|
|
246
|
-
|
|
247
|
-
```
|
|
248
|
-
|
|
249
|
-
### 8.2 Source-development path
|
|
250
|
-
|
|
251
|
-
Run:
|
|
252
|
-
|
|
253
|
-
```bash
|
|
254
|
-
bun run src/cli.ts install
|
|
255
|
-
bun run src/cli.ts doctor
|
|
256
|
-
```
|
|
257
|
-
|
|
258
|
-
If the installer can safely update the OpenCode config, you usually do not need to edit anything manually.
|
|
259
|
-
|
|
260
|
-
> `install.sh` targets GitHub Releases installs. The project-local installer targets source-development setups.
|
|
261
|
-
|
|
262
|
-
### 8.3 Manual plugin registration
|
|
263
|
-
|
|
264
|
-
OpenCode config is usually located at:
|
|
265
|
-
|
|
266
|
-
- `~/.config/opencode/opencode.json`
|
|
267
|
-
- or `~/.config/opencode/opencode.jsonc`
|
|
268
|
-
|
|
269
|
-
#### Option A: load the built plugin
|
|
270
|
-
|
|
271
|
-
Build first:
|
|
272
|
-
|
|
273
|
-
```bash
|
|
274
|
-
bun run build
|
|
275
|
-
```
|
|
276
|
-
|
|
277
|
-
Then add this to OpenCode config:
|
|
278
|
-
|
|
279
|
-
```json
|
|
280
|
-
{
|
|
281
|
-
"plugin": [
|
|
282
|
-
"file:///ABSOLUTE_PATH_TO_PROJECT/dist/plugin.js"
|
|
283
|
-
]
|
|
284
|
-
}
|
|
285
|
-
```
|
|
286
|
-
|
|
287
|
-
#### Option B: load source directly during development
|
|
288
|
-
|
|
289
|
-
```json
|
|
290
|
-
{
|
|
291
|
-
"plugin": [
|
|
292
|
-
"file:///ABSOLUTE_PATH_TO_PROJECT/plugin.ts"
|
|
293
|
-
]
|
|
294
|
-
}
|
|
22
|
+
[autopilot] Autopilot plugin loaded (... commands)
|
|
295
23
|
```
|
|
296
24
|
|
|
297
|
-
|
|
25
|
+
## Use
|
|
298
26
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
```bash
|
|
302
|
-
opencode
|
|
303
|
-
```
|
|
27
|
+
Start with a natural-language request, for example:
|
|
304
28
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
```bash
|
|
308
|
-
opencode serve
|
|
29
|
+
```txt
|
|
30
|
+
Add sorting to the product list page and make sure regression risks are reviewed.
|
|
309
31
|
```
|
|
310
32
|
|
|
311
|
-
|
|
33
|
+
Autopilot will guide the workflow through the available tools:
|
|
312
34
|
|
|
313
|
-
The plugin exposes these tools/commands:
|
|
314
|
-
|
|
315
|
-
- `workflow_channel`
|
|
316
35
|
- `workflow_open`
|
|
317
36
|
- `workflow_attach`
|
|
318
37
|
- `workflow_status`
|
|
319
38
|
- `workflow_answer`
|
|
320
39
|
- `workflow_approve`
|
|
321
40
|
- `workflow_resume`
|
|
322
|
-
- `workflow_back`
|
|
323
|
-
- `workflow_doctor`
|
|
324
41
|
|
|
325
|
-
|
|
42
|
+
You usually only need to follow the next recommended tool shown by the workflow output.
|
|
326
43
|
|
|
327
|
-
|
|
328
|
-
- `workflow_attach`
|
|
329
|
-
- `workflow_status`
|
|
330
|
-
- `workflow_answer`
|
|
331
|
-
- `workflow_approve`
|
|
332
|
-
- `workflow_resume`
|
|
333
|
-
- `workflow_back`
|
|
44
|
+
## Configuration
|
|
334
45
|
|
|
335
|
-
|
|
46
|
+
Autopilot automatically creates these files when needed:
|
|
336
47
|
|
|
337
48
|
```txt
|
|
338
|
-
|
|
49
|
+
.workflow-harness/autopilot.json
|
|
50
|
+
~/.config/opencode/autopilot.json
|
|
339
51
|
```
|
|
340
52
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
### 10.1 Configuration layers
|
|
344
|
-
|
|
345
|
-
- user default: `~/.config/opencode/workflow.json`
|
|
346
|
-
- project override: `<repo>/.workflow-harness/workflow.json`
|
|
347
|
-
- runtime state: `<repo>/.workflow-harness/workflows/<workflowId>/`
|
|
53
|
+
If they are left empty, Autopilot uses default behavior.
|
|
348
54
|
|
|
349
|
-
###
|
|
55
|
+
### `autopilot.json`
|
|
350
56
|
|
|
351
|
-
|
|
352
|
-
- `packages/runtime/` — workflow runtime implementation
|
|
353
|
-
- `tests/` — tests
|
|
354
|
-
- `scripts/` — auxiliary scripts
|
|
355
|
-
- `.workflow-harness/` — runtime config, state, and artifacts
|
|
356
|
-
- `dist/` — build output
|
|
357
|
-
|
|
358
|
-
## 11. Minimal `workflow.json` example
|
|
359
|
-
|
|
360
|
-
Start with a fully neutral config:
|
|
57
|
+
Minimal example:
|
|
361
58
|
|
|
362
59
|
```json
|
|
363
60
|
{
|
|
364
61
|
"skillRoots": ["~/.claude/skills", "~/.config/opencode/skills"],
|
|
365
62
|
"phases": {
|
|
63
|
+
"spec_refinement": { "requiredSkills": [] },
|
|
64
|
+
"plan": { "requiredSkills": [] },
|
|
366
65
|
"develop": { "requiredSkills": [] },
|
|
66
|
+
"review": { "requiredSkills": [] },
|
|
367
67
|
"test": { "requiredSkills": [] }
|
|
368
68
|
}
|
|
369
69
|
}
|
|
370
70
|
```
|
|
371
71
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
```json
|
|
375
|
-
{
|
|
376
|
-
"skillRoots": ["~/.claude/skills", "~/.config/opencode/skills"],
|
|
377
|
-
"phases": {
|
|
378
|
-
"develop": { "requiredSkills": ["frontend-design"] },
|
|
379
|
-
"test": { "requiredSkills": ["playwright"] }
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
```
|
|
383
|
-
|
|
384
|
-
That frontend example is only an example. The workflow runtime is not frontend-bound by default.
|
|
72
|
+
Field meanings:
|
|
385
73
|
|
|
386
|
-
|
|
74
|
+
- `skillRoots`: directories to scan for skill files
|
|
75
|
+
- `phases.<phase>.requiredSkills`: skills to inject into that phase
|
|
387
76
|
|
|
388
|
-
|
|
389
|
-
- do not put skill config under `workflows/<workflowId>/`
|
|
390
|
-
- run `workflow_doctor` or CLI `doctor` before using a new config
|
|
77
|
+
Supported phases:
|
|
391
78
|
|
|
392
|
-
|
|
79
|
+
- `spec_refinement`
|
|
80
|
+
- `plan`
|
|
81
|
+
- `develop`
|
|
82
|
+
- `review`
|
|
83
|
+
- `test`
|
|
393
84
|
|
|
394
|
-
|
|
85
|
+
If an old `workflow.json` exists and `autopilot.json` does not, Autopilot can reuse the legacy file and warn you to migrate.
|
|
395
86
|
|
|
396
|
-
|
|
87
|
+
## Fallback Install
|
|
397
88
|
|
|
398
|
-
|
|
399
|
-
{
|
|
400
|
-
"plugin": [
|
|
401
|
-
"file:///Users/<your-user>/.config/opencode/plugins/autopilot/plugin.js"
|
|
402
|
-
]
|
|
403
|
-
}
|
|
404
|
-
```
|
|
405
|
-
|
|
406
|
-
For source development, you can also point to your local `dist/plugin.js`.
|
|
89
|
+
If you prefer a local file install instead of the npm package:
|
|
407
90
|
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
```json
|
|
411
|
-
{
|
|
412
|
-
"plugin": ["@fkqfkq123/opencode-autopilot"]
|
|
413
|
-
}
|
|
91
|
+
```bash
|
|
92
|
+
curl -fsSL https://raw.githubusercontent.com/juhuaxia/Autopilot/main/install.sh | bash
|
|
414
93
|
```
|
|
415
94
|
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
That usually means the host integration layer has not actually registered the exported `workflowCommands` onto the host command/tool surface.
|
|
419
|
-
|
|
420
|
-
### Q3: What should I validate first?
|
|
421
|
-
|
|
422
|
-
Validate this order first:
|
|
95
|
+
## Troubleshooting
|
|
423
96
|
|
|
424
|
-
|
|
425
|
-
2. the host can call the default export
|
|
426
|
-
3. the host receives a plugin-like object
|
|
97
|
+
### OpenCode fails to start
|
|
427
98
|
|
|
428
|
-
|
|
99
|
+
Temporarily remove the plugin from `opencode.json`, restart OpenCode, then re-enable it after checking the config.
|
|
429
100
|
|
|
430
|
-
###
|
|
101
|
+
### The plugin loads but workflow commands do not appear
|
|
431
102
|
|
|
432
|
-
|
|
103
|
+
This usually means the host did not register the exported workflow tools correctly.
|
|
433
104
|
|
|
434
|
-
|
|
105
|
+
### A workflow seems broken
|
|
435
106
|
|
|
436
|
-
|
|
437
|
-
|---|---|
|
|
438
|
-
| `README.md` | Main entry for installation, release, and usage |
|
|
439
|
-
| `WORKFLOW_SKILL_PROFILE_ARCHITECTURE_CN.md` | Skill/profile configuration design |
|
|
440
|
-
| `OPENCODE_WORKFLOW_AGENT_GUIDE.md` | Agent/tool calling loop |
|
|
441
|
-
| `REQUIREMENT_TEMPLATE.md` | Requirement input template |
|
|
107
|
+
Delete the project runtime folder and start again:
|
|
442
108
|
|
|
443
|
-
|
|
109
|
+
```bash
|
|
110
|
+
rm -rf .workflow-harness
|
|
111
|
+
```
|
|
444
112
|
|
|
445
|
-
##
|
|
113
|
+
## For source development
|
|
446
114
|
|
|
447
|
-
If you
|
|
115
|
+
If you want to work on the plugin itself:
|
|
448
116
|
|
|
449
117
|
```bash
|
|
450
118
|
bun install
|
|
451
|
-
bun run
|
|
452
|
-
bun
|
|
119
|
+
bun run typecheck
|
|
120
|
+
bun test
|
|
453
121
|
bun run build
|
|
454
|
-
opencode
|
|
455
122
|
```
|
|
456
|
-
|
|
457
|
-
Then:
|
|
458
|
-
|
|
459
|
-
1. confirm `.workflow-harness/workflow.json` exists
|
|
460
|
-
2. confirm `dist/plugin.js` exists
|
|
461
|
-
3. if OpenCode does not auto-load the plugin, add `file:///ABSOLUTE_PATH_TO_PROJECT/dist/plugin.js` manually to config
|
|
462
|
-
4. verify `workflow_open`, `workflow_attach`, and `workflow_status` are visible in the host
|
|
@@ -14,6 +14,7 @@ export interface CreateHarnessOptions {
|
|
|
14
14
|
sessionClient?: OpencodeSessionClient;
|
|
15
15
|
opencodeBaseUrl?: string;
|
|
16
16
|
opencodePassword?: string;
|
|
17
|
+
homeDir?: string;
|
|
17
18
|
}
|
|
18
19
|
export declare function createHarness(baseDir: string, options?: CreateHarnessOptions): Promise<{
|
|
19
20
|
stateStore: FileSystemWorkflowStateStore;
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { mkdir } from "node:fs/promises";
|
|
2
|
+
import { homedir } from "node:os";
|
|
2
3
|
import { join } from "node:path";
|
|
3
4
|
import { HttpOpencodeSessionClient, InMemoryOpencodeSessionClient, } from "../../../adapters/opencode/src/opencode-session-client";
|
|
4
5
|
import { DefaultPhaseTransition } from "../../../core/src/transitions/default-phase-transition";
|
|
5
6
|
import { FileSystemArtifactEvaluator } from "../artifacts/file-system-artifact-evaluator";
|
|
6
7
|
import { DefaultAttachService } from "../attach/attach-service";
|
|
7
8
|
import { buildSkillRegistryWithWarnings } from "../config/skill-registry";
|
|
8
|
-
import { resolveWorkflowConfig } from "../config/workflow-config";
|
|
9
|
+
import { ensureAutopilotConfigFile, resolveWorkflowConfig, AUTOPILOT_CONFIG_FILENAME } from "../config/workflow-config";
|
|
9
10
|
import { DefaultWorkflowEngine } from "../engine/default-workflow-engine";
|
|
10
11
|
import { FileSystemWorkflowEventStore } from "../events/file-system-workflow-event-store";
|
|
11
12
|
import { BasicRecoveryClassifier } from "../recovery/basic-recovery-classifier";
|
|
@@ -20,8 +21,11 @@ import { DefaultWorkflowWorkspace } from "../workspace/workflow-workspace";
|
|
|
20
21
|
export async function createHarness(baseDir, options = {}) {
|
|
21
22
|
await mkdir(join(baseDir, "workflows"), { recursive: true });
|
|
22
23
|
const workspace = new DefaultWorkflowWorkspace(baseDir);
|
|
24
|
+
await ensureAutopilotConfigFile(workspace.workflowConfigFile());
|
|
25
|
+
await ensureAutopilotConfigFile(join(options.homeDir ?? homedir(), ".config", "opencode", AUTOPILOT_CONFIG_FILENAME));
|
|
23
26
|
const resolvedConfig = await resolveWorkflowConfig({
|
|
24
27
|
projectConfigFile: workspace.workflowConfigFile(),
|
|
28
|
+
...(options.homeDir ? { homeDir: options.homeDir } : {}),
|
|
25
29
|
});
|
|
26
30
|
const skillRegistryResult = await buildSkillRegistryWithWarnings(resolvedConfig.skillRoots);
|
|
27
31
|
const skillRegistry = skillRegistryResult.registry;
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
export declare const AUTOPILOT_CONFIG_FILENAME = "autopilot.json";
|
|
2
|
+
export declare const LEGACY_WORKFLOW_CONFIG_FILENAME = "workflow.json";
|
|
3
|
+
export declare const DEFAULT_SKILL_ROOTS: string[];
|
|
1
4
|
export type WorkflowConfigPhase = "spec_refinement" | "plan" | "develop" | "review" | "test";
|
|
2
5
|
export type WorkflowPhaseConfig = {
|
|
3
6
|
requiredSkills?: string[];
|
|
@@ -11,7 +14,9 @@ export type ResolvedWorkflowConfig = {
|
|
|
11
14
|
phases: Partial<Record<WorkflowConfigPhase, WorkflowPhaseConfig>>;
|
|
12
15
|
warnings: string[];
|
|
13
16
|
};
|
|
17
|
+
export declare const DEFAULT_AUTOPILOT_CONFIG: WorkflowConfigFile;
|
|
14
18
|
export declare function resolveWorkflowConfig(args: {
|
|
15
19
|
projectConfigFile: string;
|
|
16
20
|
homeDir?: string;
|
|
17
21
|
}): Promise<ResolvedWorkflowConfig>;
|
|
22
|
+
export declare function ensureAutopilotConfigFile(filePath: string): Promise<void>;
|
|
@@ -1,6 +1,20 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
1
2
|
import { homedir } from "node:os";
|
|
2
|
-
import { join } from "node:path";
|
|
3
|
-
import { readJsonFile } from "../shared/json-file";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
import { fileExists, readJsonFile, writeJsonFile } from "../shared/json-file";
|
|
5
|
+
export const AUTOPILOT_CONFIG_FILENAME = "autopilot.json";
|
|
6
|
+
export const LEGACY_WORKFLOW_CONFIG_FILENAME = "workflow.json";
|
|
7
|
+
export const DEFAULT_SKILL_ROOTS = ["~/.claude/skills", "~/.config/opencode/skills"];
|
|
8
|
+
export const DEFAULT_AUTOPILOT_CONFIG = {
|
|
9
|
+
skillRoots: DEFAULT_SKILL_ROOTS,
|
|
10
|
+
phases: {
|
|
11
|
+
spec_refinement: { requiredSkills: [] },
|
|
12
|
+
plan: { requiredSkills: [] },
|
|
13
|
+
develop: { requiredSkills: [] },
|
|
14
|
+
review: { requiredSkills: [] },
|
|
15
|
+
test: { requiredSkills: [] },
|
|
16
|
+
},
|
|
17
|
+
};
|
|
4
18
|
const EMPTY_CONFIG = {
|
|
5
19
|
skillRoots: [],
|
|
6
20
|
phases: {},
|
|
@@ -43,9 +57,84 @@ function mergeConfigs(base, incoming) {
|
|
|
43
57
|
}
|
|
44
58
|
return next;
|
|
45
59
|
}
|
|
60
|
+
async function readConfigFileWithWarnings(filePath, label) {
|
|
61
|
+
if (!(await fileExists(filePath))) {
|
|
62
|
+
return { config: null, warnings: [] };
|
|
63
|
+
}
|
|
64
|
+
try {
|
|
65
|
+
const raw = await readFile(filePath, "utf8");
|
|
66
|
+
if (!raw.trim()) {
|
|
67
|
+
return {
|
|
68
|
+
config: null,
|
|
69
|
+
warnings: [`${label} is empty and will be treated as defaults: ${filePath}`],
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
const parsed = JSON.parse(raw);
|
|
73
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
74
|
+
return {
|
|
75
|
+
config: null,
|
|
76
|
+
warnings: [`${label} is not a JSON object and will be ignored: ${filePath}`],
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
return {
|
|
80
|
+
config: parsed,
|
|
81
|
+
warnings: [],
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
if (error instanceof SyntaxError) {
|
|
86
|
+
return {
|
|
87
|
+
config: null,
|
|
88
|
+
warnings: [`${label} contains invalid JSON and will be ignored: ${filePath}`],
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
throw error;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
async function loadConfigWithLegacy(args) {
|
|
95
|
+
const preferred = await readConfigFileWithWarnings(args.preferredFile, args.label);
|
|
96
|
+
if (preferred.config || preferred.warnings.length > 0 || await fileExists(args.preferredFile)) {
|
|
97
|
+
return preferred;
|
|
98
|
+
}
|
|
99
|
+
const legacy = await readConfigFileWithWarnings(args.legacyFile, `Legacy ${args.label}`);
|
|
100
|
+
if (!legacy.config && legacy.warnings.length === 0) {
|
|
101
|
+
return legacy;
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
config: legacy.config,
|
|
105
|
+
warnings: [
|
|
106
|
+
`Using legacy ${LEGACY_WORKFLOW_CONFIG_FILENAME}; migrate to ${AUTOPILOT_CONFIG_FILENAME}: ${args.legacyFile}`,
|
|
107
|
+
...legacy.warnings,
|
|
108
|
+
],
|
|
109
|
+
};
|
|
110
|
+
}
|
|
46
111
|
export async function resolveWorkflowConfig(args) {
|
|
47
|
-
const globalConfigFile = join(args.homeDir ?? homedir(), ".config", "opencode",
|
|
48
|
-
const
|
|
49
|
-
const
|
|
50
|
-
|
|
112
|
+
const globalConfigFile = join(args.homeDir ?? homedir(), ".config", "opencode", AUTOPILOT_CONFIG_FILENAME);
|
|
113
|
+
const globalLegacyFile = join(args.homeDir ?? homedir(), ".config", "opencode", LEGACY_WORKFLOW_CONFIG_FILENAME);
|
|
114
|
+
const projectLegacyFile = join(dirname(args.projectConfigFile), LEGACY_WORKFLOW_CONFIG_FILENAME);
|
|
115
|
+
const globalConfig = await loadConfigWithLegacy({
|
|
116
|
+
preferredFile: globalConfigFile,
|
|
117
|
+
legacyFile: globalLegacyFile,
|
|
118
|
+
label: `Global ${AUTOPILOT_CONFIG_FILENAME}`,
|
|
119
|
+
});
|
|
120
|
+
const projectConfig = await loadConfigWithLegacy({
|
|
121
|
+
preferredFile: args.projectConfigFile,
|
|
122
|
+
legacyFile: projectLegacyFile,
|
|
123
|
+
label: `Project ${AUTOPILOT_CONFIG_FILENAME}`,
|
|
124
|
+
});
|
|
125
|
+
const merged = mergeConfigs(mergeConfigs(EMPTY_CONFIG, globalConfig.config), projectConfig.config);
|
|
126
|
+
merged.warnings.push(...globalConfig.warnings, ...projectConfig.warnings);
|
|
127
|
+
return merged;
|
|
128
|
+
}
|
|
129
|
+
export async function ensureAutopilotConfigFile(filePath) {
|
|
130
|
+
if (await fileExists(filePath)) {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
const legacyFilePath = join(dirname(filePath), LEGACY_WORKFLOW_CONFIG_FILENAME);
|
|
134
|
+
const legacyConfig = await readJsonFile(legacyFilePath);
|
|
135
|
+
if (legacyConfig) {
|
|
136
|
+
await writeJsonFile(filePath, legacyConfig);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
await writeJsonFile(filePath, DEFAULT_AUTOPILOT_CONFIG);
|
|
51
140
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { AUTOPILOT_CONFIG_FILENAME } from "../config/workflow-config";
|
|
1
2
|
const divider = "=".repeat(64);
|
|
2
3
|
export function formatWorkflowDoctorResult(result) {
|
|
3
4
|
const lines = [
|
|
@@ -50,7 +51,7 @@ export function formatWorkflowInstallResult(result) {
|
|
|
50
51
|
const lines = [
|
|
51
52
|
divider,
|
|
52
53
|
`Workflow Install: ${result.ok ? "OK" : "ATTENTION"}`,
|
|
53
|
-
`Project
|
|
54
|
+
`Project ${AUTOPILOT_CONFIG_FILENAME}: ${result.projectWorkflowConfigFile}`,
|
|
54
55
|
`OpenCode config: ${result.opencodeConfigFile}`,
|
|
55
56
|
`Plugin entry: ${result.pluginEntry}`,
|
|
56
57
|
];
|
|
@@ -20,4 +20,6 @@ export type WorkflowDoctorResult = {
|
|
|
20
20
|
nextSteps: string[];
|
|
21
21
|
warnings: string[];
|
|
22
22
|
};
|
|
23
|
-
export declare function runWorkflowDoctor(workspace: WorkflowWorkspace
|
|
23
|
+
export declare function runWorkflowDoctor(workspace: WorkflowWorkspace, options?: {
|
|
24
|
+
homeDir?: string;
|
|
25
|
+
}): Promise<WorkflowDoctorResult>;
|
|
@@ -3,7 +3,7 @@ import { readFile } from "node:fs/promises";
|
|
|
3
3
|
import { homedir } from "node:os";
|
|
4
4
|
import { dirname, join } from "node:path";
|
|
5
5
|
import { buildSkillRegistryWithWarnings } from "../config/skill-registry";
|
|
6
|
-
import { resolveWorkflowConfig } from "../config/workflow-config";
|
|
6
|
+
import { AUTOPILOT_CONFIG_FILENAME, resolveWorkflowConfig } from "../config/workflow-config";
|
|
7
7
|
async function fileExists(filePath) {
|
|
8
8
|
try {
|
|
9
9
|
await access(filePath);
|
|
@@ -27,11 +27,12 @@ function gitignoreHasWorkflowHarness(content) {
|
|
|
27
27
|
return normalized.includes(".workflow-harness/");
|
|
28
28
|
});
|
|
29
29
|
}
|
|
30
|
-
export async function runWorkflowDoctor(workspace) {
|
|
30
|
+
export async function runWorkflowDoctor(workspace, options = {}) {
|
|
31
31
|
const projectConfigFile = workspace.workflowConfigFile();
|
|
32
|
-
const globalConfigFile = join(homedir(), ".config", "opencode",
|
|
32
|
+
const globalConfigFile = join(options.homeDir ?? homedir(), ".config", "opencode", AUTOPILOT_CONFIG_FILENAME);
|
|
33
33
|
const resolvedConfig = await resolveWorkflowConfig({
|
|
34
34
|
projectConfigFile,
|
|
35
|
+
...(options.homeDir ? { homeDir: options.homeDir } : {}),
|
|
35
36
|
});
|
|
36
37
|
const registryResult = await buildSkillRegistryWithWarnings(resolvedConfig.skillRoots);
|
|
37
38
|
const checks = [];
|
|
@@ -52,7 +53,7 @@ export async function runWorkflowDoctor(workspace) {
|
|
|
52
53
|
}
|
|
53
54
|
const hasGlobalConfig = await fileExists(globalConfigFile);
|
|
54
55
|
if (!hasGlobalConfig) {
|
|
55
|
-
warnings.push(`Global
|
|
56
|
+
warnings.push(`Global ${AUTOPILOT_CONFIG_FILENAME} not found: ${globalConfigFile}`);
|
|
56
57
|
}
|
|
57
58
|
const workspaceRoot = workspace.baseDir().endsWith(".workflow-harness")
|
|
58
59
|
? dirname(workspace.baseDir())
|
|
@@ -91,10 +92,10 @@ export async function runWorkflowDoctor(workspace) {
|
|
|
91
92
|
});
|
|
92
93
|
const nextSteps = [];
|
|
93
94
|
if (!(await fileExists(projectConfigFile))) {
|
|
94
|
-
nextSteps.push(`Run installer to generate project
|
|
95
|
+
nextSteps.push(`Run installer to generate project ${AUTOPILOT_CONFIG_FILENAME}: ${projectConfigFile}`);
|
|
95
96
|
}
|
|
96
97
|
if (resolvedConfig.skillRoots.length === 0) {
|
|
97
|
-
nextSteps.push(
|
|
98
|
+
nextSteps.push(`Add skillRoots to ${AUTOPILOT_CONFIG_FILENAME} if you want phase skill injection`);
|
|
98
99
|
}
|
|
99
100
|
if (missingSkills.length > 0) {
|
|
100
101
|
nextSteps.push("Fix missing requiredSkills or add corresponding skill files under configured skillRoots");
|
|
@@ -1,23 +1,7 @@
|
|
|
1
1
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2
2
|
import { join, resolve } from "node:path";
|
|
3
|
-
import {
|
|
4
|
-
import { writeJsonFile } from "../shared/json-file";
|
|
5
|
-
const DEFAULT_WORKFLOW_CONFIG = {
|
|
6
|
-
skillRoots: ["~/.claude/skills", "~/.config/opencode/skills"],
|
|
7
|
-
phases: {
|
|
8
|
-
develop: { requiredSkills: [] },
|
|
9
|
-
test: { requiredSkills: [] },
|
|
10
|
-
},
|
|
11
|
-
};
|
|
12
|
-
async function fileExists(filePath) {
|
|
13
|
-
try {
|
|
14
|
-
await access(filePath);
|
|
15
|
-
return true;
|
|
16
|
-
}
|
|
17
|
-
catch {
|
|
18
|
-
return false;
|
|
19
|
-
}
|
|
20
|
-
}
|
|
3
|
+
import { ensureAutopilotConfigFile, AUTOPILOT_CONFIG_FILENAME } from "../config/workflow-config";
|
|
4
|
+
import { fileExists, writeJsonFile } from "../shared/json-file";
|
|
21
5
|
function stripJsonComments(input) {
|
|
22
6
|
return input
|
|
23
7
|
.replace(/^\s*\/\/.*$/gm, "")
|
|
@@ -44,18 +28,18 @@ async function resolveOpencodeConfigFile(opencodeConfigDir) {
|
|
|
44
28
|
export async function runWorkflowInstall(args) {
|
|
45
29
|
const repoRoot = resolve(args.cwd);
|
|
46
30
|
const harnessDir = join(repoRoot, ".workflow-harness");
|
|
47
|
-
const projectWorkflowConfigFile = join(harnessDir,
|
|
31
|
+
const projectWorkflowConfigFile = join(harnessDir, AUTOPILOT_CONFIG_FILENAME);
|
|
48
32
|
const opencodeConfigDir = join(args.homeDir, ".config", "opencode");
|
|
33
|
+
const globalAutopilotConfigFile = join(opencodeConfigDir, AUTOPILOT_CONFIG_FILENAME);
|
|
49
34
|
const pluginEntryFile = args.options?.pluginEntryFile ?? "dist/plugin.js";
|
|
50
35
|
const pluginEntry = `file://${join(repoRoot, pluginEntryFile)}`;
|
|
51
36
|
const configResolution = await resolveOpencodeConfigFile(opencodeConfigDir);
|
|
52
37
|
const opencodeConfigFile = join(opencodeConfigDir, "opencode.json");
|
|
53
38
|
const warnings = [...configResolution.warnings];
|
|
54
39
|
await mkdir(harnessDir, { recursive: true });
|
|
55
|
-
|
|
56
|
-
await writeJsonFile(projectWorkflowConfigFile, DEFAULT_WORKFLOW_CONFIG);
|
|
57
|
-
}
|
|
40
|
+
await ensureAutopilotConfigFile(projectWorkflowConfigFile);
|
|
58
41
|
await mkdir(opencodeConfigDir, { recursive: true });
|
|
42
|
+
await ensureAutopilotConfigFile(globalAutopilotConfigFile);
|
|
59
43
|
if (!(await fileExists(configResolution.filePath))) {
|
|
60
44
|
await writeJsonFile(opencodeConfigFile, {
|
|
61
45
|
plugin: [pluginEntry],
|
|
@@ -5,10 +5,11 @@ import { createHarness } from "../bootstrap/create-harness";
|
|
|
5
5
|
import { runWorkflowDoctor } from "../diagnostics/workflow-doctor";
|
|
6
6
|
import { runWorkflowInstall } from "../install/workflow-installer";
|
|
7
7
|
import { SdkOpencodeSessionClient, } from "../../../adapters/opencode/src/opencode-session-client";
|
|
8
|
-
import { mkdir,
|
|
8
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
9
9
|
import { homedir } from "node:os";
|
|
10
|
-
import { join } from "node:path";
|
|
11
10
|
import { z } from "zod";
|
|
11
|
+
import { readJsonFile } from "../shared/json-file";
|
|
12
|
+
import { DefaultWorkflowWorkspace } from "../workspace/workflow-workspace";
|
|
12
13
|
const workflowIdSchema = z.string().min(1).describe("Workflow identifier");
|
|
13
14
|
const WORKFLOW_PRIMARY_AGENT_PROMPT = `You are the workflow execution agent.
|
|
14
15
|
|
|
@@ -29,7 +30,7 @@ Hard rules:
|
|
|
29
30
|
- If the user provides natural language only, keep it as-is and let the workflow runtime + downstream AI refinement handle understanding and document selection.
|
|
30
31
|
`;
|
|
31
32
|
const WORKFLOW_PRIMARY_AGENT_DESCRIPTION = "Primary workflow agent that drives refine->plan->develop->review->test via workflow tools";
|
|
32
|
-
const WORKFLOW_PRIMARY_AGENT_MODEL = "
|
|
33
|
+
const WORKFLOW_PRIMARY_AGENT_MODEL = "openai/gpt-5.5";
|
|
33
34
|
function buildPrimaryAgentMetadata(baseDir) {
|
|
34
35
|
return {
|
|
35
36
|
name: "workflow",
|
|
@@ -77,14 +78,8 @@ async function syncHostTodos(args) {
|
|
|
77
78
|
if (!todoClient?.list || !todoClient.create || !todoClient.update) {
|
|
78
79
|
return;
|
|
79
80
|
}
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
try {
|
|
83
|
-
workflow = JSON.parse(await readFile(stateFile, "utf8"));
|
|
84
|
-
}
|
|
85
|
-
catch {
|
|
86
|
-
return;
|
|
87
|
-
}
|
|
81
|
+
const workspace = new DefaultWorkflowWorkspace(args.baseDir);
|
|
82
|
+
const workflow = await readJsonFile(workspace.workflowStateFile(args.workflowId));
|
|
88
83
|
if (!workflow?.activeSessionId || !workflow.phase || !workflow.status) {
|
|
89
84
|
return;
|
|
90
85
|
}
|
|
@@ -320,7 +315,7 @@ export async function workflowPlugin(input) {
|
|
|
320
315
|
},
|
|
321
316
|
},
|
|
322
317
|
workflow_install: {
|
|
323
|
-
description: "Generate
|
|
318
|
+
description: "Generate autopilot.json and safely register the plugin in OpenCode config.",
|
|
324
319
|
args: {},
|
|
325
320
|
execute: async () => {
|
|
326
321
|
return JSON.stringify(await runWorkflowInstall({
|
|
@@ -1,5 +1,14 @@
|
|
|
1
|
-
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
1
|
+
import { access, mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2
2
|
import { dirname } from "node:path";
|
|
3
|
+
export async function fileExists(filePath) {
|
|
4
|
+
try {
|
|
5
|
+
await access(filePath);
|
|
6
|
+
return true;
|
|
7
|
+
}
|
|
8
|
+
catch {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
3
12
|
export async function readJsonFile(filePath) {
|
|
4
13
|
try {
|
|
5
14
|
const raw = await readFile(filePath, "utf8");
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { join } from "node:path";
|
|
2
|
+
import { AUTOPILOT_CONFIG_FILENAME } from "../config/workflow-config";
|
|
2
3
|
export class DefaultWorkflowWorkspace {
|
|
3
4
|
root;
|
|
4
5
|
constructor(root) {
|
|
@@ -9,6 +10,9 @@ export class DefaultWorkflowWorkspace {
|
|
|
9
10
|
if (!normalized) {
|
|
10
11
|
throw new Error("workflowId must be a non-empty string");
|
|
11
12
|
}
|
|
13
|
+
if (normalized.includes("..") || normalized.includes("/") || normalized.includes("\\")) {
|
|
14
|
+
throw new Error("workflowId must not contain path separators or traversal sequences");
|
|
15
|
+
}
|
|
12
16
|
return normalized;
|
|
13
17
|
}
|
|
14
18
|
baseDir() {
|
|
@@ -18,7 +22,7 @@ export class DefaultWorkflowWorkspace {
|
|
|
18
22
|
return join(this.root, "workflows");
|
|
19
23
|
}
|
|
20
24
|
workflowConfigFile() {
|
|
21
|
-
return join(this.root,
|
|
25
|
+
return join(this.root, AUTOPILOT_CONFIG_FILENAME);
|
|
22
26
|
}
|
|
23
27
|
workflowDir(workflowId) {
|
|
24
28
|
return join(this.workflowsRoot(), this.normalizeWorkflowId(workflowId));
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fkqfkq123/opencode-autopilot",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.6",
|
|
5
5
|
"description": "An OpenCode plugin for attached-session workflow execution with refinement, planning, development, review, and test phases.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"packageManager": "bun@1.3.5",
|
|
@@ -24,7 +24,8 @@
|
|
|
24
24
|
},
|
|
25
25
|
"files": [
|
|
26
26
|
"dist",
|
|
27
|
-
"README.md"
|
|
27
|
+
"README.md",
|
|
28
|
+
"GUIDE.zh-CN.md"
|
|
28
29
|
],
|
|
29
30
|
"publishConfig": {
|
|
30
31
|
"access": "public"
|