@rse/ase 1.0.7 → 2.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 (279) hide show
  1. package/dst/ase-agent-definition-api.d.ts +184 -0
  2. package/dst/ase-agent-definition-api.js +6 -0
  3. package/dst/ase-agent-definition-builtin/condenser.js +42 -0
  4. package/dst/ase-agent-definition-builtin/editor.js +45 -0
  5. package/dst/ase-agent-definition-builtin/estimator.js +98 -0
  6. package/dst/ase-agent-definition-builtin/implementer.js +121 -0
  7. package/dst/ase-agent-definition-builtin/integrator.js +56 -0
  8. package/dst/ase-agent-definition-builtin/qualifier.js +61 -0
  9. package/dst/ase-agent-definition-builtin/rebooter.js +41 -0
  10. package/dst/ase-agent-definition-builtin/researcher.js +77 -0
  11. package/dst/ase-agent-definition-core.js +827 -0
  12. package/dst/ase-agent-fleet.js +772 -0
  13. package/dst/ase-agent-process.js +232 -0
  14. package/dst/ase-agent-relay-client.js +509 -0
  15. package/dst/ase-agent-relay-core.js +213 -0
  16. package/dst/ase-agent-relay-server-bind.js +242 -0
  17. package/dst/ase-agent-relay-server-cli.js +50 -0
  18. package/dst/ase-agent-runtime-claim.js +189 -0
  19. package/dst/ase-agent-runtime-engine.js +1100 -0
  20. package/dst/ase-agent-runtime-exec.js +275 -0
  21. package/dst/ase-agent-runtime-phase.js +581 -0
  22. package/dst/ase-agent-runtime-request.js +272 -0
  23. package/dst/ase-agent-runtime-tool.js +207 -0
  24. package/dst/ase-agent-runtime.js +1316 -0
  25. package/dst/ase-agent.js +65 -0
  26. package/dst/ase-artifact.js +6 -5
  27. package/dst/ase-config-core.js +465 -0
  28. package/dst/ase-config-schema.js +351 -0
  29. package/dst/ase-config-scope.js +172 -0
  30. package/dst/ase-config.js +25 -585
  31. package/dst/ase-hook.js +228 -111
  32. package/dst/ase-lib-daemon-cli.js +130 -0
  33. package/dst/ase-lib-hash.js +20 -0
  34. package/dst/{ase-log.js → ase-lib-log.js} +40 -7
  35. package/dst/ase-lib-server-bind.js +115 -0
  36. package/dst/ase-lib-server-cli.js +474 -0
  37. package/dst/{ase-table.js → ase-lib-table.js} +1 -1
  38. package/dst/{ase-version.js → ase-lib-version.js} +3 -0
  39. package/dst/ase-man.js +96 -0
  40. package/dst/ase-mcp.js +166 -13
  41. package/dst/{ase-getopt.js → ase-service-getopt.js} +82 -80
  42. package/dst/{ase-markdown.js → ase-service-markdown.js} +18 -11
  43. package/dst/ase-service-otel.js +1246 -0
  44. package/dst/{ase-skills.js → ase-service-skills.js} +29 -64
  45. package/dst/ase-service-state.js +101 -0
  46. package/dst/ase-service.js +251 -76
  47. package/dst/ase-setup-common.js +141 -0
  48. package/dst/ase-setup-mcp.js +359 -0
  49. package/dst/ase-setup-settings.js +837 -0
  50. package/dst/ase-setup.js +113 -869
  51. package/dst/ase-spec.js +31 -19
  52. package/dst/ase-statusline.js +108 -43
  53. package/dst/ase-task-board-core.js +739 -0
  54. package/dst/ase-task-board-filter.js +127 -0
  55. package/dst/ase-task-board-flow.js +237 -0
  56. package/dst/ase-task-board-graph.js +497 -0
  57. package/dst/ase-task-board-stats.js +263 -0
  58. package/dst/ase-task-board-tui-control.js +775 -0
  59. package/dst/ase-task-board-tui-model.js +1008 -0
  60. package/dst/ase-task-board-tui-popup.js +626 -0
  61. package/dst/ase-task-board-tui-style.js +106 -0
  62. package/dst/ase-task-board-tui-view.js +847 -0
  63. package/dst/ase-task-board-tui.js +189 -0
  64. package/dst/ase-task-board-web-client.css +1 -0
  65. package/dst/ase-task-board-web-client.html +20 -0
  66. package/dst/ase-task-board-web-client.js +81 -0
  67. package/dst/ase-task-board-web-server.js +823 -0
  68. package/dst/ase-task-board.js +134 -0
  69. package/dst/ase-task-format.js +757 -0
  70. package/dst/ase-task-request.js +208 -0
  71. package/dst/ase-task-store-client.js +495 -0
  72. package/dst/ase-task-store-core.js +804 -0
  73. package/dst/ase-task-store-issues.js +237 -0
  74. package/dst/ase-task-store-plugin-api.js +6 -0
  75. package/dst/ase-task-store-plugin-ase.js +484 -0
  76. package/dst/ase-task-store-plugin-delegate.js +137 -0
  77. package/dst/ase-task-store-plugin-gitea.js +666 -0
  78. package/dst/ase-task-store-plugin-github.js +696 -0
  79. package/dst/ase-task-store-plugin-gitlab.js +668 -0
  80. package/dst/ase-task-store-server-bind.js +538 -0
  81. package/dst/ase-task-store-server-cli.js +154 -0
  82. package/dst/ase-task.js +1335 -357
  83. package/dst/{ase-compat.js → ase-util-compat.js} +2 -2
  84. package/dst/{ase-diagram.js → ase-util-diagram.js} +107 -32
  85. package/dst/{ase-meta.js → ase-util-meta.js} +2 -2
  86. package/dst/{ase-metric.js → ase-util-metric.js} +2 -2
  87. package/dst/{ase-mint.js → ase-util-mint.js} +19 -12
  88. package/dst/{ase-worktree.js → ase-util-worktree.js} +30 -19
  89. package/dst/ase-util.js +20 -0
  90. package/dst/ase.js +108 -32
  91. package/dst/man/ase-agent-adhoc.1 +515 -0
  92. package/dst/man/ase-agent-condenser.1 +193 -0
  93. package/dst/man/ase-agent-editor.1 +212 -0
  94. package/dst/man/ase-agent-estimator.1 +214 -0
  95. package/dst/man/ase-agent-fleet.1 +185 -0
  96. package/dst/man/ase-agent-implementer.1 +233 -0
  97. package/dst/man/ase-agent-integrator.1 +213 -0
  98. package/dst/man/ase-agent-qualifier.1 +214 -0
  99. package/dst/man/ase-agent-rebooter.1 +193 -0
  100. package/dst/man/ase-agent-relay.1 +128 -0
  101. package/dst/man/ase-agent-researcher.1 +217 -0
  102. package/dst/man/ase-agent.1 +264 -0
  103. package/dst/man/ase-artifact-list.1 +38 -0
  104. package/dst/man/ase-artifact-name.1 +39 -0
  105. package/dst/man/ase-artifact.1 +56 -0
  106. package/dst/man/ase-config-delete.1 +45 -0
  107. package/dst/man/ase-config-edit.1 +48 -0
  108. package/dst/man/ase-config-get.1 +46 -0
  109. package/dst/man/ase-config-init.1 +60 -0
  110. package/dst/man/ase-config-list.1 +42 -0
  111. package/dst/man/ase-config-set.1 +52 -0
  112. package/dst/man/ase-config.1 +225 -0
  113. package/dst/man/ase-hook-permission-request.1 +36 -0
  114. package/dst/man/ase-hook-pre-tool-use.1 +59 -0
  115. package/dst/man/ase-hook-session-end.1 +47 -0
  116. package/dst/man/ase-hook-session-persona.1 +37 -0
  117. package/dst/man/ase-hook-session-start.1 +81 -0
  118. package/dst/man/ase-hook-stop.1 +34 -0
  119. package/dst/man/ase-hook-user-prompt-submit.1 +34 -0
  120. package/dst/man/ase-hook.1 +51 -0
  121. package/dst/man/ase-man.1 +67 -0
  122. package/dst/man/ase-mcp.1 +61 -0
  123. package/dst/man/ase-service-log.1 +43 -0
  124. package/dst/man/ase-service-send.1 +47 -0
  125. package/dst/man/ase-service-start.1 +54 -0
  126. package/dst/man/ase-service-status.1 +46 -0
  127. package/dst/man/ase-service-stop.1 +37 -0
  128. package/dst/man/ase-service.1 +85 -0
  129. package/dst/man/ase-setup-disable.1 +44 -0
  130. package/dst/man/ase-setup-enable.1 +45 -0
  131. package/dst/man/ase-setup-install.1 +73 -0
  132. package/dst/man/ase-setup-mcp.1 +124 -0
  133. package/dst/man/ase-setup-status.1 +60 -0
  134. package/dst/man/ase-setup-statusline.1 +92 -0
  135. package/dst/man/ase-setup-telemetry.1 +92 -0
  136. package/dst/man/ase-setup-uninstall.1 +59 -0
  137. package/dst/man/ase-setup-update.1 +64 -0
  138. package/dst/man/ase-setup.1 +93 -0
  139. package/dst/man/ase-spec-export.1 +62 -0
  140. package/dst/man/ase-spec-lint.1 +40 -0
  141. package/dst/man/ase-spec-preview.1 +40 -0
  142. package/dst/man/ase-spec.1 +46 -0
  143. package/dst/man/ase-statusline.1 +189 -0
  144. package/dst/man/ase-task-assign.1 +71 -0
  145. package/dst/man/ase-task-board.1 +384 -0
  146. package/dst/man/ase-task-delete.1 +35 -0
  147. package/dst/man/ase-task-edit.1 +46 -0
  148. package/dst/man/ase-task-idscheme.1 +65 -0
  149. package/dst/man/ase-task-lifecycle.1 +57 -0
  150. package/dst/man/ase-task-list.1 +47 -0
  151. package/dst/man/ase-task-load.1 +36 -0
  152. package/dst/man/ase-task-newid.1 +61 -0
  153. package/dst/man/ase-task-purge.1 +37 -0
  154. package/dst/man/ase-task-rename.1 +44 -0
  155. package/dst/man/ase-task-request.1 +61 -0
  156. package/dst/man/ase-task-save.1 +48 -0
  157. package/dst/man/ase-task-status.1 +55 -0
  158. package/dst/man/ase-task-store.1 +194 -0
  159. package/dst/man/ase-task-view.1 +40 -0
  160. package/dst/man/ase-task.1 +160 -0
  161. package/dst/man/ase-util-compat.1 +25 -0
  162. package/dst/man/ase-util-diagram.1 +76 -0
  163. package/dst/man/ase-util-meta.1 +45 -0
  164. package/dst/man/ase-util-metric.1 +54 -0
  165. package/dst/man/ase-util-mint.1 +59 -0
  166. package/dst/man/ase-util-worktree.1 +72 -0
  167. package/dst/man/ase-util.1 +50 -0
  168. package/dst/man/ase.1 +124 -0
  169. package/package.json +79 -21
  170. package/plugin/.claude-plugin/plugin.json +1 -1
  171. package/plugin/.codex-plugin/plugin.json +1 -1
  172. package/plugin/.github/plugin/plugin.json +1 -1
  173. package/plugin/agents/ase-meta-diagram.md +12 -8
  174. package/plugin/agents/ase-repo-review.md +322 -0
  175. package/plugin/hooks/hooks-codex.json +5 -0
  176. package/plugin/hooks/hooks-copilot.json +5 -0
  177. package/plugin/hooks/hooks.json +8 -0
  178. package/plugin/meta/ase-common-approach.md +117 -0
  179. package/plugin/meta/ase-common-changeset.md +256 -0
  180. package/plugin/meta/ase-common-code.md +10 -173
  181. package/plugin/meta/ase-common-grill.md +317 -0
  182. package/plugin/meta/ase-common-resolve.md +305 -0
  183. package/plugin/meta/ase-common-task.md +83 -4
  184. package/plugin/meta/ase-constitution.md +0 -2
  185. package/plugin/meta/ase-format-specbook.md +208 -25
  186. package/plugin/meta/ase-format-specbook.yaml +242 -851
  187. package/plugin/meta/ase-format-task.md +669 -125
  188. package/plugin/meta/ase-persona.md +3 -4
  189. package/plugin/meta/ase-skill.md +9 -0
  190. package/plugin/mods/ase-mods.ts +409 -0
  191. package/plugin/mods/claude-code.d.ts +13417 -0
  192. package/plugin/skills/ase-arch-analyze/SKILL.md +1 -1
  193. package/plugin/skills/ase-arch-analyze/help.md +2 -2
  194. package/plugin/skills/ase-code-analyze/SKILL.md +59 -8
  195. package/plugin/skills/ase-code-analyze/help.md +29 -4
  196. package/plugin/skills/ase-code-edit/SKILL.md +107 -181
  197. package/plugin/skills/ase-code-edit/help.md +118 -31
  198. package/plugin/skills/ase-code-lint/SKILL.md +64 -13
  199. package/plugin/skills/ase-code-lint/help.md +32 -2
  200. package/plugin/skills/ase-docs-proofread/SKILL.md +4 -4
  201. package/plugin/skills/ase-docs-proofread/help.md +1 -1
  202. package/plugin/skills/ase-docs-refine/SKILL.md +4 -4
  203. package/plugin/skills/ase-docs-shorten/SKILL.md +4 -4
  204. package/plugin/skills/ase-help-intent/data.md +2164 -1087
  205. package/plugin/skills/ase-help-intent/help.md +1 -1
  206. package/plugin/skills/ase-help-skill/catalog.md +12 -9
  207. package/plugin/skills/ase-meta-brainstorm/SKILL.md +1 -1
  208. package/plugin/skills/ase-meta-config/SKILL.md +3 -4
  209. package/plugin/skills/ase-meta-config/help.md +31 -10
  210. package/plugin/skills/ase-meta-mint/SKILL.md +5 -5
  211. package/plugin/skills/ase-meta-mint/help.md +10 -5
  212. package/plugin/skills/ase-meta-why/help.md +1 -1
  213. package/plugin/skills/ase-meta-workflow/SKILL.md +7 -7
  214. package/plugin/skills/ase-meta-workflow/help.md +4 -4
  215. package/plugin/skills/ase-meta-workflow/sample.md +3 -3
  216. package/plugin/skills/ase-meta-workflow/workflow.txt +22 -18
  217. package/plugin/skills/{ase-meta-changelog → ase-repo-changelog}/SKILL.md +4 -3
  218. package/plugin/skills/{ase-meta-changelog → ase-repo-changelog}/help.md +5 -5
  219. package/plugin/skills/{ase-meta-commit → ase-repo-commit}/SKILL.md +6 -6
  220. package/plugin/skills/{ase-meta-commit → ase-repo-commit}/help.md +5 -5
  221. package/plugin/skills/{ase-meta-diff → ase-repo-diff}/SKILL.md +6 -6
  222. package/plugin/skills/{ase-meta-diff → ase-repo-diff}/help.md +8 -8
  223. package/plugin/skills/{ase-code-dissect → ase-repo-dissect}/SKILL.md +19 -19
  224. package/plugin/skills/{ase-code-dissect → ase-repo-dissect}/help.md +10 -12
  225. package/plugin/skills/ase-repo-merge/SKILL.md +346 -0
  226. package/plugin/skills/ase-repo-merge/help.md +107 -0
  227. package/plugin/skills/ase-repo-resolve/SKILL.md +158 -0
  228. package/plugin/skills/ase-repo-resolve/help.md +102 -0
  229. package/plugin/skills/ase-repo-review/SKILL.md +406 -0
  230. package/plugin/skills/ase-repo-review/help.md +181 -0
  231. package/plugin/skills/ase-spec-edit/SKILL.md +117 -183
  232. package/plugin/skills/ase-spec-edit/help.md +107 -26
  233. package/plugin/skills/ase-sync-reconcile/help.md +1 -1
  234. package/plugin/skills/ase-task-assign/SKILL.md +111 -0
  235. package/plugin/skills/ase-task-assign/help.md +119 -0
  236. package/plugin/skills/ase-task-condense/SKILL.md +21 -21
  237. package/plugin/skills/ase-task-condense/help.md +12 -10
  238. package/plugin/skills/ase-task-delete/SKILL.md +1 -1
  239. package/plugin/skills/ase-task-dissect/SKILL.md +71 -48
  240. package/plugin/skills/ase-task-dissect/help.md +10 -9
  241. package/plugin/skills/ase-task-edit/SKILL.md +379 -94
  242. package/plugin/skills/ase-task-edit/help.md +95 -22
  243. package/plugin/skills/ase-task-estimate/SKILL.md +492 -0
  244. package/plugin/skills/ase-task-estimate/help.md +158 -0
  245. package/plugin/skills/ase-task-grill/SKILL.md +246 -138
  246. package/plugin/skills/ase-task-grill/help.md +129 -26
  247. package/plugin/skills/ase-task-id/SKILL.md +8 -1
  248. package/plugin/skills/ase-task-id/help.md +6 -3
  249. package/plugin/skills/ase-task-implement/SKILL.md +535 -145
  250. package/plugin/skills/ase-task-implement/help.md +138 -47
  251. package/plugin/skills/ase-task-integrate/SKILL.md +549 -0
  252. package/plugin/skills/ase-task-integrate/help.md +187 -0
  253. package/plugin/skills/ase-task-list/SKILL.md +55 -23
  254. package/plugin/skills/ase-task-list/help.md +45 -21
  255. package/plugin/skills/ase-task-reboot/SKILL.md +84 -43
  256. package/plugin/skills/ase-task-reboot/help.md +28 -8
  257. package/plugin/skills/ase-task-rename/SKILL.md +10 -2
  258. package/plugin/skills/ase-task-research/SKILL.md +386 -0
  259. package/plugin/skills/ase-task-research/help.md +102 -0
  260. package/plugin/skills/ase-task-status/SKILL.md +137 -0
  261. package/plugin/skills/ase-task-status/help.md +80 -0
  262. package/plugin/skills/ase-task-view/SKILL.md +49 -24
  263. package/plugin/skills/ase-task-view/help.md +19 -9
  264. package/plugin/agents/ase-meta-review.md +0 -187
  265. package/plugin/skills/ase-code-craft/SKILL.md +0 -264
  266. package/plugin/skills/ase-code-craft/help.md +0 -122
  267. package/plugin/skills/ase-code-refactor/SKILL.md +0 -232
  268. package/plugin/skills/ase-code-refactor/help.md +0 -109
  269. package/plugin/skills/ase-code-resolve/SKILL.md +0 -289
  270. package/plugin/skills/ase-code-resolve/help.md +0 -116
  271. package/plugin/skills/ase-meta-review/SKILL.md +0 -210
  272. package/plugin/skills/ase-meta-review/help.md +0 -96
  273. package/plugin/skills/ase-task-preflight/SKILL.md +0 -166
  274. package/plugin/skills/ase-task-preflight/help.md +0 -82
  275. /package/dst/{ase-ignore.js → ase-lib-ignore.js} +0 -0
  276. /package/dst/{ase-stdio.js → ase-lib-stdio.js} +0 -0
  277. /package/dst/{ase-kv.js → ase-service-kv.js} +0 -0
  278. /package/dst/{ase-sleep.js → ase-service-sleep.js} +0 -0
  279. /package/dst/{ase-timestamp.js → ase-service-timestamp.js} +0 -0
