@evalops/maestro 0.10.47 → 0.10.48
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/README.md +4 -0
- package/dist/audit/logger.d.ts +1 -1
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +2 -0
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/commands/update.d.ts +12 -0
- package/dist/cli/commands/update.d.ts.map +1 -0
- package/dist/cli/commands/update.js +148 -0
- package/dist/cli/commands/update.js.map +1 -0
- package/dist/cli/help.d.ts.map +1 -1
- package/dist/cli/help.js +4 -0
- package/dist/cli/help.js.map +1 -1
- package/dist/cli-tui/commands/command-catalog.js +2 -2
- package/dist/cli-tui/commands/command-catalog.js.map +1 -1
- package/dist/cli-tui/commands/subcommands/ui-commands.d.ts +1 -1
- package/dist/cli-tui/commands/subcommands/ui-commands.js +2 -2
- package/dist/cli-tui/commands/subcommands/ui-commands.js.map +1 -1
- package/dist/cli-tui/footer.d.ts.map +1 -1
- package/dist/cli-tui/footer.js +1 -1
- package/dist/cli-tui/footer.js.map +1 -1
- package/dist/cli-tui/tui-renderer/ui-state-controller.d.ts +1 -1
- package/dist/cli-tui/tui-renderer/ui-state-controller.d.ts.map +1 -1
- package/dist/cli-tui/tui-renderer/ui-state-controller.js +5 -11
- package/dist/cli-tui/tui-renderer/ui-state-controller.js.map +1 -1
- package/dist/cli-tui/tui-renderer.d.ts.map +1 -1
- package/dist/cli-tui/tui-renderer.js +1 -1
- package/dist/cli-tui/tui-renderer.js.map +1 -1
- package/dist/cli-tui/ui-state.js +1 -1
- package/dist/cli-tui/ui-state.js.map +1 -1
- package/dist/cli-tui/utils/footer-utils.d.ts +1 -1
- package/dist/cli-tui/utils/footer-utils.d.ts.map +1 -1
- package/dist/cli-tui/utils/footer-utils.js.map +1 -1
- package/dist/cli.js +4072 -3450
- package/dist/cli.js.map +1 -1
- package/dist/codex/app-server-client.d.ts +8 -0
- package/dist/codex/app-server-client.d.ts.map +1 -1
- package/dist/codex/app-server-client.js +49 -3
- package/dist/codex/app-server-client.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +5 -0
- package/dist/main.js.map +1 -1
- package/dist/models/config-loader.d.ts +13 -13
- package/dist/node_modules/@evalops/contracts/dist/scenario.d.ts +2 -0
- package/dist/node_modules/@evalops/contracts/dist/scenario.d.ts.map +1 -1
- package/dist/node_modules/@evalops/contracts/dist/scenario.js.map +1 -1
- package/dist/node_modules/@evalops/contracts/package.json +1 -1
- package/dist/node_modules/@evalops/tui/package.json +1 -1
- package/dist/platform/operating-plane-client.d.ts +3 -3
- package/dist/platform/operating-plane-client.d.ts.map +1 -1
- package/dist/platform/operating-plane-client.js.map +1 -1
- package/dist/platform/operating-plane-summary.js +3 -6
- package/dist/platform/operating-plane-summary.js.map +1 -1
- package/dist/server/agent-trajectory-scenarios.d.ts.map +1 -1
- package/dist/server/agent-trajectory-scenarios.js +29 -6
- package/dist/server/agent-trajectory-scenarios.js.map +1 -1
- package/dist/server/handlers/ui.d.ts.map +1 -1
- package/dist/server/handlers/ui.js +5 -5
- package/dist/server/handlers/ui.js.map +1 -1
- package/dist/server/stores/ui-store.d.ts.map +1 -1
- package/dist/server/stores/ui-store.js +8 -1
- package/dist/server/stores/ui-store.js.map +1 -1
- package/dist/tools/background/task-types.d.ts +1 -1
- package/dist/update/check.d.ts +2 -0
- package/dist/update/check.d.ts.map +1 -1
- package/dist/update/check.js +100 -41
- package/dist/update/check.js.map +1 -1
- package/dist/update/startup-refresh.d.ts +56 -0
- package/dist/update/startup-refresh.d.ts.map +1 -0
- package/dist/update/startup-refresh.js +321 -0
- package/dist/update/startup-refresh.js.map +1 -0
- package/dist/version.json +2 -2
- package/package.json +297 -296
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../src/update/check.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../src/update/check.ts"],"names":[],"mappings":"AAaA,MAAM,WAAW,iBAAiB;IACjC,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iBAAiB,EAAE,OAAO,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED,UAAU,qBAAqB;IAC9B,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CAChB;AAgBD,eAAO,MAAM,iBAAiB,GAC7B,UAAS,IAAI,CAAC,qBAAqB,EAAE,KAAK,GAAG,MAAM,CAAM,EACzD,MAAK,MAAM,CAAC,UAAwB,KAClC,MAAM,EAgBR,CAAC;AA4FF,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAmBvE;AAED,wBAAsB,cAAc,CACnC,cAAc,EAAE,MAAM,EACtB,OAAO,GAAE,qBAA0B,GACjC,OAAO,CAAC,iBAAiB,CAAC,CAoG5B"}
|
package/dist/update/check.js
CHANGED
|
@@ -1,6 +1,37 @@
|
|
|
1
|
+
import { getPackageName } from "../package-metadata.js";
|
|
1
2
|
import { withTimeout } from "../utils/async.js";
|
|
2
|
-
const
|
|
3
|
+
const DEFAULT_GCS_UPDATE_URL = "https://storage.googleapis.com/evalops-prod-maestro-releases/maestro/version.json";
|
|
4
|
+
const NPM_REGISTRY_BASE_URL = "https://registry.npmjs.org";
|
|
3
5
|
const DEFAULT_TIMEOUT_MS = 5_000;
|
|
6
|
+
const splitUrlList = (value) => {
|
|
7
|
+
if (!value) {
|
|
8
|
+
return [];
|
|
9
|
+
}
|
|
10
|
+
return value
|
|
11
|
+
.split(/[\n,]/u)
|
|
12
|
+
.map((url) => url.trim())
|
|
13
|
+
.filter(Boolean);
|
|
14
|
+
};
|
|
15
|
+
const npmLatestUrl = (packageName = getPackageName()) => {
|
|
16
|
+
return `${NPM_REGISTRY_BASE_URL}/${encodeURIComponent(packageName)}/latest`;
|
|
17
|
+
};
|
|
18
|
+
export const resolveUpdateUrls = (options = {}, env = process.env) => {
|
|
19
|
+
const explicitUrls = options.urls?.map((url) => url.trim()).filter(Boolean);
|
|
20
|
+
if (explicitUrls && explicitUrls.length > 0) {
|
|
21
|
+
return explicitUrls;
|
|
22
|
+
}
|
|
23
|
+
if (options.url?.trim()) {
|
|
24
|
+
return [options.url.trim()];
|
|
25
|
+
}
|
|
26
|
+
const envUrls = splitUrlList(env.MAESTRO_UPDATE_URLS);
|
|
27
|
+
if (envUrls.length > 0) {
|
|
28
|
+
return envUrls;
|
|
29
|
+
}
|
|
30
|
+
if (env.MAESTRO_UPDATE_URL?.trim()) {
|
|
31
|
+
return [env.MAESTRO_UPDATE_URL.trim()];
|
|
32
|
+
}
|
|
33
|
+
return [DEFAULT_GCS_UPDATE_URL, npmLatestUrl()];
|
|
34
|
+
};
|
|
4
35
|
const toErrorMessage = (error) => {
|
|
5
36
|
if (error instanceof Error) {
|
|
6
37
|
return error.message;
|
|
@@ -102,58 +133,86 @@ export function compareVersions(current, latest) {
|
|
|
102
133
|
return comparePreRelease(currentPre, latestPre);
|
|
103
134
|
}
|
|
104
135
|
export async function checkForUpdate(currentVersion, options = {}) {
|
|
105
|
-
const
|
|
136
|
+
const urls = resolveUpdateUrls(options);
|
|
106
137
|
const fetchImpl = options.fetch ?? fetch;
|
|
107
138
|
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
if (!response.ok) {
|
|
113
|
-
return {
|
|
114
|
-
currentVersion,
|
|
115
|
-
isUpdateAvailable: false,
|
|
116
|
-
sourceUrl: url,
|
|
117
|
-
error: `Update check failed (${response.status} ${response.statusText || ""})`.trim(),
|
|
118
|
-
};
|
|
119
|
-
}
|
|
120
|
-
let payload;
|
|
139
|
+
let lastResult = null;
|
|
140
|
+
let bestUpdateResult = null;
|
|
141
|
+
let bestCurrentResult = null;
|
|
142
|
+
for (const url of urls) {
|
|
121
143
|
try {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
144
|
+
const response = await withTimeout(fetchImpl(url, {
|
|
145
|
+
headers: { Accept: "application/json" },
|
|
146
|
+
}), timeoutMs, `Update check timed out after ${timeoutMs}ms`);
|
|
147
|
+
if (!response.ok) {
|
|
148
|
+
lastResult = {
|
|
149
|
+
currentVersion,
|
|
150
|
+
isUpdateAvailable: false,
|
|
151
|
+
sourceUrl: url,
|
|
152
|
+
error: `Update check failed (${response.status} ${response.statusText || ""})`.trim(),
|
|
153
|
+
};
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
let payload;
|
|
157
|
+
try {
|
|
158
|
+
payload = (await response.json());
|
|
159
|
+
}
|
|
160
|
+
catch (error) {
|
|
161
|
+
lastResult = {
|
|
162
|
+
currentVersion,
|
|
163
|
+
isUpdateAvailable: false,
|
|
164
|
+
sourceUrl: url,
|
|
165
|
+
error: `Invalid update metadata: ${toErrorMessage(error)}`,
|
|
166
|
+
};
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
if (!payload || typeof payload.version !== "string") {
|
|
170
|
+
lastResult = {
|
|
171
|
+
currentVersion,
|
|
172
|
+
isUpdateAvailable: false,
|
|
173
|
+
sourceUrl: url,
|
|
174
|
+
error: "Update metadata missing version field",
|
|
175
|
+
};
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
const latestVersion = payload.version.trim();
|
|
179
|
+
const comparison = compareVersions(currentVersion.trim(), latestVersion);
|
|
180
|
+
const result = {
|
|
126
181
|
currentVersion,
|
|
127
|
-
|
|
182
|
+
latestVersion,
|
|
183
|
+
notes: normalizeNotes(payload.notes),
|
|
184
|
+
isUpdateAvailable: comparison < 0,
|
|
128
185
|
sourceUrl: url,
|
|
129
|
-
error: `Invalid update metadata: ${toErrorMessage(error)}`,
|
|
130
186
|
};
|
|
187
|
+
lastResult = result;
|
|
188
|
+
if (result.isUpdateAvailable) {
|
|
189
|
+
if (!bestUpdateResult ||
|
|
190
|
+
compareVersions(bestUpdateResult.latestVersion ?? currentVersion, latestVersion) < 0) {
|
|
191
|
+
bestUpdateResult = result;
|
|
192
|
+
}
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
if (!bestCurrentResult ||
|
|
196
|
+
compareVersions(bestCurrentResult.latestVersion ?? currentVersion, latestVersion) < 0) {
|
|
197
|
+
bestCurrentResult = result;
|
|
198
|
+
}
|
|
131
199
|
}
|
|
132
|
-
|
|
133
|
-
|
|
200
|
+
catch (error) {
|
|
201
|
+
lastResult = {
|
|
134
202
|
currentVersion,
|
|
135
203
|
isUpdateAvailable: false,
|
|
136
204
|
sourceUrl: url,
|
|
137
|
-
error:
|
|
205
|
+
error: toErrorMessage(error),
|
|
138
206
|
};
|
|
139
207
|
}
|
|
140
|
-
const latestVersion = payload.version.trim();
|
|
141
|
-
const comparison = compareVersions(currentVersion.trim(), latestVersion);
|
|
142
|
-
return {
|
|
143
|
-
currentVersion,
|
|
144
|
-
latestVersion,
|
|
145
|
-
notes: normalizeNotes(payload.notes),
|
|
146
|
-
isUpdateAvailable: comparison < 0,
|
|
147
|
-
sourceUrl: url,
|
|
148
|
-
};
|
|
149
|
-
}
|
|
150
|
-
catch (error) {
|
|
151
|
-
return {
|
|
152
|
-
currentVersion,
|
|
153
|
-
isUpdateAvailable: false,
|
|
154
|
-
sourceUrl: url,
|
|
155
|
-
error: toErrorMessage(error),
|
|
156
|
-
};
|
|
157
208
|
}
|
|
209
|
+
return (bestUpdateResult ??
|
|
210
|
+
bestCurrentResult ??
|
|
211
|
+
lastResult ?? {
|
|
212
|
+
currentVersion,
|
|
213
|
+
isUpdateAvailable: false,
|
|
214
|
+
sourceUrl: urls[0] ?? "",
|
|
215
|
+
error: "No update metadata sources configured",
|
|
216
|
+
});
|
|
158
217
|
}
|
|
159
218
|
//# sourceMappingURL=check.js.map
|
package/dist/update/check.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"check.js","sourceRoot":"","sources":["../../src/update/check.ts"],"names":[],"mappings":"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","sourcesContent":["import { withTimeout } from \"../utils/async.js\";\n\nconst DEFAULT_UPDATE_URL =\n\t\"https://raw.githubusercontent.com/evalops/hopper/main/public/composer/version.json\";\nconst DEFAULT_TIMEOUT_MS = 5_000;\n\ninterface VersionMetadata {\n\tversion: string;\n\tnotes?: string;\n}\n\nexport interface UpdateCheckResult {\n\tcurrentVersion: string;\n\tlatestVersion?: string;\n\tnotes?: string;\n\tisUpdateAvailable: boolean;\n\tsourceUrl: string;\n\terror?: string;\n}\n\ninterface CheckForUpdateOptions {\n\tfetch?: typeof fetch;\n\ttimeoutMs?: number;\n\turl?: string;\n}\n\nconst toErrorMessage = (error: unknown): string => {\n\tif (error instanceof Error) {\n\t\treturn error.message;\n\t}\n\tif (typeof error === \"string\") {\n\t\treturn error;\n\t}\n\treturn \"Unknown error\";\n};\n\nconst normalizeNotes = (value: unknown): string | undefined => {\n\tif (typeof value !== \"string\") {\n\t\treturn undefined;\n\t}\n\tconst trimmed = value.trim();\n\treturn trimmed.length ? trimmed : undefined;\n};\n\nconst parseNumericSegment = (segment: string): number => {\n\tconst value = Number.parseInt(segment, 10);\n\treturn Number.isNaN(value) ? 0 : value;\n};\n\nconst parseMainSegments = (version: string): number[] => {\n\treturn version.split(\".\").map((segment) => parseNumericSegment(segment));\n};\n\nconst parsePreReleaseSegments = (version: string): string[] => {\n\treturn version ? version.split(\".\") : [];\n};\n\nconst isNumericIdentifier = (segment: string): boolean => {\n\treturn /^[0-9]+$/.test(segment);\n};\n\nconst comparePreRelease = (\n\taSegments: string[],\n\tbSegments: string[],\n): number => {\n\tif (aSegments.length === 0 && bSegments.length === 0) {\n\t\treturn 0;\n\t}\n\tif (aSegments.length === 0) {\n\t\treturn 1;\n\t}\n\tif (bSegments.length === 0) {\n\t\treturn -1;\n\t}\n\tconst length = Math.max(aSegments.length, bSegments.length);\n\tfor (let i = 0; i < length; i++) {\n\t\tconst a = aSegments[i];\n\t\tconst b = bSegments[i];\n\t\tif (a === undefined) {\n\t\t\treturn -1;\n\t\t}\n\t\tif (b === undefined) {\n\t\t\treturn 1;\n\t\t}\n\t\tif (a === b) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst aIsNum = isNumericIdentifier(a);\n\t\tconst bIsNum = isNumericIdentifier(b);\n\t\tif (aIsNum && bIsNum) {\n\t\t\tconst aNum = Number.parseInt(a, 10);\n\t\t\tconst bNum = Number.parseInt(b, 10);\n\t\t\tif (aNum < bNum) {\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t\tif (aNum > bNum) {\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tif (aIsNum && !bIsNum) {\n\t\t\treturn -1;\n\t\t}\n\t\tif (!aIsNum && bIsNum) {\n\t\t\treturn 1;\n\t\t}\n\t\tif (a < b) {\n\t\t\treturn -1;\n\t\t}\n\t\tif (a > b) {\n\t\t\treturn 1;\n\t\t}\n\t}\n\treturn 0;\n};\n\nexport function compareVersions(current: string, latest: string): number {\n\tconst [currentMainPart, currentPreReleasePart = \"\"] = current.split(\"-\", 2);\n\tconst [latestMainPart, latestPreReleasePart = \"\"] = latest.split(\"-\", 2);\n\tconst currentMain = parseMainSegments(currentMainPart!);\n\tconst latestMain = parseMainSegments(latestMainPart!);\n\tconst length = Math.max(currentMain.length, latestMain.length);\n\tfor (let i = 0; i < length; i++) {\n\t\tconst currentValue = currentMain[i] ?? 0;\n\t\tconst latestValue = latestMain[i] ?? 0;\n\t\tif (currentValue < latestValue) {\n\t\t\treturn -1;\n\t\t}\n\t\tif (currentValue > latestValue) {\n\t\t\treturn 1;\n\t\t}\n\t}\n\tconst currentPre = parsePreReleaseSegments(currentPreReleasePart);\n\tconst latestPre = parsePreReleaseSegments(latestPreReleasePart);\n\treturn comparePreRelease(currentPre, latestPre);\n}\n\nexport async function checkForUpdate(\n\tcurrentVersion: string,\n\toptions: CheckForUpdateOptions = {},\n): Promise<UpdateCheckResult> {\n\tconst url =\n\t\toptions.url ?? process.env.MAESTRO_UPDATE_URL ?? DEFAULT_UPDATE_URL;\n\tconst fetchImpl = options.fetch ?? fetch;\n\tconst timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n\n\ttry {\n\t\tconst response = await withTimeout(\n\t\t\tfetchImpl(url, {\n\t\t\t\theaders: { Accept: \"application/json\" },\n\t\t\t}),\n\t\t\ttimeoutMs,\n\t\t\t`Update check timed out after ${timeoutMs}ms`,\n\t\t);\n\n\t\tif (!response.ok) {\n\t\t\treturn {\n\t\t\t\tcurrentVersion,\n\t\t\t\tisUpdateAvailable: false,\n\t\t\t\tsourceUrl: url,\n\t\t\t\terror:\n\t\t\t\t\t`Update check failed (${response.status} ${response.statusText || \"\"})`.trim(),\n\t\t\t};\n\t\t}\n\t\tlet payload: VersionMetadata;\n\t\ttry {\n\t\t\tpayload = (await response.json()) as VersionMetadata;\n\t\t} catch (error) {\n\t\t\treturn {\n\t\t\t\tcurrentVersion,\n\t\t\t\tisUpdateAvailable: false,\n\t\t\t\tsourceUrl: url,\n\t\t\t\terror: `Invalid update metadata: ${toErrorMessage(error)}`,\n\t\t\t};\n\t\t}\n\t\tif (!payload || typeof payload.version !== \"string\") {\n\t\t\treturn {\n\t\t\t\tcurrentVersion,\n\t\t\t\tisUpdateAvailable: false,\n\t\t\t\tsourceUrl: url,\n\t\t\t\terror: \"Update metadata missing version field\",\n\t\t\t};\n\t\t}\n\t\tconst latestVersion = payload.version.trim();\n\t\tconst comparison = compareVersions(currentVersion.trim(), latestVersion);\n\t\treturn {\n\t\t\tcurrentVersion,\n\t\t\tlatestVersion,\n\t\t\tnotes: normalizeNotes(payload.notes),\n\t\t\tisUpdateAvailable: comparison < 0,\n\t\t\tsourceUrl: url,\n\t\t};\n\t} catch (error) {\n\t\treturn {\n\t\t\tcurrentVersion,\n\t\t\tisUpdateAvailable: false,\n\t\t\tsourceUrl: url,\n\t\t\terror: toErrorMessage(error),\n\t\t};\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"check.js","sourceRoot":"","sources":["../../src/update/check.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,MAAM,sBAAsB,GAC3B,mFAAmF,CAAC;AACrF,MAAM,qBAAqB,GAAG,4BAA4B,CAAC;AAC3D,MAAM,kBAAkB,GAAG,KAAK,CAAC;AAuBjC,MAAM,YAAY,GAAG,CAAC,KAAyB,EAAY,EAAE;IAC5D,IAAI,CAAC,KAAK,EAAE,CAAC;QACZ,OAAO,EAAE,CAAC;IACX,CAAC;IACD,OAAO,KAAK;SACV,KAAK,CAAC,QAAQ,CAAC;SACf,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;SACxB,MAAM,CAAC,OAAO,CAAC,CAAC;AACnB,CAAC,CAAC;AAEF,MAAM,YAAY,GAAG,CAAC,WAAW,GAAG,cAAc,EAAE,EAAU,EAAE;IAC/D,OAAO,GAAG,qBAAqB,IAAI,kBAAkB,CAAC,WAAW,CAAC,SAAS,CAAC;AAC7E,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAChC,UAAuD,EAAE,EACzD,MAAyB,OAAO,CAAC,GAAG,EACzB,EAAE;IACb,MAAM,YAAY,GAAG,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC5E,IAAI,YAAY,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7C,OAAO,YAAY,CAAC;IACrB,CAAC;IACD,IAAI,OAAO,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC;QACzB,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;IAC7B,CAAC;IACD,MAAM,OAAO,GAAG,YAAY,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;IACtD,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,OAAO,OAAO,CAAC;IAChB,CAAC;IACD,IAAI,GAAG,CAAC,kBAAkB,EAAE,IAAI,EAAE,EAAE,CAAC;QACpC,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,IAAI,EAAE,CAAC,CAAC;IACxC,CAAC;IACD,OAAO,CAAC,sBAAsB,EAAE,YAAY,EAAE,CAAC,CAAC;AACjD,CAAC,CAAC;AAEF,MAAM,cAAc,GAAG,CAAC,KAAc,EAAU,EAAE;IACjD,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAC5B,OAAO,KAAK,CAAC,OAAO,CAAC;IACtB,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC/B,OAAO,KAAK,CAAC;IACd,CAAC;IACD,OAAO,eAAe,CAAC;AACxB,CAAC,CAAC;AAEF,MAAM,cAAc,GAAG,CAAC,KAAc,EAAsB,EAAE;IAC7D,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC/B,OAAO,SAAS,CAAC;IAClB,CAAC;IACD,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC7B,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;AAC7C,CAAC,CAAC;AAEF,MAAM,mBAAmB,GAAG,CAAC,OAAe,EAAU,EAAE;IACvD,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IAC3C,OAAO,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;AACxC,CAAC,CAAC;AAEF,MAAM,iBAAiB,GAAG,CAAC,OAAe,EAAY,EAAE;IACvD,OAAO,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,mBAAmB,CAAC,OAAO,CAAC,CAAC,CAAC;AAC1E,CAAC,CAAC;AAEF,MAAM,uBAAuB,GAAG,CAAC,OAAe,EAAY,EAAE;IAC7D,OAAO,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AAC1C,CAAC,CAAC;AAEF,MAAM,mBAAmB,GAAG,CAAC,OAAe,EAAW,EAAE;IACxD,OAAO,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;AACjC,CAAC,CAAC;AAEF,MAAM,iBAAiB,GAAG,CACzB,SAAmB,EACnB,SAAmB,EACV,EAAE;IACX,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtD,OAAO,CAAC,CAAC;IACV,CAAC;IACD,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5B,OAAO,CAAC,CAAC;IACV,CAAC;IACD,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5B,OAAO,CAAC,CAAC,CAAC;IACX,CAAC;IACD,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC;IAC5D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACjC,MAAM,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;QACvB,MAAM,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;QACvB,IAAI,CAAC,KAAK,SAAS,EAAE,CAAC;YACrB,OAAO,CAAC,CAAC,CAAC;QACX,CAAC;QACD,IAAI,CAAC,KAAK,SAAS,EAAE,CAAC;YACrB,OAAO,CAAC,CAAC;QACV,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YACb,SAAS;QACV,CAAC;QACD,MAAM,MAAM,GAAG,mBAAmB,CAAC,CAAC,CAAC,CAAC;QACtC,MAAM,MAAM,GAAG,mBAAmB,CAAC,CAAC,CAAC,CAAC;QACtC,IAAI,MAAM,IAAI,MAAM,EAAE,CAAC;YACtB,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACpC,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACpC,IAAI,IAAI,GAAG,IAAI,EAAE,CAAC;gBACjB,OAAO,CAAC,CAAC,CAAC;YACX,CAAC;YACD,IAAI,IAAI,GAAG,IAAI,EAAE,CAAC;gBACjB,OAAO,CAAC,CAAC;YACV,CAAC;YACD,SAAS;QACV,CAAC;QACD,IAAI,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC;YACvB,OAAO,CAAC,CAAC,CAAC;QACX,CAAC;QACD,IAAI,CAAC,MAAM,IAAI,MAAM,EAAE,CAAC;YACvB,OAAO,CAAC,CAAC;QACV,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YACX,OAAO,CAAC,CAAC,CAAC;QACX,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YACX,OAAO,CAAC,CAAC;QACV,CAAC;IACF,CAAC;IACD,OAAO,CAAC,CAAC;AACV,CAAC,CAAC;AAEF,MAAM,UAAU,eAAe,CAAC,OAAe,EAAE,MAAc;IAC9D,MAAM,CAAC,eAAe,EAAE,qBAAqB,GAAG,EAAE,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;IAC5E,MAAM,CAAC,cAAc,EAAE,oBAAoB,GAAG,EAAE,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;IACzE,MAAM,WAAW,GAAG,iBAAiB,CAAC,eAAgB,CAAC,CAAC;IACxD,MAAM,UAAU,GAAG,iBAAiB,CAAC,cAAe,CAAC,CAAC;IACtD,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,MAAM,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;IAC/D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACjC,MAAM,YAAY,GAAG,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACzC,MAAM,WAAW,GAAG,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACvC,IAAI,YAAY,GAAG,WAAW,EAAE,CAAC;YAChC,OAAO,CAAC,CAAC,CAAC;QACX,CAAC;QACD,IAAI,YAAY,GAAG,WAAW,EAAE,CAAC;YAChC,OAAO,CAAC,CAAC;QACV,CAAC;IACF,CAAC;IACD,MAAM,UAAU,GAAG,uBAAuB,CAAC,qBAAqB,CAAC,CAAC;IAClE,MAAM,SAAS,GAAG,uBAAuB,CAAC,oBAAoB,CAAC,CAAC;IAChE,OAAO,iBAAiB,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CACnC,cAAsB,EACtB,UAAiC,EAAE;IAEnC,MAAM,IAAI,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;IACxC,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,IAAI,KAAK,CAAC;IACzC,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,kBAAkB,CAAC;IAC1D,IAAI,UAAU,GAA6B,IAAI,CAAC;IAChD,IAAI,gBAAgB,GAA6B,IAAI,CAAC;IACtD,IAAI,iBAAiB,GAA6B,IAAI,CAAC;IAEvD,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACxB,IAAI,CAAC;YACJ,MAAM,QAAQ,GAAG,MAAM,WAAW,CACjC,SAAS,CAAC,GAAG,EAAE;gBACd,OAAO,EAAE,EAAE,MAAM,EAAE,kBAAkB,EAAE;aACvC,CAAC,EACF,SAAS,EACT,gCAAgC,SAAS,IAAI,CAC7C,CAAC;YAEF,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBAClB,UAAU,GAAG;oBACZ,cAAc;oBACd,iBAAiB,EAAE,KAAK;oBACxB,SAAS,EAAE,GAAG;oBACd,KAAK,EACJ,wBAAwB,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE;iBAC/E,CAAC;gBACF,SAAS;YACV,CAAC;YACD,IAAI,OAAwB,CAAC;YAC7B,IAAI,CAAC;gBACJ,OAAO,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAoB,CAAC;YACtD,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBAChB,UAAU,GAAG;oBACZ,cAAc;oBACd,iBAAiB,EAAE,KAAK;oBACxB,SAAS,EAAE,GAAG;oBACd,KAAK,EAAE,4BAA4B,cAAc,CAAC,KAAK,CAAC,EAAE;iBAC1D,CAAC;gBACF,SAAS;YACV,CAAC;YACD,IAAI,CAAC,OAAO,IAAI,OAAO,OAAO,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;gBACrD,UAAU,GAAG;oBACZ,cAAc;oBACd,iBAAiB,EAAE,KAAK;oBACxB,SAAS,EAAE,GAAG;oBACd,KAAK,EAAE,uCAAuC;iBAC9C,CAAC;gBACF,SAAS;YACV,CAAC;YACD,MAAM,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;YAC7C,MAAM,UAAU,GAAG,eAAe,CAAC,cAAc,CAAC,IAAI,EAAE,EAAE,aAAa,CAAC,CAAC;YACzE,MAAM,MAAM,GAAG;gBACd,cAAc;gBACd,aAAa;gBACb,KAAK,EAAE,cAAc,CAAC,OAAO,CAAC,KAAK,CAAC;gBACpC,iBAAiB,EAAE,UAAU,GAAG,CAAC;gBACjC,SAAS,EAAE,GAAG;aACd,CAAC;YACF,UAAU,GAAG,MAAM,CAAC;YACpB,IAAI,MAAM,CAAC,iBAAiB,EAAE,CAAC;gBAC9B,IACC,CAAC,gBAAgB;oBACjB,eAAe,CACd,gBAAgB,CAAC,aAAa,IAAI,cAAc,EAChD,aAAa,CACb,GAAG,CAAC,EACJ,CAAC;oBACF,gBAAgB,GAAG,MAAM,CAAC;gBAC3B,CAAC;gBACD,SAAS;YACV,CAAC;YACD,IACC,CAAC,iBAAiB;gBAClB,eAAe,CACd,iBAAiB,CAAC,aAAa,IAAI,cAAc,EACjD,aAAa,CACb,GAAG,CAAC,EACJ,CAAC;gBACF,iBAAiB,GAAG,MAAM,CAAC;YAC5B,CAAC;QACF,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,UAAU,GAAG;gBACZ,cAAc;gBACd,iBAAiB,EAAE,KAAK;gBACxB,SAAS,EAAE,GAAG;gBACd,KAAK,EAAE,cAAc,CAAC,KAAK,CAAC;aAC5B,CAAC;QACH,CAAC;IACF,CAAC;IAED,OAAO,CACN,gBAAgB;QAChB,iBAAiB;QACjB,UAAU,IAAI;QACb,cAAc;QACd,iBAAiB,EAAE,KAAK;QACxB,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE;QACxB,KAAK,EAAE,uCAAuC;KAC9C,CACD,CAAC;AACH,CAAC","sourcesContent":["import { getPackageName } from \"../package-metadata.js\";\nimport { withTimeout } from \"../utils/async.js\";\n\nconst DEFAULT_GCS_UPDATE_URL =\n\t\"https://storage.googleapis.com/evalops-prod-maestro-releases/maestro/version.json\";\nconst NPM_REGISTRY_BASE_URL = \"https://registry.npmjs.org\";\nconst DEFAULT_TIMEOUT_MS = 5_000;\n\ninterface VersionMetadata {\n\tversion: string;\n\tnotes?: string;\n}\n\nexport interface UpdateCheckResult {\n\tcurrentVersion: string;\n\tlatestVersion?: string;\n\tnotes?: string;\n\tisUpdateAvailable: boolean;\n\tsourceUrl: string;\n\terror?: string;\n}\n\ninterface CheckForUpdateOptions {\n\tfetch?: typeof fetch;\n\ttimeoutMs?: number;\n\turl?: string;\n\turls?: string[];\n}\n\nconst splitUrlList = (value: string | undefined): string[] => {\n\tif (!value) {\n\t\treturn [];\n\t}\n\treturn value\n\t\t.split(/[\\n,]/u)\n\t\t.map((url) => url.trim())\n\t\t.filter(Boolean);\n};\n\nconst npmLatestUrl = (packageName = getPackageName()): string => {\n\treturn `${NPM_REGISTRY_BASE_URL}/${encodeURIComponent(packageName)}/latest`;\n};\n\nexport const resolveUpdateUrls = (\n\toptions: Pick<CheckForUpdateOptions, \"url\" | \"urls\"> = {},\n\tenv: NodeJS.ProcessEnv = process.env,\n): string[] => {\n\tconst explicitUrls = options.urls?.map((url) => url.trim()).filter(Boolean);\n\tif (explicitUrls && explicitUrls.length > 0) {\n\t\treturn explicitUrls;\n\t}\n\tif (options.url?.trim()) {\n\t\treturn [options.url.trim()];\n\t}\n\tconst envUrls = splitUrlList(env.MAESTRO_UPDATE_URLS);\n\tif (envUrls.length > 0) {\n\t\treturn envUrls;\n\t}\n\tif (env.MAESTRO_UPDATE_URL?.trim()) {\n\t\treturn [env.MAESTRO_UPDATE_URL.trim()];\n\t}\n\treturn [DEFAULT_GCS_UPDATE_URL, npmLatestUrl()];\n};\n\nconst toErrorMessage = (error: unknown): string => {\n\tif (error instanceof Error) {\n\t\treturn error.message;\n\t}\n\tif (typeof error === \"string\") {\n\t\treturn error;\n\t}\n\treturn \"Unknown error\";\n};\n\nconst normalizeNotes = (value: unknown): string | undefined => {\n\tif (typeof value !== \"string\") {\n\t\treturn undefined;\n\t}\n\tconst trimmed = value.trim();\n\treturn trimmed.length ? trimmed : undefined;\n};\n\nconst parseNumericSegment = (segment: string): number => {\n\tconst value = Number.parseInt(segment, 10);\n\treturn Number.isNaN(value) ? 0 : value;\n};\n\nconst parseMainSegments = (version: string): number[] => {\n\treturn version.split(\".\").map((segment) => parseNumericSegment(segment));\n};\n\nconst parsePreReleaseSegments = (version: string): string[] => {\n\treturn version ? version.split(\".\") : [];\n};\n\nconst isNumericIdentifier = (segment: string): boolean => {\n\treturn /^[0-9]+$/.test(segment);\n};\n\nconst comparePreRelease = (\n\taSegments: string[],\n\tbSegments: string[],\n): number => {\n\tif (aSegments.length === 0 && bSegments.length === 0) {\n\t\treturn 0;\n\t}\n\tif (aSegments.length === 0) {\n\t\treturn 1;\n\t}\n\tif (bSegments.length === 0) {\n\t\treturn -1;\n\t}\n\tconst length = Math.max(aSegments.length, bSegments.length);\n\tfor (let i = 0; i < length; i++) {\n\t\tconst a = aSegments[i];\n\t\tconst b = bSegments[i];\n\t\tif (a === undefined) {\n\t\t\treturn -1;\n\t\t}\n\t\tif (b === undefined) {\n\t\t\treturn 1;\n\t\t}\n\t\tif (a === b) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst aIsNum = isNumericIdentifier(a);\n\t\tconst bIsNum = isNumericIdentifier(b);\n\t\tif (aIsNum && bIsNum) {\n\t\t\tconst aNum = Number.parseInt(a, 10);\n\t\t\tconst bNum = Number.parseInt(b, 10);\n\t\t\tif (aNum < bNum) {\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t\tif (aNum > bNum) {\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tif (aIsNum && !bIsNum) {\n\t\t\treturn -1;\n\t\t}\n\t\tif (!aIsNum && bIsNum) {\n\t\t\treturn 1;\n\t\t}\n\t\tif (a < b) {\n\t\t\treturn -1;\n\t\t}\n\t\tif (a > b) {\n\t\t\treturn 1;\n\t\t}\n\t}\n\treturn 0;\n};\n\nexport function compareVersions(current: string, latest: string): number {\n\tconst [currentMainPart, currentPreReleasePart = \"\"] = current.split(\"-\", 2);\n\tconst [latestMainPart, latestPreReleasePart = \"\"] = latest.split(\"-\", 2);\n\tconst currentMain = parseMainSegments(currentMainPart!);\n\tconst latestMain = parseMainSegments(latestMainPart!);\n\tconst length = Math.max(currentMain.length, latestMain.length);\n\tfor (let i = 0; i < length; i++) {\n\t\tconst currentValue = currentMain[i] ?? 0;\n\t\tconst latestValue = latestMain[i] ?? 0;\n\t\tif (currentValue < latestValue) {\n\t\t\treturn -1;\n\t\t}\n\t\tif (currentValue > latestValue) {\n\t\t\treturn 1;\n\t\t}\n\t}\n\tconst currentPre = parsePreReleaseSegments(currentPreReleasePart);\n\tconst latestPre = parsePreReleaseSegments(latestPreReleasePart);\n\treturn comparePreRelease(currentPre, latestPre);\n}\n\nexport async function checkForUpdate(\n\tcurrentVersion: string,\n\toptions: CheckForUpdateOptions = {},\n): Promise<UpdateCheckResult> {\n\tconst urls = resolveUpdateUrls(options);\n\tconst fetchImpl = options.fetch ?? fetch;\n\tconst timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n\tlet lastResult: UpdateCheckResult | null = null;\n\tlet bestUpdateResult: UpdateCheckResult | null = null;\n\tlet bestCurrentResult: UpdateCheckResult | null = null;\n\n\tfor (const url of urls) {\n\t\ttry {\n\t\t\tconst response = await withTimeout(\n\t\t\t\tfetchImpl(url, {\n\t\t\t\t\theaders: { Accept: \"application/json\" },\n\t\t\t\t}),\n\t\t\t\ttimeoutMs,\n\t\t\t\t`Update check timed out after ${timeoutMs}ms`,\n\t\t\t);\n\n\t\t\tif (!response.ok) {\n\t\t\t\tlastResult = {\n\t\t\t\t\tcurrentVersion,\n\t\t\t\t\tisUpdateAvailable: false,\n\t\t\t\t\tsourceUrl: url,\n\t\t\t\t\terror:\n\t\t\t\t\t\t`Update check failed (${response.status} ${response.statusText || \"\"})`.trim(),\n\t\t\t\t};\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tlet payload: VersionMetadata;\n\t\t\ttry {\n\t\t\t\tpayload = (await response.json()) as VersionMetadata;\n\t\t\t} catch (error) {\n\t\t\t\tlastResult = {\n\t\t\t\t\tcurrentVersion,\n\t\t\t\t\tisUpdateAvailable: false,\n\t\t\t\t\tsourceUrl: url,\n\t\t\t\t\terror: `Invalid update metadata: ${toErrorMessage(error)}`,\n\t\t\t\t};\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (!payload || typeof payload.version !== \"string\") {\n\t\t\t\tlastResult = {\n\t\t\t\t\tcurrentVersion,\n\t\t\t\t\tisUpdateAvailable: false,\n\t\t\t\t\tsourceUrl: url,\n\t\t\t\t\terror: \"Update metadata missing version field\",\n\t\t\t\t};\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst latestVersion = payload.version.trim();\n\t\t\tconst comparison = compareVersions(currentVersion.trim(), latestVersion);\n\t\t\tconst result = {\n\t\t\t\tcurrentVersion,\n\t\t\t\tlatestVersion,\n\t\t\t\tnotes: normalizeNotes(payload.notes),\n\t\t\t\tisUpdateAvailable: comparison < 0,\n\t\t\t\tsourceUrl: url,\n\t\t\t};\n\t\t\tlastResult = result;\n\t\t\tif (result.isUpdateAvailable) {\n\t\t\t\tif (\n\t\t\t\t\t!bestUpdateResult ||\n\t\t\t\t\tcompareVersions(\n\t\t\t\t\t\tbestUpdateResult.latestVersion ?? currentVersion,\n\t\t\t\t\t\tlatestVersion,\n\t\t\t\t\t) < 0\n\t\t\t\t) {\n\t\t\t\t\tbestUpdateResult = result;\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (\n\t\t\t\t!bestCurrentResult ||\n\t\t\t\tcompareVersions(\n\t\t\t\t\tbestCurrentResult.latestVersion ?? currentVersion,\n\t\t\t\t\tlatestVersion,\n\t\t\t\t) < 0\n\t\t\t) {\n\t\t\t\tbestCurrentResult = result;\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tlastResult = {\n\t\t\t\tcurrentVersion,\n\t\t\t\tisUpdateAvailable: false,\n\t\t\t\tsourceUrl: url,\n\t\t\t\terror: toErrorMessage(error),\n\t\t\t};\n\t\t}\n\t}\n\n\treturn (\n\t\tbestUpdateResult ??\n\t\tbestCurrentResult ??\n\t\tlastResult ?? {\n\t\t\tcurrentVersion,\n\t\t\tisUpdateAvailable: false,\n\t\t\tsourceUrl: urls[0] ?? \"\",\n\t\t\terror: \"No update metadata sources configured\",\n\t\t}\n\t);\n}\n"]}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { type UpdateCheckResult } from "./check.js";
|
|
2
|
+
type PackageManager = "npm" | "bun";
|
|
3
|
+
type GlobalInstallContext = {
|
|
4
|
+
packageManager: PackageManager;
|
|
5
|
+
prefix: string;
|
|
6
|
+
};
|
|
7
|
+
export type StartupUpdateOutcome = {
|
|
8
|
+
status: "skipped";
|
|
9
|
+
reason: string;
|
|
10
|
+
} | {
|
|
11
|
+
status: "current";
|
|
12
|
+
check: UpdateCheckResult;
|
|
13
|
+
} | {
|
|
14
|
+
status: "available";
|
|
15
|
+
check: UpdateCheckResult;
|
|
16
|
+
} | {
|
|
17
|
+
status: "failed";
|
|
18
|
+
check?: UpdateCheckResult;
|
|
19
|
+
error: string;
|
|
20
|
+
} | {
|
|
21
|
+
status: "updated";
|
|
22
|
+
check: UpdateCheckResult;
|
|
23
|
+
} | {
|
|
24
|
+
status: "restarted";
|
|
25
|
+
check: UpdateCheckResult;
|
|
26
|
+
exitCode: number;
|
|
27
|
+
};
|
|
28
|
+
type StartupUpdateOptions = {
|
|
29
|
+
args?: string[];
|
|
30
|
+
argv?: string[];
|
|
31
|
+
currentVersion: string;
|
|
32
|
+
env?: NodeJS.ProcessEnv;
|
|
33
|
+
isTty?: boolean;
|
|
34
|
+
now?: number;
|
|
35
|
+
packageName?: string;
|
|
36
|
+
checkForUpdateImpl?: (currentVersion: string, options?: {
|
|
37
|
+
timeoutMs?: number;
|
|
38
|
+
urls?: string[];
|
|
39
|
+
}) => Promise<UpdateCheckResult>;
|
|
40
|
+
checkTimeoutMs?: number;
|
|
41
|
+
globalInstallContexts?: GlobalInstallContext[] | null;
|
|
42
|
+
globalPrefix?: string | null;
|
|
43
|
+
installPackage?: (packageManager: PackageManager, packageName: string, version: string) => {
|
|
44
|
+
status: number | null;
|
|
45
|
+
error?: Error;
|
|
46
|
+
};
|
|
47
|
+
restart?: false | (() => {
|
|
48
|
+
status: number | null;
|
|
49
|
+
error?: Error;
|
|
50
|
+
});
|
|
51
|
+
statePath?: string;
|
|
52
|
+
};
|
|
53
|
+
export declare const isInstalledPackageEntrypoint: (entrypoint: string | undefined, packageName?: string, globalPrefix?: string | null) => boolean;
|
|
54
|
+
export declare function attemptStartupUpdate(options: StartupUpdateOptions): Promise<StartupUpdateOutcome>;
|
|
55
|
+
export {};
|
|
56
|
+
//# sourceMappingURL=startup-refresh.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"startup-refresh.d.ts","sourceRoot":"","sources":["../../src/update/startup-refresh.ts"],"names":[],"mappings":"AAgBA,OAAO,EACN,KAAK,iBAAiB,EAGtB,MAAM,YAAY,CAAC;AAapB,KAAK,cAAc,GAAG,KAAK,GAAG,KAAK,CAAC;AAEpC,KAAK,oBAAoB,GAAG;IAC3B,cAAc,EAAE,cAAc,CAAC;IAC/B,MAAM,EAAE,MAAM,CAAC;CACf,CAAC;AAQF,MAAM,MAAM,oBAAoB,GAC7B;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACrC;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,iBAAiB,CAAA;CAAE,GAC/C;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,KAAK,EAAE,iBAAiB,CAAA;CAAE,GACjD;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,KAAK,CAAC,EAAE,iBAAiB,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC9D;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,iBAAiB,CAAA;CAAE,GAC/C;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,KAAK,EAAE,iBAAiB,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvE,KAAK,oBAAoB,GAAG;IAC3B,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kBAAkB,CAAC,EAAE,CACpB,cAAc,EAAE,MAAM,EACtB,OAAO,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,KAC7C,OAAO,CAAC,iBAAiB,CAAC,CAAC;IAChC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,qBAAqB,CAAC,EAAE,oBAAoB,EAAE,GAAG,IAAI,CAAC;IACtD,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,cAAc,CAAC,EAAE,CAChB,cAAc,EAAE,cAAc,EAC9B,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,KACX;QACJ,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;QACtB,KAAK,CAAC,EAAE,KAAK,CAAC;KACd,CAAC;IACF,OAAO,CAAC,EAAE,KAAK,GAAG,CAAC,MAAM;QAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,KAAK,CAAC,EAAE,KAAK,CAAA;KAAE,CAAC,CAAC;IACnE,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AA+DF,eAAO,MAAM,4BAA4B,GACxC,YAAY,MAAM,GAAG,SAAS,EAC9B,oBAA8B,EAC9B,eAAe,MAAM,GAAG,IAAI,KAC1B,OAgBF,CAAC;AA+KF,wBAAsB,oBAAoB,CACzC,OAAO,EAAE,oBAAoB,GAC3B,OAAO,CAAC,oBAAoB,CAAC,CAmJ/B"}
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, realpathSync, writeFileSync, } from "node:fs";
|
|
3
|
+
import { basename, dirname, join, resolve } from "node:path";
|
|
4
|
+
import { parseArgs } from "../cli/args.js";
|
|
5
|
+
import { getAgentDir } from "../config/constants.js";
|
|
6
|
+
import { getGlobalInstallCommand, getPackageName, } from "../package-metadata.js";
|
|
7
|
+
import { withTimeout } from "../utils/async.js";
|
|
8
|
+
import { checkForUpdate, resolveUpdateUrls, } from "./check.js";
|
|
9
|
+
const SKIP_ENV = "MAESTRO_SKIP_STARTUP_UPDATE";
|
|
10
|
+
const STARTUP_UPDATE_ENV = "MAESTRO_STARTUP_UPDATE";
|
|
11
|
+
const STARTUP_UPDATE_STATE_ENV = "MAESTRO_STARTUP_UPDATE_STATE";
|
|
12
|
+
const STARTUP_UPDATE_TIMEOUT_ENV = "MAESTRO_STARTUP_UPDATE_TIMEOUT_MS";
|
|
13
|
+
const STARTUP_UPDATE_TTL_ENV = "MAESTRO_STARTUP_UPDATE_RETRY_MS";
|
|
14
|
+
const DEFAULT_INSTALL_TIMEOUT_MS = 60_000;
|
|
15
|
+
const DEFAULT_RETRY_MS = 24 * 60 * 60 * 1_000;
|
|
16
|
+
const DEFAULT_STARTUP_UPDATE_TIMEOUT_MS = 1_500;
|
|
17
|
+
const NPM_PREFIX_TIMEOUT_MS = 2_000;
|
|
18
|
+
const BUN_PREFIX_TIMEOUT_MS = 2_000;
|
|
19
|
+
const OFF_VALUES = new Set(["0", "false", "off", "skip", "disabled"]);
|
|
20
|
+
const CHECK_ONLY_VALUES = new Set(["check", "notice", "notify"]);
|
|
21
|
+
const INSTALLABLE_VERSION = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/u;
|
|
22
|
+
const envValue = (env, key) => env[key]?.trim().toLowerCase() ?? "";
|
|
23
|
+
const toErrorMessage = (error) => {
|
|
24
|
+
if (error instanceof Error) {
|
|
25
|
+
return error.message;
|
|
26
|
+
}
|
|
27
|
+
if (typeof error === "string") {
|
|
28
|
+
return error;
|
|
29
|
+
}
|
|
30
|
+
return "Unknown error";
|
|
31
|
+
};
|
|
32
|
+
const shouldSkipForArgs = (args) => {
|
|
33
|
+
if (args[0] === "a2a") {
|
|
34
|
+
return "a2a command";
|
|
35
|
+
}
|
|
36
|
+
if (args[0] === "exec") {
|
|
37
|
+
return "non-interactive command";
|
|
38
|
+
}
|
|
39
|
+
if (args[0] === "update") {
|
|
40
|
+
return "manual update command";
|
|
41
|
+
}
|
|
42
|
+
if (args.includes("--version") ||
|
|
43
|
+
args.includes("-v") ||
|
|
44
|
+
args.includes("--help") ||
|
|
45
|
+
args.includes("-h")) {
|
|
46
|
+
return "immediate-exit command";
|
|
47
|
+
}
|
|
48
|
+
if (args.includes("--headless") ||
|
|
49
|
+
args.includes("--json") ||
|
|
50
|
+
args.includes("--rpc") ||
|
|
51
|
+
args.includes("rpc")) {
|
|
52
|
+
return "non-interactive command";
|
|
53
|
+
}
|
|
54
|
+
for (let i = 0; i < args.length; i++) {
|
|
55
|
+
const arg = args[i];
|
|
56
|
+
if (arg === "--mode" && args[i + 1] === "headless") {
|
|
57
|
+
return "headless command";
|
|
58
|
+
}
|
|
59
|
+
if (arg?.startsWith("--mode=") &&
|
|
60
|
+
arg.slice("--mode=".length) === "headless") {
|
|
61
|
+
return "headless command";
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
if (parseArgs(args).messages.length > 0) {
|
|
65
|
+
return "single-shot prompt";
|
|
66
|
+
}
|
|
67
|
+
return null;
|
|
68
|
+
};
|
|
69
|
+
export const isInstalledPackageEntrypoint = (entrypoint, packageName = getPackageName(), globalPrefix) => {
|
|
70
|
+
if (!entrypoint) {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
if (isPackageEntrypointPath(entrypoint, packageName, globalPrefix)) {
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
try {
|
|
77
|
+
return isPackageEntrypointPath(realpathSync(entrypoint), packageName, globalPrefix);
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
const isPackageEntrypointPath = (entrypoint, packageName, globalPrefix) => {
|
|
84
|
+
const normalized = entrypoint.replace(/\\/g, "/");
|
|
85
|
+
const packageEntrypoint = `/node_modules/${packageName}/dist/cli.js`;
|
|
86
|
+
if (!normalized.endsWith(packageEntrypoint)) {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
if (!globalPrefix) {
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
const normalizedPrefix = globalPrefix
|
|
93
|
+
.replace(/\\/g, "/")
|
|
94
|
+
.replace(/\/+$/u, "");
|
|
95
|
+
const normalizedPrefixes = new Set([normalizedPrefix]);
|
|
96
|
+
try {
|
|
97
|
+
normalizedPrefixes.add(realpathSync(globalPrefix).replace(/\\/g, "/").replace(/\/+$/u, ""));
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
// A missing prefix will fail the exact path checks below.
|
|
101
|
+
}
|
|
102
|
+
for (const prefix of normalizedPrefixes) {
|
|
103
|
+
if (normalized === `${prefix}/lib/node_modules/${packageName}/dist/cli.js` ||
|
|
104
|
+
normalized === `${prefix}/node_modules/${packageName}/dist/cli.js`) {
|
|
105
|
+
return true;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return false;
|
|
109
|
+
};
|
|
110
|
+
const resolveStatePath = (env = process.env, override) => {
|
|
111
|
+
if (override) {
|
|
112
|
+
return override;
|
|
113
|
+
}
|
|
114
|
+
if (env[STARTUP_UPDATE_STATE_ENV]) {
|
|
115
|
+
return resolve(env[STARTUP_UPDATE_STATE_ENV]);
|
|
116
|
+
}
|
|
117
|
+
return resolve(getAgentDir(), "startup-update-state.json");
|
|
118
|
+
};
|
|
119
|
+
const readState = (path) => {
|
|
120
|
+
if (!existsSync(path)) {
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
try {
|
|
124
|
+
return JSON.parse(readFileSync(path, "utf-8"));
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
const writeState = (path, state) => {
|
|
131
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
132
|
+
writeFileSync(path, JSON.stringify(state, null, 2), "utf-8");
|
|
133
|
+
};
|
|
134
|
+
const retryMsFromEnv = (env) => {
|
|
135
|
+
const parsed = Number.parseInt(env[STARTUP_UPDATE_TTL_ENV] ?? "", 10);
|
|
136
|
+
if (Number.isFinite(parsed) && parsed >= 0) {
|
|
137
|
+
return parsed;
|
|
138
|
+
}
|
|
139
|
+
return DEFAULT_RETRY_MS;
|
|
140
|
+
};
|
|
141
|
+
const startupCheckTimeoutMsFromEnv = (env) => {
|
|
142
|
+
const parsed = Number.parseInt(env[STARTUP_UPDATE_TIMEOUT_ENV] ?? "", 10);
|
|
143
|
+
if (Number.isFinite(parsed) && parsed > 0) {
|
|
144
|
+
return parsed;
|
|
145
|
+
}
|
|
146
|
+
return DEFAULT_STARTUP_UPDATE_TIMEOUT_MS;
|
|
147
|
+
};
|
|
148
|
+
const startupSourceTimeoutMs = (totalTimeoutMs, sourceCount) => Math.max(1, Math.floor(totalTimeoutMs / Math.max(1, sourceCount)));
|
|
149
|
+
const shouldThrottleAttempt = (state, version, now, retryMs) => {
|
|
150
|
+
if (!state ||
|
|
151
|
+
state.version !== version ||
|
|
152
|
+
typeof state.lastAttemptAt !== "number" ||
|
|
153
|
+
state.lastStatus !== "failed") {
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
return now - state.lastAttemptAt < retryMs;
|
|
157
|
+
};
|
|
158
|
+
const isInstallableVersion = (version) => INSTALLABLE_VERSION.test(version);
|
|
159
|
+
const defaultInstallPackage = (packageManager, packageName, version) => {
|
|
160
|
+
const result = spawnSync(packageManager, ["install", "-g", `${packageName}@${version}`], {
|
|
161
|
+
encoding: "utf-8",
|
|
162
|
+
stdio: "pipe",
|
|
163
|
+
timeout: DEFAULT_INSTALL_TIMEOUT_MS,
|
|
164
|
+
});
|
|
165
|
+
return { status: result.status, error: result.error };
|
|
166
|
+
};
|
|
167
|
+
const resolveNpmGlobalPrefix = (env = process.env) => {
|
|
168
|
+
const result = spawnSync("npm", ["prefix", "-g"], {
|
|
169
|
+
encoding: "utf-8",
|
|
170
|
+
env,
|
|
171
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
172
|
+
timeout: NPM_PREFIX_TIMEOUT_MS,
|
|
173
|
+
});
|
|
174
|
+
if (result.error || result.status !== 0) {
|
|
175
|
+
return null;
|
|
176
|
+
}
|
|
177
|
+
const prefix = result.stdout.trim();
|
|
178
|
+
return prefix.length > 0 ? prefix : null;
|
|
179
|
+
};
|
|
180
|
+
const resolveBunGlobalPrefix = (env = process.env) => {
|
|
181
|
+
const result = spawnSync("bun", ["pm", "bin", "-g"], {
|
|
182
|
+
encoding: "utf-8",
|
|
183
|
+
env,
|
|
184
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
185
|
+
timeout: BUN_PREFIX_TIMEOUT_MS,
|
|
186
|
+
});
|
|
187
|
+
if (result.error || result.status !== 0) {
|
|
188
|
+
return null;
|
|
189
|
+
}
|
|
190
|
+
const binDir = result.stdout.trim();
|
|
191
|
+
if (!binDir) {
|
|
192
|
+
return null;
|
|
193
|
+
}
|
|
194
|
+
const bunHome = basename(binDir) === "bin" ? dirname(binDir) : binDir;
|
|
195
|
+
return join(bunHome, "install", "global");
|
|
196
|
+
};
|
|
197
|
+
const resolveGlobalInstallContexts = (env = process.env) => {
|
|
198
|
+
const contexts = [];
|
|
199
|
+
const npmPrefix = resolveNpmGlobalPrefix(env);
|
|
200
|
+
if (npmPrefix) {
|
|
201
|
+
contexts.push({ packageManager: "npm", prefix: npmPrefix });
|
|
202
|
+
}
|
|
203
|
+
const bunPrefix = resolveBunGlobalPrefix(env);
|
|
204
|
+
if (bunPrefix) {
|
|
205
|
+
contexts.push({ packageManager: "bun", prefix: bunPrefix });
|
|
206
|
+
}
|
|
207
|
+
return contexts;
|
|
208
|
+
};
|
|
209
|
+
export async function attemptStartupUpdate(options) {
|
|
210
|
+
const env = options.env ?? process.env;
|
|
211
|
+
const args = options.args ?? process.argv.slice(2);
|
|
212
|
+
const argv = options.argv ?? process.argv;
|
|
213
|
+
const packageName = options.packageName ?? getPackageName();
|
|
214
|
+
const updateMode = envValue(env, STARTUP_UPDATE_ENV);
|
|
215
|
+
const now = options.now ?? Date.now();
|
|
216
|
+
if (env[SKIP_ENV]) {
|
|
217
|
+
return { status: "skipped", reason: `${SKIP_ENV} is set` };
|
|
218
|
+
}
|
|
219
|
+
if (env.CI || env.NODE_ENV === "test") {
|
|
220
|
+
return { status: "skipped", reason: "test or CI environment" };
|
|
221
|
+
}
|
|
222
|
+
if (OFF_VALUES.has(updateMode)) {
|
|
223
|
+
return { status: "skipped", reason: `${STARTUP_UPDATE_ENV} is disabled` };
|
|
224
|
+
}
|
|
225
|
+
if (!(options.isTty ?? Boolean(process.stdin.isTTY && process.stdout.isTTY))) {
|
|
226
|
+
return { status: "skipped", reason: "non-TTY startup" };
|
|
227
|
+
}
|
|
228
|
+
const argsSkipReason = shouldSkipForArgs(args);
|
|
229
|
+
if (argsSkipReason) {
|
|
230
|
+
return { status: "skipped", reason: argsSkipReason };
|
|
231
|
+
}
|
|
232
|
+
const globalInstallContexts = options.globalInstallContexts ??
|
|
233
|
+
(options.globalPrefix === undefined
|
|
234
|
+
? resolveGlobalInstallContexts(env)
|
|
235
|
+
: options.globalPrefix
|
|
236
|
+
? [{ packageManager: "npm", prefix: options.globalPrefix }]
|
|
237
|
+
: []);
|
|
238
|
+
if (globalInstallContexts.length === 0) {
|
|
239
|
+
return {
|
|
240
|
+
status: "skipped",
|
|
241
|
+
reason: options.globalPrefix === null
|
|
242
|
+
? "npm global prefix unavailable"
|
|
243
|
+
: "global package prefix unavailable",
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
const installContext = globalInstallContexts.find((context) => isInstalledPackageEntrypoint(argv[1], packageName, context.prefix));
|
|
247
|
+
if (!installContext) {
|
|
248
|
+
return {
|
|
249
|
+
status: "skipped",
|
|
250
|
+
reason: "not running installed global package",
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
const checkTimeoutMs = options.checkTimeoutMs ?? startupCheckTimeoutMsFromEnv(env);
|
|
254
|
+
const updateUrls = resolveUpdateUrls({}, env);
|
|
255
|
+
const checkOptions = {
|
|
256
|
+
timeoutMs: startupSourceTimeoutMs(checkTimeoutMs, updateUrls.length),
|
|
257
|
+
urls: updateUrls,
|
|
258
|
+
};
|
|
259
|
+
const check = await withTimeout((options.checkForUpdateImpl ?? checkForUpdate)(options.currentVersion, checkOptions), checkTimeoutMs, `Startup update check timed out after ${checkTimeoutMs}ms`).catch((error) => ({
|
|
260
|
+
currentVersion: options.currentVersion,
|
|
261
|
+
isUpdateAvailable: false,
|
|
262
|
+
sourceUrl: "",
|
|
263
|
+
error: toErrorMessage(error),
|
|
264
|
+
}));
|
|
265
|
+
if (check.error) {
|
|
266
|
+
return { status: "failed", check, error: check.error };
|
|
267
|
+
}
|
|
268
|
+
if (!check.isUpdateAvailable || !check.latestVersion) {
|
|
269
|
+
return { status: "current", check };
|
|
270
|
+
}
|
|
271
|
+
if (CHECK_ONLY_VALUES.has(updateMode)) {
|
|
272
|
+
return { status: "available", check };
|
|
273
|
+
}
|
|
274
|
+
if (!isInstallableVersion(check.latestVersion)) {
|
|
275
|
+
return {
|
|
276
|
+
status: "failed",
|
|
277
|
+
check,
|
|
278
|
+
error: `Refusing to install unsupported version ${check.latestVersion}`,
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
const statePath = resolveStatePath(env, options.statePath);
|
|
282
|
+
if (shouldThrottleAttempt(readState(statePath), check.latestVersion, now, retryMsFromEnv(env))) {
|
|
283
|
+
return { status: "available", check };
|
|
284
|
+
}
|
|
285
|
+
writeState(statePath, {
|
|
286
|
+
version: check.latestVersion,
|
|
287
|
+
lastAttemptAt: now,
|
|
288
|
+
lastStatus: "failed",
|
|
289
|
+
});
|
|
290
|
+
const install = (options.installPackage ?? defaultInstallPackage)(installContext.packageManager, packageName, check.latestVersion);
|
|
291
|
+
if (install.error || install.status !== 0) {
|
|
292
|
+
return {
|
|
293
|
+
status: "failed",
|
|
294
|
+
check,
|
|
295
|
+
error: install.error?.message ??
|
|
296
|
+
`${getGlobalInstallCommand(installContext.packageManager, `${packageName}@${check.latestVersion}`)} exited ${install.status}`,
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
writeState(statePath, {
|
|
300
|
+
version: check.latestVersion,
|
|
301
|
+
lastAttemptAt: now,
|
|
302
|
+
lastStatus: "updated",
|
|
303
|
+
});
|
|
304
|
+
if (options.restart === false) {
|
|
305
|
+
return { status: "updated", check };
|
|
306
|
+
}
|
|
307
|
+
const restart = options.restart ??
|
|
308
|
+
(() => {
|
|
309
|
+
const result = spawnSync(process.execPath, argv.slice(1), {
|
|
310
|
+
stdio: "inherit",
|
|
311
|
+
env: { ...env, [SKIP_ENV]: "1" },
|
|
312
|
+
});
|
|
313
|
+
return { status: result.status, error: result.error };
|
|
314
|
+
});
|
|
315
|
+
const restarted = restart();
|
|
316
|
+
if (restarted.error) {
|
|
317
|
+
return { status: "updated", check };
|
|
318
|
+
}
|
|
319
|
+
return { status: "restarted", check, exitCode: restarted.status ?? 0 };
|
|
320
|
+
}
|
|
321
|
+
//# sourceMappingURL=startup-refresh.js.map
|