@indigoai-us/hq-cli 5.162.0 → 5.163.0
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/CHANGELOG.md +13 -0
- package/dist/command-catalog.generated.d.ts +188 -0
- package/dist/command-catalog.generated.js +235 -0
- package/dist/command-registration-plan.d.ts +7 -0
- package/dist/command-registration-plan.js +1 -0
- package/dist/commands/agent-enroll.d.ts +6 -1
- package/dist/commands/agent-enroll.js +30 -3
- package/dist/commands/agents.js +15 -22
- package/dist/commands/bot.js +56 -6
- package/dist/commands/daemon.d.ts +53 -0
- package/dist/commands/daemon.js +554 -0
- package/dist/commands/lanes.js +7 -0
- package/dist/commands/meetings.js +18 -16
- package/dist/commands/mesh.js +9 -0
- package/dist/lib/daemon/catalog.d.ts +85 -0
- package/dist/lib/daemon/catalog.js +274 -0
- package/dist/lib/daemon/config.d.ts +26 -0
- package/dist/lib/daemon/config.js +85 -0
- package/dist/lib/daemon/handoff.d.ts +53 -0
- package/dist/lib/daemon/handoff.js +136 -0
- package/dist/lib/daemon/install.d.ts +76 -0
- package/dist/lib/daemon/install.js +299 -0
- package/dist/lib/daemon/legacy.d.ts +35 -0
- package/dist/lib/daemon/legacy.js +120 -0
- package/dist/lib/daemon/lock.d.ts +47 -0
- package/dist/lib/daemon/lock.js +138 -0
- package/dist/lib/daemon/machine-type.d.ts +48 -0
- package/dist/lib/daemon/machine-type.js +139 -0
- package/dist/lib/daemon/migrate.d.ts +61 -0
- package/dist/lib/daemon/migrate.js +238 -0
- package/dist/lib/daemon/paths.d.ts +22 -0
- package/dist/lib/daemon/paths.js +42 -0
- package/dist/lib/daemon/remote-control.d.ts +35 -0
- package/dist/lib/daemon/remote-control.js +47 -0
- package/dist/lib/daemon/requests.d.ts +24 -0
- package/dist/lib/daemon/requests.js +63 -0
- package/dist/lib/daemon/run.d.ts +41 -0
- package/dist/lib/daemon/run.js +319 -0
- package/dist/lib/daemon/supervisor.d.ts +87 -0
- package/dist/lib/daemon/supervisor.js +523 -0
- package/dist/lib/daemon/updater.d.ts +39 -0
- package/dist/lib/daemon/updater.js +103 -0
- package/dist/lib/flag-registry.d.ts +7 -1
- package/dist/lib/flag-registry.js +8 -0
- package/dist/lib/mesh/live/backoff.d.ts +2 -2
- package/dist/lib/mesh/live/backoff.js +16 -3
- package/dist/lib/mesh/live/daemon/run.d.ts +2 -2
- package/dist/lib/mesh/live/daemon/run.js +5 -2
- package/dist/lib/mesh/live/flush.d.ts +3 -2
- package/dist/lib/mesh/live/flush.js +34 -7
- package/dist/lib/mesh/live/session-events-client.d.ts +2 -0
- package/dist/lib/mesh/live/session-events-client.js +25 -0
- package/dist/lib/service-manager/systemd.d.ts +2 -2
- package/dist/lib/service-manager/systemd.js +1 -1
- package/dist/lib/service-manager/types.d.ts +2 -0
- package/dist/main.d.ts +6 -0
- package/dist/main.js +53 -13
- package/dist/utils/cognito-session.d.ts +4 -0
- package/dist/utils/cognito-session.js +11 -10
- package/dist/utils/plan-gate-error.d.ts +27 -13
- package/dist/utils/plan-gate-error.js +133 -58
- package/dist/utils/self-update.d.ts +9 -0
- package/dist/utils/self-update.js +15 -2
- package/package.json +1 -1
|
@@ -1,30 +1,44 @@
|
|
|
1
|
-
export type PlanGateCode = "PLAN_LIMIT_EXCEEDED" | "PLAN_REQUIRED"
|
|
2
|
-
/**
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
* code rather than a reuse of `PLAN_REQUIRED` with company copy.
|
|
7
|
-
*/
|
|
8
|
-
| "PERSONAL_PLAN_REQUIRED";
|
|
1
|
+
export type PlanGateCode = "PLAN_LIMIT_EXCEEDED" | "PLAN_REQUIRED" | "MEETING_PLAN_REQUIRED"
|
|
2
|
+
/** A PERSONAL scope asked for a feature the paid Individual plan includes. */
|
|
3
|
+
| "PERSONAL_PLAN_REQUIRED"
|
|
4
|
+
/** External agent enrollment was denied by the company plan. */
|
|
5
|
+
| "BILLING_REQUIRED";
|
|
9
6
|
export interface PlanGateDetails {
|
|
10
7
|
resource?: string;
|
|
11
|
-
/** The refused feature, on a `PERSONAL_PLAN_REQUIRED` denial. */
|
|
12
8
|
feature?: string;
|
|
13
9
|
used?: number;
|
|
14
10
|
limit?: number;
|
|
15
11
|
upgradeUrl?: string;
|
|
16
|
-
|
|
12
|
+
reason?: string;
|
|
13
|
+
/** Company target from request context or the server's UID-keyed billing URL. */
|
|
17
14
|
companyUid?: string;
|
|
18
15
|
}
|
|
16
|
+
/** One renderer for server-selected upgrade links across CLI plan refusals. */
|
|
17
|
+
export declare function formatUpgradeRefusal(reason: string, upgradeUrl: string | undefined, options?: {
|
|
18
|
+
urlOnly?: boolean;
|
|
19
|
+
}): string;
|
|
20
|
+
/** Recover a company UID only from the server's UID-keyed billing callback. */
|
|
21
|
+
export declare function companyUidFromPlanUpgradeUrl(value: unknown): string | undefined;
|
|
19
22
|
export declare class PlanGateError extends Error {
|
|
20
23
|
readonly code: PlanGateCode;
|
|
21
24
|
readonly details: PlanGateDetails;
|
|
22
25
|
constructor(code: PlanGateCode, details: PlanGateDetails);
|
|
23
26
|
}
|
|
24
27
|
export declare function isPlanGateError(err: unknown): err is PlanGateError;
|
|
25
|
-
|
|
28
|
+
/** Plain, stable CLI copy for plan-gated resource creation. */
|
|
29
|
+
export declare function formatPlanGateError(err: PlanGateError, options?: {
|
|
30
|
+
urlOnly?: boolean;
|
|
31
|
+
}): string;
|
|
26
32
|
export declare function canOfferTeamUpgrade(argv?: readonly string[]): boolean;
|
|
27
|
-
|
|
33
|
+
export interface UpgradeLinkOfferDependencies {
|
|
34
|
+
ask?: (question: string) => Promise<string>;
|
|
35
|
+
openUrl?: (url: string) => Promise<void>;
|
|
36
|
+
argv?: readonly string[];
|
|
37
|
+
interactive?: boolean;
|
|
38
|
+
}
|
|
39
|
+
/** Ask before opening the exact URL returned by the server. */
|
|
40
|
+
export declare function offerUpgradeLink(url: string, deps?: UpgradeLinkOfferDependencies): Promise<boolean>;
|
|
41
|
+
/** Legacy checkout callback retained for callers outside the shared refusal paths. */
|
|
28
42
|
export declare function offerTeamUpgrade(onConfirm: () => Promise<void>, deps?: {
|
|
29
43
|
ask?: (question: string) => Promise<string>;
|
|
30
44
|
argv?: readonly string[];
|
|
@@ -33,7 +47,7 @@ export declare function offerTeamUpgrade(onConfirm: () => Promise<void>, deps?:
|
|
|
33
47
|
/** Decode an already-read JSON envelope from either shared HTTP client. */
|
|
34
48
|
export declare function planGateErrorFromPayload(status: number, body: unknown, companyUid?: string): PlanGateError | null;
|
|
35
49
|
/**
|
|
36
|
-
* Decode
|
|
50
|
+
* Decode the supported plan-gate envelopes. Malformed, unrelated,
|
|
37
51
|
* or non-402 responses retain their existing command-specific handling.
|
|
38
52
|
*/
|
|
39
53
|
export declare function planGateErrorFromResponse(response: Response, companyUid?: string): Promise<{
|
|
@@ -4,19 +4,74 @@
|
|
|
4
4
|
* message instead of every command parsing and printing a server response.
|
|
5
5
|
*/
|
|
6
6
|
import { renderPersonalPlanFeatureNotice } from "../lib/plan-limit-nag.js";
|
|
7
|
-
|
|
7
|
+
function planGateReason(code, details) {
|
|
8
|
+
if (details.reason?.trim())
|
|
9
|
+
return details.reason.trim();
|
|
10
|
+
if (code === "PLAN_LIMIT_EXCEEDED" &&
|
|
11
|
+
typeof details.resource === "string" &&
|
|
12
|
+
typeof details.used === "number" &&
|
|
13
|
+
typeof details.limit === "number") {
|
|
14
|
+
return `Starter plan limit reached: ${details.resource} ${details.used}/${details.limit} used.`;
|
|
15
|
+
}
|
|
16
|
+
if (code === "PERSONAL_PLAN_REQUIRED") {
|
|
17
|
+
return renderPersonalPlanFeatureNotice(details.feature ?? "this feature", null);
|
|
18
|
+
}
|
|
19
|
+
if (code === "MEETING_PLAN_REQUIRED") {
|
|
20
|
+
return "HQ Workforce plan required to invite a meeting bot.";
|
|
21
|
+
}
|
|
22
|
+
if (code === "BILLING_REQUIRED") {
|
|
23
|
+
return "Upgrade the company plan before enrolling an external agent.";
|
|
24
|
+
}
|
|
25
|
+
return "HQ Workforce plan required for this feature.";
|
|
26
|
+
}
|
|
27
|
+
/** One renderer for server-selected upgrade links across CLI plan refusals. */
|
|
28
|
+
export function formatUpgradeRefusal(reason, upgradeUrl, options = {}) {
|
|
29
|
+
const safeUrl = safeUpgradeUrl(upgradeUrl);
|
|
30
|
+
if (options.urlOnly && safeUrl)
|
|
31
|
+
return safeUrl;
|
|
32
|
+
if (!safeUrl)
|
|
33
|
+
return reason;
|
|
34
|
+
return `${reason}\nUpgrade: ${safeUrl}`;
|
|
35
|
+
}
|
|
36
|
+
function safeUpgradeUrl(value) {
|
|
37
|
+
if (typeof value !== "string" ||
|
|
38
|
+
value.trim() !== value ||
|
|
39
|
+
!/^https:\/\//i.test(value)) {
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
42
|
+
try {
|
|
43
|
+
const url = new URL(value);
|
|
44
|
+
if (url.protocol !== "https:" ||
|
|
45
|
+
!url.hostname ||
|
|
46
|
+
url.username ||
|
|
47
|
+
url.password) {
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return undefined;
|
|
53
|
+
}
|
|
54
|
+
return value;
|
|
55
|
+
}
|
|
56
|
+
/** Recover a company UID only from the server's UID-keyed billing callback. */
|
|
57
|
+
export function companyUidFromPlanUpgradeUrl(value) {
|
|
58
|
+
const safeUrl = safeUpgradeUrl(value);
|
|
59
|
+
if (!safeUrl)
|
|
60
|
+
return undefined;
|
|
61
|
+
const callbackUrl = new URL(safeUrl).searchParams.get("callbackUrl");
|
|
62
|
+
if (!callbackUrl)
|
|
63
|
+
return undefined;
|
|
64
|
+
const match = /^\/api\/companies\/(cmp_[A-Za-z0-9_-]+)\/billing\/upgrade\/?$/.exec(callbackUrl);
|
|
65
|
+
return match?.[1];
|
|
66
|
+
}
|
|
67
|
+
function formatPlanGateErrorText(code, details) {
|
|
68
|
+
return formatUpgradeRefusal(planGateReason(code, details), details.upgradeUrl);
|
|
69
|
+
}
|
|
8
70
|
export class PlanGateError extends Error {
|
|
9
71
|
code;
|
|
10
72
|
details;
|
|
11
73
|
constructor(code, details) {
|
|
12
|
-
|
|
13
|
-
// `err.message`. Keeping the friendly copy here means those boundaries
|
|
14
|
-
// retain the same plan-gate voice as main.ts without per-command handling.
|
|
15
|
-
// The HQ Workforce hint is company advice; a personal denial ends at its
|
|
16
|
-
// own notice, which already names the Individual plan and its checkout.
|
|
17
|
-
super(code === "PERSONAL_PLAN_REQUIRED"
|
|
18
|
-
? formatPlanGateDetails(code, details)
|
|
19
|
-
: [formatPlanGateDetails(code, details), TEAM_UPGRADE_HINT].join("\n"));
|
|
74
|
+
super(formatPlanGateErrorText(code, details));
|
|
20
75
|
this.code = code;
|
|
21
76
|
this.details = details;
|
|
22
77
|
this.name = "PlanGateError";
|
|
@@ -26,56 +81,52 @@ export function isPlanGateError(err) {
|
|
|
26
81
|
return err instanceof PlanGateError;
|
|
27
82
|
}
|
|
28
83
|
/** Plain, stable CLI copy for plan-gated resource creation. */
|
|
29
|
-
function
|
|
30
|
-
|
|
31
|
-
if (code === "PLAN_LIMIT_EXCEEDED" &&
|
|
32
|
-
typeof details.resource === "string" &&
|
|
33
|
-
typeof details.used === "number" &&
|
|
34
|
-
typeof details.limit === "number") {
|
|
35
|
-
const upgrade = typeof details.upgradeUrl === "string"
|
|
36
|
-
? `Upgrade to HQ Workforce ($500/mo) to remove limits: ${details.upgradeUrl}`
|
|
37
|
-
: "Upgrade to HQ Workforce ($500/mo) to remove limits.";
|
|
38
|
-
return [
|
|
39
|
-
`Starter plan limit reached: ${details.resource} ${details.used}/${details.limit} used.`,
|
|
40
|
-
upgrade,
|
|
41
|
-
existingResourcesNote,
|
|
42
|
-
].join("\n");
|
|
43
|
-
}
|
|
44
|
-
// A personal scope is not a workspace: it has no members to trim, no $500
|
|
45
|
-
// tier to buy, and nothing of its own is paused. One line, the plan's own
|
|
46
|
-
// copy, and no company remedy.
|
|
47
|
-
if (code === "PERSONAL_PLAN_REQUIRED") {
|
|
48
|
-
return renderPersonalPlanFeatureNotice(details.feature ?? "this feature", details.upgradeUrl ?? null);
|
|
49
|
-
}
|
|
50
|
-
const upgrade = typeof details.upgradeUrl === "string"
|
|
51
|
-
? `Upgrade to HQ Workforce ($500/mo) to remove limits: ${details.upgradeUrl}`
|
|
52
|
-
: "Upgrade to HQ Workforce ($500/mo) to remove limits.";
|
|
53
|
-
return [
|
|
54
|
-
"HQ Workforce plan required for this feature.",
|
|
55
|
-
upgrade,
|
|
56
|
-
existingResourcesNote,
|
|
57
|
-
].join("\n");
|
|
58
|
-
}
|
|
59
|
-
export function formatPlanGateError(err) {
|
|
60
|
-
if (err.code === "PERSONAL_PLAN_REQUIRED") {
|
|
61
|
-
return formatPlanGateDetails(err.code, err.details);
|
|
62
|
-
}
|
|
63
|
-
return [
|
|
64
|
-
formatPlanGateDetails(err.code, err.details),
|
|
65
|
-
TEAM_UPGRADE_HINT,
|
|
66
|
-
].join("\n");
|
|
84
|
+
export function formatPlanGateError(err, options = {}) {
|
|
85
|
+
return formatUpgradeRefusal(planGateReason(err.code, err.details), err.details.upgradeUrl, options);
|
|
67
86
|
}
|
|
68
87
|
export function canOfferTeamUpgrade(argv = process.argv) {
|
|
69
88
|
return Boolean(process.stdin.isTTY && process.stderr.isTTY) &&
|
|
70
89
|
!process.env.CI &&
|
|
71
90
|
!argv.includes("--json");
|
|
72
91
|
}
|
|
73
|
-
/** Ask
|
|
92
|
+
/** Ask before opening the exact URL returned by the server. */
|
|
93
|
+
export async function offerUpgradeLink(url, deps = {}) {
|
|
94
|
+
const safeUrl = safeUpgradeUrl(url);
|
|
95
|
+
if (!safeUrl)
|
|
96
|
+
return false;
|
|
97
|
+
if (!(deps.interactive ?? canOfferTeamUpgrade(deps.argv)))
|
|
98
|
+
return false;
|
|
99
|
+
let answer;
|
|
100
|
+
if (deps.ask) {
|
|
101
|
+
answer = await deps.ask("Open upgrade link now? [y/N] ");
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
const { createInterface } = await import("node:readline/promises");
|
|
105
|
+
const readline = createInterface({ input: process.stdin, output: process.stderr });
|
|
106
|
+
try {
|
|
107
|
+
answer = await readline.question("Open upgrade link now? [y/N] ");
|
|
108
|
+
}
|
|
109
|
+
finally {
|
|
110
|
+
readline.close();
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
if (!/^y(?:es)?$/i.test(answer.trim()))
|
|
114
|
+
return false;
|
|
115
|
+
if (deps.openUrl) {
|
|
116
|
+
await deps.openUrl(safeUrl);
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
const { default: open } = await import("open");
|
|
120
|
+
await open(safeUrl);
|
|
121
|
+
}
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
/** Legacy checkout callback retained for callers outside the shared refusal paths. */
|
|
74
125
|
export async function offerTeamUpgrade(onConfirm, deps = {}) {
|
|
75
126
|
if (!(deps.interactive ?? canOfferTeamUpgrade(deps.argv)))
|
|
76
127
|
return false;
|
|
77
128
|
if (deps.ask) {
|
|
78
|
-
const answer = await deps.ask("Upgrade
|
|
129
|
+
const answer = await deps.ask("Upgrade now? (opens checkout) [y/N] ");
|
|
79
130
|
if (!/^y(?:es)?$/i.test(answer.trim()))
|
|
80
131
|
return false;
|
|
81
132
|
await onConfirm();
|
|
@@ -84,7 +135,7 @@ export async function offerTeamUpgrade(onConfirm, deps = {}) {
|
|
|
84
135
|
const { createInterface } = await import("node:readline/promises");
|
|
85
136
|
const readline = createInterface({ input: process.stdin, output: process.stderr });
|
|
86
137
|
try {
|
|
87
|
-
const answer = await readline.question("Upgrade
|
|
138
|
+
const answer = await readline.question("Upgrade now? (opens checkout) [y/N] ");
|
|
88
139
|
if (!/^y(?:es)?$/i.test(answer.trim()))
|
|
89
140
|
return false;
|
|
90
141
|
await onConfirm();
|
|
@@ -106,28 +157,52 @@ export function planGateErrorFromPayload(status, body, companyUid) {
|
|
|
106
157
|
// through to the company path below (defensive consumer).
|
|
107
158
|
if (payload.error === "plan_feature_unavailable" &&
|
|
108
159
|
payload.scope === "personal") {
|
|
160
|
+
const upgradeUrl = safeUpgradeUrl(payload.upgradeUrl);
|
|
109
161
|
return new PlanGateError("PERSONAL_PLAN_REQUIRED", {
|
|
110
162
|
...(typeof payload.feature === "string"
|
|
111
163
|
? { feature: payload.feature }
|
|
112
164
|
: {}),
|
|
113
|
-
...(
|
|
114
|
-
? { upgradeUrl: payload.upgradeUrl }
|
|
115
|
-
: {}),
|
|
165
|
+
...(upgradeUrl ? { upgradeUrl } : {}),
|
|
116
166
|
});
|
|
117
167
|
}
|
|
118
|
-
|
|
168
|
+
const code = payload.code;
|
|
169
|
+
const upgradeUrl = safeUpgradeUrl(payload.upgradeUrl);
|
|
170
|
+
const targetCompanyUid = companyUid ?? companyUidFromPlanUpgradeUrl(upgradeUrl);
|
|
171
|
+
const planLimit = payload.planLimit !== null &&
|
|
172
|
+
typeof payload.planLimit === "object" &&
|
|
173
|
+
!Array.isArray(payload.planLimit)
|
|
174
|
+
? payload.planLimit
|
|
175
|
+
: undefined;
|
|
176
|
+
const isTeamPlanBillingRequired = code === "BILLING_REQUIRED" && planLimit?.requiredPlan === "team";
|
|
177
|
+
if (code === "BILLING_REQUIRED") {
|
|
178
|
+
if (!isTeamPlanBillingRequired ||
|
|
179
|
+
!targetCompanyUid ||
|
|
180
|
+
!/^cmp_[A-Za-z0-9_-]+$/.test(targetCompanyUid)) {
|
|
181
|
+
return null;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
else if (code !== "PLAN_LIMIT_EXCEEDED" &&
|
|
185
|
+
code !== "PLAN_REQUIRED" &&
|
|
186
|
+
code !== "MEETING_PLAN_REQUIRED") {
|
|
119
187
|
return null;
|
|
120
188
|
}
|
|
121
|
-
|
|
189
|
+
const reason = typeof payload.message === "string"
|
|
190
|
+
? payload.message
|
|
191
|
+
: typeof payload.error === "string" && payload.error !== payload.code
|
|
192
|
+
? payload.error
|
|
193
|
+
: undefined;
|
|
194
|
+
return new PlanGateError(code, {
|
|
122
195
|
...(typeof payload.resource === "string" ? { resource: payload.resource } : {}),
|
|
196
|
+
...(typeof payload.feature === "string" ? { feature: payload.feature } : {}),
|
|
123
197
|
...(typeof payload.used === "number" ? { used: payload.used } : {}),
|
|
124
198
|
...(typeof payload.limit === "number" ? { limit: payload.limit } : {}),
|
|
125
|
-
...(
|
|
126
|
-
...(
|
|
199
|
+
...(upgradeUrl ? { upgradeUrl } : {}),
|
|
200
|
+
...(reason ? { reason } : {}),
|
|
201
|
+
...(targetCompanyUid ? { companyUid: targetCompanyUid } : {}),
|
|
127
202
|
});
|
|
128
203
|
}
|
|
129
204
|
/**
|
|
130
|
-
* Decode
|
|
205
|
+
* Decode the supported plan-gate envelopes. Malformed, unrelated,
|
|
131
206
|
* or non-402 responses retain their existing command-specific handling.
|
|
132
207
|
*/
|
|
133
208
|
export async function planGateErrorFromResponse(response, companyUid) {
|
|
@@ -83,6 +83,8 @@ export type SelfUpdateAction =
|
|
|
83
83
|
| "update-ineffective"
|
|
84
84
|
/** Updated and the command re-ran on the new version; exit with `reexecStatus`. */
|
|
85
85
|
| "reexec"
|
|
86
|
+
/** Updated with no re-exec (the `hq daemon` updater restarts the daemon instead). */
|
|
87
|
+
| "updated"
|
|
86
88
|
/**
|
|
87
89
|
* Unattended caller: replacing the CLI in place is unsafe here, so nothing
|
|
88
90
|
* was attempted and the command runs on the current version. An attended
|
|
@@ -171,4 +173,11 @@ export declare function autoUpdateAndReexec(argv: readonly string[], latest: str
|
|
|
171
173
|
* are preserved.
|
|
172
174
|
*/
|
|
173
175
|
export declare function selfUpdateAndReexec(argv: readonly string[], deps?: SelfUpdateDeps): Promise<SelfUpdateOutcome>;
|
|
176
|
+
/**
|
|
177
|
+
* `hq daemon` updater service: update to npm latest with nobody at a terminal
|
|
178
|
+
* and no re-exec. It runs as its own short-lived child of the daemon, so no
|
|
179
|
+
* user command is waiting on the package being replaced; after an "updated"
|
|
180
|
+
* outcome the daemon restarts itself onto the new version.
|
|
181
|
+
*/
|
|
182
|
+
export declare function daemonSelfUpdate(deps?: SelfUpdateDeps): Promise<SelfUpdateOutcome>;
|
|
174
183
|
//# sourceMappingURL=self-update.d.ts.map
|
|
@@ -292,6 +292,10 @@ async function updateAndReexec(argv, flavor, known, deps) {
|
|
|
292
292
|
catch {
|
|
293
293
|
// Defensive only; the default helper already absorbs manager failures.
|
|
294
294
|
}
|
|
295
|
+
if (!flavor.reexec) {
|
|
296
|
+
console.error(chalk.dim(`✓ hq-cli updated to ${latest}.`));
|
|
297
|
+
return { action: "updated", latest };
|
|
298
|
+
}
|
|
295
299
|
const childEnv = { ...env, [REEXEC_GUARD_ENV]: "1" };
|
|
296
300
|
const status = (deps.reexec ?? reexecHq)([...argv.slice(2)], childEnv);
|
|
297
301
|
if (status === null) {
|
|
@@ -309,7 +313,7 @@ async function updateAndReexec(argv, flavor, known, deps) {
|
|
|
309
313
|
* this resolve it from the registry.
|
|
310
314
|
*/
|
|
311
315
|
export async function autoUpdateAndReexec(argv, latest, deps = {}) {
|
|
312
|
-
return updateAndReexec(argv, { noun: "command", verbose: false, lock: true, onlyWhenAttended: true }, latest, deps);
|
|
316
|
+
return updateAndReexec(argv, { noun: "command", verbose: false, lock: true, onlyWhenAttended: true, reexec: true }, latest, deps);
|
|
313
317
|
}
|
|
314
318
|
/**
|
|
315
319
|
* Rescue path: update to npm latest and re-exec the rescue on the new version.
|
|
@@ -318,6 +322,15 @@ export async function autoUpdateAndReexec(argv, latest, deps = {}) {
|
|
|
318
322
|
* are preserved.
|
|
319
323
|
*/
|
|
320
324
|
export async function selfUpdateAndReexec(argv, deps = {}) {
|
|
321
|
-
return updateAndReexec(argv, { noun: "rescue", verbose: true, lock: true, onlyWhenAttended: false }, null, deps);
|
|
325
|
+
return updateAndReexec(argv, { noun: "rescue", verbose: true, lock: true, onlyWhenAttended: false, reexec: true }, null, deps);
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* `hq daemon` updater service: update to npm latest with nobody at a terminal
|
|
329
|
+
* and no re-exec. It runs as its own short-lived child of the daemon, so no
|
|
330
|
+
* user command is waiting on the package being replaced; after an "updated"
|
|
331
|
+
* outcome the daemon restarts itself onto the new version.
|
|
332
|
+
*/
|
|
333
|
+
export async function daemonSelfUpdate(deps = {}) {
|
|
334
|
+
return updateAndReexec([], { noun: "daemon update", verbose: false, lock: true, onlyWhenAttended: false, reexec: false }, null, deps);
|
|
322
335
|
}
|
|
323
336
|
//# sourceMappingURL=self-update.js.map
|