@mastra/code-sdk 1.0.3-alpha.0 → 1.1.0-alpha.2

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 (258) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/dist/acp/agent.js +155 -167
  3. package/dist/acp/agent.js.map +1 -1
  4. package/dist/acp/event-mapper.js +193 -168
  5. package/dist/acp/event-mapper.js.map +1 -1
  6. package/dist/acp/index.js +60 -49
  7. package/dist/acp/index.js.map +1 -1
  8. package/dist/acp/server.js +31 -30
  9. package/dist/acp/server.js.map +1 -1
  10. package/dist/acp.js +1 -4
  11. package/dist/agents/credential-resolver.js +40 -29
  12. package/dist/agents/credential-resolver.js.map +1 -1
  13. package/dist/agents/custom-provider-source.js +16 -9
  14. package/dist/agents/custom-provider-source.js.map +1 -1
  15. package/dist/agents/instructions.js +27 -36
  16. package/dist/agents/instructions.js.map +1 -1
  17. package/dist/agents/mastracode-gateway.js +355 -428
  18. package/dist/agents/mastracode-gateway.js.map +1 -1
  19. package/dist/agents/memory.js +87 -78
  20. package/dist/agents/memory.js.map +1 -1
  21. package/dist/agents/model.js +114 -119
  22. package/dist/agents/model.js.map +1 -1
  23. package/dist/agents/modes/build.js +12 -13
  24. package/dist/agents/modes/build.js.map +1 -1
  25. package/dist/agents/modes/explore.js +14 -13
  26. package/dist/agents/modes/explore.js.map +1 -1
  27. package/dist/agents/modes/plan.js +14 -15
  28. package/dist/agents/modes/plan.js.map +1 -1
  29. package/dist/agents/prompts/agent-instructions.js +78 -69
  30. package/dist/agents/prompts/agent-instructions.js.map +1 -1
  31. package/dist/agents/prompts/build.js +19 -16
  32. package/dist/agents/prompts/build.js.map +1 -1
  33. package/dist/agents/prompts/fast.js +8 -4
  34. package/dist/agents/prompts/fast.js.map +1 -1
  35. package/dist/agents/prompts/index.js +48 -47
  36. package/dist/agents/prompts/index.js.map +1 -1
  37. package/dist/agents/prompts/model.js +6 -5
  38. package/dist/agents/prompts/model.js.map +1 -1
  39. package/dist/agents/prompts/plan.js +20 -16
  40. package/dist/agents/prompts/plan.js.map +1 -1
  41. package/dist/agents/prompts/tool-guidance.js +77 -109
  42. package/dist/agents/prompts/tool-guidance.js.map +1 -1
  43. package/dist/agents/sandbox-filesystem.js +245 -259
  44. package/dist/agents/sandbox-filesystem.js.map +1 -1
  45. package/dist/agents/sandbox-reattach.js +9 -11
  46. package/dist/agents/sandbox-reattach.js.map +1 -1
  47. package/dist/agents/thread-caveman-state.js +92 -81
  48. package/dist/agents/thread-caveman-state.js.map +1 -1
  49. package/dist/agents/tool-availability.js +62 -80
  50. package/dist/agents/tool-availability.js.map +1 -1
  51. package/dist/agents/tools.js +99 -139
  52. package/dist/agents/tools.js.map +1 -1
  53. package/dist/agents/workspace.js +232 -225
  54. package/dist/agents/workspace.js.map +1 -1
  55. package/dist/analytics.js +139 -128
  56. package/dist/analytics.js.map +1 -1
  57. package/dist/auth/authorization-input.js +39 -25
  58. package/dist/auth/authorization-input.js.map +1 -1
  59. package/dist/auth/device-code.js +112 -80
  60. package/dist/auth/device-code.js.map +1 -1
  61. package/dist/auth/index.js +2 -9
  62. package/dist/auth/pkce.js +27 -16
  63. package/dist/auth/pkce.js.map +1 -1
  64. package/dist/auth/providers/anthropic.js +107 -93
  65. package/dist/auth/providers/anthropic.js.map +1 -1
  66. package/dist/auth/providers/github-copilot.js +304 -293
  67. package/dist/auth/providers/github-copilot.js.map +1 -1
  68. package/dist/auth/providers/openai-codex.js +442 -460
  69. package/dist/auth/providers/openai-codex.js.map +1 -1
  70. package/dist/auth/providers/xai.js +179 -145
  71. package/dist/auth/providers/xai.js.map +1 -1
  72. package/dist/auth/storage.js +182 -175
  73. package/dist/auth/storage.js.map +1 -1
  74. package/dist/auth/types.js +1 -1
  75. package/dist/clipboard/index.js +206 -172
  76. package/dist/clipboard/index.js.map +1 -1
  77. package/dist/constants.js +11 -16
  78. package/dist/constants.js.map +1 -1
  79. package/dist/error-classification.js +19 -11
  80. package/dist/error-classification.js.map +1 -1
  81. package/dist/evals/context-builder.js +145 -104
  82. package/dist/evals/context-builder.js.map +1 -1
  83. package/dist/evals/index.js +4 -7
  84. package/dist/evals/scorers/classify-command.js +62 -41
  85. package/dist/evals/scorers/classify-command.js.map +1 -1
  86. package/dist/evals/scorers/efficiency.js +239 -181
  87. package/dist/evals/scorers/efficiency.js.map +1 -1
  88. package/dist/evals/scorers/extract-tools.js +51 -47
  89. package/dist/evals/scorers/extract-tools.js.map +1 -1
  90. package/dist/evals/scorers/index.js +1 -5
  91. package/dist/evals/scorers/outcome.js +321 -212
  92. package/dist/evals/scorers/outcome.js.map +1 -1
  93. package/dist/goal-manager.js +266 -261
  94. package/dist/goal-manager.js.map +1 -1
  95. package/dist/goal-signal.js +14 -13
  96. package/dist/goal-signal.js.map +1 -1
  97. package/dist/headless/cli.js +153 -154
  98. package/dist/headless/cli.js.map +1 -1
  99. package/dist/headless/flags.js +180 -178
  100. package/dist/headless/flags.js.map +1 -1
  101. package/dist/headless/format.js +72 -71
  102. package/dist/headless/format.js.map +1 -1
  103. package/dist/headless/index.js +5 -31
  104. package/dist/headless/policy.js +35 -31
  105. package/dist/headless/policy.js.map +1 -1
  106. package/dist/headless/run-mc.js +332 -334
  107. package/dist/headless/run-mc.js.map +1 -1
  108. package/dist/headless/types.js +16 -7
  109. package/dist/headless/types.js.map +1 -1
  110. package/dist/hooks/config.js +56 -61
  111. package/dist/hooks/config.js.map +1 -1
  112. package/dist/hooks/executor.js +118 -116
  113. package/dist/hooks/executor.js.map +1 -1
  114. package/dist/hooks/index.js +4 -15
  115. package/dist/hooks/manager.js +221 -280
  116. package/dist/hooks/manager.js.map +1 -1
  117. package/dist/hooks/types.js +5 -4
  118. package/dist/hooks/types.js.map +1 -1
  119. package/dist/index.d.ts.map +1 -1
  120. package/dist/index.js +632 -712
  121. package/dist/index.js.map +1 -1
  122. package/dist/ipc/ipc-reporter.js +19 -22
  123. package/dist/ipc/ipc-reporter.js.map +1 -1
  124. package/dist/lsp/client.js +248 -306
  125. package/dist/lsp/client.js.map +1 -1
  126. package/dist/lsp/index.js +1 -6
  127. package/dist/lsp/language.js +39 -43
  128. package/dist/lsp/language.js.map +1 -1
  129. package/dist/lsp/manager.js +78 -93
  130. package/dist/lsp/manager.js.map +1 -1
  131. package/dist/lsp/server.js +151 -120
  132. package/dist/lsp/server.js.map +1 -1
  133. package/dist/lsp/workspace.js +50 -47
  134. package/dist/lsp/workspace.js.map +1 -1
  135. package/dist/mcp/config.js +210 -199
  136. package/dist/mcp/config.js.map +1 -1
  137. package/dist/mcp/index.js +2 -9
  138. package/dist/mcp/manager.js +482 -475
  139. package/dist/mcp/manager.js.map +1 -1
  140. package/dist/mcp/types.js +1 -1
  141. package/dist/onboarding/custom-packs.js +14 -17
  142. package/dist/onboarding/custom-packs.js.map +1 -1
  143. package/dist/onboarding/custom-providers.js +22 -20
  144. package/dist/onboarding/custom-providers.js.map +1 -1
  145. package/dist/onboarding/index.d.ts +1 -1
  146. package/dist/onboarding/index.d.ts.map +1 -1
  147. package/dist/onboarding/index.js +3 -21
  148. package/dist/onboarding/om-settings.d.ts +5 -0
  149. package/dist/onboarding/om-settings.d.ts.map +1 -1
  150. package/dist/onboarding/om-settings.js +41 -20
  151. package/dist/onboarding/om-settings.js.map +1 -1
  152. package/dist/onboarding/packs.d.ts +4 -6
  153. package/dist/onboarding/packs.d.ts.map +1 -1
  154. package/dist/onboarding/packs.js +154 -105
  155. package/dist/onboarding/packs.js.map +1 -1
  156. package/dist/onboarding/settings.js +575 -517
  157. package/dist/onboarding/settings.js.map +1 -1
  158. package/dist/permissions.js +112 -99
  159. package/dist/permissions.js.map +1 -1
  160. package/dist/plugin.js +21 -23
  161. package/dist/plugin.js.map +1 -1
  162. package/dist/plugins/dependencies.js +64 -87
  163. package/dist/plugins/dependencies.js.map +1 -1
  164. package/dist/plugins/install.js +159 -169
  165. package/dist/plugins/install.js.map +1 -1
  166. package/dist/plugins/loader.js +170 -185
  167. package/dist/plugins/loader.js.map +1 -1
  168. package/dist/plugins/manager.js +374 -380
  169. package/dist/plugins/manager.js.map +1 -1
  170. package/dist/plugins/manifest.js +38 -63
  171. package/dist/plugins/manifest.js.map +1 -1
  172. package/dist/plugins/package-link.js +48 -64
  173. package/dist/plugins/package-link.js.map +1 -1
  174. package/dist/plugins/paths.js +18 -19
  175. package/dist/plugins/paths.js.map +1 -1
  176. package/dist/plugins/registry.js +97 -81
  177. package/dist/plugins/registry.js.map +1 -1
  178. package/dist/plugins/scaffold.js +62 -98
  179. package/dist/plugins/scaffold.js.map +1 -1
  180. package/dist/plugins/types.js +1 -1
  181. package/dist/processors/plan-rejection-abort.js +45 -44
  182. package/dist/processors/plan-rejection-abort.js.map +1 -1
  183. package/dist/providers/amazon-bedrock-gateway.js +134 -125
  184. package/dist/providers/amazon-bedrock-gateway.js.map +1 -1
  185. package/dist/providers/amazon-bedrock.js +68 -47
  186. package/dist/providers/amazon-bedrock.js.map +1 -1
  187. package/dist/providers/claude-max.js +153 -133
  188. package/dist/providers/claude-max.js.map +1 -1
  189. package/dist/providers/github-copilot.js +232 -230
  190. package/dist/providers/github-copilot.js.map +1 -1
  191. package/dist/providers/openai-codex.js +271 -260
  192. package/dist/providers/openai-codex.js.map +1 -1
  193. package/dist/providers/xai.js +57 -50
  194. package/dist/providers/xai.js.map +1 -1
  195. package/dist/schema.js +91 -89
  196. package/dist/schema.js.map +1 -1
  197. package/dist/theme-palette.js +18 -14
  198. package/dist/theme-palette.js.map +1 -1
  199. package/dist/tool-names.js +46 -37
  200. package/dist/tool-names.js.map +1 -1
  201. package/dist/tools/index.js +2 -8
  202. package/dist/tools/request-sandbox-access.js +71 -80
  203. package/dist/tools/request-sandbox-access.js.map +1 -1
  204. package/dist/tools/utils.js +26 -16
  205. package/dist/tools/utils.js.map +1 -1
  206. package/dist/tools/web-search.js +51 -55
  207. package/dist/tools/web-search.js.map +1 -1
  208. package/dist/utils/binaries.js +65 -61
  209. package/dist/utils/binaries.js.map +1 -1
  210. package/dist/utils/debug-log.js +51 -47
  211. package/dist/utils/debug-log.js.map +1 -1
  212. package/dist/utils/errors.js +157 -192
  213. package/dist/utils/errors.js.map +1 -1
  214. package/dist/utils/gateway-sync.js +49 -37
  215. package/dist/utils/gateway-sync.js.map +1 -1
  216. package/dist/utils/path-security.js +7 -6
  217. package/dist/utils/path-security.js.map +1 -1
  218. package/dist/utils/plan-diff.js +58 -39
  219. package/dist/utils/plan-diff.js.map +1 -1
  220. package/dist/utils/plans.js +92 -74
  221. package/dist/utils/plans.js.map +1 -1
  222. package/dist/utils/project.js +318 -256
  223. package/dist/utils/project.js.map +1 -1
  224. package/dist/utils/signals-pubsub.js +117 -99
  225. package/dist/utils/signals-pubsub.js.map +1 -1
  226. package/dist/utils/slash-command-loader.js +118 -154
  227. package/dist/utils/slash-command-loader.js.map +1 -1
  228. package/dist/utils/slash-command-processor.js +92 -83
  229. package/dist/utils/slash-command-processor.js.map +1 -1
  230. package/dist/utils/stdin-pipe.js +87 -63
  231. package/dist/utils/stdin-pipe.js.map +1 -1
  232. package/dist/utils/storage-factory.js +104 -84
  233. package/dist/utils/storage-factory.js.map +1 -1
  234. package/dist/utils/storage-maintenance.js +249 -211
  235. package/dist/utils/storage-maintenance.js.map +1 -1
  236. package/dist/utils/thread-lock.js +96 -92
  237. package/dist/utils/thread-lock.js.map +1 -1
  238. package/dist/utils/token-estimator.js +12 -12
  239. package/dist/utils/token-estimator.js.map +1 -1
  240. package/dist/utils/update-check.d.ts +1 -1
  241. package/dist/utils/update-check.js +341 -259
  242. package/dist/utils/update-check.js.map +1 -1
  243. package/dist/voice/stt-registry.js +131 -113
  244. package/dist/voice/stt-registry.js.map +1 -1
  245. package/package.json +11 -11
  246. package/dist/acp.js.map +0 -1
  247. package/dist/auth/index.js.map +0 -1
  248. package/dist/auth/types.js.map +0 -1
  249. package/dist/evals/index.js.map +0 -1
  250. package/dist/evals/scorers/index.js.map +0 -1
  251. package/dist/headless/index.js.map +0 -1
  252. package/dist/hooks/index.js.map +0 -1
  253. package/dist/lsp/index.js.map +0 -1
  254. package/dist/mcp/index.js.map +0 -1
  255. package/dist/mcp/types.js.map +0 -1
  256. package/dist/onboarding/index.js.map +0 -1
  257. package/dist/plugins/types.js.map +0 -1
  258. package/dist/tools/index.js.map +0 -1
