@mutagent/cli 0.1.197 → 0.1.198

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/dist/bin/cli.js CHANGED
@@ -728,8 +728,8 @@ var init_sdk_client = __esm(() => {
728
728
  // src/bin/cli.ts
729
729
  import { Command as Command12 } from "commander";
730
730
  import chalk18 from "chalk";
731
- import { readFileSync as readFileSync8, existsSync as existsSync9 } from "fs";
732
- import { join as join11, dirname as dirname3 } from "path";
731
+ import { readFileSync as readFileSync9, existsSync as existsSync10 } from "fs";
732
+ import { join as join12, dirname as dirname3 } from "path";
733
733
  import { fileURLToPath as fileURLToPath2 } from "url";
734
734
 
735
735
  // src/commands/auth.ts
@@ -3099,7 +3099,8 @@ name: mutagent-cli-workflows-install
3099
3099
  description: |
3100
3100
  Meta-installer workflow. Installs a MutagenT package (helix, diagnostics, or
3101
3101
  evaluator) into the user's environment via \`mutagent install <package>\`.
3102
- Login-gated. diagnostics/evaluator come from public npm; helix self-hosts.
3102
+ Login-gated. diagnostics/evaluator come from public npm; helix is fetched
3103
+ from a private registry via a login-brokered signed URL (no static secret).
3103
3104
  triggers:
3104
3105
  - "install diagnostics"
3105
3106
  - "install evaluator"
@@ -3138,7 +3139,7 @@ Where \`<package>\` is one of:
3138
3139
  |---|---|---|
3139
3140
  | \`diagnostics\` | public npm \`@mutagent/diagnostics\` | Ready to install |
3140
3141
  | \`evaluator\` | public npm \`@mutagent/evaluator\` | Ready to install |
3141
- | \`helix\` | self-hosted install | Pendingmay return \`NOT_IMPLEMENTED\` for now |
3142
+ | \`helix\` | private registry via login-brokered signed URL | Ready to install login-gated download, sha256-verified, then initialized into your project |
3142
3143
 
3143
3144
  **Flags** (verify against \`--help\`):
3144
3145
  - \`--harness <claude-code|codex|omp>\` -- target coding-agent harness (default \`claude-code\`).
@@ -3171,6 +3172,8 @@ Where \`<package>\` is one of:
3171
3172
  ## Examples
3172
3173
 
3173
3174
  \`\`\`bash
3175
+ mutagent install helix --json
3176
+ mutagent install helix --harness codex --json
3174
3177
  mutagent install diagnostics --json
3175
3178
  mutagent install evaluator --version 1.2.3 --json
3176
3179
  mutagent install diagnostics --harness codex --json
@@ -3181,15 +3184,15 @@ mutagent install diagnostics --harness codex --json
3181
3184
  ## Output handling
3182
3185
 
3183
3186
  - On success (\`{ success: true, package, version, harness, global }\`): tell the user what was installed and the resolved version. Surface \`_links.install\` / \`_links.login\`.
3184
- - If \`helix\` returns \`NOT_IMPLEMENTED\`: explain that self-hosted helix install is still pending (tracked upstream) and suggest \`diagnostics\` / \`evaluator\`, which install from public npm today.
3185
- - On an auth error: route to the login workflow, then retry.
3187
+ - For \`helix\`: the CLI resolves a signed download URL from the login broker, downloads + sha256-verifies the plugin, then runs its init into the project. An \`INTEGRITY_ERROR\` means the download failed checksum verification retry.
3188
+ - On an auth error (including a broker \`AUTH_REQUIRED\`): route to the login workflow, then retry.
3186
3189
 
3187
3190
  ---
3188
3191
 
3189
3192
  ## Common pitfalls
3190
3193
 
3191
3194
  - Running before login → auth error (install is login-gated).
3192
- - Assuming \`helix\` installs like the npm packages — it self-hosts and may not be wired yet.
3195
+ - Assuming \`helix\` installs from public npm — it is fetched from a private registry via a login-brokered signed URL (the CLI holds no static secret).
3193
3196
  - Installing without confirming with the user first (Core Rule 5).
3194
3197
 
3195
3198
  ---
@@ -4723,7 +4726,229 @@ init_errors();
4723
4726
  // src/lib/installer.ts
4724
4727
  init_errors();
4725
4728
  init_config();
4729
+ import { spawn as spawn2 } from "child_process";
4730
+
4731
+ // src/lib/installer-helix.ts
4732
+ init_errors();
4733
+ init_config();
4726
4734
  import { spawn } from "child_process";
4735
+ import { createHash } from "crypto";
4736
+ import { homedir as homedir2 } from "os";
4737
+ import { join as join11 } from "path";
4738
+ import {
4739
+ existsSync as existsSync9,
4740
+ mkdirSync as mkdirSync5,
4741
+ readFileSync as readFileSync8,
4742
+ renameSync as renameSync2,
4743
+ rmSync,
4744
+ writeFileSync as writeFileSync6
4745
+ } from "fs";
4746
+ async function installHelix(opts, deps = {}) {
4747
+ const auth = (deps.resolveAuth ?? defaultResolveAuth)();
4748
+ const fetchImpl = deps.fetchImpl ?? globalThis.fetch;
4749
+ const descriptor = await fetchDescriptor(fetchImpl, auth, opts.version);
4750
+ const baseDir = deps.homeDir ?? join11(homedir2(), ".mutagent", "helix");
4751
+ const versionDir = join11(baseDir, descriptor.version);
4752
+ mkdirSync5(versionDir, { recursive: true });
4753
+ const tgzPath = join11(versionDir, `helix-plugin-${descriptor.version}.tgz`);
4754
+ const tmpPath = `${tgzPath}.${String(process.pid)}.${String(Date.now())}.part`;
4755
+ const download = deps.download ?? defaultDownload;
4756
+ await download(descriptor.url, tmpPath);
4757
+ const sha256 = deps.sha256 ?? defaultSha256;
4758
+ const actual = (await sha256(tmpPath)).toLowerCase();
4759
+ const expected = descriptor.sha256.toLowerCase();
4760
+ if (actual !== expected) {
4761
+ safeRm(tmpPath);
4762
+ throw new MutagentError("INTEGRITY_ERROR", `Downloaded helix plugin failed sha256 verification (expected ${expected.slice(0, 12)}…, got ${actual.slice(0, 12)}…).`, "The download may be corrupt or tampered with. Retry: mutagent install helix");
4763
+ }
4764
+ renameSync2(tmpPath, tgzPath);
4765
+ const extract = deps.extract ?? defaultExtract;
4766
+ await extract(tgzPath, versionDir);
4767
+ const locateInitBin = deps.locateInitBin ?? defaultLocateInitBin;
4768
+ const binPath = await locateInitBin(versionDir);
4769
+ const initArgs = ["init", "--harness", opts.harness];
4770
+ if (opts.global)
4771
+ initArgs.push("--global");
4772
+ const runInit = deps.runInit ?? defaultRunInit;
4773
+ const code = await runInit(binPath, initArgs, process.cwd());
4774
+ if (code !== 0) {
4775
+ throw new MutagentError("INSTALL_FAILED", `helix plugin init exited with code ${String(code)}.`, "Re-run: mutagent install helix — or run the plugin init manually and report the error.");
4776
+ }
4777
+ await postTelemetry(fetchImpl, auth, {
4778
+ pkg: "helix",
4779
+ version: descriptor.version,
4780
+ harness: opts.harness,
4781
+ cliVersion: deps.cliVersion ?? readCliVersion()
4782
+ });
4783
+ return { version: descriptor.version };
4784
+ }
4785
+ async function fetchDescriptor(fetchImpl, auth, version) {
4786
+ if (!auth.apiKey) {
4787
+ throw new MutagentError("AUTH_REQUIRED", "Authentication required to install helix.", "Run: mutagent login");
4788
+ }
4789
+ const url = `${auth.apiBase}/api/helix/plugin/download?version=${encodeURIComponent(version)}`;
4790
+ let res;
4791
+ try {
4792
+ res = await fetchImpl(url, {
4793
+ method: "GET",
4794
+ headers: { "x-api-key": auth.apiKey, ...auth.headers }
4795
+ });
4796
+ } catch {
4797
+ throw new MutagentError("SERVER_UNAVAILABLE", "Could not reach the MutagenT plugin broker.", "Check your network connection or verify the endpoint with: mutagent config show");
4798
+ }
4799
+ if (res.status === 401) {
4800
+ throw new MutagentError("AUTH_REQUIRED", "The plugin broker rejected your credentials.", "Re-authenticate: mutagent login");
4801
+ }
4802
+ if (!res.ok) {
4803
+ const detail = await readErrorMessage(res);
4804
+ throw new MutagentError("INSTALL_FAILED", `Plugin broker returned ${String(res.status)}.${detail ? ` ${detail}` : ""}`, "Verify the requested version exists, then retry: mutagent install helix");
4805
+ }
4806
+ const raw = await res.json();
4807
+ if (!isBrokerResponse(raw)) {
4808
+ throw new MutagentError("INSTALL_FAILED", "Plugin broker returned a malformed response (missing version/sha256/url).", "Retry: mutagent install helix — if it persists, report it.");
4809
+ }
4810
+ return raw;
4811
+ }
4812
+ async function postTelemetry(fetchImpl, auth, event) {
4813
+ if (!auth.apiKey)
4814
+ return;
4815
+ try {
4816
+ await fetchImpl(`${auth.apiBase}/api/helix/installs`, {
4817
+ method: "POST",
4818
+ headers: {
4819
+ "Content-Type": "application/json",
4820
+ "x-api-key": auth.apiKey,
4821
+ ...auth.headers
4822
+ },
4823
+ body: JSON.stringify(event)
4824
+ });
4825
+ } catch {}
4826
+ }
4827
+ function defaultResolveAuth() {
4828
+ const apiKey = getApiKey();
4829
+ const config = loadConfig();
4830
+ const apiBase = config.endpoint ?? "https://api.mutagent.io";
4831
+ const headers = {};
4832
+ if (config.defaultWorkspace)
4833
+ headers["x-workspace-id"] = config.defaultWorkspace;
4834
+ if (config.defaultOrganization)
4835
+ headers["x-organization-id"] = config.defaultOrganization;
4836
+ return { apiBase, apiKey, headers };
4837
+ }
4838
+ async function defaultDownload(url, destPath) {
4839
+ let res;
4840
+ try {
4841
+ res = await globalThis.fetch(url);
4842
+ } catch {
4843
+ throw new MutagentError("SERVER_UNAVAILABLE", "Failed to download the helix plugin from storage.", "Check your network connection and retry: mutagent install helix");
4844
+ }
4845
+ if (!res.ok) {
4846
+ throw new MutagentError("INSTALL_FAILED", `Plugin download failed with status ${String(res.status)}.`, "The signed URL may have expired — retry: mutagent install helix");
4847
+ }
4848
+ const bytes = Buffer.from(await res.arrayBuffer());
4849
+ writeFileSync6(destPath, bytes);
4850
+ }
4851
+ async function defaultSha256(filePath) {
4852
+ return Promise.resolve(createHash("sha256").update(readFileSync8(filePath)).digest("hex"));
4853
+ }
4854
+ function defaultExtract(tgzPath, destDir) {
4855
+ return new Promise((resolve, reject) => {
4856
+ const child = spawn("tar", ["-xzf", tgzPath, "-C", destDir], {
4857
+ stdio: ["ignore", "ignore", "pipe"]
4858
+ });
4859
+ let stderr = "";
4860
+ child.stderr.on("data", (chunk) => {
4861
+ stderr += chunk.toString("utf-8");
4862
+ });
4863
+ child.on("error", (err) => {
4864
+ reject(new MutagentError("INSTALL_FAILED", `Failed to extract the helix plugin: ${err.message}`, 'Ensure "tar" is installed and available on your PATH.'));
4865
+ });
4866
+ child.on("close", (code) => {
4867
+ if (code === 0) {
4868
+ resolve();
4869
+ } else {
4870
+ reject(new MutagentError("INSTALL_FAILED", `Extracting the helix plugin failed (tar exit ${String(code ?? 1)}).${stderr ? ` ${stderr.trim().slice(0, 200)}` : ""}`, "The downloaded archive may be corrupt — retry: mutagent install helix"));
4871
+ }
4872
+ });
4873
+ });
4874
+ }
4875
+ function defaultLocateInitBin(extractedDir) {
4876
+ const pkgDir = existsSync9(join11(extractedDir, "package", "package.json")) ? join11(extractedDir, "package") : extractedDir;
4877
+ const pkgJsonPath = join11(pkgDir, "package.json");
4878
+ if (!existsSync9(pkgJsonPath)) {
4879
+ return Promise.reject(new MutagentError("INSTALL_FAILED", "Could not find package.json in the extracted helix plugin.", "The archive layout is unexpected — retry or report: mutagent install helix"));
4880
+ }
4881
+ const raw = JSON.parse(readFileSync8(pkgJsonPath, "utf-8"));
4882
+ const binRel = resolveBinField(raw);
4883
+ if (!binRel) {
4884
+ return Promise.reject(new MutagentError("INSTALL_FAILED", "The helix plugin package.json declares no runnable bin.", "The plugin package is malformed — report: mutagent install helix"));
4885
+ }
4886
+ const binPath = join11(pkgDir, binRel);
4887
+ if (!existsSync9(binPath)) {
4888
+ return Promise.reject(new MutagentError("INSTALL_FAILED", `The helix plugin bin was not found at ${binRel}.`, "The plugin package is incomplete — report: mutagent install helix"));
4889
+ }
4890
+ return Promise.resolve(binPath);
4891
+ }
4892
+ function defaultRunInit(binPath, args, cwd) {
4893
+ return new Promise((resolve, reject) => {
4894
+ const child = spawn("node", [binPath, ...args], { cwd, stdio: "inherit" });
4895
+ child.on("error", (err) => {
4896
+ reject(new MutagentError("INSTALL_FAILED", `Failed to run the helix plugin init: ${err.message}`, 'Ensure "node" is installed and available on your PATH.'));
4897
+ });
4898
+ child.on("close", (code) => {
4899
+ resolve(code ?? 1);
4900
+ });
4901
+ });
4902
+ }
4903
+ function resolveBinField(pkg) {
4904
+ if (!pkg || typeof pkg !== "object")
4905
+ return;
4906
+ const bin = pkg.bin;
4907
+ if (typeof bin === "string")
4908
+ return bin;
4909
+ if (bin && typeof bin === "object") {
4910
+ const entries = bin;
4911
+ const preferred = entries["mutagent-helix"];
4912
+ if (typeof preferred === "string")
4913
+ return preferred;
4914
+ for (const value of Object.values(entries)) {
4915
+ if (typeof value === "string")
4916
+ return value;
4917
+ }
4918
+ }
4919
+ return;
4920
+ }
4921
+ function isBrokerResponse(value) {
4922
+ if (!value || typeof value !== "object")
4923
+ return false;
4924
+ const v = value;
4925
+ return typeof v.version === "string" && typeof v.sha256 === "string" && typeof v.url === "string";
4926
+ }
4927
+ async function readErrorMessage(res) {
4928
+ try {
4929
+ const body = await res.json();
4930
+ if (body && typeof body === "object") {
4931
+ const b = body;
4932
+ if (typeof b.message === "string")
4933
+ return b.message;
4934
+ if (typeof b.error === "string")
4935
+ return b.error;
4936
+ }
4937
+ } catch {}
4938
+ return;
4939
+ }
4940
+ function readCliVersion() {
4941
+ if (process.env.CLI_VERSION)
4942
+ return process.env.CLI_VERSION;
4943
+ return "unknown";
4944
+ }
4945
+ function safeRm(path) {
4946
+ try {
4947
+ rmSync(path, { force: true });
4948
+ } catch {}
4949
+ }
4950
+
4951
+ // src/lib/installer.ts
4727
4952
  var VALID_PACKAGES = ["helix", "diagnostics", "evaluator"];
4728
4953
  var VALID_HARNESSES = ["claude-code", "codex", "omp"];
4729
4954
  var VERSION_MATRIX = {
@@ -4736,7 +4961,7 @@ var NPM_PACKAGES = {
4736
4961
  evaluator: "@mutagent/evaluator"
4737
4962
  };
4738
4963
  var defaultRunner = (cmd, args) => new Promise((resolve, reject) => {
4739
- const child = spawn(cmd, args, { stdio: ["ignore", "pipe", "pipe"] });
4964
+ const child = spawn2(cmd, args, { stdio: ["ignore", "pipe", "pipe"] });
4740
4965
  let stdout = "";
4741
4966
  let stderr = "";
4742
4967
  child.stdout.on("data", (chunk) => {
@@ -4771,7 +4996,13 @@ async function installPackage(pkg, opts, deps = {}) {
4771
4996
  }
4772
4997
  const version = opts.version ?? VERSION_MATRIX[pkg];
4773
4998
  if (pkg === "helix") {
4774
- throw new MutagentError("NOT_IMPLEMENTED", "helix self-host install is not available yet — hosting on install.mutagent.io is pending (see issue #1191, task CI1).", "Track: gh issue view 1191. For now install diagnostics/evaluator via npm.");
4999
+ const { version: resolved } = await installHelix({ harness: opts.harness, global: opts.global, version }, deps.helix ?? {});
5000
+ return {
5001
+ package: pkg,
5002
+ version: resolved,
5003
+ harness: opts.harness,
5004
+ global: opts.global
5005
+ };
4775
5006
  }
4776
5007
  const npmPackage = NPM_PACKAGES[pkg];
4777
5008
  const args = ["install", "-g", `${npmPackage}@${version}`];
@@ -4801,15 +5032,18 @@ ${chalk17.bold("Arguments & flags:")}
4801
5032
  ${chalk17.bold("--json")} Structured output
4802
5033
 
4803
5034
  ${chalk17.bold("Examples:")}
5035
+ ${chalk17.dim("$")} mutagent install helix
5036
+ ${chalk17.dim("$")} mutagent install helix --harness codex
4804
5037
  ${chalk17.dim("$")} mutagent install diagnostics
4805
5038
  ${chalk17.dim("$")} mutagent install evaluator --version 1.2.3
4806
5039
  ${chalk17.dim("$")} mutagent install diagnostics --harness codex --json
4807
5040
 
4808
5041
  ${chalk17.bold("Packages:")}
5042
+ ${chalk17.bold("helix")} ${chalk17.green("(available)")} — the ADL conductor. Downloaded from a private
5043
+ registry via a login-brokered signed URL, sha256-verified, then
5044
+ initialized into your project. No static secret ships in the CLI.
4809
5045
  ${chalk17.bold("diagnostics")} Public npm package @mutagent/diagnostics ${chalk17.green("(available)")}
4810
5046
  ${chalk17.bold("evaluator")} Public npm package @mutagent/evaluator ${chalk17.green("(available)")}
4811
- ${chalk17.bold("helix")} ${chalk17.yellow("NOT yet available")} — self-host on install.mutagent.io is pending (#1191).
4812
- Running it today errors with ${chalk17.bold("NOT_IMPLEMENTED")} by design (no fake install).
4813
5047
 
4814
5048
  ${chalk17.yellow("Note:")} install is login-gated. Run ${chalk17.cyan("mutagent login")} first (else exits with a login directive).
4815
5049
  `).action(async (pkg, options) => {
@@ -4847,8 +5081,8 @@ if (process.env.CLI_VERSION) {
4847
5081
  } else {
4848
5082
  try {
4849
5083
  const __dirname2 = dirname3(fileURLToPath2(import.meta.url));
4850
- const pkgPath = join11(__dirname2, "..", "..", "package.json");
4851
- const pkg = JSON.parse(readFileSync8(pkgPath, "utf-8"));
5084
+ const pkgPath = join12(__dirname2, "..", "..", "package.json");
5085
+ const pkg = JSON.parse(readFileSync9(pkgPath, "utf-8"));
4852
5086
  cliVersion = pkg.version ?? cliVersion;
4853
5087
  } catch {}
4854
5088
  }
@@ -4965,12 +5199,12 @@ program.addCommand(createFeedbackCommand());
4965
5199
  var isInteractive = process.stdin.isTTY && !rawArgs.includes("--json") && process.env.CI !== "true";
4966
5200
  var isSkillCommand = rawArgs[0] === "skills" || rawArgs[0] === "hooks";
4967
5201
  if (isInteractive && !isSkillCommand) {
4968
- const skillPath = join11(process.cwd(), ".claude/skills/mutagent-cli/SKILL.md");
4969
- if (!existsSync9(skillPath)) {
5202
+ const skillPath = join12(process.cwd(), ".claude/skills/mutagent-cli/SKILL.md");
5203
+ if (!existsSync10(skillPath)) {
4970
5204
  console.log(chalk18.dim("MutagenT SKILL not installed. Install it for AI agent support? Run:"), chalk18.cyan("mutagent skills install"));
4971
5205
  }
4972
5206
  }
4973
5207
  program.parse();
4974
5208
 
4975
- //# debugId=9788EBFA942A533664756E2164756E21
5209
+ //# debugId=9CA84168C389E42C64756E2164756E21
4976
5210
  //# sourceMappingURL=cli.js.map