abelworkflow 0.9.2 → 1.0.0-rc.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.
Files changed (126) hide show
  1. package/README.md +55 -182
  2. package/bin/abelworkflow.mjs +5 -3
  3. package/lib/cli/args.mjs +76 -0
  4. package/lib/cli/main.mjs +387 -0
  5. package/lib/cli/prompts.mjs +119 -0
  6. package/lib/config/dotenv.mjs +102 -0
  7. package/lib/config/jsonc.mjs +80 -0
  8. package/lib/config/store.mjs +310 -0
  9. package/lib/config/toml.mjs +638 -0
  10. package/lib/installer/assets.mjs +326 -0
  11. package/lib/installer/install.mjs +167 -0
  12. package/lib/installer/links.mjs +427 -0
  13. package/lib/installer/render.mjs +46 -0
  14. package/lib/installer/state.mjs +182 -0
  15. package/lib/paths.mjs +99 -0
  16. package/lib/providers/claude.mjs +388 -0
  17. package/lib/providers/codex.mjs +433 -0
  18. package/lib/providers/pi.mjs +362 -0
  19. package/lib/providers/skills.mjs +164 -0
  20. package/lib/templates/codex/agents/default.toml +7 -0
  21. package/lib/templates/codex/agents/explorer.toml +7 -0
  22. package/lib/templates/codex/agents/planner.toml +7 -0
  23. package/lib/templates/codex/agents/reviewer.toml +7 -0
  24. package/lib/templates/codex/agents/worker.toml +7 -0
  25. package/lib/templates/codex/config-base.toml +11 -3
  26. package/{AGENTS.md → lib/templates/workflow/AGENTS.md} +8 -3
  27. package/{commands → lib/templates/workflow/commands}/abel-diagnose.md +5 -5
  28. package/{commands → lib/templates/workflow/commands}/abel-implement.md +3 -8
  29. package/{commands → lib/templates/workflow/commands}/abel-init.md +1 -1
  30. package/{commands → lib/templates/workflow/commands}/abel-plan.md +1 -7
  31. package/{commands → lib/templates/workflow/commands}/abel-research.md +1 -1
  32. package/{.gitignore → lib/templates/workflow/gitignore.template} +0 -2
  33. package/lib/tools/cli-installer.mjs +277 -0
  34. package/package.json +43 -10
  35. package/skills/context7-auto-research/SKILL.md +5 -5
  36. package/skills/context7-auto-research/{context7-api.js → context7-api.cjs} +5 -8
  37. package/skills/dev-browser/SKILL.md +53 -33
  38. package/skills/dev-browser/dist/scripts/start.d.ts +2 -0
  39. package/skills/dev-browser/dist/scripts/start.d.ts.map +1 -0
  40. package/skills/dev-browser/dist/scripts/start.js +118 -0
  41. package/skills/dev-browser/dist/scripts/start.js.map +1 -0
  42. package/skills/dev-browser/dist/src/client.d.ts +93 -0
  43. package/skills/dev-browser/dist/src/client.d.ts.map +1 -0
  44. package/skills/dev-browser/dist/src/client.js +310 -0
  45. package/skills/dev-browser/dist/src/client.js.map +1 -0
  46. package/skills/dev-browser/dist/src/entrypoint.d.ts +29 -0
  47. package/skills/dev-browser/dist/src/entrypoint.d.ts.map +1 -0
  48. package/skills/dev-browser/dist/src/entrypoint.js +106 -0
  49. package/skills/dev-browser/dist/src/entrypoint.js.map +1 -0
  50. package/skills/dev-browser/dist/src/index.d.ts +4 -0
  51. package/skills/dev-browser/dist/src/index.d.ts.map +1 -0
  52. package/skills/dev-browser/dist/src/index.js +2 -0
  53. package/skills/dev-browser/dist/src/index.js.map +1 -0
  54. package/skills/dev-browser/dist/src/page-api.d.ts +25 -0
  55. package/skills/dev-browser/dist/src/page-api.d.ts.map +1 -0
  56. package/skills/dev-browser/dist/src/page-api.js +104 -0
  57. package/skills/dev-browser/dist/src/page-api.js.map +1 -0
  58. package/skills/dev-browser/dist/src/relay.d.ts +27 -0
  59. package/skills/dev-browser/dist/src/relay.d.ts.map +1 -0
  60. package/skills/dev-browser/dist/src/relay.js +521 -0
  61. package/skills/dev-browser/dist/src/relay.js.map +1 -0
  62. package/skills/dev-browser/dist/src/runtime.d.ts +45 -0
  63. package/skills/dev-browser/dist/src/runtime.d.ts.map +1 -0
  64. package/skills/dev-browser/dist/src/runtime.js +54 -0
  65. package/skills/dev-browser/dist/src/runtime.js.map +1 -0
  66. package/skills/dev-browser/dist/src/snapshot/browser-script.d.ts +23 -0
  67. package/skills/dev-browser/dist/src/snapshot/browser-script.d.ts.map +1 -0
  68. package/skills/dev-browser/{src/snapshot/browser-script.ts → dist/src/snapshot/browser-script.js} +21 -30
  69. package/skills/dev-browser/dist/src/snapshot/browser-script.js.map +1 -0
  70. package/skills/dev-browser/dist/src/snapshot/index.d.ts +14 -0
  71. package/skills/dev-browser/dist/src/snapshot/index.d.ts.map +1 -0
  72. package/skills/dev-browser/{src/snapshot/index.ts → dist/src/snapshot/index.js} +2 -2
  73. package/skills/dev-browser/dist/src/snapshot/index.js.map +1 -0
  74. package/skills/dev-browser/dist/src/snapshot/inject.d.ts +13 -0
  75. package/skills/dev-browser/dist/src/snapshot/inject.d.ts.map +1 -0
  76. package/skills/dev-browser/{src/snapshot/inject.ts → dist/src/snapshot/inject.js} +2 -2
  77. package/skills/dev-browser/dist/src/snapshot/inject.js.map +1 -0
  78. package/skills/dev-browser/dist/src/standalone.d.ts +32 -0
  79. package/skills/dev-browser/dist/src/standalone.d.ts.map +1 -0
  80. package/skills/dev-browser/dist/src/standalone.js +174 -0
  81. package/skills/dev-browser/dist/src/standalone.js.map +1 -0
  82. package/skills/dev-browser/dist/src/startup.d.ts +55 -0
  83. package/skills/dev-browser/dist/src/startup.d.ts.map +1 -0
  84. package/skills/dev-browser/dist/src/startup.js +81 -0
  85. package/skills/dev-browser/dist/src/startup.js.map +1 -0
  86. package/skills/dev-browser/dist/src/target-registry.d.ts +29 -0
  87. package/skills/dev-browser/dist/src/target-registry.d.ts.map +1 -0
  88. package/skills/dev-browser/dist/src/target-registry.js +135 -0
  89. package/skills/dev-browser/dist/src/target-registry.js.map +1 -0
  90. package/skills/dev-browser/dist/src/types.d.ts +27 -0
  91. package/skills/dev-browser/dist/src/types.d.ts.map +1 -0
  92. package/skills/dev-browser/dist/src/types.js +2 -0
  93. package/skills/dev-browser/dist/src/types.js.map +1 -0
  94. package/skills/dev-browser/package-lock.json +67 -1510
  95. package/skills/dev-browser/package.json +18 -14
  96. package/skills/dev-browser/references/scraping.md +94 -105
  97. package/skills/grok-search/defaults.json +3 -0
  98. package/skills/grok-search/gitignore.template +4 -0
  99. package/skills/grok-search/scripts/_dotenv.py +5 -1
  100. package/skills/grok-search/scripts/groksearch_cli.py +15 -33
  101. package/skills/prompt-enhancer/TEMPLATE.md +0 -4
  102. package/skills/prompt-enhancer/requirements.txt +0 -1
  103. package/skills/prompt-enhancer/scripts/_dotenv.py +5 -1
  104. package/skills/prompt-enhancer/scripts/enhance.py +4 -51
  105. package/skills/prompt-enhancer/scripts/prompt_enhancer_entry.py +1 -16
  106. package/.skill-lock.json +0 -29
  107. package/lib/cli/logic.mjs +0 -213
  108. package/lib/cli.mjs +0 -3016
  109. package/skills/confidence-check/SKILL.md +0 -34
  110. package/skills/confidence-check/confidence.ts +0 -276
  111. package/skills/dev-browser/bun.lock +0 -460
  112. package/skills/dev-browser/scripts/start.ts +0 -280
  113. package/skills/dev-browser/src/client.ts +0 -474
  114. package/skills/dev-browser/src/entrypoint.ts +0 -157
  115. package/skills/dev-browser/src/index.ts +0 -289
  116. package/skills/dev-browser/src/relay.ts +0 -731
  117. package/skills/dev-browser/src/runtime.test.ts +0 -60
  118. package/skills/dev-browser/src/runtime.ts +0 -171
  119. package/skills/dev-browser/src/startup.test.ts +0 -95
  120. package/skills/dev-browser/src/startup.ts +0 -153
  121. package/skills/dev-browser/src/types.ts +0 -35
  122. package/skills/dev-browser/tsconfig.json +0 -36
  123. package/skills/dev-browser/vitest.config.ts +0 -12
  124. package/skills/sequential-think/SKILL.md +0 -198
  125. package/skills/sequential-think/scripts/.env.example +0 -5
  126. package/skills/sequential-think/scripts/sequential_think_cli.py +0 -253
