mthds 0.2.1 → 0.3.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 (40) hide show
  1. package/README.md +1 -1
  2. package/dist/agent/binaries.d.ts +14 -1
  3. package/dist/agent/binaries.js +21 -6
  4. package/dist/agent/binaries.js.map +1 -1
  5. package/dist/agent/commands/bootstrap.d.ts +15 -0
  6. package/dist/agent/commands/bootstrap.js +152 -0
  7. package/dist/agent/commands/bootstrap.js.map +1 -0
  8. package/dist/agent/commands/doctor.js +25 -17
  9. package/dist/agent/commands/doctor.js.map +1 -1
  10. package/dist/agent/commands/install.js +2 -2
  11. package/dist/agent/commands/install.js.map +1 -1
  12. package/dist/agent/commands/update-check.d.ts +16 -0
  13. package/dist/agent/commands/update-check.js +169 -0
  14. package/dist/agent/commands/update-check.js.map +1 -0
  15. package/dist/agent/commands/upgrade.d.ts +17 -0
  16. package/dist/agent/commands/upgrade.js +155 -0
  17. package/dist/agent/commands/upgrade.js.map +1 -0
  18. package/dist/agent/passthrough.d.ts +1 -0
  19. package/dist/agent/passthrough.js +93 -32
  20. package/dist/agent/passthrough.js.map +1 -1
  21. package/dist/agent/snooze.d.ts +32 -0
  22. package/dist/agent/snooze.js +108 -0
  23. package/dist/agent/snooze.js.map +1 -0
  24. package/dist/agent/update-cache.d.ts +43 -0
  25. package/dist/agent/update-cache.js +125 -0
  26. package/dist/agent/update-cache.js.map +1 -0
  27. package/dist/agent-cli.js +56 -11
  28. package/dist/agent-cli.js.map +1 -1
  29. package/dist/cli/commands/install.js +3 -3
  30. package/dist/cli/commands/install.js.map +1 -1
  31. package/dist/config/credentials.d.ts +2 -0
  32. package/dist/config/credentials.js +64 -33
  33. package/dist/config/credentials.js.map +1 -1
  34. package/dist/installer/runtime/installer.d.ts +21 -6
  35. package/dist/installer/runtime/installer.js +90 -22
  36. package/dist/installer/runtime/installer.js.map +1 -1
  37. package/dist/installer/runtime/version-check.d.ts +31 -0
  38. package/dist/installer/runtime/version-check.js +78 -0
  39. package/dist/installer/runtime/version-check.js.map +1 -0
  40. package/package.json +1 -1
@@ -1,31 +1,78 @@
1
- import { execSync } from "node:child_process";
1
+ import { execFileSync, execSync } from "node:child_process";
2
+ import { homedir } from "node:os";
3
+ import { join } from "node:path";
2
4
  import ora from "ora";
3
5
  import { isPipelexInstalled } from "./check.js";
