@agent-team-foundation/first-tree-hub 0.14.9-alpha.292.1 → 0.14.9-alpha.294.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.
package/dist/cli/index.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { $ as cleanWorkspaces, A as printResults, B as ClientRuntime, C as migrateLocalAgentDirs, D as checkNodeVersion, E as checkClientConfig, G as removeLocalAgent, I as restartClientService, J as ClientOrgMismatchError, K as fail, L as startClientService, M as getClientServiceStatus, N as installClientService, O as checkServerReachable, P as isServiceSupported, Q as SessionRegistry, R as stopClientService, S as createApiNameResolver, T as checkBackgroundService, U as findStaleAliases, V as handleClientOrgMismatch, W as formatStaleReason, X as FirstTreeHubSDK, Y as ClientUserMismatchError, Z as SdkError, _ as loadOnboardState, a as declineUpdate, b as saveOnboardState, c as detectInstallMode, d as reconcileLocalRuntimeProviders, et as probeCapabilities, f as uploadClientCapabilities, g as formatCheckReport, h as promptMissingFields, i as createExecuteUpdate, j as reconcileAgentConfigs, k as checkWebSocket, l as fetchLatestVersion, m as promptAddAgent, nt as configureClientLoggerForService, o as promptUpdate, p as isInteractive, q as success, r as registerSaaSConnectCommand, s as PACKAGE_NAME, tt as applyClientLoggerConfig, u as installGlobalLatest, v as onboardCheck, w as checkAgentConfigs, x as runHomeMigration, y as onboardCreate } from "../saas-connect-
|
|
2
|
+
import { $ as cleanWorkspaces, A as printResults, B as ClientRuntime, C as migrateLocalAgentDirs, D as checkNodeVersion, E as checkClientConfig, G as removeLocalAgent, I as restartClientService, J as ClientOrgMismatchError, K as fail, L as startClientService, M as getClientServiceStatus, N as installClientService, O as checkServerReachable, P as isServiceSupported, Q as SessionRegistry, R as stopClientService, S as createApiNameResolver, T as checkBackgroundService, U as findStaleAliases, V as handleClientOrgMismatch, W as formatStaleReason, X as FirstTreeHubSDK, Y as ClientUserMismatchError, Z as SdkError, _ as loadOnboardState, a as declineUpdate, b as saveOnboardState, c as detectInstallMode, d as reconcileLocalRuntimeProviders, et as probeCapabilities, f as uploadClientCapabilities, g as formatCheckReport, h as promptMissingFields, i as createExecuteUpdate, j as reconcileAgentConfigs, k as checkWebSocket, l as fetchLatestVersion, m as promptAddAgent, nt as configureClientLoggerForService, o as promptUpdate, p as isInteractive, q as success, r as registerSaaSConnectCommand, s as PACKAGE_NAME, tt as applyClientLoggerConfig, u as installGlobalLatest, v as onboardCheck, w as checkAgentConfigs, x as runHomeMigration, y as onboardCreate } from "../saas-connect-DzbieDfo.mjs";
|
|
3
3
|
import { C as resolveConfigReadonly, S as resetConfigMeta, _ as initConfig, a as loadCredentials, b as readConfigFile, c as saveAgentConfig, d as DEFAULT_DATA_DIR, f as DEFAULT_HOME_DIR, g as getConfigValue, i as ensureFreshAdminToken, m as clientConfigSchema, p as agentConfigSchema, r as ensureFreshAccessToken, s as resolveServerUrl, u as DEFAULT_CONFIG_DIR, v as loadAgents, w as setConfigValue, x as resetConfig } from "../bootstrap-D6RsdtJg.mjs";
|
|
4
4
|
import { a as print, n as CLI_USER_AGENT, o as setJsonMode, r as COMMAND_VERSION, t as cliFetch } from "../cli-fetch-BGVItZxo.mjs";
|
|
5
|
-
import { n as bindFeishuUser, t as bindFeishuBot } from "../feishu-
|
|
5
|
+
import { n as bindFeishuUser, t as bindFeishuBot } from "../feishu-CwD_5b9W.mjs";
|
|
6
6
|
import { join } from "node:path";
|
|
7
7
|
import { existsSync, mkdirSync, readFileSync, readdirSync } from "node:fs";
|
|
8
8
|
import * as semver from "semver";
|
|
@@ -682,12 +682,37 @@ z.object({
|
|
|
682
682
|
* mandatory on this server build.
|
|
683
683
|
*/
|
|
684
684
|
const clientWireCapabilitiesSchema = z.object({ wsInboxDeliver: z.boolean().default(false) }).partial();
|
|
685
|
+
/**
|
|
686
|
+
* Outcome of the client's last self-update attempt. Carried on
|
|
687
|
+
* `client:register` so the server can persist it into
|
|
688
|
+
* `clients.metadata.lastUpdateAttempt`, surfacing in the admin
|
|
689
|
+
* dashboard whichever clients are failing to auto-update — without
|
|
690
|
+
* needing per-machine SSH to grep `client.log`.
|
|
691
|
+
*
|
|
692
|
+
* Length caps protect the WS frame budget: even a verbose npm stderr
|
|
693
|
+
* gets truncated client-side before persisting, but `.max()` here is the
|
|
694
|
+
* server-side guard against a hostile or buggy client sending a
|
|
695
|
+
* megabyte-long reason.
|
|
696
|
+
*/
|
|
697
|
+
const updateAttemptSchema = z.object({
|
|
698
|
+
result: z.enum([
|
|
699
|
+
"ok",
|
|
700
|
+
"failed",
|
|
701
|
+
"blocked"
|
|
702
|
+
]),
|
|
703
|
+
target: z.string().min(1).max(64),
|
|
704
|
+
currentBefore: z.string().min(1).max(64),
|
|
705
|
+
installedVersion: z.string().min(1).max(64).nullable(),
|
|
706
|
+
reason: z.string().max(500).nullable(),
|
|
707
|
+
at: z.string().min(1).max(40)
|
|
708
|
+
});
|
|
685
709
|
z.object({
|
|
686
710
|
clientId: z.string().min(1).max(100),
|
|
687
711
|
hostname: z.string().max(100).optional(),
|
|
688
712
|
os: z.string().max(50).optional(),
|
|
689
713
|
sdkVersion: z.string().max(50).optional(),
|
|
690
|
-
wireCapabilities: clientWireCapabilitiesSchema.optional()
|
|
714
|
+
wireCapabilities: clientWireCapabilitiesSchema.optional(),
|
|
715
|
+
lastUpdateAttempt: updateAttemptSchema.optional()
|
|
691
716
|
});
|
|
692
717
|
z.object({
|
|
693
718
|
clientId: z.string(),
|
|
@@ -1826,4 +1851,4 @@ async function bindFeishuUser(serverUrl, accessToken, agentId, humanAgentId, fei
|
|
|
1826
1851
|
}
|
|
1827
1852
|
}
|
|
1828
1853
|
//#endregion
|
|
1829
|
-
export { bindFeishuUser as n, bindFeishuBot as t };
|
|
1854
|
+
export { bindFeishuUser as n, updateAttemptSchema as r, bindFeishuBot as t };
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { A as printResults, B as ClientRuntime, D as checkNodeVersion, E as checkClientConfig, F as resolveCliInvocation, H as rotateClientIdWithBackup, I as restartClientService, L as startClientService, M as getClientServiceStatus, N as installClientService, O as checkServerReachable, P as isServiceSupported, R as stopClientService, V as handleClientOrgMismatch, X as FirstTreeHubSDK, Z as SdkError, g as formatCheckReport, h as promptMissingFields, k as checkWebSocket, m as promptAddAgent, n as deriveHubUrlFromToken, p as isInteractive, t as HubUrlDerivationError, v as onboardCheck, w as checkAgentConfigs, x as runHomeMigration, y as onboardCreate, z as uninstallClientService } from "./saas-connect-
|
|
1
|
+
import { A as printResults, B as ClientRuntime, D as checkNodeVersion, E as checkClientConfig, F as resolveCliInvocation, H as rotateClientIdWithBackup, I as restartClientService, L as startClientService, M as getClientServiceStatus, N as installClientService, O as checkServerReachable, P as isServiceSupported, R as stopClientService, V as handleClientOrgMismatch, X as FirstTreeHubSDK, Z as SdkError, g as formatCheckReport, h as promptMissingFields, k as checkWebSocket, m as promptAddAgent, n as deriveHubUrlFromToken, p as isInteractive, t as HubUrlDerivationError, v as onboardCheck, w as checkAgentConfigs, x as runHomeMigration, y as onboardCreate, z as uninstallClientService } from "./saas-connect-DzbieDfo.mjs";
|
|
2
2
|
import { i as ensureFreshAdminToken, n as AuthRefreshRateLimitedError, o as resolveAccessToken, r as ensureFreshAccessToken, s as resolveServerUrl, t as AuthRefreshFailedError } from "./bootstrap-D6RsdtJg.mjs";
|
|
3
3
|
import { i as blank, s as status } from "./cli-fetch-BGVItZxo.mjs";
|
|
4
|
-
import { n as bindFeishuUser, t as bindFeishuBot } from "./feishu-
|
|
4
|
+
import { n as bindFeishuUser, t as bindFeishuBot } from "./feishu-CwD_5b9W.mjs";
|
|
5
5
|
export { AuthRefreshFailedError, AuthRefreshRateLimitedError, ClientRuntime, FirstTreeHubSDK, HubUrlDerivationError, SdkError, bindFeishuBot, bindFeishuUser, blank, checkAgentConfigs, checkClientConfig, checkNodeVersion, checkServerReachable, checkWebSocket, deriveHubUrlFromToken, ensureFreshAccessToken, ensureFreshAdminToken, formatCheckReport, getClientServiceStatus, handleClientOrgMismatch, installClientService, isInteractive, isServiceSupported, onboardCheck, onboardCreate, printResults, promptAddAgent, promptMissingFields, resolveAccessToken, resolveCliInvocation, resolveServerUrl, restartClientService, rotateClientIdWithBackup, runHomeMigration, startClientService, status, stopClientService, uninstallClientService };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { C as resolveConfigReadonly, S as resetConfigMeta, _ as initConfig, a as loadCredentials, c as saveAgentConfig, d as DEFAULT_DATA_DIR$1, f as DEFAULT_HOME_DIR$1, h as collectMissingPrompts, l as saveCredentials, m as clientConfigSchema, p as agentConfigSchema, r as ensureFreshAccessToken, s as resolveServerUrl, u as DEFAULT_CONFIG_DIR, v as loadAgents, w as setConfigValue, x as resetConfig, y as migrateLegacyHome } from "./bootstrap-D6RsdtJg.mjs";
|
|
2
2
|
import { a as print, i as blank, n as CLI_USER_AGENT, r as COMMAND_VERSION, t as cliFetch } from "./cli-fetch-BGVItZxo.mjs";
|
|
3
|
+
import { r as updateAttemptSchema$1 } from "./feishu-CwD_5b9W.mjs";
|
|
3
4
|
import { createRequire } from "node:module";
|
|
4
5
|
import { z } from "zod";
|
|
5
6
|
import { basename, delimiter, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
@@ -4509,12 +4510,37 @@ z.object({
|
|
|
4509
4510
|
* mandatory on this server build.
|
|
4510
4511
|
*/
|
|
4511
4512
|
const clientWireCapabilitiesSchema = z.object({ wsInboxDeliver: z.boolean().default(false) }).partial();
|
|
4513
|
+
/**
|
|
4514
|
+
* Outcome of the client's last self-update attempt. Carried on
|
|
4515
|
+
* `client:register` so the server can persist it into
|
|
4516
|
+
* `clients.metadata.lastUpdateAttempt`, surfacing in the admin
|
|
4517
|
+
* dashboard whichever clients are failing to auto-update — without
|
|
4518
|
+
* needing per-machine SSH to grep `client.log`.
|
|
4519
|
+
*
|
|
4520
|
+
* Length caps protect the WS frame budget: even a verbose npm stderr
|
|
4521
|
+
* gets truncated client-side before persisting, but `.max()` here is the
|
|
4522
|
+
* server-side guard against a hostile or buggy client sending a
|
|
4523
|
+
* megabyte-long reason.
|
|
4524
|
+
*/
|
|
4525
|
+
const updateAttemptSchema = z.object({
|
|
4526
|
+
result: z.enum([
|
|
4527
|
+
"ok",
|
|
4528
|
+
"failed",
|
|
4529
|
+
"blocked"
|
|
4530
|
+
]),
|
|
4531
|
+
target: z.string().min(1).max(64),
|
|
4532
|
+
currentBefore: z.string().min(1).max(64),
|
|
4533
|
+
installedVersion: z.string().min(1).max(64).nullable(),
|
|
4534
|
+
reason: z.string().max(500).nullable(),
|
|
4535
|
+
at: z.string().min(1).max(40)
|
|
4536
|
+
});
|
|
4512
4537
|
z.object({
|
|
4513
4538
|
clientId: z.string().min(1).max(100),
|
|
4514
4539
|
hostname: z.string().max(100).optional(),
|
|
4515
4540
|
os: z.string().max(50).optional(),
|
|
4516
4541
|
sdkVersion: z.string().max(50).optional(),
|
|
4517
|
-
wireCapabilities: clientWireCapabilitiesSchema.optional()
|
|
4542
|
+
wireCapabilities: clientWireCapabilitiesSchema.optional(),
|
|
4543
|
+
lastUpdateAttempt: updateAttemptSchema.optional()
|
|
4518
4544
|
});
|
|
4519
4545
|
z.object({
|
|
4520
4546
|
clientId: z.string(),
|
|
@@ -6290,6 +6316,7 @@ var ClientConnection = class extends EventEmitter {
|
|
|
6290
6316
|
sdkVersion;
|
|
6291
6317
|
userAgent;
|
|
6292
6318
|
getAccessToken;
|
|
6319
|
+
getLastUpdateAttempt;
|
|
6293
6320
|
heartbeatIntervalMs;
|
|
6294
6321
|
heartbeatTimeoutMs;
|
|
6295
6322
|
ws = null;
|
|
@@ -6353,6 +6380,7 @@ var ClientConnection = class extends EventEmitter {
|
|
|
6353
6380
|
this.sdkVersion = config.sdkVersion;
|
|
6354
6381
|
this.userAgent = config.userAgent;
|
|
6355
6382
|
this.getAccessToken = config.getAccessToken;
|
|
6383
|
+
this.getLastUpdateAttempt = config.getLastUpdateAttempt;
|
|
6356
6384
|
this.heartbeatIntervalMs = config.heartbeatIntervalMs ?? HEARTBEAT_INTERVAL_MS;
|
|
6357
6385
|
this.heartbeatTimeoutMs = config.heartbeatTimeoutMs ?? HEARTBEAT_TIMEOUT_MS;
|
|
6358
6386
|
this.wsLogger = createLogger("ws").child({ clientId: this.clientId });
|
|
@@ -6604,12 +6632,19 @@ var ClientConnection = class extends EventEmitter {
|
|
|
6604
6632
|
const type = msg.type;
|
|
6605
6633
|
if (type === "auth:ok") {
|
|
6606
6634
|
this.authLogger.info("auth accepted, registering client");
|
|
6635
|
+
let lastUpdateAttempt = null;
|
|
6636
|
+
try {
|
|
6637
|
+
lastUpdateAttempt = this.getLastUpdateAttempt?.() ?? null;
|
|
6638
|
+
} catch (err) {
|
|
6639
|
+
this.authLogger.warn({ err }, "getLastUpdateAttempt threw; omitting from register frame");
|
|
6640
|
+
}
|
|
6607
6641
|
this.ws?.send(JSON.stringify({
|
|
6608
6642
|
type: "client:register",
|
|
6609
6643
|
clientId: this.clientId,
|
|
6610
6644
|
hostname: hostname(),
|
|
6611
6645
|
os: platform(),
|
|
6612
|
-
sdkVersion: this.sdkVersion
|
|
6646
|
+
sdkVersion: this.sdkVersion,
|
|
6647
|
+
...lastUpdateAttempt ? { lastUpdateAttempt } : {}
|
|
6613
6648
|
}));
|
|
6614
6649
|
return;
|
|
6615
6650
|
}
|
|
@@ -11781,6 +11816,54 @@ async function handleClientOrgMismatch(err, opts) {
|
|
|
11781
11816
|
}
|
|
11782
11817
|
}
|
|
11783
11818
|
//#endregion
|
|
11819
|
+
//#region src/core/update-state.ts
|
|
11820
|
+
/**
|
|
11821
|
+
* Override-able location of the state file. Production code uses the
|
|
11822
|
+
* default; tests pass a temp path so they don't stomp on the real
|
|
11823
|
+
* `~/.first-tree/hub/state/update-state.json`.
|
|
11824
|
+
*/
|
|
11825
|
+
function defaultUpdateStatePath() {
|
|
11826
|
+
return join(DEFAULT_HOME_DIR$1, "state", "update-state.json");
|
|
11827
|
+
}
|
|
11828
|
+
/** Read the most recent attempt, or `null` if no attempt has ever been recorded. */
|
|
11829
|
+
function readUpdateState(path = defaultUpdateStatePath()) {
|
|
11830
|
+
if (!existsSync(path)) return null;
|
|
11831
|
+
try {
|
|
11832
|
+
const raw = readFileSync(path, "utf8");
|
|
11833
|
+
const parsed = JSON.parse(raw);
|
|
11834
|
+
if (!parsed || typeof parsed !== "object") return null;
|
|
11835
|
+
const last = updateAttemptSchema$1.safeParse(parsed.last);
|
|
11836
|
+
if (!last.success) return null;
|
|
11837
|
+
return { last: last.data };
|
|
11838
|
+
} catch {
|
|
11839
|
+
return null;
|
|
11840
|
+
}
|
|
11841
|
+
}
|
|
11842
|
+
/**
|
|
11843
|
+
* Persist the given attempt as the most recent record. Atomic in the
|
|
11844
|
+
* single-writer sense — only `update-glue.createExecuteUpdate` writes to
|
|
11845
|
+
* this file, and a CLI process never runs two `executeUpdate` calls
|
|
11846
|
+
* concurrently (UpdateManager's `updateInFlight` lock guarantees it).
|
|
11847
|
+
*/
|
|
11848
|
+
function recordUpdateAttempt(attempt, path = defaultUpdateStatePath()) {
|
|
11849
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
11850
|
+
const payload = { last: attempt };
|
|
11851
|
+
writeFileSync(path, `${JSON.stringify(payload, null, 2)}\n`, { mode: 384 });
|
|
11852
|
+
}
|
|
11853
|
+
/**
|
|
11854
|
+
* `true` when the last recorded attempt was `blocked` for *this exact
|
|
11855
|
+
* target version*. Server moving on to a different version clears the
|
|
11856
|
+
* block automatically — only the specific (target, machine) pair stays
|
|
11857
|
+
* frozen. Loop guard does not block on `failed`: those should retry
|
|
11858
|
+
* (transient EACCES / network), and the UpdateManager already handles
|
|
11859
|
+
* the back-off via "next welcome frame".
|
|
11860
|
+
*/
|
|
11861
|
+
function isLoopGuarded(target, path = defaultUpdateStatePath()) {
|
|
11862
|
+
const state = readUpdateState(path);
|
|
11863
|
+
if (!state) return false;
|
|
11864
|
+
return state.last.result === "blocked" && state.last.target === target;
|
|
11865
|
+
}
|
|
11866
|
+
//#endregion
|
|
11784
11867
|
//#region src/core/client-runtime.ts
|
|
11785
11868
|
/**
|
|
11786
11869
|
* Client runtime — one shared ClientConnection, multiple agents multiplexed.
|
|
@@ -11825,7 +11908,8 @@ var ClientRuntime = class {
|
|
|
11825
11908
|
clientId,
|
|
11826
11909
|
sdkVersion: options.currentVersion,
|
|
11827
11910
|
userAgent: CLI_USER_AGENT,
|
|
11828
|
-
getAccessToken: (opts) => ensureFreshAccessToken(opts)
|
|
11911
|
+
getAccessToken: (opts) => ensureFreshAccessToken(opts),
|
|
11912
|
+
getLastUpdateAttempt: () => readUpdateState()?.last ?? null
|
|
11829
11913
|
});
|
|
11830
11914
|
this.gitMirrorManager = createGitMirrorManager({
|
|
11831
11915
|
dataDir: DEFAULT_DATA_DIR$1,
|
|
@@ -13322,7 +13406,7 @@ async function onboardCreate(args) {
|
|
|
13322
13406
|
}
|
|
13323
13407
|
const runtimeAgent = args.type === "human" ? args.assistant : args.id;
|
|
13324
13408
|
if (args.feishuBotAppId && args.feishuBotAppSecret) {
|
|
13325
|
-
const { bindFeishuBot } = await import("./feishu-
|
|
13409
|
+
const { bindFeishuBot } = await import("./feishu-DXF_NJHg.mjs");
|
|
13326
13410
|
const targetAgentUuid = args.type === "human" ? assistantUuid : primary.uuid;
|
|
13327
13411
|
if (!targetAgentUuid) print.line(`Warning: Cannot bind Feishu bot — no runtime agent available for "${args.id}".\n`);
|
|
13328
13412
|
else {
|
|
@@ -13784,7 +13868,7 @@ const declineUpdate = async () => false;
|
|
|
13784
13868
|
* operator restarts manually.
|
|
13785
13869
|
*/
|
|
13786
13870
|
function createExecuteUpdate({ managed }) {
|
|
13787
|
-
return async ({ targetVersion }) => {
|
|
13871
|
+
return async ({ currentVersion, targetVersion }) => {
|
|
13788
13872
|
const mode = detectInstallMode();
|
|
13789
13873
|
if (mode === "source") {
|
|
13790
13874
|
print.line(" [update] Running from source checkout — self-update skipped. Use `git pull` instead.\n");
|
|
@@ -13794,18 +13878,57 @@ function createExecuteUpdate({ managed }) {
|
|
|
13794
13878
|
print.line(" [update] Cannot self-update — not launched from a global npm install.\n Run `npm i -g @agent-team-foundation/first-tree-hub` manually.\n");
|
|
13795
13879
|
return { installed: false };
|
|
13796
13880
|
}
|
|
13881
|
+
if (isLoopGuarded(targetVersion)) {
|
|
13882
|
+
print.line(` [update] Refusing to retry ${targetVersion} — a previous attempt completed without\n advancing the on-disk version. The most likely cause is npm's \`latest\`
|
|
13883
|
+
dist-tag resolving to the same version this client is already running.
|
|
13884
|
+
Operator action: manually run \`npm install -g @agent-team-foundation/first-tree-hub@latest\`,
|
|
13885
|
+
then restart the service.
|
|
13886
|
+
`);
|
|
13887
|
+
return { installed: true };
|
|
13888
|
+
}
|
|
13797
13889
|
print.line(` [update] Running \`npm install -g @agent-team-foundation/first-tree-hub@${targetVersion}\`...\n`);
|
|
13798
13890
|
const result = await installGlobalSpec(targetVersion);
|
|
13799
13891
|
if (!result.ok) {
|
|
13800
13892
|
print.line(` [update] Install failed: ${result.reason}\n`);
|
|
13893
|
+
recordUpdateAttempt({
|
|
13894
|
+
result: "failed",
|
|
13895
|
+
target: targetVersion,
|
|
13896
|
+
currentBefore: currentVersion,
|
|
13897
|
+
installedVersion: null,
|
|
13898
|
+
reason: result.reason,
|
|
13899
|
+
at: (/* @__PURE__ */ new Date()).toISOString()
|
|
13900
|
+
});
|
|
13801
13901
|
return { installed: false };
|
|
13802
13902
|
}
|
|
13803
|
-
const installed = result.installedVersion
|
|
13903
|
+
const installed = result.installedVersion;
|
|
13904
|
+
if (installed && semver.valid(installed) && semver.valid(targetVersion) && semver.lt(installed, targetVersion)) {
|
|
13905
|
+
const reason = `npm reported install of ${installed}, but the server-advertised target was ${targetVersion} (running ${currentVersion})`;
|
|
13906
|
+
print.line(` [update] WARNING: ${reason}\n`);
|
|
13907
|
+
print.line(" [update] Skipping restart to avoid an exit-75 → reboot loop. Loop guard armed.\n");
|
|
13908
|
+
recordUpdateAttempt({
|
|
13909
|
+
result: "blocked",
|
|
13910
|
+
target: targetVersion,
|
|
13911
|
+
currentBefore: currentVersion,
|
|
13912
|
+
installedVersion: installed,
|
|
13913
|
+
reason,
|
|
13914
|
+
at: (/* @__PURE__ */ new Date()).toISOString()
|
|
13915
|
+
});
|
|
13916
|
+
return { installed: true };
|
|
13917
|
+
}
|
|
13918
|
+
const installedLabel = installed ?? targetVersion;
|
|
13919
|
+
recordUpdateAttempt({
|
|
13920
|
+
result: "ok",
|
|
13921
|
+
target: targetVersion,
|
|
13922
|
+
currentBefore: currentVersion,
|
|
13923
|
+
installedVersion: installed,
|
|
13924
|
+
reason: null,
|
|
13925
|
+
at: (/* @__PURE__ */ new Date()).toISOString()
|
|
13926
|
+
});
|
|
13804
13927
|
if (managed) {
|
|
13805
|
-
print.line(` [update] Installed ${
|
|
13928
|
+
print.line(` [update] Installed ${installedLabel}. Restarting (exit 75).\n`);
|
|
13806
13929
|
process.exit(75);
|
|
13807
13930
|
}
|
|
13808
|
-
print.line(` [update] Installed ${
|
|
13931
|
+
print.line(` [update] Installed ${installedLabel}. Restart the client manually (Ctrl+C then \`first-tree-hub client start\`) to pick up the new version.\n`);
|
|
13809
13932
|
return { installed: true };
|
|
13810
13933
|
};
|
|
13811
13934
|
}
|