@@ -12,7 +12,7 @@ argument-hint: <problem-description>
12
12
  **Guardrails**
13
13
  - Root cause first; never fix symptoms only
14
14
  - Verify root cause hypothesis with evidence before fix
15
- - Confidence gate: ≥90% before applying fixes
15
+ - Only fixes with evidence-verified root cause may be applied
16
16
  - Every fix must include a regression test
17
17
  - Keep changes minimal and scoped
18
18
  - If verification fails, rollback and iterate
@@ -32,9 +32,9 @@ argument-hint: <problem-description>
32
32
  **Steps**
33
33
  1. Parse input, infer scope, and split into issue list (single or multiple).
34
34
  2. For each issue in parallel: collect logs/traces and locate code via the configured codebase retrieval policy.
35
- 3. For each issue in parallel: perform root cause analysis; use `/sequential-think` for multi-component chains.
35
+ 3. For each issue in parallel: perform root cause analysis; for multi-component chains, decompose the failure chain step by step with evidence.
36
36
  4. Build dependency/conflict graph across issues and compute safe fix order.
37
- 5. Run `/confidence-check` per issue; only issues with score ≥90% can move to fix generation.
37
+ 5. Verify each issue's root cause against collected evidence; only issues with a verified root cause can move to fix generation.
38
38
  6. Spawn one subagent per READY issue to generate `unified diff patch` and regression test with minimal scoped context.