@@ -1,301 +1,383 @@
1
- import { execFile } from "node:child_process";
2
- import { readFileSync, realpathSync } from "node:fs";
3
- import { homedir } from "node:os";
4
- import { dirname, join, resolve, sep } from "node:path";
5
- import { fileURLToPath } from "node:url";
1
+ import { readFileSync, realpathSync } from "fs";
2
+ import { homedir } from "os";
3
+ import { dirname, join, resolve, sep } from "path";
4
+ import { execFile } from "child_process";
5
+ import { fileURLToPath } from "url";
6
+ //#region src/utils/update-check.ts
7
+ /**
8
+ * Check for newer versions of mastracode on npm.
9
+ */
6
10
  const PACKAGE_NAME = "mastracode";
7
11
  const NPM_REGISTRY_URL = `https://registry.npmjs.org/${PACKAGE_NAME}/latest`;
12
+ /** Timeout for the npm registry fetch (ms). */
8
13
  const FETCH_TIMEOUT_MS = 5e3;
9
14
  const USE_SHELL = process.platform === "win32";
10
15
  function matchPM(str) {
11
- if (/pnpm/i.test(str)) return "pnpm";
12
- if (/\byarn\b/i.test(str)) return "yarn";
13
- if (/\bbun\b/i.test(str)) return "bun";
14
- if (/\bnpm\b/i.test(str)) return "npm";
15
- return null;
16
+ if (/pnpm/i.test(str)) return "pnpm";
17
+ if (/\byarn\b/i.test(str)) return "yarn";
18
+ if (/\bbun\b/i.test(str)) return "bun";
19
+ if (/\bnpm\b/i.test(str)) return "npm";
20
+ return null;
16
21
  }
