@rse/ase 1.0.6 → 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.
- package/dst/ase-agent-definition-api.d.ts +184 -0
- package/dst/ase-agent-definition-api.js +6 -0
- package/dst/ase-agent-definition-builtin/condenser.js +42 -0
- package/dst/ase-agent-definition-builtin/editor.js +45 -0
- package/dst/ase-agent-definition-builtin/estimator.js +98 -0
- package/dst/ase-agent-definition-builtin/implementer.js +121 -0
- package/dst/ase-agent-definition-builtin/integrator.js +56 -0
- package/dst/ase-agent-definition-builtin/qualifier.js +61 -0
- package/dst/ase-agent-definition-builtin/rebooter.js +41 -0
- package/dst/ase-agent-definition-builtin/researcher.js +77 -0
- package/dst/ase-agent-definition-core.js +827 -0
- package/dst/ase-agent-fleet.js +772 -0
- package/dst/ase-agent-process.js +232 -0
- package/dst/ase-agent-relay-client.js +509 -0
- package/dst/ase-agent-relay-core.js +213 -0
- package/dst/ase-agent-relay-server-bind.js +242 -0
- package/dst/ase-agent-relay-server-cli.js +50 -0
- package/dst/ase-agent-runtime-claim.js +189 -0
- package/dst/ase-agent-runtime-engine.js +1100 -0
- package/dst/ase-agent-runtime-exec.js +275 -0
- package/dst/ase-agent-runtime-phase.js +581 -0
- package/dst/ase-agent-runtime-request.js +272 -0
- package/dst/ase-agent-runtime-tool.js +207 -0
- package/dst/ase-agent-runtime.js +1316 -0
- package/dst/ase-agent.js +65 -0
- package/dst/ase-artifact.js +6 -5
- package/dst/ase-config-core.js +465 -0
- package/dst/ase-config-schema.js +351 -0
- package/dst/ase-config-scope.js +172 -0
- package/dst/ase-config.js +25 -585
- package/dst/ase-hook.js +230 -116
- package/dst/ase-lib-daemon-cli.js +130 -0
- package/dst/ase-lib-hash.js +20 -0
- package/dst/{ase-log.js → ase-lib-log.js} +40 -7
- package/dst/ase-lib-server-bind.js +115 -0
- package/dst/ase-lib-server-cli.js +474 -0
- package/dst/{ase-table.js → ase-lib-table.js} +1 -1
- package/dst/{ase-version.js → ase-lib-version.js} +3 -0
- package/dst/ase-man.js +96 -0
- package/dst/ase-mcp.js +166 -13
- package/dst/{ase-getopt.js → ase-service-getopt.js} +82 -80
- package/dst/{ase-markdown.js → ase-service-markdown.js} +18 -11
- package/dst/ase-service-otel.js +1246 -0
- package/dst/{ase-skills.js → ase-service-skills.js} +29 -64
- package/dst/ase-service-state.js +101 -0
- package/dst/ase-service.js +251 -76
- package/dst/ase-setup-common.js +141 -0
- package/dst/ase-setup-mcp.js +359 -0
- package/dst/ase-setup-settings.js +837 -0
- package/dst/ase-setup.js +113 -869
- package/dst/ase-spec.js +31 -19
- package/dst/ase-statusline.js +108 -43
- package/dst/ase-task-board-core.js +739 -0
- package/dst/ase-task-board-filter.js +127 -0
- package/dst/ase-task-board-flow.js +237 -0
- package/dst/ase-task-board-graph.js +497 -0
- package/dst/ase-task-board-stats.js +263 -0
- package/dst/ase-task-board-tui-control.js +775 -0
- package/dst/ase-task-board-tui-model.js +1008 -0
- package/dst/ase-task-board-tui-popup.js +626 -0
- package/dst/ase-task-board-tui-style.js +106 -0
- package/dst/ase-task-board-tui-view.js +847 -0
- package/dst/ase-task-board-tui.js +189 -0
- package/dst/ase-task-board-web-client.css +1 -0
- package/dst/ase-task-board-web-client.html +20 -0
- package/dst/ase-task-board-web-client.js +81 -0
- package/dst/ase-task-board-web-server.js +823 -0
- package/dst/ase-task-board.js +134 -0
- package/dst/ase-task-format.js +757 -0
- package/dst/ase-task-request.js +208 -0
- package/dst/ase-task-store-client.js +495 -0
- package/dst/ase-task-store-core.js +804 -0
- package/dst/ase-task-store-issues.js +237 -0
- package/dst/ase-task-store-plugin-api.js +6 -0
- package/dst/ase-task-store-plugin-ase.js +484 -0
- package/dst/ase-task-store-plugin-delegate.js +137 -0
- package/dst/ase-task-store-plugin-gitea.js +666 -0
- package/dst/ase-task-store-plugin-github.js +696 -0
- package/dst/ase-task-store-plugin-gitlab.js +668 -0
- package/dst/ase-task-store-server-bind.js +538 -0
- package/dst/ase-task-store-server-cli.js +154 -0
- package/dst/ase-task.js +1335 -357
- package/dst/{ase-compat.js → ase-util-compat.js} +2 -2
- package/dst/{ase-diagram.js → ase-util-diagram.js} +107 -32
- package/dst/{ase-meta.js → ase-util-meta.js} +2 -2
- package/dst/{ase-metric.js → ase-util-metric.js} +2 -2
- package/dst/{ase-mint.js → ase-util-mint.js} +19 -12
- package/dst/{ase-worktree.js → ase-util-worktree.js} +30 -19
- package/dst/ase-util.js +20 -0
- package/dst/ase.js +108 -32
- package/dst/man/ase-agent-adhoc.1 +515 -0
- package/dst/man/ase-agent-condenser.1 +193 -0
- package/dst/man/ase-agent-editor.1 +212 -0
- package/dst/man/ase-agent-estimator.1 +214 -0
- package/dst/man/ase-agent-fleet.1 +185 -0
- package/dst/man/ase-agent-implementer.1 +233 -0
- package/dst/man/ase-agent-integrator.1 +213 -0
- package/dst/man/ase-agent-qualifier.1 +214 -0
- package/dst/man/ase-agent-rebooter.1 +193 -0
- package/dst/man/ase-agent-relay.1 +128 -0
- package/dst/man/ase-agent-researcher.1 +217 -0
- package/dst/man/ase-agent.1 +264 -0
- package/dst/man/ase-artifact-list.1 +38 -0
- package/dst/man/ase-artifact-name.1 +39 -0
- package/dst/man/ase-artifact.1 +56 -0
- package/dst/man/ase-config-delete.1 +45 -0
- package/dst/man/ase-config-edit.1 +48 -0
- package/dst/man/ase-config-get.1 +46 -0
- package/dst/man/ase-config-init.1 +60 -0
- package/dst/man/ase-config-list.1 +42 -0
- package/dst/man/ase-config-set.1 +52 -0
- package/dst/man/ase-config.1 +225 -0
- package/dst/man/ase-hook-permission-request.1 +36 -0
- package/dst/man/ase-hook-pre-tool-use.1 +59 -0
- package/dst/man/ase-hook-session-end.1 +47 -0
- package/dst/man/ase-hook-session-persona.1 +37 -0
- package/dst/man/ase-hook-session-start.1 +81 -0
- package/dst/man/ase-hook-stop.1 +34 -0
- package/dst/man/ase-hook-user-prompt-submit.1 +34 -0
- package/dst/man/ase-hook.1 +51 -0
- package/dst/man/ase-man.1 +67 -0
- package/dst/man/ase-mcp.1 +61 -0
- package/dst/man/ase-service-log.1 +43 -0
- package/dst/man/ase-service-send.1 +47 -0
- package/dst/man/ase-service-start.1 +54 -0
- package/dst/man/ase-service-status.1 +46 -0
- package/dst/man/ase-service-stop.1 +37 -0
- package/dst/man/ase-service.1 +85 -0
- package/dst/man/ase-setup-disable.1 +44 -0
- package/dst/man/ase-setup-enable.1 +45 -0
- package/dst/man/ase-setup-install.1 +73 -0
- package/dst/man/ase-setup-mcp.1 +124 -0
- package/dst/man/ase-setup-status.1 +60 -0
- package/dst/man/ase-setup-statusline.1 +92 -0
- package/dst/man/ase-setup-telemetry.1 +92 -0
- package/dst/man/ase-setup-uninstall.1 +59 -0
- package/dst/man/ase-setup-update.1 +64 -0
- package/dst/man/ase-setup.1 +93 -0
- package/dst/man/ase-spec-export.1 +62 -0
- package/dst/man/ase-spec-lint.1 +40 -0
- package/dst/man/ase-spec-preview.1 +40 -0
- package/dst/man/ase-spec.1 +46 -0
- package/dst/man/ase-statusline.1 +189 -0
- package/dst/man/ase-task-assign.1 +71 -0
- package/dst/man/ase-task-board.1 +384 -0
- package/dst/man/ase-task-delete.1 +35 -0
- package/dst/man/ase-task-edit.1 +46 -0
- package/dst/man/ase-task-idscheme.1 +65 -0
- package/dst/man/ase-task-lifecycle.1 +57 -0
- package/dst/man/ase-task-list.1 +47 -0
- package/dst/man/ase-task-load.1 +36 -0
- package/dst/man/ase-task-newid.1 +61 -0
- package/dst/man/ase-task-purge.1 +37 -0
- package/dst/man/ase-task-rename.1 +44 -0
- package/dst/man/ase-task-request.1 +61 -0
- package/dst/man/ase-task-save.1 +48 -0
- package/dst/man/ase-task-status.1 +55 -0
- package/dst/man/ase-task-store.1 +194 -0
- package/dst/man/ase-task-view.1 +40 -0
- package/dst/man/ase-task.1 +160 -0
- package/dst/man/ase-util-compat.1 +25 -0
- package/dst/man/ase-util-diagram.1 +76 -0
- package/dst/man/ase-util-meta.1 +45 -0
- package/dst/man/ase-util-metric.1 +54 -0
- package/dst/man/ase-util-mint.1 +59 -0
- package/dst/man/ase-util-worktree.1 +72 -0
- package/dst/man/ase-util.1 +50 -0
- package/dst/man/ase.1 +124 -0
- package/package.json +79 -21
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/.codex-plugin/plugin.json +1 -1
- package/plugin/.github/plugin/plugin.json +1 -1
- package/plugin/agents/ase-meta-diagram.md +12 -8
- package/plugin/agents/ase-repo-review.md +322 -0
- package/plugin/hooks/hooks-codex.json +5 -0
- package/plugin/hooks/hooks-copilot.json +5 -0
- package/plugin/hooks/hooks.json +8 -0
- package/plugin/meta/ase-common-approach.md +117 -0
- package/plugin/meta/ase-common-changeset.md +256 -0
- package/plugin/meta/ase-common-code.md +10 -173
- package/plugin/meta/ase-common-grill.md +317 -0
- package/plugin/meta/ase-common-resolve.md +305 -0
- package/plugin/meta/ase-common-task.md +83 -4
- package/plugin/meta/ase-constitution.md +0 -2
- package/plugin/meta/ase-format-specbook.md +208 -25
- package/plugin/meta/ase-format-specbook.yaml +242 -851
- package/plugin/meta/ase-format-task.md +669 -125
- package/plugin/meta/ase-persona.md +3 -4
- package/plugin/meta/ase-skill.md +9 -0
- package/plugin/mods/ase-mods.ts +409 -0
- package/plugin/mods/claude-code.d.ts +13417 -0
- package/plugin/skills/ase-arch-analyze/SKILL.md +1 -1
- package/plugin/skills/ase-arch-analyze/help.md +2 -2
- package/plugin/skills/ase-code-analyze/SKILL.md +59 -8
- package/plugin/skills/ase-code-analyze/help.md +29 -4
- package/plugin/skills/ase-code-edit/SKILL.md +107 -181
- package/plugin/skills/ase-code-edit/help.md +118 -31
- package/plugin/skills/ase-code-lint/SKILL.md +64 -13
- package/plugin/skills/ase-code-lint/help.md +32 -2
- package/plugin/skills/ase-docs-proofread/SKILL.md +4 -4
- package/plugin/skills/ase-docs-proofread/help.md +1 -1
- package/plugin/skills/ase-docs-refine/SKILL.md +4 -4
- package/plugin/skills/ase-docs-shorten/SKILL.md +4 -4
- package/plugin/skills/ase-help-intent/data.md +2164 -1087
- package/plugin/skills/ase-help-intent/help.md +1 -1
- package/plugin/skills/ase-help-skill/catalog.md +12 -9
- package/plugin/skills/ase-meta-brainstorm/SKILL.md +1 -1
- package/plugin/skills/ase-meta-config/SKILL.md +3 -4
- package/plugin/skills/ase-meta-config/help.md +31 -10
- package/plugin/skills/ase-meta-mint/SKILL.md +5 -5
- package/plugin/skills/ase-meta-mint/help.md +10 -5
- package/plugin/skills/ase-meta-why/help.md +1 -1
- package/plugin/skills/ase-meta-workflow/SKILL.md +7 -7
- package/plugin/skills/ase-meta-workflow/help.md +4 -4
- package/plugin/skills/ase-meta-workflow/sample.md +3 -3
- package/plugin/skills/ase-meta-workflow/workflow.txt +22 -18
- package/plugin/skills/{ase-meta-changelog → ase-repo-changelog}/SKILL.md +4 -3
- package/plugin/skills/{ase-meta-changelog → ase-repo-changelog}/help.md +5 -5
- package/plugin/skills/{ase-meta-commit → ase-repo-commit}/SKILL.md +6 -6
- package/plugin/skills/{ase-meta-commit → ase-repo-commit}/help.md +5 -5
- package/plugin/skills/{ase-meta-diff → ase-repo-diff}/SKILL.md +6 -6
- package/plugin/skills/{ase-meta-diff → ase-repo-diff}/help.md +8 -8
- package/plugin/skills/{ase-code-dissect → ase-repo-dissect}/SKILL.md +19 -19
- package/plugin/skills/{ase-code-dissect → ase-repo-dissect}/help.md +10 -12
- package/plugin/skills/ase-repo-merge/SKILL.md +346 -0
- package/plugin/skills/ase-repo-merge/help.md +107 -0
- package/plugin/skills/ase-repo-resolve/SKILL.md +158 -0
- package/plugin/skills/ase-repo-resolve/help.md +102 -0
- package/plugin/skills/ase-repo-review/SKILL.md +406 -0
- package/plugin/skills/ase-repo-review/help.md +181 -0
- package/plugin/skills/ase-spec-edit/SKILL.md +117 -183
- package/plugin/skills/ase-spec-edit/help.md +107 -26
- package/plugin/skills/ase-sync-reconcile/help.md +1 -1
- package/plugin/skills/ase-task-assign/SKILL.md +111 -0
- package/plugin/skills/ase-task-assign/help.md +119 -0
- package/plugin/skills/ase-task-condense/SKILL.md +21 -21
- package/plugin/skills/ase-task-condense/help.md +12 -10
- package/plugin/skills/ase-task-delete/SKILL.md +1 -1
- package/plugin/skills/ase-task-dissect/SKILL.md +71 -48
- package/plugin/skills/ase-task-dissect/help.md +10 -9
- package/plugin/skills/ase-task-edit/SKILL.md +379 -94
- package/plugin/skills/ase-task-edit/help.md +95 -22
- package/plugin/skills/ase-task-estimate/SKILL.md +492 -0
- package/plugin/skills/ase-task-estimate/help.md +158 -0
- package/plugin/skills/ase-task-grill/SKILL.md +246 -138
- package/plugin/skills/ase-task-grill/help.md +129 -26
- package/plugin/skills/ase-task-id/SKILL.md +8 -1
- package/plugin/skills/ase-task-id/help.md +6 -3
- package/plugin/skills/ase-task-implement/SKILL.md +535 -145
- package/plugin/skills/ase-task-implement/help.md +138 -47
- package/plugin/skills/ase-task-integrate/SKILL.md +549 -0
- package/plugin/skills/ase-task-integrate/help.md +187 -0
- package/plugin/skills/ase-task-list/SKILL.md +55 -23
- package/plugin/skills/ase-task-list/help.md +45 -21
- package/plugin/skills/ase-task-reboot/SKILL.md +84 -43
- package/plugin/skills/ase-task-reboot/help.md +28 -8
- package/plugin/skills/ase-task-rename/SKILL.md +10 -2
- package/plugin/skills/ase-task-research/SKILL.md +386 -0
- package/plugin/skills/ase-task-research/help.md +102 -0
- package/plugin/skills/ase-task-status/SKILL.md +137 -0
- package/plugin/skills/ase-task-status/help.md +80 -0
- package/plugin/skills/ase-task-view/SKILL.md +49 -24
- package/plugin/skills/ase-task-view/help.md +19 -9
- package/plugin/agents/ase-meta-review.md +0 -187
- package/plugin/skills/ase-code-craft/SKILL.md +0 -264
- package/plugin/skills/ase-code-craft/help.md +0 -122
- package/plugin/skills/ase-code-refactor/SKILL.md +0 -232
- package/plugin/skills/ase-code-refactor/help.md +0 -109
- package/plugin/skills/ase-code-resolve/SKILL.md +0 -289
- package/plugin/skills/ase-code-resolve/help.md +0 -116
- package/plugin/skills/ase-meta-review/SKILL.md +0 -210
- package/plugin/skills/ase-meta-review/help.md +0 -96
- package/plugin/skills/ase-task-preflight/SKILL.md +0 -166
- package/plugin/skills/ase-task-preflight/help.md +0 -82
- /package/dst/{ase-ignore.js → ase-lib-ignore.js} +0 -0
- /package/dst/{ase-stdio.js → ase-lib-stdio.js} +0 -0
- /package/dst/{ase-kv.js → ase-service-kv.js} +0 -0
- /package/dst/{ase-sleep.js → ase-service-sleep.js} +0 -0
- /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
|
+
}
|