39
39
  7. Main agent reviews/merges subagent outputs by dependency order and outputs one batch report with all issue statuses and patches.
40
40
  8. Apply merged patches strictly sequentially by dependency order.
@@ -42,13 +42,13 @@ argument-hint: <problem-description>
42
42
 
43
43
  **Batch Output**
44
44
  ```text
45
- ## /oc:diagnose Batch Report
45
+ ## /abel-diagnose Batch Report
46
46
 
47
47
  ### Batch Summary
48
48
  Total: {n} | ReadyToFix: {n_ready} | Blocked: {n_blocked}
49
49
 
50
50
  ### Issue Results
51
- - [{id}] Classification: {category}/{severity} | Root Cause: {summary} | Confidence: {score} | Subagent: {agent_id|none} | Status: {READY|BLOCKED}
51
+ - [{id}] Classification: {category}/{severity} | Root Cause: {summary} | Verified: {yes|no} | Subagent: {agent_id|none} | Status: {READY|BLOCKED}
52
52
 
53
53
  ### Patch Queue (dependency order)
54
54
  1. [{id}] [subagent:{agent_id}] {file_list}
@@ -44,9 +44,6 @@ argument-hint: [change_name]
44
44
 
45
45
  ```
46
46
  ┌─────────────────────────────────────────────────────────┐
47
- │ Step 0: Pre-Check │
48
- │ └─ /confidence-check → require ≥90% to proceed │
49
- ├─────────────────────────────────────────────────────────┤
50
47
  │ Step 1: 🔴 Red Phase - Generate Failing Test │
51
48
  │ ├─ Analyze task → determine test type │
52
49
  │ │ ├─ Backend → pytest/jest │
@@ -101,17 +98,15 @@ argument-hint: [change_name]
101
98
  13. Run all tests → MUST ALL PASS.
102
99
  14. If any test fails → analyze root cause, fix or rollback.
103
100
  15. Perform final side-effect review.
104
- 16. Run `openspec archive <change_name>` or `/opsx:archive`.
101
+ 16. Report that the change is ready for archive; do not archive until the user explicitly authorizes `/opsx:archive`.
105
102
 