@@ -0,0 +1,359 @@
1
+ /*
2
+ ** Agentic Software Engineering (ASE)
3
+ ** Copyright (c) 2025-2026 Dr. Ralf S. Engelschall <rse@engelschall.com>
4
+ ** Licensed under Apache 2.0 <https://spdx.org/licenses/Apache-2.0>
5
+ */
6
+ import * as dotenvx from "@dotenvx/dotenvx";
7
+ import chalk from "chalk";
8
+ import { execa } from "execa";
9
+ import { renderTable } from "./ase-lib-table.js";
10
+ import { toolSpecs, requireClaudeScope } from "./ase-setup-common.js";
11
+ /* MCP server handling of "ase setup mcp" */
12
+ export class SetupMcp {
13
+ log;
14
+ runner;
15
+ constructor(log, runner) {
16
+ this.log = log;
17
+ this.runner = runner;
18
+ }
19
+ /* handler for "ase setup mcp list" */
20
+ async doMcpList() {
21
+ const rows = [];
22
+ for (const handle of this.mcpServers)
23
+ rows.push([
24
+ chalk.bold(handle.id),
25
+ handle.name,
26
+ handle.version ?? "(unknown)",
27
+ handle.server,
28
+ handle.env.join(", "),
29
+ handle.skills.join(", ")
30
+ ]);
31
+ process.stdout.write(renderTable(["ID", "NAME", "VERS", "MCP", "KEY", "SKILLS"], rows));
32
+ return 0;
33
+ }
34
+ /* handler for "ase setup mcp activate|deactivate [<servers>]" */
35
+ async doMcp(action, tool, servers, scope) {
36
+ requireClaudeScope(tool, scope);
37
+ await this.runner.ensureTool(toolSpecs[tool].cli);
38
+ /* source .env files into the environment so the per-server
39
+ API keys (ASE_MCP_KEY_<XXX>) can live in a .env file instead
40
+ of the exported interactive shell environment */
41
+ dotenvx.config({ quiet: true, ignore: ["MISSING_ENV_FILE"] });
42
+ /* resolve the comma-separated list of server ids, with an empty
43
+ list or the literal "all" expanding to every registered server
44
+ id; track whether the ids were explicitly given on the CLI */
45
+ const known = this.mcpServers.map((handle) => handle.id);
46
+ const explicit = servers.trim() !== "" && servers.trim() !== "all";
47
+ const ids = explicit ?
48
+ servers.split(",").map((s) => s.trim()).filter((s) => s !== "") : known;
49
+ for (const id of ids)
50
+ if (this.mcpServers.find((handle) => handle.id === id) === undefined)
51
+ throw new Error(`unknown MCP server "${id}" ` +
52
+ `(known: ${known.join(", ")})`);
53
+ /* dispatch each selected server to its dedicated handler */
54
+ for (const id of ids) {
55
+ /* find handle */
56
+ const handle = this.mcpServers.find((handle) => handle.id === id);
57
+ /* determine information and action */
58
+ let envKey = "";
59
+ let envVal = "";
60
+ if (action === "activate") {
61
+ /* on activation, require at least one of the per-server API
62
+ key environment variables (ASE_MCP_KEY_<XXX>) to
63
+ be set; skip the server when its id was only
64
+ implicitly selected (empty list or "all"), but fail
65
+ hard when it was given explicitly on the CLI */
66
+ envKey = handle.env.find((name) => (process.env[`ASE_MCP_KEY_${name}`] ?? "") !== "") ?? "";
67
+ if (envKey === "") {
68
+ const vars = handle.env.map((name) => `ASE_MCP_KEY_${name}`).join(", ");
69
+ if (explicit)
70
+ throw new Error(`none of ${vars} set: ` +
71
+ `cannot activate MCP server "${handle.server}"`);
72
+ this.log.write("info", `setup: mcp: activate: [${id}]: none of ${vars} set: ` +
73
+ `skipping MCP server "${handle.server}" (${handle.name})`);
74
+ continue;
75
+ }
76
+ envVal = process.env[`ASE_MCP_KEY_${envKey}`] ?? "";
77
+ }
78
+ /* probe whether the MCP server is currently registered with the tool */
79
+ const installed = await this.mcpInstalled(tool, handle.server);
80
+ if (action === "activate") {
81
+ /* on activation, remove a stale registration first so the
82
+ handler can re-create it cleanly */
83
+ if (installed) {
84
+ this.log.write("info", `setup: mcp: activate: [${id}]: MCP server "${handle.server}" ` +
85
+ "already registered: removing stale registration first");
86
+ await this.mcpRemove(tool, handle.server, scope);
87
+ }
88
+ }
89
+ else if (!installed) {
90
+ /* on deactivation, skip the removal of an absent server */
91
+ this.log.write("info", `setup: mcp: deactivate: [${id}]: MCP server "${handle.server}" ` +
92
+ "not registered: skipping removal");
93
+ continue;
94
+ }
95
+ /* call the handler */
96
+ this.log.write("info", `setup: mcp: ${action}: [${id}]: MCP server "${handle.server}" ` +
97
+ `(name: ${handle.name}${handle.version ? (", version: " + handle.version) : ""})`);
98
+ await handle.handler(handle, tool, scope, action, envKey, envVal);
99
+ }
100
+ return 0;
101
+ }
102
+ /* probe whether an MCP server is currently registered with the tool
103
+ by inspecting the exit code of "<cli> mcp get <name>" */
104
+ async mcpInstalled(tool, name) {
105
+ const result = await execa(toolSpecs[tool].cli, ["mcp", "get", name], { stdio: "ignore", reject: false });
106
+ return result.exitCode === 0;
107
+ }
108
+ /* probe the registration scope of an MCP server by scraping the
109
+ human-readable output of "<cli> mcp get <name>"; returns "undefined"
110
+ for a server which is not registered with the tool at all */
111
+ async mcpScope(tool, name) {
112
+ const result = await execa(toolSpecs[tool].cli, ["mcp", "get", name], { stdio: "pipe", reject: false });
113
+ if (result.exitCode !== 0)
114
+ return undefined;
115
+ /* the Anthropic Claude Code CLI reports "Scope: <scope> config (...)",
116
+ the GitHub Copilot CLI reports "Source: <scope>", and the
117
+ OpenAI Codex CLI reports no scope information at all */
118
+ const m = (result.stdout ?? "").match(/^\s*(?:Scope|Source):\s*(\S+)/m);
119
+ return m !== null ? m[1].toLowerCase() : "(n/a)";
120
+ }
121
+ /* register an MCP server with the tool, supporting both the "stdio"
122
+ (a local subprocess command) and "http" (a remote URL, optionally
123
+ with HTTP headers) transports; the per-tool command line differs
124
+ between Anthropic Claude Code CLI, GitHub Copilot CLI, and OpenAI Codex CLI */
125
+ async mcpAdd(tool, name, env, transport, scope) {
126
+ const args = ["mcp", "add"];
127
+ if (tool === "claude") {
128
+ /* always pass the scope explicitly, as the Anthropic Claude Code CLI
129
+ defaults to the "local" scope (and not the "user" scope) for "mcp add" */
130
+ args.push("--scope", scope);
131
+ args.push("--transport", transport.type);
132
+ if (transport.type === "stdio") {
133
+ for (const [key, val] of Object.entries(env))
134
+ args.push("-e", `${key}=${val}`);
135
+ args.push("--", name, ...transport.command);
136
+ }
137
+ else {
138
+ for (const [key, val] of Object.entries(transport.headers ?? {}))
139
+ args.push("--header", `${key}: ${val}`);
140
+ args.push(name, transport.url);
141
+ }
142
+ }
143
+ else {
144
+ /* the GitHub Copilot CLI and OpenAI Codex CLI both take the
145
+ server name as a positional argument and imply the stdio
146
+ transport when the command is provided after "--"; for "http"
147
+ servers the GitHub Copilot CLI needs an explicit
148
+ "--transport" flag and takes the URL positionally, while the
149
+ OpenAI Codex CLI takes it via the "--url" option */
150
+ if (transport.type === "stdio") {
151
+ args.push(name);
152
+ for (const [key, val] of Object.entries(env))
153
+ args.push("--env", `${key}=${val}`);
154
+ args.push("--", ...transport.command);
155
+ }
156
+ else {
157
+ if (tool === "copilot")
158
+ args.push("--transport", "http");
159
+ for (const [key, val] of Object.entries(transport.headers ?? {}))
160
+ args.push("--header", `${key}: ${val}`);
161
+ if (tool === "copilot")
162
+ args.push(name, transport.url);
163
+ else
164
+ args.push(name, "--url", transport.url);
165
+ }
166
+ }
167
+ await this.runner.run(toolSpecs[tool].cli, args);
168
+ }
169
+ /* unregister an MCP server from the tool; the per-tool command line
170
+ differs between Anthropic Claude Code CLI, GitHub Copilot CLI, and OpenAI Codex CLI */
171
+ async mcpRemove(tool, name, scope) {
172
+ /* always pass the scope explicitly, as the Anthropic Claude Code CLI
173
+ does not default to the "user" scope for its "mcp" commands */
174
+ const scopeArgs = tool === "claude" ? ["--scope", scope] : [];
175
+ const args = ["mcp", "remove", ...scopeArgs, name];
176
+ await this.runner.run(toolSpecs[tool].cli, args, { ignoreError: `MCP server "${name}" not registered` });
177
+ }
178
+ /* build a chat-model MCP handler from the per-model direct and
179
+ OPENROUTER url/api/model triples, factoring out the shared
180
+ mcp-to-openai stdio scaffold common to all chat-model servers */
181
+ chatMcpHandler(direct, router) {
182
+ return async (spec, tool, scope, action, envKey, envVal) => {
183
+ if (action === "activate")
184
+ await this.mcpAdd(tool, spec.server, { OPENAI_KEY: envVal }, {
185
+ type: "stdio", command: [
186
+ "npx", "-y", "mcp-to-openai",
187
+ "--service", spec.name,
188
+ "--mcp-tool", "query",
189
+ ...(envKey === "OPENROUTER" ? [
190
+ "--openai-url", "https://openrouter.ai/api/v1",
191
+ "--openai-api", "completion",
192
+ "--openai-model", router.model
193
+ ] : [
194
+ "--openai-url", direct.url,
195
+ "--openai-api", direct.api,
196
+ "--openai-model", direct.model
197
+ ])
198
+ ]
199
+ }, scope);
200
+ else
201
+ await this.mcpRemove(tool, spec.server, scope);
202
+ };
203
+ }
204
+ /* build a chat-model MCP handler which bridges to a locally
205
+ installed AI agent harness CLI via the mcp-to-harness stdio
206
+ scaffold; the API key environment variable carries no key at all,
207
+ but instead the harness model identifier, with the special value
208
+ "default" selecting the default model of the harness */
209
+ harnessMcpHandler(harness) {
210
+ return async (spec, tool, scope, action, _envKey, envVal) => {
211
+ if (action === "activate")
212
+ await this.mcpAdd(tool, spec.server, {}, {
213
+ type: "stdio", command: [
214
+ "npx", "-y", "mcp-to-harness",
215
+ "--service", spec.name,
216
+ "--mcp-tool", "query",
217
+ "--harness", harness,
218
+ ...(envVal !== "default" ? [
219
+ "--harness-model", envVal
220
+ ] : [])
221
+ ]
222
+ }, scope);
223
+ else
224
+ await this.mcpRemove(tool, spec.server, scope);
225
+ };
226
+ }
227
+ /* registry of pre-defined MCP servers: maps each server id onto its
228
+ dedicated handler which performs the activate/deactivate operation */
229
+ mcpServers = [
230
+ {
231
+ id: "openai-chatgpt",
232
+ name: "OpenAI ChatGPT",
233
+ version: "5.5",
234
+ env: ["OPENAI_CHATGPT", "OPENROUTER"],
235
+ server: "chat-openai-chatgpt",
236
+ skills: ["ase-meta-chat", "ase-meta-quorum"],
237
+ handler: this.chatMcpHandler({ url: "https://api.openai.com/v1", api: "responses", model: "gpt-5.5" }, { model: "openai/gpt-5.5" })
238
+ },
239
+ {
240
+ id: "google-gemini",
241
+ name: "Google Gemini",
242
+ version: "3.5",
243
+ env: ["GOOGLE_GEMINI", "OPENROUTER"],
244
+ server: "chat-google-gemini",
245
+ skills: ["ase-meta-chat", "ase-meta-quorum"],
246
+ handler: this.chatMcpHandler({ url: "https://generativelanguage.googleapis.com/v1beta/openai/", api: "completion", model: "gemini-3.5-flash" }, { model: "google/gemini-3.5-flash" })
247
+ },
248
+ {
249
+ id: "deepseek",
250
+ name: "DeepSeek",
251
+ version: "4.0",
252
+ env: ["DEEPSEEK", "OPENROUTER"],
253
+ server: "chat-deepseek",
254
+ skills: ["ase-meta-chat", "ase-meta-quorum"],
255
+ handler: this.chatMcpHandler({ url: "https://api.deepseek.com/v1", api: "completion", model: "deepseek-v4-flash" }, { model: "deepseek/deepseek-v4-flash" })
256
+ },
257
+ {
258
+ id: "xai-grok",
259
+ name: "xAI Grok",
260
+ version: "4.3",
261
+ env: ["XAI_GROK", "OPENROUTER"],
262
+ server: "chat-xai-grok",
263
+ skills: ["ase-meta-chat", "ase-meta-quorum"],
264
+ handler: this.chatMcpHandler({ url: "https://api.x.ai/v1", api: "completion", model: "grok-4.3" }, { model: "x-ai/grok-4.3" })
265
+ },
266
+ {
267
+ id: "alibaba-qwen",
268
+ name: "Alibaba Qwen",
269
+ version: "3.7",
270
+ env: ["ALIBABA_QWEN", "OPENROUTER"],
271
+ server: "chat-alibaba-qwen",
272
+ skills: ["ase-meta-chat", "ase-meta-quorum"],
273
+ handler: this.chatMcpHandler({ url: "https://dashscope.aliyuncs.com/compatible-mode/v1", api: "completion", model: "qwen3.7-max" }, { model: "qwen/qwen3.7-max" })
274
+ },
275
+ {
276
+ id: "zai-glm",
277
+ name: "Z.AI GLM",
278
+ version: "5.1",
279
+ env: ["ZAI_GLM", "OPENROUTER"],
280
+ server: "chat-zai-glm",
281
+ skills: ["ase-meta-chat", "ase-meta-quorum"],
282
+ handler: this.chatMcpHandler({ url: "https://api.z.ai/api/paas/v4/", api: "completion", model: "glm-5.1" }, { model: "z-ai/glm-5.1" })
283
+ },
284
+ {
285
+ id: "anthropic-claude",
286
+ name: "Anthropic Claude",
287
+ version: "latest",
288
+ env: ["ANTHROPIC_CLAUDE"],
289
+ server: "chat-anthropic-claude",
290
+ skills: ["ase-meta-chat", "ase-meta-quorum"],
291
+ handler: this.harnessMcpHandler("claude")
292
+ },
293
+ {
294
+ id: "openai-codex",
295
+ name: "OpenAI Codex",
296
+ version: "latest",
297
+ env: ["OPENAI_CODEX"],
298
+ server: "chat-openai-codex",
299
+ skills: ["ase-meta-chat", "ase-meta-quorum"],
300
+ handler: this.harnessMcpHandler("codex")
301
+ },
302
+ {
303
+ id: "github-copilot",
304
+ name: "GitHub Copilot",
305
+ version: "latest",
306
+ env: ["GITHUB_COPILOT"],
307
+ server: "chat-github-copilot",
308
+ skills: ["ase-meta-chat", "ase-meta-quorum"],
309
+ handler: this.harnessMcpHandler("copilot")
310
+ },
311
+ {
312
+ id: "brave",
313
+ name: "Brave",
314
+ version: "latest",
315
+ env: ["BRAVE"],
316
+ server: "search-brave",
317
+ skills: ["ase-meta-search", "ase-meta-evaluate", "ase-arch-discover"],
318
+ handler: async (spec, tool, scope, action, _envKey, envVal) => {
319
+ if (action === "activate")
320
+ await this.mcpAdd(tool, spec.server, {
321
+ "BRAVE_API_KEY": envVal,
322
+ "BRAVE_MCP_ENABLED_TOOLS": "brave_web_search"
323
+ }, { type: "stdio", command: ["npx", "-y", "@brave/brave-search-mcp-server"] }, scope);
324
+ else
325
+ await this.mcpRemove(tool, spec.server, scope);
326
+ }
327
+ },
328
+ {
329
+ id: "perplexity",
330
+ name: "Perplexity",
331
+ version: "latest",
332
+ env: ["PERPLEXITY"],
333
+ server: "search-perplexity",
334
+ skills: ["ase-meta-search", "ase-meta-evaluate", "ase-arch-discover"],
335
+ handler: async (spec, tool, scope, action, _envKey, envVal) => {
336
+ if (action === "activate")
337
+ await this.mcpAdd(tool, spec.server, {
338
+ "PERPLEXITY_API_KEY": envVal
339
+ }, { type: "stdio", command: ["npx", "-y", "@perplexity-ai/mcp-server"] }, scope);
340
+ else
341
+ await this.mcpRemove(tool, spec.server, scope);
342
+ }
343
+ },
344
+ {
345
+ id: "exa",
346
+ name: "Exa",
347
+ version: "latest",
348
+ env: ["EXA"],
349
+ server: "search-exa",
350
+ skills: ["ase-meta-search", "ase-meta-evaluate", "ase-arch-discover"],
351
+ handler: async (spec, tool, scope, action, _envKey, envVal) => {
352
+ if (action === "activate")
353
+ await this.mcpAdd(tool, spec.server, {}, { type: "http", url: `https://mcp.exa.ai/mcp?exaApiKey=${encodeURIComponent(envVal)}` }, scope);
354
+ else
355
+ await this.mcpRemove(tool, spec.server, scope);
356
+ }
357
+ }
358
+ ];
359
+ }