4
- // ── Shared helpers ───────────────────────────────────────────────────
5
- function runPipelexInstallSync() {
6
- if (process.platform === "win32") {
7
- execSync('powershell -Command "irm https://pipelex.com/install.ps1 | iex"', { stdio: "pipe" });
6
+ import { BINARY_RECOVERY } from "../../agent/binaries.js";
7
+ // All binary installation goes through uv, which provides version-constraint-aware
8
+ // installs and consistent cross-platform behavior.
9
+ // ── uv presence / auto-install ─────────────────────────────────────
10
+ /**
11
+ * Check whether `uv` is on PATH without throwing.
12
+ */
13
+ export function isUvInstalled() {
14
+ try {
15
+ execFileSync("uv", ["--version"], { stdio: "ignore", timeout: 5000 });
16
+ return true;
17
+ }
18
+ catch {
19
+ return false;
20
+ }
21
+ }
22
+ /**
23
+ * Install uv via the official install script and add its bin dir to PATH
24
+ * for the current process. Throws on failure.
25
+ */
26
+ export function installUv() {
27
+ const isWindows = process.platform === "win32";
28
+ const uvBinDir = isWindows
29
+ ? join(process.env.APPDATA ?? join(homedir(), "AppData", "Roaming"), "uv", "bin")
30
+ : join(homedir(), ".local", "bin");
31
+ // Official uv install scripts (https://docs.astral.sh/uv/getting-started/installation/).
32
+ // These execute a remote script without checksum verification — accepted tradeoff for the
33
+ // standard install path. The scripts are served over HTTPS from astral.sh's CDN.
34
+ const cmd = isWindows
35
+ ? 'powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"'
36
+ : "curl -LsSf https://astral.sh/uv/install.sh | sh";
37
+ try {
38
+ execSync(cmd, { stdio: "pipe", timeout: 30_000 });
39
+ }
40
+ catch (err) {
41
+ const stderr = err?.stderr?.toString().trim();
42
+ const detail = stderr || (err instanceof Error ? err.message : String(err));
43
+ throw new Error(`Failed to install uv: ${detail}`);
8
44
  }
9
- else {
10
- execSync("curl -fsSL https://pipelex.com/install.sh | sh", { stdio: "pipe", shell: "/bin/sh" });
45
+ // Make uv available in the current process
46
+ const sep = isWindows ? ";" : ":";
47
+ if (!process.env.PATH?.includes(uvBinDir)) {
48
+ process.env.PATH = `${uvBinDir}${sep}${process.env.PATH}`;
11
49
  }
12
50
  }
13
51
  // ── Async install (interactive, with spinner) ────────────────────────
52
+ /**
53
+ * Ensure pipelex is installed, using uv tool install with spinner feedback.
54
+ * Used by interactive CLI commands (mthds install, mthds setup, etc.).
55
+ */
14
56
  export async function ensureRuntime() {
15
57
  if (!isPipelexInstalled()) {
16
- await installPipelex();
58
+ await installPipelexViaUv();
17
59
  }
18
60
  }
19
- async function installPipelex() {
20
- const spinner = ora("Installing pipelex...").start();
61
+ async function installPipelexViaUv() {
62
+ const spinner = ora("Installing pipelex via uv...").start();
63
+ const recovery = BINARY_RECOVERY["pipelex"];
64
+ if (!recovery) {
65
+ spinner.fail("pipelex recovery info is missing — this is a bug.");
66
+ throw new Error("BINARY_RECOVERY is missing the 'pipelex' entry.");
67
+ }
21
68
  try {
22
- runPipelexInstallSync();
69
+ uvToolInstallSync(recovery.uv_package, recovery.version_constraint);
23
70
  }
24
71
  catch (error) {
25
72
  spinner.fail("Failed to install pipelex");
26
73
  const msg = error instanceof Error ? error.message : String(error);
27
74
  throw new Error(`Could not install pipelex: ${msg}\n` +
28
- "Install manually: https://pipelex.com");
75
+ `Install manually: uv tool install --upgrade "${recovery.uv_package}${recovery.version_constraint}"`);
29
76
  }
30
77
  if (!isPipelexInstalled()) {
31
78
  spinner.fail("pipelex was installed but is not reachable");
@@ -34,20 +81,41 @@ async function installPipelex() {
34
81
  }
35
82
  spinner.succeed("pipelex installed");
36
83
  }
37
- // ── Sync silent install functions (for mthds-agent --auto-install) ──
84
+ // ── uv helpers ──────────────────────────────────────────────────────
38
85
  /**
39
- * Install pipelex synchronously without interactive output (no spinner).
40
- * Throws on failure.
86
+ * Locate the `uv` binary. Throws with install instructions if not found.
41
87
  */
42
- export function installPipelexSync() {
43
- runPipelexInstallSync();
88
+ export function requireUv() {
89
+ try {
90
+ execFileSync("uv", ["--version"], { stdio: "ignore", timeout: 5000 });
91
+ return "uv";
92
+ }
93
+ catch (err) {
94
+ const errno = err.code;
95
+ if (errno === "ENOENT") {
96
+ throw new Error("uv is required but not found in PATH. Install it: https://docs.astral.sh/uv/getting-started/installation/");
97
+ }
98
+ const msg = err instanceof Error ? err.message : String(err);
99
+ throw new Error(`uv was found but failed to run: ${msg}`);
100
+ }
44
101
  }
45
102
  /**
46
- * Install pipelex-tools (plxt) synchronously without interactive output.
47
- * Throws on failure.
103
+ * Install or upgrade a Python tool via `uv tool install`.
104
+ * Uses execFileSync (no shell) for cross-platform safety.
105
+ *
106
+ * @param pkg - PyPI package name (e.g. "pipelex")
107
+ * @param versionConstraint - Optional semver range appended to the package spec (e.g. ">=0.22.0").
48
108
  */
49
- export function installPlxtSync() {
50
- const pythonCmd = process.platform === "win32" ? "python" : "python3";
51
- execSync(`${pythonCmd} -m pip install --quiet pipelex-tools`, { stdio: "pipe" });
109
+ export function uvToolInstallSync(pkg, versionConstraint) {
110
+ const uv = requireUv();
111
+ const spec = versionConstraint ? `${pkg}${versionConstraint}` : pkg;
112
+ try {
113
+ execFileSync(uv, ["tool", "install", "--upgrade", spec], { stdio: "pipe", timeout: 60000 });
114
+ }
115
+ catch (err) {
116
+ const stderr = err?.stderr?.toString().trim();
117
+ const detail = stderr || (err instanceof Error ? err.message : String(err));
118
+ throw new Error(`uv tool install failed for "${spec}": ${detail}`);
119
+ }
52
120
  }
53
121
  //# sourceMappingURL=installer.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"installer.js","sourceRoot":"","sources":["../../../src/installer/runtime/installer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAEhD,wEAAwE;AAExE,SAAS,qBAAqB;IAC5B,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACjC,QAAQ,CACN,iEAAiE,EACjE,EAAE,KAAK,EAAE,MAAM,EAAE,CAClB,CAAC;IACJ,CAAC;SAAM,CAAC;QACN,QAAQ,CACN,gDAAgD,EAChD,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,CACpC,CAAC;IACJ,CAAC;AACH,CAAC;AAED,wEAAwE;AAExE,MAAM,CAAC,KAAK,UAAU,aAAa;IACjC,IAAI,CAAC,kBAAkB,EAAE,EAAE,CAAC;QAC1B,MAAM,cAAc,EAAE,CAAC;IACzB,CAAC;AACH,CAAC;AAED,KAAK,UAAU,cAAc;IAC3B,MAAM,OAAO,GAAG,GAAG,CAAC,uBAAuB,CAAC,CAAC,KAAK,EAAE,CAAC;IACrD,IAAI,CAAC;QACH,qBAAqB,EAAE,CAAC;IAC1B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;QAC1C,MAAM,GAAG,GACP,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACzD,MAAM,IAAI,KAAK,CACb,8BAA8B,GAAG,IAAI;YACnC,uCAAuC,CAC1C,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,kBAAkB,EAAE,EAAE,CAAC;QAC1B,OAAO,CAAC,IAAI,CAAC,4CAA4C,CAAC,CAAC;QAC3D,MAAM,IAAI,KAAK,CACb,mDAAmD;YACjD,+EAA+E,CAClF,CAAC;IACJ,CAAC;IAED,OAAO,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC;AACvC,CAAC;AAED,uEAAuE;AAEvE;;;GAGG;AACH,MAAM,UAAU,kBAAkB;IAChC,qBAAqB,EAAE,CAAC;AAC1B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe;IAC7B,MAAM,SAAS,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC;IACtE,QAAQ,CAAC,GAAG,SAAS,uCAAuC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;AACnF,CAAC"}
1
+ {"version":3,"file":"installer.js","sourceRoot":"","sources":["../../../src/installer/runtime/installer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Version checking for external CLI binaries.
3
+ *
4
+ * Runs `<binary> --version`, extracts the semver, and compares against the
5
+ * declared constraint from BinaryRecoveryInfo.
6
+ *
7
+ * NOTE: The skill preamble (skills/shared/preamble.md) implements a parallel
8
+ * bash version comparison for mthds-agent itself (chicken-and-egg: must check
9
+ * mthds-agent before calling it). That bash comparison is intentionally simpler
10
+ * (major.minor.patch arithmetic only, no prerelease/build metadata). Both
11
+ * implementations must stay in sync for the version gate to behave consistently.
12
+ */
13
+ import type { BinaryRecoveryInfo } from "../../agent/binaries.js";
14
+ export type VersionStatus = "ok" | "missing" | "outdated" | "unparseable";
15
+ export interface VersionCheckResult {
16
+ status: VersionStatus;
17
+ /** The installed version string, or null if missing/unparseable. */
18
+ installed_version: string | null;
19
+ /** The constraint from BinaryRecoveryInfo. */
20
+ version_constraint: string;
21
+ }
22
+ /**
23
+ * Check whether a binary is installed and satisfies its version constraint.
24
+ *
25
+ * Returns one of four statuses:
26
+ * - `ok` — installed and satisfies the constraint
27
+ * - `missing` — binary not found in PATH
28
+ * - `outdated` — installed but below the required version
29
+ * - `unparseable` — `--version` output could not be parsed (warns, doesn't block)
30
+ */
31
+ export declare function checkBinaryVersion(recovery: BinaryRecoveryInfo): VersionCheckResult;
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Version checking for external CLI binaries.
3
+ *
4
+ * Runs `<binary> --version`, extracts the semver, and compares against the
5
+ * declared constraint from BinaryRecoveryInfo.
6
+ *
7
+ * NOTE: The skill preamble (skills/shared/preamble.md) implements a parallel
8
+ * bash version comparison for mthds-agent itself (chicken-and-egg: must check
9
+ * mthds-agent before calling it). That bash comparison is intentionally simpler
10
+ * (major.minor.patch arithmetic only, no prerelease/build metadata). Both
11
+ * implementations must stay in sync for the version gate to behave consistently.
12
+ */
13
+ import { execFileSync } from "node:child_process";
14
+ import semver from "semver";
15
+ /**
16
+ * Check whether a binary is installed and satisfies its version constraint.
17
+ *
18
+ * Returns one of four statuses:
19
+ * - `ok` — installed and satisfies the constraint
20
+ * - `missing` — binary not found in PATH
21
+ * - `outdated` — installed but below the required version
22
+ * - `unparseable` — `--version` output could not be parsed (warns, doesn't block)
23
+ */
24
+ export function checkBinaryVersion(recovery) {
25
+ const { version_constraint } = recovery;
26
+ // 1. Try running `<binary> --version`
27
+ let rawOutput;
28
+ try {
29
+ rawOutput = execFileSync(recovery.binary, ["--version"], {
30
+ stdio: "pipe",
31
+ timeout: 5000,
32
+ })
33
+ .toString()
34
+ .trim();
35
+ }
36
+ catch (err) {
37
+ // ENOENT means the binary is genuinely not in PATH.
38
+ // Any other error (EACCES, non-zero exit, crash) means the binary exists
39
+ // but is broken — report as unparseable so callers don't blindly reinstall.
40
+ const errno = err.code;
41
+ if (errno === "ENOENT") {
42
+ return { status: "missing", installed_version: null, version_constraint };
43
+ }
44
+ return { status: "unparseable", installed_version: null, version_constraint };
45
+ }
46
+ // 2. Extract version via the recovery's regex
47
+ const match = rawOutput.match(recovery.version_extract);
48
+ if (!match?.[1]) {
49
+ return {
50
+ status: "unparseable",
51
+ installed_version: null,
52
+ version_constraint,
53
+ };
54
+ }
55
+ // 3. Coerce to semver (lenient — handles "v" prefix, pre-release tags, etc.)
56
+ const parsed = semver.coerce(match[1]);
57
+ if (!parsed) {
58
+ return {
59
+ status: "unparseable",
60
+ installed_version: match[1],
61
+ version_constraint,
62
+ };
63
+ }
64
+ // 4. Check against constraint
65
+ if (semver.satisfies(parsed, version_constraint)) {
66
+ return {
67
+ status: "ok",
68
+ installed_version: parsed.version,
69
+ version_constraint,
70
+ };
71
+ }
72
+ return {
73
+ status: "outdated",
74
+ installed_version: parsed.version,
75
+ version_constraint,
76
+ };
77
+ }
78
+ //# sourceMappingURL=version-check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version-check.js","sourceRoot":"","sources":["../../../src/installer/runtime/version-check.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,MAAM,MAAM,QAAQ,CAAC;AAa5B;;;;;;;;GAQG;AACH,MAAM,UAAU,kBAAkB,CAChC,QAA4B;IAE5B,MAAM,EAAE,kBAAkB,EAAE,GAAG,QAAQ,CAAC;IAExC,sCAAsC;IACtC,IAAI,SAAiB,CAAC;IACtB,IAAI,CAAC;QACH,SAAS,GAAG,YAAY,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,WAAW,CAAC,EAAE;YACvD,KAAK,EAAE,MAAM;YACb,OAAO,EAAE,IAAI;SACd,CAAC;aACC,QAAQ,EAAE;aACV,IAAI,EAAE,CAAC;IACZ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,oDAAoD;QACpD,yEAAyE;QACzE,4EAA4E;QAC5E,MAAM,KAAK,GAAI,GAA6B,CAAC,IAAI,CAAC;QAClD,IAAI,KAAK,KAAK,QAAQ,EAAE,CAAC;YACvB,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,iBAAiB,EAAE,IAAI,EAAE,kBAAkB,EAAE,CAAC;QAC5E,CAAC;QACD,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,iBAAiB,EAAE,IAAI,EAAE,kBAAkB,EAAE,CAAC;IAChF,CAAC;IAED,8CAA8C;IAC9C,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC;IACxD,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAChB,OAAO;YACL,MAAM,EAAE,aAAa;YACrB,iBAAiB,EAAE,IAAI;YACvB,kBAAkB;SACnB,CAAC;IACJ,CAAC;IAED,6EAA6E;IAC7E,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACvC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO;YACL,MAAM,EAAE,aAAa;YACrB,iBAAiB,EAAE,KAAK,CAAC,CAAC,CAAC;YAC3B,kBAAkB;SACnB,CAAC;IACJ,CAAC;IAED,8BAA8B;IAC9B,IAAI,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,kBAAkB,CAAC,EAAE,CAAC;QACjD,OAAO;YACL,MAAM,EAAE,IAAI;YACZ,iBAAiB,EAAE,MAAM,CAAC,OAAO;YACjC,kBAAkB;SACnB,CAAC;IACJ,CAAC;IAED,OAAO;QACL,MAAM,EAAE,UAAU;QAClB,iBAAiB,EAAE,MAAM,CAAC,OAAO;QACjC,kBAAkB;KACnB,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mthds",
3
- "version": "0.2.1",
3
+ "version": "0.3.1",
4
4
  "description": "CLI and SDK for MTHDS — the open standard for reusable AI agent methods. Install, execute, and manage methods.",
5
5
  "license": "MIT",
6
6
  "repository": {