106
103
  **TDD Output Format**
107
104
 
108
105
  ```
109
- ## /oc:implementation (TDD Mode)
106
+ ## /abel-implement (TDD Mode)
110
107
 
111
108
  ### Task 1/N: {task_description}
112
109
 
113
- 📋 Confidence Check: {score}% {status}
114
-
115
110
  🔴 Red Phase
116
111
  ├─ Generated: tests/{test_file}
117
112
  ├─ Run: {test_command}
@@ -150,7 +145,7 @@ Frontend Review
150
145
  ✓ Reviews complete
151
146
  ├─ Applied: {refactoring_summary}
152
147
  ├─ Tests: {count} passed ✓
153
- └─ Ready for archive
148
+ └─ Ready for user-authorized archive
154
149
 
155
150
  ✓ Implementation complete
156
151
  ```
@@ -18,7 +18,7 @@ tags: [openspec, init, setup]
18
18
  4. Run `openspec init` (or `openspec update` for existing projects).
19
19
  5. {{AUGMENT_CONTEXT_ENGINE_VALIDATION}}
20
20
  6. Verify required skills:
21
- - Skills: `/dev-browser` `/sequential-think` `/context7-auto-research` `/grok-search` `/confidence-check`
21
+ - Skills: `/dev-browser` `/context7-auto-research` `/grok-search`
22
22
  7. Output summary with ✓/✗:
23
23
  - OpenSpec installation
24
24
  - Project initialization
@@ -25,14 +25,8 @@ argument-hint: [change_name]
25
25
  - Check `openspec status --change <change_name>` for artifact completion
26
26
  - Use `openspec instructions specs --change <change_name>` for specs guidance
27
27
 
28
- 3. **Implementation Analysis**: Invoke skills to perform systematic analysis to derive a plan:
28
+ 3. **Implementation Analysis**: Perform systematic analysis to derive a plan. If the proposal has 3+ interconnected requirements, first break it down into components, identify dependencies, evaluate architectural trade-offs, and surface potential conflicts. Then invoke `/context7-auto-research` to validate framework/library choices:
29
29
  ```
30
- # First, invoke /sequential-think skill for systematic analysis if proposal has 3+ interconnected requirements
31
-
32
- /sequential-think: "Analyze change <change_name> systematically: Break down into components, identify dependencies, evaluate architectural trade-offs, and surface potential conflicts."
33
-
34
- # Then invoke /context7-auto-research skill to validate framework/library choices
35
-
36
30
  /context7-auto-research: "For each technology mentioned in change <change_name>, retrieve official documentation patterns and best practices."
37
31
  ```
38
32
  Produce a consolidated, constraint-complete plan and list any missing constraints as questions to the user.
@@ -77,7 +77,7 @@ All explore subagents MUST return valid JSON using this schema:
77
77
  - Clear scope
78
78
  - self-contained with independent output
79
79
  - Required output template (from Phase 4)
80
- - If boundary involves 3+ interconnected components, invoke `/sequential-think` skill
80
+ - If boundary involves 3+ interconnected components, require explicit step-by-step dependency analysis
81
81
  - Clear success criteria: complete analysis of assigned boundary
82
82
 
83
83
 
@@ -14,5 +14,3 @@ skills/dev-browser/.cache/
14
14
  .claude/
15
15
  .codex/
16
16
  *pycache*/
