@nick848/fet 0.1.0 → 1.0.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.
Files changed (51) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +101 -44
  3. package/dist/chunk-FZOVNHE7.js +104 -0
  4. package/dist/chunk-FZOVNHE7.js.map +1 -0
  5. package/dist/cli/index.js +1795 -0
  6. package/dist/cli/index.js.map +1 -0
  7. package/dist/index.js +12 -0
  8. package/dist/index.js.map +1 -0
  9. package/package.json +43 -49
  10. package/dist/apply.d.ts +0 -1
  11. package/dist/apply.js +0 -172
  12. package/dist/approval.d.ts +0 -2
  13. package/dist/approval.js +0 -26
  14. package/dist/atomic-write.d.ts +0 -5
  15. package/dist/atomic-write.js +0 -41
  16. package/dist/cli.d.ts +0 -2
  17. package/dist/cli.js +0 -178
  18. package/dist/doctor.d.ts +0 -1
  19. package/dist/doctor.js +0 -93
  20. package/dist/fingerprint.d.ts +0 -6
  21. package/dist/fingerprint.js +0 -77
  22. package/dist/hooks.d.ts +0 -12
  23. package/dist/hooks.js +0 -47
  24. package/dist/init.d.ts +0 -4
  25. package/dist/init.js +0 -47
  26. package/dist/opencode-skills.d.ts +0 -3
  27. package/dist/opencode-skills.js +0 -236
  28. package/dist/openspec.d.ts +0 -16
  29. package/dist/openspec.js +0 -73
  30. package/dist/paths.d.ts +0 -9
  31. package/dist/paths.js +0 -20
  32. package/dist/prompt.d.ts +0 -4
  33. package/dist/prompt.js +0 -30
  34. package/dist/scanner.d.ts +0 -23
  35. package/dist/scanner.js +0 -352
  36. package/dist/skills.d.ts +0 -3
  37. package/dist/skills.js +0 -142
  38. package/dist/state.d.ts +0 -17
  39. package/dist/state.js +0 -126
  40. package/dist/tasks.d.ts +0 -13
  41. package/dist/tasks.js +0 -69
  42. package/dist/types.d.ts +0 -38
  43. package/dist/types.js +0 -1
  44. package/dist/validate.d.ts +0 -1
  45. package/dist/validate.js +0 -150
  46. package/dist/verify.d.ts +0 -6
  47. package/dist/verify.js +0 -193
  48. package/dist/watch-paths.d.ts +0 -2
  49. package/dist/watch-paths.js +0 -70
  50. package/dist/workflow-hints.d.ts +0 -2
  51. 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,101 @@