22
+ /**
23
+ * Detect which package manager was used to install mastracode globally.
24
+ *
25
+ * Uses a multi-tier approach:
26
+ * 1. npm_config_user_agent env var (set when run via `pnpm run`, `npm run`, etc.)
27
+ * 2. npm_execpath env var (fallback for script-based invocation)
28
+ * 3. NODE_PATH env var (set by pnpm global bin stubs)
29
+ * 4. Resolved path of the running script (process.argv[1])
30
+ * 5. Shell-out to `pnpm list -g` to check if pnpm manages the package
31
+ * 6. Falls back to 'npm'
32
+ */
17
33
  async function detectPackageManager() {
18
- const userAgent = process.env.npm_config_user_agent;
19
- if (userAgent) {
20
- const pm = matchPM(userAgent);
21
- if (pm) return pm;
22
- }
23
- const execPath = process.env.npm_execpath;
24
- if (execPath) {
25
- const pm = matchPM(execPath);
26
- if (pm) return pm;
27
- }
28
- const nodePath = process.env.NODE_PATH;
29
- if (nodePath) {
30
- if (/[/\\]\.pnpm[/\\]/.test(nodePath) || /[/\\]pnpm[/\\]/.test(nodePath)) return "pnpm";
31
- if (/[/\\]\.yarn[/\\]/.test(nodePath)) return "yarn";
32
- if (/[/\\]\.bun[/\\]/.test(nodePath)) return "bun";
33
- }
34
- try {
35
- const scriptPath = realpathSync(process.argv[1] ?? "");
36
- if (/[/\\]\.?pnpm[/\\]/.test(scriptPath)) return "pnpm";
37
- if (/[/\\]\.?yarn[/\\]/.test(scriptPath)) return "yarn";
38
- if (/[/\\]\.?bun[/\\]/.test(scriptPath)) return "bun";
39
- } catch {
40
- }
41
- const pnpmResult = await new Promise((resolve2) => {
42
- execFile(
43
- "pnpm",
44
- ["list", "-g", "--depth=0", PACKAGE_NAME],
45
- { timeout: 3e3, shell: USE_SHELL },
46
- (error, stdout) => {
47
- resolve2(!error && stdout.includes(PACKAGE_NAME));
48
- }
49
- );
50
- });
51
- if (pnpmResult) return "pnpm";
52
- return "npm";
34
+ const userAgent = process.env.npm_config_user_agent;
35
+ if (userAgent) {
36
+ const pm = matchPM(userAgent);
37
+ if (pm) return pm;
38
+ }
39
+ const execPath = process.env.npm_execpath;
40
+ if (execPath) {
41
+ const pm = matchPM(execPath);
42
+ if (pm) return pm;
43
+ }
44
+ const nodePath = process.env.NODE_PATH;
45
+ if (nodePath) {
46
+ if (/[/\\]\.pnpm[/\\]/.test(nodePath) || /[/\\]pnpm[/\\]/.test(nodePath)) return "pnpm";
47
+ if (/[/\\]\.yarn[/\\]/.test(nodePath)) return "yarn";
48
+ if (/[/\\]\.bun[/\\]/.test(nodePath)) return "bun";
49
+ }
50
+ try {
51
+ const scriptPath = realpathSync(process.argv[1] ?? "");
52
+ if (/[/\\]\.?pnpm[/\\]/.test(scriptPath)) return "pnpm";
53
+ if (/[/\\]\.?yarn[/\\]/.test(scriptPath)) return "yarn";
54
+ if (/[/\\]\.?bun[/\\]/.test(scriptPath)) return "bun";
55
+ } catch {}
56
+ if (await new Promise((resolve) => {
57
+ execFile("pnpm", [
58
+ "list",
59
+ "-g",
60
+ "--depth=0",
61
+ PACKAGE_NAME
62
+ ], {
63
+ timeout: 3e3,
64
+ shell: USE_SHELL
65
+ }, (error, stdout) => {
66
+ resolve(!error && stdout.includes(PACKAGE_NAME));
67
+ });
68
+ })) return "pnpm";
69
+ return "npm";
53
70
  }
