@nick848/fet 0.1.0 → 1.0.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/LICENSE +21 -21
- package/README.md +265 -44
- package/dist/chunk-FZOVNHE7.js +104 -0
- package/dist/chunk-FZOVNHE7.js.map +1 -0
- package/dist/cli/index.js +1816 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/package.json +43 -49
- package/dist/apply.d.ts +0 -1
- package/dist/apply.js +0 -172
- package/dist/approval.d.ts +0 -2
- package/dist/approval.js +0 -26
- package/dist/atomic-write.d.ts +0 -5
- package/dist/atomic-write.js +0 -41
- package/dist/cli.d.ts +0 -2
- package/dist/cli.js +0 -178
- package/dist/doctor.d.ts +0 -1
- package/dist/doctor.js +0 -93
- package/dist/fingerprint.d.ts +0 -6
- package/dist/fingerprint.js +0 -77
- package/dist/hooks.d.ts +0 -12
- package/dist/hooks.js +0 -47
- package/dist/init.d.ts +0 -4
- package/dist/init.js +0 -47
- package/dist/opencode-skills.d.ts +0 -3
- package/dist/opencode-skills.js +0 -236
- package/dist/openspec.d.ts +0 -16
- package/dist/openspec.js +0 -73
- package/dist/paths.d.ts +0 -9
- package/dist/paths.js +0 -20
- package/dist/prompt.d.ts +0 -4
- package/dist/prompt.js +0 -30
- package/dist/scanner.d.ts +0 -23
- package/dist/scanner.js +0 -352
- package/dist/skills.d.ts +0 -3
- package/dist/skills.js +0 -142
- package/dist/state.d.ts +0 -17
- package/dist/state.js +0 -126
- package/dist/tasks.d.ts +0 -13
- package/dist/tasks.js +0 -69
- package/dist/types.d.ts +0 -38
- package/dist/types.js +0 -1
- package/dist/validate.d.ts +0 -1
- package/dist/validate.js +0 -150
- package/dist/verify.d.ts +0 -6
- package/dist/verify.js +0 -193
- package/dist/watch-paths.d.ts +0 -2
- package/dist/watch-paths.js +0 -70
- package/dist/workflow-hints.d.ts +0 -2
- package/dist/workflow-hints.js +0 -9
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 nick848
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 nick848
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,44 +1,265 @@
|
|
|
1
|
-
# FET
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
1
|
+
# FET
|
|
2
|
+
|
|
3
|
+
FET 是一个围绕 OpenSpec 构建的前端开发工作流编排 CLI。它不会直接生成业务代码,而是代理 OpenSpec 命令、维护本地工作流状态、生成可审计的项目上下文,并帮助 Cursor 等 AI 编程工具读取正确的项目资料。
|
|
4
|
+
|
|
5
|
+
### 作用
|
|
6
|
+
|
|
7
|
+
- 统一入口:用 `fet <command>` 包装 OpenSpec 工作流,避免用户和 AI 工具绕过 FET 的状态记录。
|
|
8
|
+
- 生成上下文:扫描项目并生成 `AGENTS.md` 与 `openspec/config.yaml` 中的 `fet:` 配置。
|
|
9
|
+
- 管理状态:记录 active change、任务同步、手动验证声明、工具适配状态等本地工作流信息。
|
|
10
|
+
- 集成 AI 工具:为 Cursor 生成项目规则和 Skill 说明,引导 AI 读取 OpenSpec 规划产物和项目上下文。
|
|
11
|
+
- 保护关键阶段:在 `sync` / `archive` 前检查 FET 的 verify 状态,降低未验证变更被归档的风险。
|
|
12
|
+
|
|
13
|
+
### 基本原理
|
|
14
|
+
|
|
15
|
+
FET 是 OpenSpec 的透明代理和本地编排层。用户运行 `fet apply`、`fet archive` 等命令时,FET 会先读取项目状态和 change 状态,执行必要的 pre-hook,再调用真实的 `openspec` CLI,最后根据 OpenSpec 的结果更新 FET 状态。
|
|
16
|
+
|
|
17
|
+
对于 OpenSpec 1.2.x,FET 会把部分高层命令映射到真实 OpenSpec 命令。例如 `fet apply` 会调用 `openspec instructions apply --change <id>` 输出实施指令,`fet sync` 会调用 `openspec validate <change> --type change --strict` 做归档前校验。
|
|
18
|
+
|
|
19
|
+
### 环境要求
|
|
20
|
+
|
|
21
|
+
- Node.js 18 或更高版本
|
|
22
|
+
- OpenSpec CLI 在 `PATH` 中可用
|
|
23
|
+
|
|
24
|
+
安装 OpenSpec:
|
|
25
|
+
|
|
26
|
+
```sh
|
|
27
|
+
npm install -g @fission-ai/openspec
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### 安装 FET
|
|
31
|
+
|
|
32
|
+
```sh
|
|
33
|
+
npm install -g @nick848/fet
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
安装后检查:
|
|
37
|
+
|
|
38
|
+
```sh
|
|
39
|
+
fet --version
|
|
40
|
+
fet --help
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### 快速开始
|
|
44
|
+
|
|
45
|
+
在需要接入 OpenSpec 的项目根目录运行:
|
|
46
|
+
|
|
47
|
+
```sh
|
|
48
|
+
fet init
|
|
49
|
+
fet doctor
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
典型流程:
|
|
53
|
+
|
|
54
|
+
```sh
|
|
55
|
+
fet new my-change
|
|
56
|
+
fet apply --change my-change
|
|
57
|
+
fet verify --change my-change
|
|
58
|
+
fet verify --done --change my-change
|
|
59
|
+
fet sync --change my-change
|
|
60
|
+
fet archive --change my-change
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### 全局参数
|
|
64
|
+
|
|
65
|
+
| 参数 | 说明 | 示例 |
|
|
66
|
+
|------|------|------|
|
|
67
|
+
| `--cwd <path>` | 指定项目根目录,默认当前目录。 | `fet doctor --cwd ./app` |
|
|
68
|
+
| `--change <id>` | 指定 OpenSpec change。 | `fet apply --change add-login` |
|
|
69
|
+
| `--yes` | 对低风险确认使用默认同意。 | `fet init --yes` |
|
|
70
|
+
| `--json` | 输出机器可读 JSON。 | `fet doctor --json` |
|
|
71
|
+
| `--verbose` | 输出更多诊断信息。 | `fet doctor --verbose` |
|
|
72
|
+
| `--no-color` | 禁用终端颜色。 | `fet --no-color doctor` |
|
|
73
|
+
|
|
74
|
+
### 命令列表
|
|
75
|
+
|
|
76
|
+
| 命令 | 用法 | 说明 |
|
|
77
|
+
|------|------|------|
|
|
78
|
+
| `fet init` | `fet init [--yes]` | 初始化 FET 和 OpenSpec;生成上下文文件、状态文件、Cursor 规则和 Skill。 |
|
|
79
|
+
| `fet update-context` | `fet update-context [--yes]` | 重新扫描项目并更新 `AGENTS.md` 与 `openspec/config.yaml` 的 FET 托管区域。 |
|
|
80
|
+
| `fet doctor` | `fet doctor [--fix-lock]` | 诊断 OpenSpec、FET 状态、上下文文件、Cursor 集成和锁文件。 |
|
|
81
|
+
| `fet explore` | `fet explore --change <id>` | 输出探索/提案相关 OpenSpec 指令,帮助 AI 讨论需求。 |
|
|
82
|
+
| `fet propose` | `fet propose <change-id>` | 创建新的 OpenSpec change;等价于 FET 高层提案入口。 |
|
|
83
|
+
| `fet new` | `fet new <change-id>` | 创建新的 OpenSpec change。 |
|
|
84
|
+
| `fet continue` | `fet continue [artifact] --change <id>` | 输出指定 artifact 的 OpenSpec 指令,默认 `proposal`。 |
|
|
85
|
+
| `fet ff` | `fet ff --change <id>` | 查看当前 change 的 OpenSpec artifact 状态。 |
|
|
86
|
+
| `fet apply` | `fet apply --change <id>` | 输出实施当前 change 的 OpenSpec apply 指令,并同步 FET 状态。 |
|
|
87
|
+
| `fet verify` | `fet verify --change <id>` | 生成 `.fet/verify-instructions.md` 手动验证指令。 |
|
|
88
|
+
| `fet verify --done` | `fet verify --done --change <id>` | 声明已完成手动验证,允许后续 `sync` / `archive`。 |
|
|
89
|
+
| `fet verify --auto` | `fet verify --auto [--yes]` | 生成自动验证执行计划;当前版本不执行项目脚本,`--yes` 会记录授权计划指纹。 |
|
|
90
|
+
| `fet sync` | `fet sync --change <id>` | 在 FET verify gate 通过后,调用 OpenSpec 严格校验 change。 |
|
|
91
|
+
| `fet archive` | `fet archive --change <id>` | 在 FET verify gate 通过后,归档 change 并更新 OpenSpec 主规范。 |
|
|
92
|
+
| `fet bulk-archive` | `fet bulk-archive` | 当前 OpenSpec 1.2.x 无对应顶层命令;请逐个执行 `fet archive --change <id>`。 |
|
|
93
|
+
| `fet onboard` | `fet onboard` | 输出 OpenSpec onboarding / instruction 信息。 |
|
|
94
|
+
| `fet passthrough` | `fet passthrough <command> [...args]` | 透传暂未接管的 OpenSpec 命令,不更新 FET 生命周期状态。 |
|
|
95
|
+
|
|
96
|
+
### 生成文件
|
|
97
|
+
|
|
98
|
+
FET 可能创建或更新:
|
|
99
|
+
|
|
100
|
+
- `AGENTS.md`
|
|
101
|
+
- `openspec/config.yaml` 的 `fet:` 命名空间
|
|
102
|
+
- `openspec/fet-state.json`
|
|
103
|
+
- `openspec/changes/<change-id>/fet-state.json`
|
|
104
|
+
- `openspec/changes/<change-id>/.fet/verify-instructions.md`
|
|
105
|
+
- `.cursor/skills/fet-*/SKILL.md`
|
|
106
|
+
- `.cursor/rules/fet-context.mdc`
|
|
107
|
+
|
|
108
|
+
FET 只拥有明确标记的托管区域,托管区域之外的用户内容应被保留。`fet init` 还会向 `.gitignore` 添加 FET 本地状态块,避免把锁文件和本地状态误提交。
|
|
109
|
+
|
|
110
|
+
### 安全边界
|
|
111
|
+
|
|
112
|
+
FET 是本地工作流辅助工具,不是沙箱、CI 强制 gate 或密码学审计系统。直接调用 `openspec` 可以绕过 FET 的本地 gate。团队如果需要强制执行验证,应在 CI、分支保护或代码审查规则中重复校验。
|
|
113
|
+
|
|
114
|
+
### 开发
|
|
115
|
+
|
|
116
|
+
```sh
|
|
117
|
+
npm install
|
|
118
|
+
npm run typecheck
|
|
119
|
+
npm run test
|
|
120
|
+
npm run build
|
|
121
|
+
npm run release:check
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
运行真实 OpenSpec 烟测:
|
|
125
|
+
|
|
126
|
+
```powershell
|
|
127
|
+
$env:FET_REAL_OPENSPEC='1'; npm run test:real-openspec
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### 许可证
|
|
131
|
+
|
|
132
|
+
MIT
|
|
133
|
+
|
|
134
|
+
## English
|
|
135
|
+
|
|
136
|
+
FET is a frontend development workflow orchestration CLI built around OpenSpec. It does not generate business code directly. Instead, it proxies OpenSpec commands, maintains local workflow state, generates auditable project context, and helps AI coding tools such as Cursor load the right files.
|
|
137
|
+
|
|
138
|
+
### What It Does
|
|
139
|
+
|
|
140
|
+
- Provides one entry point through `fet <command>` for OpenSpec workflows.
|
|
141
|
+
- Generates `AGENTS.md` and the `fet:` namespace in `openspec/config.yaml`.
|
|
142
|
+
- Tracks local workflow state such as active changes, synced tasks, manual verification declarations, and tool adapter state.
|
|
143
|
+
- Integrates with AI tools by generating Cursor project rules and Skill instructions.
|
|
144
|
+
- Guards important stages by checking FET verification state before `sync` and `archive`.
|
|
145
|
+
|
|
146
|
+
### How It Works
|
|
147
|
+
|
|
148
|
+
FET is a transparent proxy and local orchestration layer for OpenSpec. When you run commands such as `fet apply` or `fet archive`, FET loads project and change state, runs pre-hooks, calls the real `openspec` CLI, and then updates FET state based on the result.
|
|
149
|
+
|
|
150
|
+
For OpenSpec 1.2.x, some high-level FET commands are mapped to the actual OpenSpec command surface. For example, `fet apply` calls `openspec instructions apply --change <id>`, and `fet sync` calls `openspec validate <change> --type change --strict`.
|
|
151
|
+
|
|
152
|
+
### Requirements
|
|
153
|
+
|
|
154
|
+
- Node.js 18 or newer
|
|
155
|
+
- OpenSpec CLI available on `PATH`
|
|
156
|
+
|
|
157
|
+
Install OpenSpec:
|
|
158
|
+
|
|
159
|
+
```sh
|
|
160
|
+
npm install -g @fission-ai/openspec
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Installation
|
|
164
|
+
|
|
165
|
+
```sh
|
|
166
|
+
npm install -g @nick848/fet
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Check the installation:
|
|
170
|
+
|
|
171
|
+
```sh
|
|
172
|
+
fet --version
|
|
173
|
+
fet --help
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### Quick Start
|
|
177
|
+
|
|
178
|
+
Run this in a project root:
|
|
179
|
+
|
|
180
|
+
```sh
|
|
181
|
+
fet init
|
|
182
|
+
fet doctor
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Typical workflow:
|
|
186
|
+
|
|
187
|
+
```sh
|
|
188
|
+
fet new my-change
|
|
189
|
+
fet apply --change my-change
|
|
190
|
+
fet verify --change my-change
|
|
191
|
+
fet verify --done --change my-change
|
|
192
|
+
fet sync --change my-change
|
|
193
|
+
fet archive --change my-change
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Global Options
|
|
197
|
+
|
|
198
|
+
| Option | Description | Example |
|
|
199
|
+
|--------|-------------|---------|
|
|
200
|
+
| `--cwd <path>` | Set project root. Defaults to current directory. | `fet doctor --cwd ./app` |
|
|
201
|
+
| `--change <id>` | Select an OpenSpec change. | `fet apply --change add-login` |
|
|
202
|
+
| `--yes` | Accept low-risk confirmations. | `fet init --yes` |
|
|
203
|
+
| `--json` | Print machine-readable JSON. | `fet doctor --json` |
|
|
204
|
+
| `--verbose` | Print more diagnostics. | `fet doctor --verbose` |
|
|
205
|
+
| `--no-color` | Disable terminal colors. | `fet --no-color doctor` |
|
|
206
|
+
|
|
207
|
+
### Commands
|
|
208
|
+
|
|
209
|
+
| Command | Usage | Description |
|
|
210
|
+
|---------|-------|-------------|
|
|
211
|
+
| `fet init` | `fet init [--yes]` | Initialize FET and OpenSpec; generate context, state, Cursor rules, and Skills. |
|
|
212
|
+
| `fet update-context` | `fet update-context [--yes]` | Rescan the project and update FET-managed regions in `AGENTS.md` and `openspec/config.yaml`. |
|
|
213
|
+
| `fet doctor` | `fet doctor [--fix-lock]` | Diagnose OpenSpec, FET state, context files, Cursor integration, and lock files. |
|
|
214
|
+
| `fet explore` | `fet explore --change <id>` | Print OpenSpec exploration/proposal instructions for discussing requirements. |
|
|
215
|
+
| `fet propose` | `fet propose <change-id>` | Create a new OpenSpec change through FET's proposal entry point. |
|
|
216
|
+
| `fet new` | `fet new <change-id>` | Create a new OpenSpec change. |
|
|
217
|
+
| `fet continue` | `fet continue [artifact] --change <id>` | Print OpenSpec instructions for an artifact. Defaults to `proposal`. |
|
|
218
|
+
| `fet ff` | `fet ff --change <id>` | Show OpenSpec artifact status for a change. |
|
|
219
|
+
| `fet apply` | `fet apply --change <id>` | Print OpenSpec apply instructions and update FET state. |
|
|
220
|
+
| `fet verify` | `fet verify --change <id>` | Generate `.fet/verify-instructions.md` for manual verification. |
|
|
221
|
+
| `fet verify --done` | `fet verify --done --change <id>` | Declare manual verification complete and allow `sync` / `archive`. |
|
|
222
|
+
| `fet verify --auto` | `fet verify --auto [--yes]` | Generate an automatic verification plan. This version does not run project scripts; `--yes` records the plan fingerprint. |
|
|
223
|
+
| `fet sync` | `fet sync --change <id>` | After FET verify gate passes, run strict OpenSpec validation for the change. |
|
|
224
|
+
| `fet archive` | `fet archive --change <id>` | After FET verify gate passes, archive the change and update main OpenSpec specs. |
|
|
225
|
+
| `fet bulk-archive` | `fet bulk-archive` | Not supported by OpenSpec 1.2.x as a top-level command. Archive changes one by one. |
|
|
226
|
+
| `fet onboard` | `fet onboard` | Print OpenSpec onboarding / instruction information. |
|
|
227
|
+
| `fet passthrough` | `fet passthrough <command> [...args]` | Pass through unmanaged OpenSpec commands without updating FET lifecycle state. |
|
|
228
|
+
|
|
229
|
+
### Generated Files
|
|
230
|
+
|
|
231
|
+
FET may create or update:
|
|
232
|
+
|
|
233
|
+
- `AGENTS.md`
|
|
234
|
+
- the `fet:` namespace in `openspec/config.yaml`
|
|
235
|
+
- `openspec/fet-state.json`
|
|
236
|
+
- `openspec/changes/<change-id>/fet-state.json`
|
|
237
|
+
- `openspec/changes/<change-id>/.fet/verify-instructions.md`
|
|
238
|
+
- `.cursor/skills/fet-*/SKILL.md`
|
|
239
|
+
- `.cursor/rules/fet-context.mdc`
|
|
240
|
+
|
|
241
|
+
FET only owns explicitly marked managed regions. User content outside those regions should be preserved. During `fet init`, FET also adds a managed `.gitignore` block for local workflow state.
|
|
242
|
+
|
|
243
|
+
### Safety Model
|
|
244
|
+
|
|
245
|
+
FET is a local workflow helper. It is not a sandbox, mandatory CI gate, or cryptographic audit system. Direct `openspec` calls can bypass FET local gates. Teams that require enforcement should repeat validation in CI, branch protection, or review policy.
|
|
246
|
+
|
|
247
|
+
### Development
|
|
248
|
+
|
|
249
|
+
```sh
|
|
250
|
+
npm install
|
|
251
|
+
npm run typecheck
|
|
252
|
+
npm run test
|
|
253
|
+
npm run build
|
|
254
|
+
npm run release:check
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
Run the real OpenSpec smoke test:
|
|
258
|
+
|
|
259
|
+
```powershell
|
|
260
|
+
$env:FET_REAL_OPENSPEC='1'; npm run test:real-openspec
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### License
|
|
264
|
+
|
|
265
|
+
MIT
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/errors/codes.ts
|
|
4
|
+
var ErrorCode = /* @__PURE__ */ ((ErrorCode2) => {
|
|
5
|
+
ErrorCode2["Unknown"] = "UNKNOWN";
|
|
6
|
+
ErrorCode2["InvalidArguments"] = "INVALID_ARGUMENTS";
|
|
7
|
+
ErrorCode2["OpenSpecNotFound"] = "OPENSPEC_NOT_FOUND";
|
|
8
|
+
ErrorCode2["OpenSpecUnsupportedVersion"] = "OPENSPEC_UNSUPPORTED_VERSION";
|
|
9
|
+
ErrorCode2["OpenSpecCommandFailed"] = "OPENSPEC_COMMAND_FAILED";
|
|
10
|
+
ErrorCode2["OpenSpecStructureUnknown"] = "OPENSPEC_STRUCTURE_UNKNOWN";
|
|
11
|
+
ErrorCode2["StateSchemaUnsupported"] = "STATE_SCHEMA_UNSUPPORTED";
|
|
12
|
+
ErrorCode2["StateCorrupted"] = "STATE_CORRUPTED";
|
|
13
|
+
ErrorCode2["LockHeld"] = "LOCK_HELD";
|
|
14
|
+
ErrorCode2["UserCancelled"] = "USER_CANCELLED";
|
|
15
|
+
ErrorCode2["UnsafeScriptApprovalRequired"] = "UNSAFE_SCRIPT_APPROVAL_REQUIRED";
|
|
16
|
+
ErrorCode2["ToolAdapterConflict"] = "TOOL_ADAPTER_CONFLICT";
|
|
17
|
+
ErrorCode2["ConfigInvalid"] = "CONFIG_INVALID";
|
|
18
|
+
ErrorCode2["FileSystemError"] = "FILE_SYSTEM_ERROR";
|
|
19
|
+
return ErrorCode2;
|
|
20
|
+
})(ErrorCode || {});
|
|
21
|
+
function exitCodeForError(code) {
|
|
22
|
+
switch (code) {
|
|
23
|
+
case "INVALID_ARGUMENTS" /* InvalidArguments */:
|
|
24
|
+
case "CONFIG_INVALID" /* ConfigInvalid */:
|
|
25
|
+
return 2;
|
|
26
|
+
case "OPENSPEC_NOT_FOUND" /* OpenSpecNotFound */:
|
|
27
|
+
case "OPENSPEC_UNSUPPORTED_VERSION" /* OpenSpecUnsupportedVersion */:
|
|
28
|
+
return 3;
|
|
29
|
+
case "OPENSPEC_COMMAND_FAILED" /* OpenSpecCommandFailed */:
|
|
30
|
+
return 4;
|
|
31
|
+
case "OPENSPEC_STRUCTURE_UNKNOWN" /* OpenSpecStructureUnknown */:
|
|
32
|
+
case "STATE_SCHEMA_UNSUPPORTED" /* StateSchemaUnsupported */:
|
|
33
|
+
case "STATE_CORRUPTED" /* StateCorrupted */:
|
|
34
|
+
case "TOOL_ADAPTER_CONFLICT" /* ToolAdapterConflict */:
|
|
35
|
+
case "FILE_SYSTEM_ERROR" /* FileSystemError */:
|
|
36
|
+
return 5;
|
|
37
|
+
case "LOCK_HELD" /* LockHeld */:
|
|
38
|
+
return 6;
|
|
39
|
+
case "USER_CANCELLED" /* UserCancelled */:
|
|
40
|
+
return 7;
|
|
41
|
+
case "UNSAFE_SCRIPT_APPROVAL_REQUIRED" /* UnsafeScriptApprovalRequired */:
|
|
42
|
+
return 8;
|
|
43
|
+
case "UNKNOWN" /* Unknown */:
|
|
44
|
+
default:
|
|
45
|
+
return 1;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// src/errors/fet-error.ts
|
|
50
|
+
var FetError = class extends Error {
|
|
51
|
+
code;
|
|
52
|
+
exitCode;
|
|
53
|
+
details;
|
|
54
|
+
recoverable;
|
|
55
|
+
suggestedCommand;
|
|
56
|
+
cause;
|
|
57
|
+
constructor(options) {
|
|
58
|
+
super(options.message);
|
|
59
|
+
this.name = "FetError";
|
|
60
|
+
this.code = options.code;
|
|
61
|
+
this.exitCode = exitCodeForError(options.code);
|
|
62
|
+
this.details = options.details;
|
|
63
|
+
this.recoverable = options.recoverable ?? true;
|
|
64
|
+
this.suggestedCommand = options.suggestedCommand;
|
|
65
|
+
this.cause = options.cause;
|
|
66
|
+
}
|
|
67
|
+
toJSON() {
|
|
68
|
+
return {
|
|
69
|
+
code: this.code,
|
|
70
|
+
exitCode: this.exitCode,
|
|
71
|
+
message: this.message,
|
|
72
|
+
details: this.details,
|
|
73
|
+
recoverable: this.recoverable,
|
|
74
|
+
suggestedCommand: this.suggestedCommand
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
function toFetError(error) {
|
|
79
|
+
if (error instanceof FetError) {
|
|
80
|
+
return error;
|
|
81
|
+
}
|
|
82
|
+
if (error instanceof Error) {
|
|
83
|
+
return new FetError({
|
|
84
|
+
code: "UNKNOWN" /* Unknown */,
|
|
85
|
+
message: error.message,
|
|
86
|
+
recoverable: false,
|
|
87
|
+
cause: error
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
return new FetError({
|
|
91
|
+
code: "UNKNOWN" /* Unknown */,
|
|
92
|
+
message: "Unknown error",
|
|
93
|
+
details: error,
|
|
94
|
+
recoverable: false
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export {
|
|
99
|
+
ErrorCode,
|
|
100
|
+
exitCodeForError,
|
|
101
|
+
FetError,
|
|
102
|
+
toFetError
|
|
103
|
+
};
|
|
104
|
+
//# sourceMappingURL=chunk-FZOVNHE7.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/errors/codes.ts","../src/errors/fet-error.ts"],"sourcesContent":["export enum ErrorCode {\n Unknown = \"UNKNOWN\",\n InvalidArguments = \"INVALID_ARGUMENTS\",\n OpenSpecNotFound = \"OPENSPEC_NOT_FOUND\",\n OpenSpecUnsupportedVersion = \"OPENSPEC_UNSUPPORTED_VERSION\",\n OpenSpecCommandFailed = \"OPENSPEC_COMMAND_FAILED\",\n OpenSpecStructureUnknown = \"OPENSPEC_STRUCTURE_UNKNOWN\",\n StateSchemaUnsupported = \"STATE_SCHEMA_UNSUPPORTED\",\n StateCorrupted = \"STATE_CORRUPTED\",\n LockHeld = \"LOCK_HELD\",\n UserCancelled = \"USER_CANCELLED\",\n UnsafeScriptApprovalRequired = \"UNSAFE_SCRIPT_APPROVAL_REQUIRED\",\n ToolAdapterConflict = \"TOOL_ADAPTER_CONFLICT\",\n ConfigInvalid = \"CONFIG_INVALID\",\n FileSystemError = \"FILE_SYSTEM_ERROR\"\n}\n\nexport function exitCodeForError(code: ErrorCode): number {\n switch (code) {\n case ErrorCode.InvalidArguments:\n case ErrorCode.ConfigInvalid:\n return 2;\n case ErrorCode.OpenSpecNotFound:\n case ErrorCode.OpenSpecUnsupportedVersion:\n return 3;\n case ErrorCode.OpenSpecCommandFailed:\n return 4;\n case ErrorCode.OpenSpecStructureUnknown:\n case ErrorCode.StateSchemaUnsupported:\n case ErrorCode.StateCorrupted:\n case ErrorCode.ToolAdapterConflict:\n case ErrorCode.FileSystemError:\n return 5;\n case ErrorCode.LockHeld:\n return 6;\n case ErrorCode.UserCancelled:\n return 7;\n case ErrorCode.UnsafeScriptApprovalRequired:\n return 8;\n case ErrorCode.Unknown:\n default:\n return 1;\n }\n}\n","import { ErrorCode, exitCodeForError } from \"./codes.js\";\n\nexport interface FetErrorOptions {\n code: ErrorCode;\n message: string;\n details?: unknown;\n recoverable?: boolean;\n suggestedCommand?: string;\n cause?: unknown;\n}\n\nexport class FetError extends Error {\n readonly code: ErrorCode;\n readonly exitCode: number;\n readonly details?: unknown;\n readonly recoverable: boolean;\n readonly suggestedCommand?: string;\n override readonly cause?: unknown;\n\n constructor(options: FetErrorOptions) {\n super(options.message);\n this.name = \"FetError\";\n this.code = options.code;\n this.exitCode = exitCodeForError(options.code);\n this.details = options.details;\n this.recoverable = options.recoverable ?? true;\n this.suggestedCommand = options.suggestedCommand;\n this.cause = options.cause;\n }\n\n toJSON() {\n return {\n code: this.code,\n exitCode: this.exitCode,\n message: this.message,\n details: this.details,\n recoverable: this.recoverable,\n suggestedCommand: this.suggestedCommand\n };\n }\n}\n\nexport function toFetError(error: unknown): FetError {\n if (error instanceof FetError) {\n return error;\n }\n\n if (error instanceof Error) {\n return new FetError({\n code: ErrorCode.Unknown,\n message: error.message,\n recoverable: false,\n cause: error\n });\n }\n\n return new FetError({\n code: ErrorCode.Unknown,\n message: \"Unknown error\",\n details: error,\n recoverable: false\n });\n}\n"],"mappings":";;;AAAO,IAAK,YAAL,kBAAKA,eAAL;AACL,EAAAA,WAAA,aAAU;AACV,EAAAA,WAAA,sBAAmB;AACnB,EAAAA,WAAA,sBAAmB;AACnB,EAAAA,WAAA,gCAA6B;AAC7B,EAAAA,WAAA,2BAAwB;AACxB,EAAAA,WAAA,8BAA2B;AAC3B,EAAAA,WAAA,4BAAyB;AACzB,EAAAA,WAAA,oBAAiB;AACjB,EAAAA,WAAA,cAAW;AACX,EAAAA,WAAA,mBAAgB;AAChB,EAAAA,WAAA,kCAA+B;AAC/B,EAAAA,WAAA,yBAAsB;AACtB,EAAAA,WAAA,mBAAgB;AAChB,EAAAA,WAAA,qBAAkB;AAdR,SAAAA;AAAA,GAAA;AAiBL,SAAS,iBAAiB,MAAyB;AACxD,UAAQ,MAAM;AAAA,IACZ,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL;AACE,aAAO;AAAA,EACX;AACF;;;AChCO,IAAM,WAAN,cAAuB,MAAM;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACS;AAAA,EAElB,YAAY,SAA0B;AACpC,UAAM,QAAQ,OAAO;AACrB,SAAK,OAAO;AACZ,SAAK,OAAO,QAAQ;AACpB,SAAK,WAAW,iBAAiB,QAAQ,IAAI;AAC7C,SAAK,UAAU,QAAQ;AACvB,SAAK,cAAc,QAAQ,eAAe;AAC1C,SAAK,mBAAmB,QAAQ;AAChC,SAAK,QAAQ,QAAQ;AAAA,EACvB;AAAA,EAEA,SAAS;AACP,WAAO;AAAA,MACL,MAAM,KAAK;AAAA,MACX,UAAU,KAAK;AAAA,MACf,SAAS,KAAK;AAAA,MACd,SAAS,KAAK;AAAA,MACd,aAAa,KAAK;AAAA,MAClB,kBAAkB,KAAK;AAAA,IACzB;AAAA,EACF;AACF;AAEO,SAAS,WAAW,OAA0B;AACnD,MAAI,iBAAiB,UAAU;AAC7B,WAAO;AAAA,EACT;AAEA,MAAI,iBAAiB,OAAO;AAC1B,WAAO,IAAI,SAAS;AAAA,MAClB;AAAA,MACA,SAAS,MAAM;AAAA,MACf,aAAa;AAAA,MACb,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AAEA,SAAO,IAAI,SAAS;AAAA,IAClB;AAAA,IACA,SAAS;AAAA,IACT,SAAS;AAAA,IACT,aAAa;AAAA,EACf,CAAC;AACH;","names":["ErrorCode"]}
|