1
- # FET
2
-
3
- 在项目中以 [OpenSpec](https://github.com/Fission-AI/OpenSpec) 为基座做**工作流编排**:`fet` 命令在前后挂钩子、管理 `openspec/fet-state.json`、生成上下文与工具技能(Cursor / OpenCode),并把 `openspec` CLI 透传执行。
4
-
5
- ## 要求
6
-
7
- - Node.js **≥ 18**
8
- - 已安装 OpenSpec CLI(PATH 中的 `openspec`,否则将尝试 `npx @fission-ai/openspec`)
9
-
10
- ## 安装
11
-
12
- ```bash
13
- npm install -g @nick848/fet
14
- ```
15
-
16
- ## 常用命令
17
-
18
- | 命令 | 说明 |
19
- |------|------|
20
- | `fet init` | 初始化 OpenSpec + FET 状态、扫描上下文、生成工具文件(`--tool cursor \| opencode \| both`) |
21
- | `fet apply` / `fet validate` | 实施循环与任务校验 |
22
- | `fet verify` | 终验(`--auto` / `--done` 等) |
23
- | `fet doctor` | 诊断配置与 openspec 解析路径 |
24
- | `fet update-context` | 刷新 `AGENTS.md` 与 `openspec/config.yaml` 中的 FET 区块 |
25
-
26
- 其余子命令多为对 `openspec` 的透传,详见 `fet --help`。
27
-
28
- ## 文档
29
-
30
- 仓库内 [DESIGN.md](./DESIGN.md) 为完整设计说明(威胁模型、状态机、与 OpenSpec 关系等)。
31
-
32
- ## 维护者:发布到 npm
33
-
34
- 1. 登录:`npm login`(首次)
35
- 2. 确认版本号:编辑 `package.json` 的 `version`(语义化版本)
36
- 3. 本地校验:`npm run build && npm test`
37
- 4. 干跑包内容:`npm pack --dry-run`
38
- 5. 发布(作用域包已设 `publishConfig.access: public`):`npm publish`
39
-
40
- `prepublishOnly` 会在发布前自动执行 `npm run build && npm test`。
41
-
42
- ## 开源协议
43
-
44
- MIT,见 [LICENSE](./LICENSE)。
1
+ # FET
2
+
3
+ FET is a frontend workflow orchestration CLI built around OpenSpec. It does not generate business code itself. Instead, it proxies OpenSpec commands, maintains local workflow state, generates auditable context files, and helps AI coding tools read the right project context.
4
+
5
+ ## Status
6
+
7
+ This package is currently `0.3.0-dev`: a development build aimed at stabilizing the MVP before a public stable release. The supported surface includes:
8
+
9
+ - `fet init`
10
+ - `fet update-context`
11
+ - `fet doctor`
12
+ - OpenSpec proxy commands such as `fet propose`, `fet apply`, `fet sync`, `fet archive`
13
+ - manual verification with `fet verify` and `fet verify --done`
14
+ - Cursor project files generation and doctor checks
15
+ - scanner support for package manager conflicts, TypeScript, basic workspaces, and common frontend frameworks
16
+
17
+ `fet verify --auto` currently generates and optionally records an approved execution plan only. It does not run project scripts yet.
18
+
19
+ Not stable yet:
20
+
21
+ - Real OpenSpec compatibility is still limited to the currently tested command lifecycle.
22
+ - Cursor integration writes project files and includes best-effort rule/skill guidance, but users should confirm their Cursor version recognizes the generated format.
23
+ - CI configuration is included for Windows/macOS/Linux and Node 18/20/22; it still needs to run in a hosted repository before stable release.
24
+
25
+ ## Requirements
26
+
27
+ - Node.js 18 or newer
28
+ - OpenSpec CLI available on `PATH`
29
+
30
+ Install OpenSpec if needed:
31
+
32
+ ```sh
33
+ npm install -g @fission-ai/openspec
34
+ ```
35
+
36
+ ## Installation
37
+
38
+ ```sh
39
+ npm install -g @nick848/fet
40
+ ```
41
+
42
+ For local development:
43
+
44
+ ```sh
45
+ npm install
46
+ npm run build
47
+ node dist/cli/index.js --help
48
+ ```
49
+
50
+ ## Quick Start
51
+
52
+ In a project that should use OpenSpec:
53
+
54
+ ```sh
55
+ fet init
56
+ fet doctor
57
+ ```
58
+
59
+ Then follow your OpenSpec workflow:
60
+
61
+ ```sh
62
+ fet propose
63
+ fet apply
64
+ fet verify
65
+ fet verify --done
66
+ fet sync
67
+ fet archive
68
+ ```
69
+
70
+ ## Generated Files
71
+
72
+ FET may create or update:
73
+
74
+ - `AGENTS.md`
75
+ - `openspec/config.yaml` under the `fet:` namespace
76
+ - `openspec/fet-state.json`
77
+ - `openspec/changes/<change-id>/fet-state.json`
78
+ - `openspec/changes/<change-id>/.fet/verify-instructions.md`
79
+ - `.cursor/skills/fet-*/SKILL.md`
80
+ - `.cursor/rules/fet-context.mdc`
81
+
82
+ FET only owns marked managed regions. User content outside managed regions should be preserved.
83
+
84
+ During `fet init`, FET also adds a managed block to `.gitignore` for local workflow state such as `openspec/fet-state.json`, lock files, and generated verify instructions.
85
+
86
+ ## Safety Model
87
+
88
+ FET is a local workflow helper. It is not a sandbox, CI gate, or cryptographic audit system. Direct `openspec` calls can bypass FET workflow gates. Teams that require enforcement should repeat validation in CI and branch protection rules.
89
+
90
+ ## Development
91
+
92
+ ```sh
93
+ npm run typecheck
94
+ npm run test
95
+ npm run build
96
+ npm run release:check
97
+ ```
98
+
99
+ ## License
100
+
101
+ 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"]}