71
+ /**
72
+ * Build the shell command string a user would run to install/update globally.
73
+ */
54
74
  function getInstallCommand(pm, version) {
55
- const pkg = version ? `${PACKAGE_NAME}@${version}` : `${PACKAGE_NAME}@latest`;
56
- switch (pm) {
57
- case "pnpm":
58
- return `pnpm add -g ${pkg}`;
59
- case "yarn":
60
- return `yarn global add ${pkg}`;
61
- case "bun":
62
- return `bun add -g ${pkg}`;
63
- default:
64
- return `npm install -g ${pkg}`;
65
- }
75
+ const pkg = version ? `${PACKAGE_NAME}@${version}` : `${PACKAGE_NAME}@latest`;
76
+ switch (pm) {
77
+ case "pnpm": return `pnpm add -g ${pkg}`;
78
+ case "yarn": return `yarn global add ${pkg}`;
79
+ case "bun": return `bun add -g ${pkg}`;
80
+ default: return `npm install -g ${pkg}`;
81
+ }
66
82
  }
83
+ /**
84
+ * Read the current version, injected at build time by tsdown's `define` option.
85
+ * Falls back to reading package.json at runtime (e.g. when running from source with tsx).
86
+ */
67
87
  function getCurrentVersion() {
68
- if (typeof MASTRACODE_VERSION !== "undefined") {
69
- return MASTRACODE_VERSION;
70
- }
71
- const dir = dirname(fileURLToPath(import.meta.url));
72
- const pkgPath = resolve(dir, "../../package.json");
73
- const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
74
- return pkg.version;
88
+ if (typeof MASTRACODE_VERSION !== "undefined") return MASTRACODE_VERSION;
89
+ const pkgPath = resolve(dirname(fileURLToPath(import.meta.url)), "../../package.json");
90
+ return JSON.parse(readFileSync(pkgPath, "utf-8")).version;
75
91
  }