17
- openspec/
18
- package-lock.json
@@ -0,0 +1,277 @@
1
+ import { spawn, spawnSync } from "node:child_process";
2
+ import { join } from "node:path";
3
+ import * as p from "@clack/prompts";
4
+ import c from "picocolors";
5
+ import { defaultPaths, getPlatform, isWindows } from "../paths.mjs";
6
+
7
+ const { homeDir: home } = defaultPaths;
8
+
9
+ function getRunCommandSpawnOptions(platform = getPlatform()) {
10
+ return { stdio: "inherit", shell: platform === "win32" };
11
+ }
12
+
13
+ function getCommandPath(command) {
14
+ const checker = isWindows() ? "where" : "which";
15
+ const result = spawnSync(checker, [command], { encoding: "utf8" });
16
+ if (result.status !== 0) {
17
+ return undefined;
18
+ }
19
+ return result.stdout
20
+ .split(/\r?\n/u)
21
+ .map((line) => line.trim())
22
+ .find(Boolean);
23
+ }
24
+
25
+ function commandExists(command) {
26
+ return Boolean(getCommandPath(command));
27
+ }
28
+
29
+ function readCommandOutput(command, args) {
30
+ const result = spawnSync(command, args, {
31
+ encoding: "utf8",
32
+ shell: isWindows(),
33
+ stdio: ["ignore", "pipe", "ignore"]
34
+ });
35
+ if (result.status !== 0) {
36
+ return undefined;
37
+ }
38
+ const outputValue = result.stdout.trim();
39
+ return outputValue || undefined;
40
+ }
41
+
42
+ async function runCommand(command, args) {
43
+ await new Promise((resolvePromise, rejectPromise) => {
44
+ const child = spawn(command, args, getRunCommandSpawnOptions(getPlatform()));
45
+ child.on("error", rejectPromise);
46
+ child.on("close", (code) => {
47
+ if (code === 0) {
48
+ resolvePromise();
49
+ return;
50
+ }
51
+ rejectPromise(new Error(`${command} ${args.join(" ")} exited with code ${code}`));
52
+ });
53
+ });
54
+ }
55
+
56
+ function normalizeInstallPath(value) {
57
+ if (!value) {
58
+ return "";
59
+ }
60
+ return value.replace(/\\/gu, "/").replace(/\/+$/u, "").toLowerCase();
61
+ }
62
+
63
+ function installPathIsWithin(path, parentPath) {
64
+ const normalizedPath = normalizeInstallPath(path);
65
+ const normalizedParent = normalizeInstallPath(parentPath);
66
+ return Boolean(normalizedPath && normalizedParent)
67
+ && (normalizedPath === normalizedParent || normalizedPath.startsWith(`${normalizedParent}/`));
68
+ }
69
+
70
+ function getNpmGlobalBinDirs(npmGlobalPrefix, platform = getPlatform()) {
71
+ if (!npmGlobalPrefix) {
72
+ return [];
73
+ }
74
+ return platform === "win32" ? [npmGlobalPrefix] : [join(npmGlobalPrefix, "bin")];
75
+ }
76
+
77
+ function inferPackageManagerFromCommandPath(commandPath, {
78
+ bunGlobalBinDir,
79
+ npmGlobalPrefix,
80
+ platform = getPlatform()
81
+ } = {}) {
82
+ if (installPathIsWithin(commandPath, bunGlobalBinDir)) {
83
+ return "bun";
84
+ }
85
+ if (getNpmGlobalBinDirs(npmGlobalPrefix, platform)
86
+ .some((binDir) => installPathIsWithin(commandPath, binDir))) {
87
+ return "npm";
88
+ }
89
+ return null;
90
+ }
91
+
92
+ function chooseCliInstallPackageManager({
93
+ commandPath,
94
+ availablePackageManagers = [],
95
+ bunGlobalBinDir,
96
+ npmGlobalPrefix,
97
+ platform = getPlatform(),
98
+ nodeAvailable = true,
99
+ supportedPackageManagers = ["bun", "npm"]
100
+ } = {}) {
101
+ const supported = new Set(supportedPackageManagers);
102
+ const available = new Set(availablePackageManagers.filter((packageManager) => {
103
+ if (!supported.has(packageManager)) {
104
+ return false;
105
+ }
106
+ return packageManager !== "bun" || nodeAvailable;
107
+ }));
108
+ const bunBlockedByMissingNode = !nodeAvailable
109
+ && supported.has("bun")
110
+ && availablePackageManagers.includes("bun");
111
+ const existingPackageManager = inferPackageManagerFromCommandPath(commandPath, {
112
+ bunGlobalBinDir,
113
+ npmGlobalPrefix,
114
+ platform
115
+ });
116
+
117
+ if (existingPackageManager && available.has(existingPackageManager)) {
118
+ return { packageManager: existingPackageManager, source: "existing" };
119
+ }
120
+ for (const packageManager of ["bun", "npm"]) {
121
+ if (available.has(packageManager)) {
122
+ return { packageManager, source: "available" };
123
+ }
124
+ }
125
+ return {
126
+ packageManager: null,
127
+ source: bunBlockedByMissingNode ? "missing-node" : (availablePackageManagers.length > 0 ? "unsupported" : "missing")
128
+ };
129
+ }
130
+
131
+ function buildCliToolInstallCommand(packageManager, { packageName, skipScripts = false }) {
132
+ if (packageManager === "npm") {
133
+ return {
134
+ command: "npm",
135
+ args: [
136
+ "install",
137
+ "-g",
138
+ ...(skipScripts ? ["--ignore-scripts"] : []),
139
+ packageName,
140
+ "--force"
141
+ ]
142
+ };
143
+ }
144
+ if (packageManager === "bun") {
145
+ return {
146
+ command: "bun",
147
+ args: [
148
+ "install",
149
+ "-g",
150
+ ...(skipScripts ? ["--ignore-scripts"] : []),
151
+ packageName
152
+ ]
153
+ };
154
+ }
155
+ throw new Error(`Unsupported package manager: ${packageManager}`);
156
+ }
157
+
158
+ function getPackageManagerInstallHelp(platform = getPlatform()) {
159
+ const platformLabel = {
160
+ darwin: "macOS",
161
+ win32: "Windows",
162
+ linux: "Linux"
163
+ }[platform] || platform;
164
+ return {
165
+ platformLabel,
166
+ mainlandUrl: "https://npmmirror.com/mirrors/node/",
167
+ officialUrl: "https://nodejs.org/en/download/"
168
+ };
169
+ }
170
+
171
+ function getAvailablePackageManagers() {
172
+ return ["bun", "npm"].filter((packageManager) => commandExists(packageManager));
173
+ }
174
+
175
+ function getBunGlobalBinDir(availablePackageManagers = getAvailablePackageManagers()) {
176
+ if (!availablePackageManagers.includes("bun")) {
177
+ return undefined;
178
+ }
179
+ return readCommandOutput("bun", ["pm", "bin", "-g"]) || join(home, ".bun", "bin");
180
+ }
181
+
182
+ function getNpmGlobalPrefix(availablePackageManagers = getAvailablePackageManagers()) {
183
+ if (!availablePackageManagers.includes("npm")) {
184
+ return undefined;
185
+ }
186
+ return readCommandOutput("npm", ["prefix", "-g"]);
187
+ }
188
+
189
+ async function installCliTool(tool, { confirmOrCancel }) {
190
+ const toolConfig = {
191
+ claude: {
192
+ label: "Claude Code",
193
+ command: "claude",
194
+ packageName: "@anthropic-ai/claude-code",
195
+ supportedPackageManagers: ["npm"],
196
+ installRequirement: "Claude Code 安装需要执行 postinstall;Bun 默认会阻止该脚本,因此需使用 npm。"
197
+ },
198
+ codex: {
199
+ label: "Codex",
200
+ command: "codex",
201
+ packageName: "@openai/codex"
202
+ },
203
+ pi: {
204
+ label: "Pi",
205
+ command: "pi",
206
+ packageName: "@earendil-works/pi-coding-agent",
207
+ skipScripts: true
208
+ }
209
+ }[tool];
210
+
211
+ if (!toolConfig) {
212
+ throw new Error(`Unsupported tool: ${tool}`);
213
+ }
214
+
215
+ const commandPath = getCommandPath(toolConfig.command);
216
+ const installed = Boolean(commandPath);
217
+ const availablePackageManagers = getAvailablePackageManagers();
218
+ const packageManagerChoice = chooseCliInstallPackageManager({
219
+ commandPath,
220
+ availablePackageManagers,
221
+ bunGlobalBinDir: getBunGlobalBinDir(availablePackageManagers),
222
+ npmGlobalPrefix: getNpmGlobalPrefix(availablePackageManagers),
223
+ platform: getPlatform(),
224
+ nodeAvailable: commandExists("node"),
225
+ supportedPackageManagers: toolConfig.supportedPackageManagers
226
+ });
227
+
228
+ if (!packageManagerChoice.packageManager) {
229
+ const help = getPackageManagerInstallHelp();
230
+ p.log.warn(`未检测到可用于安装 ${toolConfig.label} 的包管理器。`);
231
+ if (packageManagerChoice.source === "missing-node") {
232
+ p.log.message(`${toolConfig.label} 是 Node CLI;使用 Bun 安装前也需要先安装 Node.js。`);
233
+ }
234
+ if (toolConfig.installRequirement) {
235
+ p.log.message(toolConfig.installRequirement);
236
+ }
237
+ p.log.message(`${help.platformLabel} 可先安装 Node.js/npm,再重新运行安装。`);
238
+ p.log.message(`中国大陆镜像: ${help.mainlandUrl}`);
239
+ p.log.message(`官方下载页: ${help.officialUrl}`);
240
+ return;
241
+ }
242
+
243
+ if (installed) {
244
+ const managerMessage = packageManagerChoice.source === "existing"
245
+ ? `检测到原安装方式为 ${packageManagerChoice.packageManager}`
246
+ : `未识别原安装方式,将使用 ${packageManagerChoice.packageManager}`;
247
+ const shouldUpdate = await confirmOrCancel({
248
+ message: `${toolConfig.label} 已检测到(${managerMessage}),是否继续安装/更新?`,
249
+ initialValue: false
250
+ });
251
+ if (!shouldUpdate) {
252
+ p.log.message(`跳过 ${toolConfig.label} 安装。`);
253
+ return;
254
+ }
255
+ }
256
+
257
+ const installCommand = buildCliToolInstallCommand(packageManagerChoice.packageManager, toolConfig);
258
+ const s = p.spinner();
259
+ s.start(`正在使用 ${packageManagerChoice.packageManager} 安装 ${toolConfig.label}...`);
260
+ try {
261
+ await runCommand(installCommand.command, installCommand.args);
262
+ s.stop(`${toolConfig.label} 安装完成`);
263
+ } catch (e) {
264
+ s.cancel(c.red(`${toolConfig.label} 安装失败: ${e.message}`));
265
+ throw e;
266
+ }
267
+ }
268
+
269
+ export {
270
+ buildCliToolInstallCommand,
271
+ chooseCliInstallPackageManager,
272
+ getPackageManagerInstallHelp,
273
+ getRunCommandSpawnOptions,
274
+ inferPackageManagerFromCommandPath,
275
+ installCliTool,
276
+ commandExists
277
+ };
package/package.json CHANGED
@@ -1,11 +1,20 @@
1
1
  {
2
2
  "name": "abelworkflow",
3
- "version": "0.9.2",
3
+ "version": "1.0.0-rc.1",
4
4
  "description": "Install AbelWorkflow into ~/.agents and create Claude/Codex symlinks.",
5
5
  "type": "module",
6
6
  "scripts": {
7
- "test": "node --test test/runtime-doc-contracts.test.mjs test/cli-contracts.test.mjs test/codex-config.test.mjs test/pi-auth-precedence.test.mjs test/pi-auth-write.test.mjs test/pi-provider-tls.test.mjs",
8
- "test:contracts": "node --test test/runtime-doc-contracts.test.mjs test/cli-contracts.test.mjs"
7
+ "test": "npm run test:node",
8
+ "test:node": "node --test test/*.test.mjs",
9
+ "test:python": "python -m unittest discover -s test",
10
+ "test:dev-browser": "npm test --prefix skills/dev-browser",
11
+ "test:contracts": "node --test test/runtime-doc-contracts.test.mjs test/cli-args.test.mjs",
12
+ "typecheck": "npm run typecheck --prefix skills/dev-browser",
13
+ "build": "npm run build --prefix skills/dev-browser",
14
+ "prepack": "npm run build",
15
+ "check:docs": "node --test test/docs-contracts.test.mjs test/runtime-doc-contracts.test.mjs",
16
+ "check:package": "node --test test/package-contents.test.mjs",
17
+ "check": "npm run build && npm run test:node && npm run test:python && npm run test:dev-browser && npm run typecheck && npm run check:docs && npm run check:package"
9
18
  },
10
19
  "bin": {
11
20
  "abelworkflow": "bin/abelworkflow.mjs"
@@ -13,21 +22,45 @@
13
22
  "files": [
14
23
  "bin",
15
24
  "lib",
16
- "AGENTS.md",
17
25
  "README.md",
18
- "commands",
19
- "skills",
20
26
  "extensions",
21
- ".skill-lock.json",
22
- ".gitignore"
27
+ "skills/context7-auto-research/.env.example",
28
+ "skills/context7-auto-research/SKILL.md",
29
+ "skills/context7-auto-research/context7-api.cjs",
30
+ "skills/dev-browser/SKILL.md",
31
+ "skills/dev-browser/dist",
32
+ "skills/dev-browser/package-lock.json",
33
+ "skills/dev-browser/package.json",
34
+ "skills/dev-browser/references",
35
+ "skills/git-commit/SKILL.md",
36
+ "skills/grok-search/.env.example",
37
+ "skills/grok-search/SKILL.md",
38
+ "skills/grok-search/defaults.json",
39
+ "skills/grok-search/gitignore.template",
40
+ "skills/grok-search/requirements.txt",
41
+ "skills/grok-search/scripts/_dotenv.py",
42
+ "skills/grok-search/scripts/groksearch_cli.py",
43
+ "skills/grok-search/scripts/groksearch_entry.py",
44
+ "skills/prompt-enhancer/.env.example",
45
+ "skills/prompt-enhancer/ADVANCED.md",
46
+ "skills/prompt-enhancer/SKILL.md",
47
+ "skills/prompt-enhancer/TEMPLATE.md",
48
+ "skills/prompt-enhancer/requirements.txt",
49
+ "skills/prompt-enhancer/scripts/_dotenv.py",
50
+ "skills/prompt-enhancer/scripts/enhance.py",
51
+ "skills/prompt-enhancer/scripts/prompt_enhancer_entry.py",
52
+ "skills/time/SKILL.md",
53
+ "skills/time/scripts/time_cli.py"
23
54
  ],
24
55
  "engines": {
25
- "node": ">=18"
56
+ "node": ">=22"
26
57
  },
58
+ "packageManager": "npm@10.9.2",
27
59
  "license": "MIT",
28
60
  "dependencies": {
29
61
  "@clack/prompts": "^1.2.0",
30
62
  "picocolors": "^1.1.1",
31
- "proper-lockfile": "4.1.2"
63
+ "proper-lockfile": "4.1.2",
64
+ "smol-toml": "1.7.0"
32
65
  }
33
66
  }
@@ -30,13 +30,13 @@ Common cues:
30
30
 
31
31
  ## Workflow
32
32
 
33
- 1. Run from this skill directory and use `./context7-api.js`.
33
+ 1. Run from this skill directory and use `./context7-api.cjs`.
34
34
  2. Search with the full user query:
35
35
 
36
36
  ```bash
37
37
  cd skills/context7-auto-research
38
- node ./context7-api.js --help
39
- node ./context7-api.js search '<library-name>' - <<'__C7_QUERY__'
38
+ node ./context7-api.cjs --help
39
+ node ./context7-api.cjs search '<library-name>' - <<'__C7_QUERY__'
40
40
  <full user query>
41
41
  __C7_QUERY__
42
42
  ```
@@ -50,7 +50,7 @@ __C7_QUERY__
50
50
  4. Fetch focused documentation:
51
51
 
52
52
  ```bash
53
- node ./context7-api.js context '<library-id>' - <<'__C7_QUERY__'
53
+ node ./context7-api.cjs context '<library-id>' - <<'__C7_QUERY__'
54
54
  <feature name or focused question>
55
55
  __C7_QUERY__
56
56
  ```
@@ -72,7 +72,7 @@ __C7_QUERY__
72
72
 
73
73
  - Preferred: `CONTEXT7_API_KEY` environment variable
74
74
  - Also supported: `<skill-dir>/.env`
75
- - CLI help: `node ./context7-api.js --help`
75
+ - CLI help: `node ./context7-api.cjs --help`
76
76
 
77
77
  ## Notes
78
78
 
@@ -44,12 +44,12 @@ function printErrorResult(commandName, error, exitCode = 1) {
44
44
 
45
45
  function printUsage() {
46
46
  console.error(`Usage:
47
- context7-api.js search <libraryName> <query|->
48
- context7-api.js context <libraryId> <query|->
47
+ context7-api.cjs search <libraryName> <query|->
48
+ context7-api.cjs context <libraryId> <query|->
49
49
 
50
50
  Examples:
51
- node context7-api.js search react "useEffect cleanup"
52
- node context7-api.js context /facebook/react -
51
+ node context7-api.cjs search react "useEffect cleanup"
52
+ node context7-api.cjs context /facebook/react -
53
53
 
54
54
  Config:
55
55
  CONTEXT7_API_KEY from environment, or .env in the script directory`);
@@ -83,10 +83,7 @@ function loadApiKey() {
83
83
  if (key !== 'CONTEXT7_API_KEY') {
84
84
  continue;
85
85
  }
86
- const value = trimmed.slice(separatorIndex + 1).trim();
87
- if (value) {
88
- return value.replace(/^["']|["']$/g, '');
89
- }
86
+ return trimmed.slice(separatorIndex + 1).trim().replace(/^["']|["']$/g, '');
90
87
  }
91
88
 
92
89
  return null;