92
+ /**
93
+ * Fetch the latest published version from npm.
94
+ * Returns null if the fetch fails (network error, timeout, etc.).
95
+ */
76
96
  async function fetchLatestVersion() {
77
- if (process.env.MASTRACODE_UPDATE_LATEST_VERSION) return process.env.MASTRACODE_UPDATE_LATEST_VERSION;
78
- try {
79
- const controller = new AbortController();
80
- const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
81
- const res = await fetch(NPM_REGISTRY_URL, { signal: controller.signal });
82
- clearTimeout(timeout);
83
- if (!res.ok) return null;
84
- const data = await res.json();
85
- return data.version ?? null;
86
- } catch {
87
- return null;
88
- }
97
+ if (process.env.MASTRACODE_UPDATE_LATEST_VERSION) return process.env.MASTRACODE_UPDATE_LATEST_VERSION;
98
+ try {
99
+ const controller = new AbortController();
100
+ const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
101
+ const res = await fetch(NPM_REGISTRY_URL, { signal: controller.signal });
102
+ clearTimeout(timeout);
103
+ if (!res.ok) return null;
104
+ return (await res.json()).version ?? null;
105
+ } catch {
106
+ return null;
107
+ }
89
108
  }
109
+ /**
110
+ * Simple semver comparison: returns true if `latest` is newer than `current`.
111
+ * Handles standard x.y.z versions. Ignores pre-release tags.
112
+ */
90
113
  function isNewerVersion(current, latest) {
91
- const parse = (v) => v.replace(/^v/, "").split("-")[0].split(".").map((s) => {
92
- const n = Number(s);
93
- return Number.isFinite(n) ? n : 0;
94
- });
95
- const [cMajor = 0, cMinor = 0, cPatch = 0] = parse(current);
96
- const [lMajor = 0, lMinor = 0, lPatch = 0] = parse(latest);
97
- if (lMajor !== cMajor) return lMajor > cMajor;
98
- if (lMinor !== cMinor) return lMinor > cMinor;
99
- return lPatch > cPatch;
114
+ const parse = (v) => v.replace(/^v/, "").split("-")[0].split(".").map((s) => {
115
+ const n = Number(s);
116
+ return Number.isFinite(n) ? n : 0;
117
+ });
118
+ const [cMajor = 0, cMinor = 0, cPatch = 0] = parse(current);
119
+ const [lMajor = 0, lMinor = 0, lPatch = 0] = parse(latest);
120
+ if (lMajor !== cMajor) return lMajor > cMajor;
121
+ if (lMinor !== cMinor) return lMinor > cMinor;
122
+ return lPatch > cPatch;
100
123
  }
124
+ /** Max entries to show in the changelog summary. */
101
125
  const MAX_CHANGELOG_ENTRIES = 20;
126
+ /**
127
+ * Fetch the CHANGELOG.md for a specific published version from the npm CDN
128
+ * and extract a human-readable summary of changes.
129
+ * Returns null if the fetch fails or the changelog can't be parsed.
130
+ */
102
131
  async function fetchChangelog(version) {
103
- if (process.env.MASTRACODE_UPDATE_CHANGELOG) return process.env.MASTRACODE_UPDATE_CHANGELOG;
104
- try {
105
- const url = `https://unpkg.com/${PACKAGE_NAME}@${version}/CHANGELOG.md`;
106
- const controller = new AbortController();
107
- const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
108
- const res = await fetch(url, { signal: controller.signal });
109
- clearTimeout(timeout);
110
- if (!res.ok) return null;
111
- const text = await res.text();
112
- return parseChangelog(text, version);
113
- } catch {
114
- return null;
115
- }
132
+ if (process.env.MASTRACODE_UPDATE_CHANGELOG) return process.env.MASTRACODE_UPDATE_CHANGELOG;
133
+ try {
134
+ const url = `https://unpkg.com/${PACKAGE_NAME}@${version}/CHANGELOG.md`;
135
+ const controller = new AbortController();
136
+ const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
137
+ const res = await fetch(url, { signal: controller.signal });
138
+ clearTimeout(timeout);
139
+ if (!res.ok) return null;
140
+ return parseChangelog(await res.text(), version);
141
+ } catch {
142
+ return null;
143
+ }
116
144
  }
145
+ /**
146
+ * Extract the changelog section for a specific version and format it
147
+ * as a concise bullet list suitable for terminal display.
148
+ */
117
149
  function parseChangelog(markdown, version) {
118
- const versionHeader = `## ${version}`;
119
- const startIdx = markdown.indexOf(versionHeader);
120
- if (startIdx === -1) return null;
121
- const afterHeader = startIdx + versionHeader.length;
122
- const nextHeaderIdx = markdown.indexOf("\n## ", afterHeader);
123
- const section = nextHeaderIdx === -1 ? markdown.slice(afterHeader) : markdown.slice(afterHeader, nextHeaderIdx);
124
- const lines = section.split("\n");
125
- const entries = [];
126
- let skipIndented = false;
127
- for (let i = 0; i < lines.length; i++) {
128
- const raw = lines[i];
129
- const trimmed = raw.trim();
130
- const isTopLevel = raw === trimmed && trimmed.startsWith("- ");
131
- if (!isTopLevel) {
132
- if (skipIndented && /^\s+-\s/.test(raw)) continue;
133
- skipIndented = false;
134
- continue;
135
- }
136
- if (/^- Updated dependenc/i.test(trimmed)) {
137
- skipIndented = true;
138
- continue;
139
- }
140
- skipIndented = false;
141
- let entry = trimmed.slice(2);
142
- entry = entry.replace(/\[([^\]]+)\]\([^)]+\)/g, "$1");
143
- entry = entry.replace(/\s*\(#\d+\)\s*/g, " ");
144
- entry = entry.replace(/\s*\(`[a-f0-9]+`\)\s*/g, " ");
145
- entry = entry.replace(/\.\s*$/, "");
146
- entry = entry.trim();
147
- if (entry) entries.push(entry);
148
- if (entries.length >= MAX_CHANGELOG_ENTRIES) break;
149
- }
150
- if (entries.length === 0) return null;
151
- return entries.map((e) => ` \u2022 ${e}`).join("\n");
150
+ const versionHeader = `## ${version}`;
151
+ const startIdx = markdown.indexOf(versionHeader);
152
+ if (startIdx === -1) return null;
153
+ const afterHeader = startIdx + versionHeader.length;
154
+ const nextHeaderIdx = markdown.indexOf("\n## ", afterHeader);
155
+ const lines = (nextHeaderIdx === -1 ? markdown.slice(afterHeader) : markdown.slice(afterHeader, nextHeaderIdx)).split("\n");
156
+ const entries = [];
157
+ let skipIndented = false;
158
+ for (let i = 0; i < lines.length; i++) {
159
+ const raw = lines[i];
160
+ const trimmed = raw.trim();
161
+ if (!(raw === trimmed && trimmed.startsWith("- "))) {
162
+ if (skipIndented && /^\s+-\s/.test(raw)) continue;
163
+ skipIndented = false;
164
+ continue;
165
+ }
166
+ if (/^- Updated dependenc/i.test(trimmed)) {
167
+ skipIndented = true;
168
+ continue;
169
+ }
170
+ skipIndented = false;
171
+ let entry = trimmed.slice(2);
172
+ entry = entry.replace(/\[([^\]]+)\]\([^)]+\)/g, "$1");
173
+ entry = entry.replace(/\s*\(#\d+\)\s*/g, " ");
174
+ entry = entry.replace(/\s*\(`[a-f0-9]+`\)\s*/g, " ");
175
+ entry = entry.replace(/\.\s*$/, "");
176
+ entry = entry.trim();
177
+ if (entry) entries.push(entry);
178
+ if (entries.length >= MAX_CHANGELOG_ENTRIES) break;
179
+ }
180
+ if (entries.length === 0) return null;
181
+ return entries.map((e) => ` • ${e}`).join("\n");
152
182
  }
183
+ /**
184
+ * Run the appropriate global install command to update mastracode.
185
+ * Exit code 0 does not prove the running binary changed (the install may land
186
+ * in a location the PATH shim doesn't use) — verify with {@link locateOwnInstall}.
187
+ */
153
188
  function runUpdate(pm, targetVersion) {
154
- return execUpdate(pm, buildInstallArgs(pm, targetVersion));
189
+ return execUpdate(pm, buildInstallArgs(pm, targetVersion));
155
190
  }
156
191
  function execUpdate(cmd, args) {
157
- return new Promise((resolve2) => {
158
- execFile(cmd, args, { timeout: 6e4, shell: USE_SHELL }, (error, _stdout, stderr) => {
159
- const captured = (stderr ?? "").trim();
160
- if (error) {
161
- resolve2({ ok: false, stderr: captured || error.message });
162
- } else {
163
- resolve2({ ok: true, stderr: captured || void 0 });
164
- }
165
- });
166
- });
192
+ return new Promise((resolve) => {
193
+ execFile(cmd, args, {
194
+ timeout: 6e4,
195
+ shell: USE_SHELL
196
+ }, (error, _stdout, stderr) => {
197
+ const captured = (stderr ?? "").trim();
198
+ if (error) resolve({
199
+ ok: false,
200
+ stderr: captured || error.message
201
+ });
202
+ else resolve({
203
+ ok: true,
204
+ stderr: captured || void 0
205
+ });
206
+ });
207
+ });
167
208
  }
168
209
  function buildInstallArgs(pm, version) {
169
- const pkg = `${PACKAGE_NAME}@${version}`;
170
- switch (pm) {
171
- case "pnpm":
172
- return ["add", "-g", pkg];
173
- case "yarn":
174
- return ["global", "add", pkg];
175
- case "bun":
176
- return ["add", "-g", pkg];
177
- default:
178
- return ["install", "-g", pkg];
179
- }
210
+ const pkg = `${PACKAGE_NAME}@${version}`;
211
+ switch (pm) {
212
+ case "pnpm": return [
213
+ "add",
214
+ "-g",
215
+ pkg
216
+ ];
217
+ case "yarn": return [
218
+ "global",
219
+ "add",
220
+ pkg
221
+ ];
222
+ case "bun": return [
223
+ "add",
224
+ "-g",
225
+ pkg
226
+ ];
227
+ default: return [
228
+ "install",
229
+ "-g",
230
+ pkg
231
+ ];
232
+ }
180
233
  }
181
- const MAX_UPDATE_ERROR_LINES = 5;
182
234
  function formatUpdaterError(stderr) {
183
- if (!stderr) return null;
184
- const lines = stderr.split("\n").map((line) => line.trimEnd()).filter((line) => line.trim().length > 0);
185
- if (lines.length === 0) return null;
186
- return lines.slice(-MAX_UPDATE_ERROR_LINES).join("\n");
235
+ if (!stderr) return null;
236
+ const lines = stderr.split("\n").map((line) => line.trimEnd()).filter((line) => line.trim().length > 0);
237
+ if (lines.length === 0) return null;
238
+ return lines.slice(-5).join("\n");
187
239
  }
240
+ /**
241
+ * Find the installed mastracode package the running binary belongs to (walking
242
+ * up from `process.argv[1]`) and read its version fresh from disk. Returns
243
+ * null when it can't be determined, e.g. when running from source.
244
+ */
188
245
  function locateOwnInstall() {
189
- const entry = process.argv[1];
190
- if (!entry) return null;
191
- let dir;
192
- try {
193
- dir = dirname(realpathSync(entry));
194
- } catch {
195
- return null;
196
- }
197
- let previous = "";
198
- while (dir && dir !== previous) {
199
- try {
200
- const pkg = JSON.parse(readFileSync(resolve(dir, "package.json"), "utf-8"));
201
- if (pkg.name === PACKAGE_NAME) {
202
- return { dir, version: typeof pkg.version === "string" ? pkg.version : null };
203
- }
204
- } catch {
205
- }
206
- previous = dir;
207
- dir = dirname(dir);
208
- }
209
- return null;
246
+ const entry = process.argv[1];
247
+ if (!entry) return null;
248
+ let dir;
249
+ try {
250
+ dir = dirname(realpathSync(entry));
251
+ } catch {
252
+ return null;
253
+ }
254
+ let previous = "";
255
+ while (dir && dir !== previous) {
256
+ try {
257
+ const pkg = JSON.parse(readFileSync(resolve(dir, "package.json"), "utf-8"));
258
+ if (pkg.name === PACKAGE_NAME) return {
259
+ dir,
260
+ version: typeof pkg.version === "string" ? pkg.version : null
261
+ };
262
+ } catch {}
263
+ previous = dir;
264
+ dir = dirname(dir);
265
+ }
266
+ return null;
210
267
  }
268
+ /**
269
+ * Decide what to tell the user after {@link runUpdate}: `updated` when the
270
+ * on-disk version matches the target (or can't be determined), `unchanged`
271
+ * when the package manager succeeded but the running install didn't change,
272
+ * `failed` on error (with the package manager's stderr).
273
+ */
211
274
  function resolveUpdateOutcome(opts) {
212
- const { pm, targetVersion, result, install } = opts;
213
- const cmd = opts.manualCommand ?? getInstallCommand(pm, targetVersion);
214
- if (!result.ok) {
215
- const details = formatUpdaterError(result.stderr);
216
- let message = `Auto-update failed. Run \`${cmd}\` manually.`;
217
- if (details) message += `
218
-
219
- ${details}`;
220
- return { status: "failed", message };
221
- }
222
- if (install?.version != null && install.version !== targetVersion) {
223
- const message = opts.manualCommand ? `The update ran, but the Mastra Code you are running (at ${install.dir}) is still v${install.version}. Try \`${cmd}\` manually.` : `The update installed, but the Mastra Code you are running (at ${install.dir}) is still v${install.version} \u2014 it looks like it is managed by another tool. Update it with that tool, or try \`${cmd}\`.`;
224
- return { status: "unchanged", message };
225
- }
226
- return { status: "updated", message: `Updated to v${targetVersion}. Please restart Mastra Code.` };
275
+ const { pm, targetVersion, result, install } = opts;
276
+ const cmd = opts.manualCommand ?? getInstallCommand(pm, targetVersion);
277
+ if (!result.ok) {
278
+ const details = formatUpdaterError(result.stderr);
279
+ let message = `Auto-update failed. Run \`${cmd}\` manually.`;
280
+ if (details) message += `\n\n${details}`;
281
+ return {
282
+ status: "failed",
283
+ message
284
+ };
285
+ }
286
+ if (install?.version != null && install.version !== targetVersion) return {
287
+ status: "unchanged",
288
+ message: opts.manualCommand ? `The update ran, but the Mastra Code you are running (at ${install.dir}) is still v${install.version}. Try \`${cmd}\` manually.` : `The update installed, but the Mastra Code you are running (at ${install.dir}) is still v${install.version} — it looks like it is managed by another tool. Update it with that tool, or try \`${cmd}\`.`
289
+ };
290
+ return {
291
+ status: "updated",
292
+ message: `Updated to v${targetVersion}. Please restart Mastra Code.`
293
+ };
227
294
  }
295
+ /** Global node_modules directory the package manager installs into, or null when unknown. */
228
296
  function getGlobalRoot(pm) {
229
- const args = pm === "yarn" ? ["global", "dir"] : ["root", "-g"];
230
- return new Promise((res) => {
231
- execFile(pm, args, { timeout: 1e4, shell: USE_SHELL }, (error, stdout) => {
232
- const out = (stdout ?? "").trim().split("\n").pop()?.trim();
233
- if (error || !out) return res(null);
234
- res(pm === "yarn" ? resolve(out, "node_modules") : out);
235
- });
236
- });
297
+ const args = pm === "yarn" ? ["global", "dir"] : ["root", "-g"];
298
+ return new Promise((res) => {
299
+ execFile(pm, args, {
300
+ timeout: 1e4,
301
+ shell: USE_SHELL
302
+ }, (error, stdout) => {
303
+ const out = (stdout ?? "").trim().split("\n").pop()?.trim();
304
+ if (error || !out) return res(null);
305
+ res(pm === "yarn" ? resolve(out, "node_modules") : out);
306
+ });
307
+ });
237
308
  }
309
+ /**
310
+ * Whether updating via `pm` would touch the install the running binary uses.
311
+ * Fail-open: returns true when either side can't be determined, so the update
312
+ * proceeds and the post-install verification has the final word.
313
+ */
238
314
  async function isOwnInstallManagedBy(pm, install) {
239
- if (!install) return true;
240
- const root = await getGlobalRoot(pm);
241
- if (!root) return true;
242
- try {
243
- return realpathSync(resolve(root, PACKAGE_NAME)) === install.dir;
244
- } catch {
245
- return false;
246
- }
315
+ if (!install) return true;
316
+ const root = await getGlobalRoot(pm);
317
+ if (!root) return true;
318
+ try {
319
+ return realpathSync(resolve(root, PACKAGE_NAME)) === install.dir;
320
+ } catch {
321
+ return false;
322
+ }
247
323
  }
248
324
  function findInstallOwner(dir, version) {
249
- if (dir.startsWith(join(homedir(), ".vite-plus") + sep)) {
250
- return {
251
- name: "vite-plus",
252
- exec: { cmd: "vp", args: ["install", "-g", `${PACKAGE_NAME}@${version}`] },
253
- command: `vp install -g ${PACKAGE_NAME}@${version}`
254
- };
255
- }
256
- if (dir.split(sep).includes("Cellar")) {
257
- return { name: "Homebrew", command: `brew upgrade ${PACKAGE_NAME}` };
258
- }
259
- return null;
325
+ if (dir.startsWith(join(homedir(), ".vite-plus") + sep)) return {
326
+ name: "vite-plus",
327
+ exec: {
328
+ cmd: "vp",
329
+ args: [
330
+ "install",
331
+ "-g",
332
+ `${PACKAGE_NAME}@${version}`
333
+ ]
334
+ },
335
+ command: `vp install -g ${PACKAGE_NAME}@${version}`
336
+ };
337
+ if (dir.split(sep).includes("Cellar")) return {
338
+ name: "Homebrew",
339
+ command: `brew upgrade ${PACKAGE_NAME}`
340
+ };
341
+ return null;
260
342
  }
343
+ /**
344
+ * Update mastracode and verify the result: delegates to the tool that owns the
345
+ * running install when we recognize it, skips the install when it isn't
346
+ * managed by `pm`, otherwise runs the package manager. Every executed update
347
+ * is verified against the on-disk version.
348
+ */
261
349
  async function performUpdate(pm, targetVersion) {
262
- if (!/^[\w.+-]+$/.test(targetVersion)) {
263
- return { status: "failed", message: `Auto-update aborted: unexpected version "${targetVersion}".` };
264
- }
265
- const install = locateOwnInstall();
266
- const owner = install ? findInstallOwner(install.dir, targetVersion) : null;
267
- if (owner) {
268
- if (!owner.exec) {
269
- const message = `Your Mastra Code install (at ${install.dir}) is managed by ${owner.name}. Update it with \`${owner.command}\`.`;
270
- return { status: "unchanged", message };
271
- }
272
- const result2 = await execUpdate(owner.exec.cmd, owner.exec.args);
273
- return resolveUpdateOutcome({
274
- pm,
275
- targetVersion,
276
- result: result2,
277
- install: locateOwnInstall(),
278
- manualCommand: owner.command
279
- });
280
- }
281
- if (!await isOwnInstallManagedBy(pm, install)) {
282
- const message = `Your Mastra Code install (at ${install.dir}) is not managed by ${pm} \u2014 it looks like it was installed by another tool. Update it with that tool, or try \`${getInstallCommand(pm, targetVersion)}\`.`;
283
- return { status: "unchanged", message };
284
- }
285
- const result = await runUpdate(pm, targetVersion);
286
- return resolveUpdateOutcome({ pm, targetVersion, result, install: locateOwnInstall() });
350
+ if (!/^[\w.+-]+$/.test(targetVersion)) return {
351
+ status: "failed",
352
+ message: `Auto-update aborted: unexpected version "${targetVersion}".`
353
+ };
354
+ const install = locateOwnInstall();
355
+ const owner = install ? findInstallOwner(install.dir, targetVersion) : null;
356
+ if (owner) {
357
+ if (!owner.exec) return {
358
+ status: "unchanged",
359
+ message: `Your Mastra Code install (at ${install.dir}) is managed by ${owner.name}. Update it with \`${owner.command}\`.`
360
+ };
361
+ return resolveUpdateOutcome({
362
+ pm,
363
+ targetVersion,
364
+ result: await execUpdate(owner.exec.cmd, owner.exec.args),
365
+ install: locateOwnInstall(),
366
+ manualCommand: owner.command
367
+ });
368
+ }
369
+ if (!await isOwnInstallManagedBy(pm, install)) return {
370
+ status: "unchanged",
371
+ message: `Your Mastra Code install (at ${install.dir}) is not managed by ${pm} — it looks like it was installed by another tool. Update it with that tool, or try \`${getInstallCommand(pm, targetVersion)}\`.`
372
+ };
373
+ return resolveUpdateOutcome({
374
+ pm,
375
+ targetVersion,
376
+ result: await runUpdate(pm, targetVersion),
377
+ install: locateOwnInstall()
378
+ });
287
379
  }
288
- export {
289
- detectPackageManager,
290
- fetchChangelog,
291
- fetchLatestVersion,
292
- getCurrentVersion,
293
- getInstallCommand,
294
- isNewerVersion,
295
- locateOwnInstall,
296
- parseChangelog,
297
- performUpdate,
298
- resolveUpdateOutcome,
299
- runUpdate
300
- };
380
+ //#endregion
381
+ export { detectPackageManager, fetchChangelog, fetchLatestVersion, getCurrentVersion, getInstallCommand, isNewerVersion, locateOwnInstall, parseChangelog, performUpdate, resolveUpdateOutcome, runUpdate };
382
+
301
383
  //# sourceMappingURL=update-check.js.map