@indigoai-us/hq-cli 5.345.121 → 5.345.123
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 +22 -0
- package/README.md +15 -0
- package/assets/scaffold/core/scripts/handoff-sync-prefetch.sh +121 -0
- package/assets/scaffold/core/scripts/handoff-sync-publish.sh +124 -0
- package/assets/scaffold/core/scripts/knowledge-pulse-lock.sh +27 -0
- package/assets/scaffold/core/scripts/lib/session-skill-catalog.sh +226 -0
- package/assets/scaffold/core/scripts/skill-installed.sh +43 -0
- package/dist/command-catalog.generated.d.ts +97 -0
- package/dist/command-catalog.generated.js +116 -0
- package/dist/command-registration-plan.d.ts +6 -0
- package/dist/command-registration-plan.js +1 -0
- package/dist/commands/core-bucket-c-handoff-sync-fast.d.ts +3 -0
- package/dist/commands/core-bucket-c-handoff-sync-fast.js +16 -0
- package/dist/commands/core-bucket-c-handoff-sync-native.d.ts +45 -0
- package/dist/commands/core-bucket-c-handoff-sync-native.js +300 -0
- package/dist/commands/core-bucket-c-small-fast.d.ts +5 -0
- package/dist/commands/core-bucket-c-small-fast.js +19 -0
- package/dist/commands/core-bucket-c-small-native.d.ts +11 -0
- package/dist/commands/core-bucket-c-small-native.js +197 -0
- package/dist/commands/core-derive-trigger-facts-native.js +4 -1
- package/dist/commands/core.js +25 -0
- package/dist/commands/deploy-comments.d.ts +2 -0
- package/dist/commands/deploy-comments.js +2 -2
- package/dist/commands/deploy-list.d.ts +22 -0
- package/dist/commands/deploy-list.js +153 -0
- package/dist/commands/lanes.js +50 -3
- package/dist/fast-scaffold.js +48 -0
- package/dist/lib/capacity/collectors/claude-oauth.d.ts +1 -1
- package/dist/lib/capacity/collectors/claude-oauth.js +48 -4
- package/dist/lib/capacity/ledger.d.ts +7 -0
- package/dist/lib/capacity/ledger.js +17 -1
- package/dist/lib/capacity/sign-in.d.ts +2 -0
- package/dist/lib/capacity/sign-in.js +19 -4
- package/dist/lib/core-utils/session-company.d.ts +3 -0
- package/dist/lib/core-utils/session-company.js +78 -0
- package/dist/lib/lanes/spawn.d.ts +1 -0
- package/dist/lib/lanes/spawn.js +4 -1
- package/dist/lib/lanes/store.js +11 -0
- package/dist/lib/lanes/types.d.ts +2 -0
- package/dist/lib/lanes/types.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { KNOWLEDGE_PULSE_LOCK_ASSET, runKnowledgePulseLock, runSkillInstalled, SKILL_INSTALLED_ASSET } from "./core-bucket-c-small-native.js";
|
|
2
|
+
export { KNOWLEDGE_PULSE_LOCK_ASSET, SKILL_INSTALLED_ASSET, runKnowledgePulseLock, runSkillInstalled };
|
|
3
|
+
export function runKnowledgePulseLockFast(args, _stdin, _cwd, _root) {
|
|
4
|
+
const result = runKnowledgePulseLock(args);
|
|
5
|
+
if (result.stdout)
|
|
6
|
+
process.stdout.write(result.stdout);
|
|
7
|
+
if (result.stderr)
|
|
8
|
+
process.stderr.write(result.stderr);
|
|
9
|
+
return result.code;
|
|
10
|
+
}
|
|
11
|
+
export async function runSkillInstalledFast(args, _stdin, _cwd, root) {
|
|
12
|
+
const result = await runSkillInstalled(args, root);
|
|
13
|
+
if (result.stdout)
|
|
14
|
+
process.stdout.write(result.stdout);
|
|
15
|
+
if (result.stderr)
|
|
16
|
+
process.stderr.write(result.stderr);
|
|
17
|
+
return result.code;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=core-bucket-c-small-fast.js.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare const KNOWLEDGE_PULSE_LOCK_ASSET = "core/scripts/knowledge-pulse-lock.sh";
|
|
2
|
+
export declare const SKILL_INSTALLED_ASSET = "core/scripts/skill-installed.sh";
|
|
3
|
+
export type BucketCSmallResult = {
|
|
4
|
+
code: number;
|
|
5
|
+
stdout: string;
|
|
6
|
+
stderr: string;
|
|
7
|
+
};
|
|
8
|
+
export declare function mkdirFailure(error: unknown, target: string, platform?: NodeJS.Platform): string;
|
|
9
|
+
export declare function runKnowledgePulseLock(args: readonly string[]): BucketCSmallResult;
|
|
10
|
+
export declare function runSkillInstalled(args: readonly string[], root: string, env?: NodeJS.ProcessEnv): Promise<BucketCSmallResult>;
|
|
11
|
+
//# sourceMappingURL=core-bucket-c-small-native.d.ts.map
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
export const KNOWLEDGE_PULSE_LOCK_ASSET = "core/scripts/knowledge-pulse-lock.sh";
|
|
4
|
+
export const SKILL_INSTALLED_ASSET = "core/scripts/skill-installed.sh";
|
|
5
|
+
const failure = (stderr, code = 1) => ({ code, stdout: "", stderr: `${stderr}\n` });
|
|
6
|
+
export function mkdirFailure(error, target, platform = process.platform) {
|
|
7
|
+
const fsError = error;
|
|
8
|
+
// Node's Windows fs wrapper may report this ENOTDIR as code UNKNOWN, errno -20.
|
|
9
|
+
let code = platform === "win32" && fsError.errno === -20 ? "ENOTDIR" : fsError.code;
|
|
10
|
+
const absolute = path.resolve(target);
|
|
11
|
+
const parsed = path.parse(absolute);
|
|
12
|
+
const parts = absolute.slice(parsed.root.length).split(path.sep).filter(Boolean);
|
|
13
|
+
if (platform === "win32" && parts.some((part) => part.length > 255))
|
|
14
|
+
code = "ENAMETOOLONG";
|
|
15
|
+
const reason = {
|
|
16
|
+
EACCES: "Permission denied",
|
|
17
|
+
EEXIST: "File exists",
|
|
18
|
+
ELOOP: "Too many levels of symbolic links",
|
|
19
|
+
EMFILE: "Too many open files",
|
|
20
|
+
ENAMETOOLONG: "File name too long",
|
|
21
|
+
ENFILE: "Too many open files in system",
|
|
22
|
+
ENOENT: "No such file or directory",
|
|
23
|
+
ENOMEM: "Cannot allocate memory",
|
|
24
|
+
ENOSPC: "No space left on device",
|
|
25
|
+
ENOTDIR: "Not a directory",
|
|
26
|
+
EPERM: "Operation not permitted",
|
|
27
|
+
EROFS: "Read-only file system",
|
|
28
|
+
}[code ?? ""] ?? "Input/output error";
|
|
29
|
+
let failingPath = target;
|
|
30
|
+
if (code === "ENOTDIR" || code === "ELOOP" || code === "ENAMETOOLONG") {
|
|
31
|
+
let current = parsed.root;
|
|
32
|
+
for (const part of parts) {
|
|
33
|
+
current = path.join(current, part);
|
|
34
|
+
if (platform === "win32" && part.length > 255) {
|
|
35
|
+
failingPath = current;
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
if (!fs.statSync(current).isDirectory()) {
|
|
40
|
+
failingPath = current;
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
if (error.code === code)
|
|
46
|
+
failingPath = current;
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
if (platform === "darwin")
|
|
52
|
+
return `mkdir: ${failingPath}: ${reason}`;
|
|
53
|
+
if (platform === "win32") {
|
|
54
|
+
const shellPathParts = path.parse(failingPath);
|
|
55
|
+
// MSYS converts the incoming drive path for mkdir, retaining Node's root slash and adding its own.
|
|
56
|
+
const driveRoot = shellPathParts.root.endsWith("\\") ? `${shellPathParts.root}\\` : shellPathParts.root;
|
|
57
|
+
const shellPath = `${driveRoot}${failingPath.slice(shellPathParts.root.length).replaceAll("\\", "/")}`;
|
|
58
|
+
return `mkdir: cannot create directory '${shellPath}': ${reason}`;
|
|
59
|
+
}
|
|
60
|
+
return `mkdir: cannot create directory ‘${failingPath}’: ${reason}`;
|
|
61
|
+
}
|
|
62
|
+
export function runKnowledgePulseLock(args) {
|
|
63
|
+
if (args.length !== 4 || args[0] !== "claim") {
|
|
64
|
+
return failure("Usage: knowledge-pulse-lock.sh claim <claim-root> <company-slug> <YYYY-MM-DD>", 2);
|
|
65
|
+
}
|
|
66
|
+
const [_, claimRoot, company, date] = args;
|
|
67
|
+
if (!claimRoot || !/^[a-z0-9][a-z0-9-]*$/.test(company) || !/^\d{4}-\d{2}-\d{2}$/.test(date)) {
|
|
68
|
+
return failure("knowledge-pulse-lock: invalid claim root, company slug, or date", 2);
|
|
69
|
+
}
|
|
70
|
+
try {
|
|
71
|
+
fs.mkdirSync(claimRoot, { recursive: true });
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
return failure(mkdirFailure(error, claimRoot));
|
|
75
|
+
}
|
|
76
|
+
const marker = path.join(claimRoot, `${company}-${date}.claimed`);
|
|
77
|
+
try {
|
|
78
|
+
fs.mkdirSync(marker);
|
|
79
|
+
return { code: 0, stdout: "claimed\n", stderr: "" };
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
if (error.code === "EEXIST") {
|
|
83
|
+
try {
|
|
84
|
+
if (fs.statSync(marker).isDirectory())
|
|
85
|
+
return { code: 0, stdout: "already-claimed\n", stderr: "" };
|
|
86
|
+
}
|
|
87
|
+
catch { /* fall through to the shell-compatible failure */ }
|
|
88
|
+
}
|
|
89
|
+
return failure("knowledge-pulse-lock: could not create claim marker");
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function skillName(file) {
|
|
93
|
+
try {
|
|
94
|
+
if (!fs.statSync(file).isFile())
|
|
95
|
+
return undefined;
|
|
96
|
+
const contents = fs.readFileSync(file, "utf8");
|
|
97
|
+
const lines = (process.platform === "win32" ? contents.replaceAll("\r\n", "\n") : contents).split("\n");
|
|
98
|
+
let inFrontmatter = false;
|
|
99
|
+
let name;
|
|
100
|
+
for (const line of lines) {
|
|
101
|
+
if (/^---[ \t]*$/.test(line)) {
|
|
102
|
+
if (inFrontmatter)
|
|
103
|
+
return name;
|
|
104
|
+
inFrontmatter = true;
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
if (!inFrontmatter || !/^name:[ \t]*/.test(line))
|
|
108
|
+
continue;
|
|
109
|
+
name = line.replace(/^name:[ \t]*/, "").replace(/^["']|["']$/g, "");
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
catch { /* unreadable skill files are skipped by the shell catalog */ }
|
|
113
|
+
return undefined;
|
|
114
|
+
}
|
|
115
|
+
function skillFiles(root, companies) {
|
|
116
|
+
const files = [];
|
|
117
|
+
const appendDirectories = (base, skipHidden) => {
|
|
118
|
+
let names;
|
|
119
|
+
try {
|
|
120
|
+
names = fs.readdirSync(base).sort((a, b) => a.localeCompare(b, "en"));
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
for (const name of names) {
|
|
126
|
+
if (name.startsWith(".") || (skipHidden && (name.startsWith("_") || name.startsWith("README"))))
|
|
127
|
+
continue;
|
|
128
|
+
const dir = path.join(base, name);
|
|
129
|
+
try {
|
|
130
|
+
if (!fs.statSync(dir).isDirectory())
|
|
131
|
+
continue;
|
|
132
|
+
const file = path.join(dir, "SKILL.md");
|
|
133
|
+
if (fs.statSync(file).isFile())
|
|
134
|
+
files.push(file);
|
|
135
|
+
}
|
|
136
|
+
catch { /* non-directories and missing/unreadable files are skipped */ }
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
for (const company of companies)
|
|
140
|
+
appendDirectories(path.join(root, "companies", company, "skills"), false);
|
|
141
|
+
appendDirectories(path.join(root, ".claude", "skills"), true);
|
|
142
|
+
let packages = [];
|
|
143
|
+
try {
|
|
144
|
+
packages = fs.readdirSync(path.join(root, "core", "packages")).sort((a, b) => a.localeCompare(b, "en"));
|
|
145
|
+
}
|
|
146
|
+
catch {
|
|
147
|
+
return files;
|
|
148
|
+
}
|
|
149
|
+
for (const pkg of packages)
|
|
150
|
+
appendDirectories(path.join(root, "core", "packages", pkg, "skills"), false);
|
|
151
|
+
return files;
|
|
152
|
+
}
|
|
153
|
+
export async function runSkillInstalled(args, root, env = process.env) {
|
|
154
|
+
const skill = args[0] ?? "";
|
|
155
|
+
let company = args[1] ?? env.HQ_ACTIVE_COMPANY ?? "";
|
|
156
|
+
if (!company) {
|
|
157
|
+
const [{ sessionCompanySlugs }, { fastFlagEnabledDefaultOn }, { MULTI_COMPANY_SESSION_LOCK_FLAG }] = await Promise.all([
|
|
158
|
+
import("../lib/core-utils/session-company.js"),
|
|
159
|
+
import("../native-fast-route.js"),
|
|
160
|
+
import("../lib/cli-flag-keys.js"),
|
|
161
|
+
]);
|
|
162
|
+
const multiCompanyLockEnabled = await fastFlagEnabledDefaultOn(MULTI_COMPANY_SESSION_LOCK_FLAG, env);
|
|
163
|
+
company = sessionCompanySlugs(root, env, multiCompanyLockEnabled).join(",");
|
|
164
|
+
}
|
|
165
|
+
if (!/^[a-z0-9][a-z0-9_-]*$/.test(skill))
|
|
166
|
+
return { code: 1, stdout: "", stderr: "" };
|
|
167
|
+
if (!company)
|
|
168
|
+
company = "__hq_unbound_session__";
|
|
169
|
+
const companies = company.split(",");
|
|
170
|
+
if (companies.at(-1) === "")
|
|
171
|
+
companies.pop();
|
|
172
|
+
if (companies.some((slug) => !/^[a-z][a-z0-9_-]*$/.test(slug)))
|
|
173
|
+
return { code: 1, stdout: "", stderr: "" };
|
|
174
|
+
const resolver = path.join(root, "core", "scripts", "lib", "session-skill-catalog.sh");
|
|
175
|
+
try {
|
|
176
|
+
fs.accessSync(resolver, fs.constants.R_OK);
|
|
177
|
+
}
|
|
178
|
+
catch {
|
|
179
|
+
return failure(`skill availability resolver is missing: ${resolver}`, 2);
|
|
180
|
+
}
|
|
181
|
+
const seen = new Set();
|
|
182
|
+
for (const file of skillFiles(root, companies)) {
|
|
183
|
+
const name = skillName(file);
|
|
184
|
+
if (!name || seen.has(name))
|
|
185
|
+
continue;
|
|
186
|
+
seen.add(name);
|
|
187
|
+
if (name === skill) {
|
|
188
|
+
try {
|
|
189
|
+
if (fs.statSync(file).isFile())
|
|
190
|
+
return { code: 0, stdout: "", stderr: "" };
|
|
191
|
+
}
|
|
192
|
+
catch { /* catalog entry disappeared, continue */ }
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return { code: 1, stdout: "", stderr: "" };
|
|
196
|
+
}
|
|
197
|
+
//# sourceMappingURL=core-bucket-c-small-native.js.map
|
|
@@ -591,7 +591,10 @@ export function runDeriveTriggerFacts(options) {
|
|
|
591
591
|
}
|
|
592
592
|
}
|
|
593
593
|
export function runDeriveTriggerFactsFast(argv, stdin, cwd, hqRoot) {
|
|
594
|
-
|
|
594
|
+
// The shell fast route runs from the live root and injects it as
|
|
595
|
+
// CLAUDE_PROJECT_DIR. Keep the native handler's PWD fallback aligned with
|
|
596
|
+
// that route when the caller supplied --hq-root.
|
|
597
|
+
const result = runDeriveTriggerFactsFastResult(argv, stdin, hqRoot ?? cwd, hqRoot);
|
|
595
598
|
if (result.stdout.length)
|
|
596
599
|
process.stdout.write(result.stdout);
|
|
597
600
|
if (result.stderr.length)
|
package/dist/commands/core.js
CHANGED
|
@@ -218,12 +218,36 @@ export const REBUILD_INDEX_TARGETS = [
|
|
|
218
218
|
* would make the forwarders harder to audit against this table.
|
|
219
219
|
*/
|
|
220
220
|
export const SCAFFOLD_COMMANDS = [
|
|
221
|
+
{
|
|
222
|
+
name: "handoff-sync-prefetch",
|
|
223
|
+
asset: "core/scripts/handoff-sync-prefetch.sh",
|
|
224
|
+
root: "live",
|
|
225
|
+
summary: "Pull the latest continuity pointer before a session resumes",
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
name: "handoff-sync-publish",
|
|
229
|
+
asset: "core/scripts/handoff-sync-publish.sh",
|
|
230
|
+
root: "live",
|
|
231
|
+
summary: "Publish the session continuity pointer to the personal vault",
|
|
232
|
+
},
|
|
221
233
|
{
|
|
222
234
|
name: "hq-task",
|
|
223
235
|
asset: "core/scripts/hq-task.sh",
|
|
224
236
|
root: "live",
|
|
225
237
|
summary: "List and update tasks on personal or company boards",
|
|
226
238
|
},
|
|
239
|
+
{
|
|
240
|
+
name: "knowledge-pulse-lock",
|
|
241
|
+
asset: "core/scripts/knowledge-pulse-lock.sh",
|
|
242
|
+
root: "live",
|
|
243
|
+
summary: "Atomically claim a company knowledge-pulse run",
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
name: "skill-installed",
|
|
247
|
+
asset: "core/scripts/skill-installed.sh",
|
|
248
|
+
root: "live",
|
|
249
|
+
summary: "Check whether a company-scoped skill is installed",
|
|
250
|
+
},
|
|
227
251
|
// Session/harness plumbing relocated out of the HQ tree so a single published
|
|
228
252
|
// CLI owns it. Both are `root: "live"`: they read and write the live HQ tree
|
|
229
253
|
// (workspace/sessions, companies/, workspace/orchestrator/hook-state), so the
|
|
@@ -250,6 +274,7 @@ export const SCAFFOLD_COMMANDS = [
|
|
|
250
274
|
*/
|
|
251
275
|
export const SCAFFOLD_ONLY_ASSETS = [
|
|
252
276
|
{ asset: "core/scripts/hq-task.mjs", root: "live", summary: "Sibling implementation used by the hq-task shell rollback companion" },
|
|
277
|
+
{ asset: "core/scripts/lib/session-skill-catalog.sh", root: "live", summary: "Shared skill catalog helper used by bundled skill-installed" },
|
|
253
278
|
{ asset: "core/scripts/session-journal.sh", root: "live", summary: "Rollback companion for native session journal" },
|
|
254
279
|
{ asset: "core/scripts/session-project.sh", root: "live", summary: "Rollback companion for native session project" },
|
|
255
280
|
{ asset: "core/scripts/session-title.sh", root: "live", summary: "Rollback companion for native session title" },
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
import { Command } from "commander";
|
|
2
|
+
export declare function displayText(value: unknown): string;
|
|
3
|
+
export declare function safeJson(value: object): string;
|
|
2
4
|
export declare function registerDeployCommentsCommand(deploy: Command): void;
|
|
3
5
|
//# sourceMappingURL=deploy-comments.d.ts.map
|
|
@@ -74,7 +74,7 @@ async function listComments(token, appId, orgHeaders) {
|
|
|
74
74
|
}
|
|
75
75
|
return { commentsEnabled: result.commentsEnabled, comments: result.comments };
|
|
76
76
|
}
|
|
77
|
-
function displayText(value) {
|
|
77
|
+
export function displayText(value) {
|
|
78
78
|
return [...String(value ?? "")].map((character) => {
|
|
79
79
|
const code = character.codePointAt(0) ?? 0;
|
|
80
80
|
return isUnsafeTerminalCodePoint(code)
|
|
@@ -88,7 +88,7 @@ function isUnsafeTerminalCodePoint(code) {
|
|
|
88
88
|
|| (code >= 0x202a && code <= 0x202e)
|
|
89
89
|
|| (code >= 0x2066 && code <= 0x2069);
|
|
90
90
|
}
|
|
91
|
-
function safeJson(value) {
|
|
91
|
+
export function safeJson(value) {
|
|
92
92
|
return JSON.stringify(value, null, 2).replace(/[\u007f-\u009f\u202a-\u202e\u2066-\u2069]/gu, (character) => `\\u${(character.codePointAt(0) ?? 0).toString(16).padStart(4, "0")}`);
|
|
93
93
|
}
|
|
94
94
|
function printCommentLine(comment) {
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
type ApiApp = Record<string, unknown>;
|
|
3
|
+
export interface DeployAppSummary {
|
|
4
|
+
id: string | null;
|
|
5
|
+
name: string | null;
|
|
6
|
+
title: string | null;
|
|
7
|
+
subdomain: string | null;
|
|
8
|
+
url: string | null;
|
|
9
|
+
type: string | null;
|
|
10
|
+
accessMode: string | null;
|
|
11
|
+
status: string | null;
|
|
12
|
+
createdAt: string | null;
|
|
13
|
+
updatedAt: string | null;
|
|
14
|
+
lastVisitAt: string | null;
|
|
15
|
+
}
|
|
16
|
+
/** Public app base domain, derived from the deploy API host (api.<base>). */
|
|
17
|
+
export declare function appBaseDomain(apiUrl?: string): string | null;
|
|
18
|
+
export declare function summarizeApp(app: ApiApp): DeployAppSummary;
|
|
19
|
+
export declare function matchesQuery(app: DeployAppSummary, query: string | undefined): boolean;
|
|
20
|
+
export declare function registerDeployListCommand(deploy: Command): void;
|
|
21
|
+
export {};
|
|
22
|
+
//# sourceMappingURL=deploy-list.d.ts.map
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { DEPLOY_API_URL, deployApiRequest } from "../lib/deploy-api.js";
|
|
2
|
+
import { listDeployApps } from "../lib/deploy-apps.js";
|
|
3
|
+
import { DEFAULT_HQ_ROOT, ensureCognitoToken } from "../utils/cognito-session.js";
|
|
4
|
+
import { displayText, safeJson } from "./deploy-comments.js";
|
|
5
|
+
import { readActiveCompanySlug } from "./skill.js";
|
|
6
|
+
class DeployListError extends Error {
|
|
7
|
+
}
|
|
8
|
+
const SLUG_PATTERN = /^[a-z0-9][a-z0-9-]{0,62}$/;
|
|
9
|
+
function resolveCompany(companyFlag) {
|
|
10
|
+
const slug = companyFlag ?? readActiveCompanySlug(DEFAULT_HQ_ROOT);
|
|
11
|
+
if (slug === undefined) {
|
|
12
|
+
throw new DeployListError("No active company. Pass --company <slug>.");
|
|
13
|
+
}
|
|
14
|
+
if (!SLUG_PATTERN.test(slug))
|
|
15
|
+
throw new DeployListError("The company slug is not valid.");
|
|
16
|
+
return slug;
|
|
17
|
+
}
|
|
18
|
+
function str(value) {
|
|
19
|
+
return typeof value === "string" && value.length > 0 ? value : null;
|
|
20
|
+
}
|
|
21
|
+
/** Public app base domain, derived from the deploy API host (api.<base>). */
|
|
22
|
+
export function appBaseDomain(apiUrl = DEPLOY_API_URL) {
|
|
23
|
+
try {
|
|
24
|
+
const host = new URL(apiUrl).hostname;
|
|
25
|
+
return host.startsWith("api.") ? host.slice(4) : null;
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function appUrl(app, subdomain) {
|
|
32
|
+
const url = str(app.url);
|
|
33
|
+
if (url)
|
|
34
|
+
return url;
|
|
35
|
+
const base = appBaseDomain();
|
|
36
|
+
return subdomain && base ? `https://${subdomain}.${base}` : null;
|
|
37
|
+
}
|
|
38
|
+
export function summarizeApp(app) {
|
|
39
|
+
const subdomain = str(app.subdomain);
|
|
40
|
+
return {
|
|
41
|
+
id: str(app.id),
|
|
42
|
+
name: str(app.name),
|
|
43
|
+
title: str(app.title),
|
|
44
|
+
subdomain,
|
|
45
|
+
url: appUrl(app, subdomain),
|
|
46
|
+
type: str(app.type),
|
|
47
|
+
accessMode: str(app.accessMode),
|
|
48
|
+
status: str(app.status),
|
|
49
|
+
createdAt: str(app.createdAt),
|
|
50
|
+
updatedAt: str(app.updatedAt),
|
|
51
|
+
lastVisitAt: str(app.lastVisitAt),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
export function matchesQuery(app, query) {
|
|
55
|
+
if (!query)
|
|
56
|
+
return true;
|
|
57
|
+
const needle = query.toLowerCase();
|
|
58
|
+
return [app.name, app.subdomain, app.title].some((field) => field?.toLowerCase().includes(needle) ?? false);
|
|
59
|
+
}
|
|
60
|
+
async function responseError(response, slug) {
|
|
61
|
+
const body = await response.json().catch(() => ({}));
|
|
62
|
+
const raw = body.error?.code;
|
|
63
|
+
const code = typeof raw === "string" && /^[A-Z0-9_]+$/.test(raw) ? raw : `HTTP_${response.status}`;
|
|
64
|
+
if (response.status === 401) {
|
|
65
|
+
return new DeployListError(`hq-deploy rejected your sign-in. Run 'hq login' and retry. (${code})`);
|
|
66
|
+
}
|
|
67
|
+
if (response.status === 403) {
|
|
68
|
+
return new DeployListError(`Company '${slug}' was not found in hq-deploy, or you do not have access to it. (${code})`);
|
|
69
|
+
}
|
|
70
|
+
if (response.status === 404) {
|
|
71
|
+
return new DeployListError(`Company '${slug}' was not found in hq-deploy. (${code})`);
|
|
72
|
+
}
|
|
73
|
+
return new DeployListError(`Could not list deploy apps (HTTP ${response.status}, ${code}).`);
|
|
74
|
+
}
|
|
75
|
+
async function fetchPage(token, slug, cursor) {
|
|
76
|
+
const route = cursor ? `/api/apps?cursor=${encodeURIComponent(cursor)}` : "/api/apps";
|
|
77
|
+
let response;
|
|
78
|
+
try {
|
|
79
|
+
response = await deployApiRequest(token, route, "GET", undefined, { "X-Org-Slug": slug });
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
throw new DeployListError("Could not reach hq-deploy.");
|
|
83
|
+
}
|
|
84
|
+
if (!response.ok)
|
|
85
|
+
throw await responseError(response, slug);
|
|
86
|
+
try {
|
|
87
|
+
return await response.json();
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
throw new DeployListError("hq-deploy returned an invalid response.");
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
function printApp(app) {
|
|
94
|
+
const updated = app.updatedAt ?? app.lastVisitAt ?? app.createdAt;
|
|
95
|
+
console.log([
|
|
96
|
+
displayText(app.name ?? app.subdomain ?? app.id ?? "unnamed"),
|
|
97
|
+
displayText(app.url ?? "-"),
|
|
98
|
+
displayText(app.type ?? "-"),
|
|
99
|
+
displayText(app.accessMode ?? "-"),
|
|
100
|
+
displayText(updated ?? "-"),
|
|
101
|
+
].join(" | "));
|
|
102
|
+
}
|
|
103
|
+
async function listAction(query, options) {
|
|
104
|
+
const slug = resolveCompany(options.company);
|
|
105
|
+
const token = await ensureCognitoToken();
|
|
106
|
+
let raw;
|
|
107
|
+
try {
|
|
108
|
+
raw = await listDeployApps((cursor) => fetchPage(token, slug, cursor));
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
if (error instanceof DeployListError)
|
|
112
|
+
throw error;
|
|
113
|
+
throw new DeployListError(error instanceof Error ? error.message : "Could not list deploy apps.");
|
|
114
|
+
}
|
|
115
|
+
const apps = raw
|
|
116
|
+
.filter((app) => typeof app === "object" && app !== null)
|
|
117
|
+
.map(summarizeApp)
|
|
118
|
+
.filter((app) => matchesQuery(app, query));
|
|
119
|
+
if (options.json) {
|
|
120
|
+
console.log(safeJson({ company: slug, query: query ?? null, apps }));
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
if (apps.length === 0) {
|
|
124
|
+
if (query) {
|
|
125
|
+
console.log(`No deploy apps in '${slug}' matched '${displayText(query)}'.`);
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
console.log(`hq-deploy returned no apps for '${slug}'.`);
|
|
129
|
+
console.log("Hint: this list can come back empty while the org still has apps. "
|
|
130
|
+
+ "Check the HQ console before concluding none exist.");
|
|
131
|
+
}
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
for (const app of apps)
|
|
135
|
+
printApp(app);
|
|
136
|
+
}
|
|
137
|
+
export function registerDeployListCommand(deploy) {
|
|
138
|
+
deploy
|
|
139
|
+
.command("list [query]")
|
|
140
|
+
.description("List deploy apps in your company, optionally filtered by name or subdomain")
|
|
141
|
+
.option("--company <slug>", "use this company instead of the active company")
|
|
142
|
+
.option("--json", "print the matching apps as JSON")
|
|
143
|
+
.action(async (query, options) => {
|
|
144
|
+
try {
|
|
145
|
+
await listAction(query, options);
|
|
146
|
+
}
|
|
147
|
+
catch (error) {
|
|
148
|
+
console.error(error instanceof DeployListError ? error.message : "Deploy list command failed.");
|
|
149
|
+
process.exitCode = 1;
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
//# sourceMappingURL=deploy-list.js.map
|
package/dist/commands/lanes.js
CHANGED
|
@@ -38,6 +38,7 @@ import { registerLanesLinkCommand } from "./lanes-link.js";
|
|
|
38
38
|
import { laneDepthCap } from "../lib/lanes/depth-cap.js";
|
|
39
39
|
import { isSsmRunCommandProcess } from "../lib/lanes/ssm-command-context.js";
|
|
40
40
|
import { runResidentCommandWithPackageLease } from "../utils/resident-package-preload.js";
|
|
41
|
+
import { codexEnvEvidence, grokEnvEvidence } from "../lib/doctor/platform.js";
|
|
41
42
|
import { readLanesFlagLocalOverride, readLanesRegistryFlag, readLanesRegistryFlagFailOff, readLanesRegistryFlagFailOpen } from "../lib/lanes/registry-flag.js";
|
|
42
43
|
import { readLaneStatusRowFields } from "../lib/lanes/status-fields.js";
|
|
43
44
|
import { appendProjectFocusOverride, readProjectStoryFocusData, removeProjectFocusOverride } from "../lib/lanes/story-ledger.js";
|
|
@@ -74,7 +75,7 @@ import { sessionIdFromEnv } from "../lib/mesh/live/session-identity.js";
|
|
|
74
75
|
import { listLaneReviews } from "../lib/lanes/reviews.js";
|
|
75
76
|
import { effectiveAccountHome } from "../lib/lanes/account-home.js";
|
|
76
77
|
import { remoteControlSelectionConfig, remoteControlSessionHome } from "../lib/lanes/remote-control-lane.js";
|
|
77
|
-
import { AccountResolutionError, compareLaneQueueOrder, LANE_PROVIDERS, LANE_STATES, QUESTION_STATUSES, SENIOR_KINDS, accountStatus, appendCappedHistory, canonicalizeHome, createLane, decideAdmission, defaultLivenessDeps, defaultSystemdUserDir, defaultThrottleDeps, installReconcileTimer, providerPathEnv, probeDrainHookRegistration, isLanesError, isLaneVersionConflict, isTerminalLaneState, isFinishedResumableHireChild, childrenHoldingHireGrantCarve, laneHoldsHireGrantCarve, assignedChildHireGrants, hireGrantCapacityError, planHireGrantBackfill, terminalChildResumeHireGrantError, withHireGrantAdmission, laneStoryLedgerEnabled, syncLaneToProjectStoryLedger, removeLaneFromProjectStoryLedger, validateProjectStories, buildLaneStatusSnapshot, formatLaneStatusHuman, listLaneIds, listQuestionIds, loadLanesConfig, laneRunsHere, MAX_LANE_DEPTH, MONITOR_ERROR_EXIT_CODE, readLiveMonitorEvidence, resolveMachineIdentity as lookupMachineIdentity, loadLivenessIndex, parseLaneProvider, parseLaneRecord, parseLaneState, parseQuestionRecord, parseSeniorKind, readAllLanes, readLane, sanitizeHostComponent, retryUpdateLane, syncLaneRecordFromOwner, readQuestion, resolveAccount, resolveLaneWorker, ignoredWorkerProfileFields, loadWorkerProfile, loadWorkerProfileWithRegistry, registryWorkerRecord, runReconcilePass, DEAD_HOST_MS, sessionLiveness, tryReadLane, uninstallReconcileTimer, updateLane, updateQuestion, dropboxDir, laneDeliveryMechanism, hasActiveAdmissionReservation, hasActivePendingResume, hasRecordedSessionId, hasEarlierEligibleQueuedLane, laneAdmissionCapReason, providerSupportsSessionResume, providerSessionPortable, isFailedQuotaKeepAliveLane, sessionNotPortableMessage, withLaneAdmissionLock, withAllLaneAdmissionLocks, readWorkerRunResult, resumeCommandRefusal, withLaneHireLocks, raiseLaneQuestion, sha256Text, } from "../lib/lanes/index.js";
|
|
78
|
+
import { AccountResolutionError, compareLaneQueueOrder, LANE_PROVIDERS, LANE_STATES, QUESTION_STATUSES, SENIOR_KINDS, accountStatus, appendCappedHistory, canonicalizeHome, createLane, decideAdmission, defaultLivenessDeps, defaultSystemdUserDir, defaultThrottleDeps, installReconcileTimer, providerPathEnv, probeDrainHookRegistration, isLanesError, isLaneVersionConflict, isTerminalLaneState, isFinishedResumableHireChild, childrenHoldingHireGrantCarve, laneHoldsHireGrantCarve, assignedChildHireGrants, hireGrantCapacityError, planHireGrantBackfill, terminalChildResumeHireGrantError, withHireGrantAdmission, laneStoryLedgerEnabled, syncLaneToProjectStoryLedger, removeLaneFromProjectStoryLedger, validateProjectStories, buildLaneStatusSnapshot, formatLaneStatusHuman, listLaneIds, listQuestionIds, loadLanesConfig, laneRunsHere, MAX_LANE_DEPTH, MONITOR_ERROR_EXIT_CODE, readLiveMonitorEvidence, resolveMachineIdentity as lookupMachineIdentity, loadLivenessIndex, parseLaneProvider, isLaneProvider, parseLaneRecord, parseLaneState, parseQuestionRecord, parseSeniorKind, readAllLanes, readLane, sanitizeHostComponent, retryUpdateLane, syncLaneRecordFromOwner, readQuestion, resolveAccount, resolveLaneWorker, ignoredWorkerProfileFields, loadWorkerProfile, loadWorkerProfileWithRegistry, registryWorkerRecord, runReconcilePass, DEAD_HOST_MS, sessionLiveness, tryReadLane, uninstallReconcileTimer, updateLane, updateQuestion, dropboxDir, laneDeliveryMechanism, hasActiveAdmissionReservation, hasActivePendingResume, hasRecordedSessionId, hasEarlierEligibleQueuedLane, laneAdmissionCapReason, providerSupportsSessionResume, providerSessionPortable, isFailedQuotaKeepAliveLane, sessionNotPortableMessage, withLaneAdmissionLock, withAllLaneAdmissionLocks, readWorkerRunResult, resumeCommandRefusal, withLaneHireLocks, raiseLaneQuestion, sha256Text, } from "../lib/lanes/index.js";
|
|
78
79
|
import { laneStories, storyWarning, } from "../lib/lanes/stories.js";
|
|
79
80
|
import { resolveLaneKeepAlive } from "../lib/lanes/profile.js";
|
|
80
81
|
import { laneCompanyUidSource, resolveLaneCompany } from "../lib/lanes/lane-company.js";
|
|
@@ -2295,6 +2296,41 @@ function callerDepth(hqRoot, ctx) {
|
|
|
2295
2296
|
}
|
|
2296
2297
|
return 0;
|
|
2297
2298
|
}
|
|
2299
|
+
/**
|
|
2300
|
+
* Engine of the orchestrator that is creating a lane, used as the provider
|
|
2301
|
+
* fallback when neither --provider nor the worker profile names one. Order:
|
|
2302
|
+
* the senior lane's provider, the senior session's `conduct_engine` metadata,
|
|
2303
|
+
* then the harness markers in the environment (`HQ_HARNESS`, Codex/Grok
|
|
2304
|
+
* runtime variables, `CLAUDECODE=1`). Returns undefined when none apply.
|
|
2305
|
+
*/
|
|
2306
|
+
function orchestratorEngine(hqRoot, senior, ctx) {
|
|
2307
|
+
if (senior.kind === "lane" && senior.id) {
|
|
2308
|
+
try {
|
|
2309
|
+
const provider = readLane(hqRoot, senior.id).provider;
|
|
2310
|
+
if (isLaneProvider(provider))
|
|
2311
|
+
return provider;
|
|
2312
|
+
}
|
|
2313
|
+
catch {
|
|
2314
|
+
// Fall through to the environment markers.
|
|
2315
|
+
}
|
|
2316
|
+
}
|
|
2317
|
+
if (senior.kind === "session" && senior.id) {
|
|
2318
|
+
const engine = readSessionMeta(hqRoot, senior.id, ctx)?.conduct_engine;
|
|
2319
|
+
const value = typeof engine === "string" ? engine.trim().toLowerCase() : "";
|
|
2320
|
+
if (isLaneProvider(value))
|
|
2321
|
+
return value;
|
|
2322
|
+
}
|
|
2323
|
+
const harness = ctx.env.HQ_HARNESS?.trim().toLowerCase() ?? "";
|
|
2324
|
+
if (isLaneProvider(harness))
|
|
2325
|
+
return harness;
|
|
2326
|
+
if (codexEnvEvidence(ctx.env).length > 0)
|
|
2327
|
+
return "codex";
|
|
2328
|
+
if (grokEnvEvidence(ctx.env).length > 0)
|
|
2329
|
+
return "grok";
|
|
2330
|
+
if (ctx.env.CLAUDECODE?.trim() === "1")
|
|
2331
|
+
return "claude";
|
|
2332
|
+
return undefined;
|
|
2333
|
+
}
|
|
2298
2334
|
function defaultSenior(ctx) {
|
|
2299
2335
|
const parent = ctx.env.HQ_PARENT_SESSION_ID?.trim();
|
|
2300
2336
|
if (parent)
|
|
@@ -3450,10 +3486,20 @@ async function runCreate(ctx, opts) {
|
|
|
3450
3486
|
const profile = resolvedWorker?.profile;
|
|
3451
3487
|
const provider = explicitProvider ??
|
|
3452
3488
|
profile?.meta.provider ??
|
|
3453
|
-
|
|
3489
|
+
(opts.remoteControl === true ? parseLaneProvider("claude") : orchestratorEngine(hqRoot, senior, ctx));
|
|
3490
|
+
if (provider === undefined) {
|
|
3491
|
+
throw new LanesError("provider_required", "Cannot tell which engine runs the orchestrator session, so no lane provider was chosen. Pass --provider claude, --provider codex, or --provider grok.", { accepted: [...LANE_PROVIDERS] });
|
|
3492
|
+
}
|
|
3454
3493
|
if (opts.remoteControl === true && provider !== "claude") {
|
|
3455
3494
|
throw new LanesError("remote_control_requires_claude", "--remote-control requires a Claude lane", { provider });
|
|
3456
3495
|
}
|
|
3496
|
+
const remoteControlTitle = opts.title?.trim();
|
|
3497
|
+
if (opts.remoteControl === true && (!remoteControlTitle || remoteControlTitle.length > 80 || /\p{Cc}/u.test(remoteControlTitle))) {
|
|
3498
|
+
throw new LanesError("remote_control_title_required", "--remote-control requires --title with 1–80 printable characters", {});
|
|
3499
|
+
}
|
|
3500
|
+
if (opts.remoteControl !== true && opts.title !== undefined) {
|
|
3501
|
+
throw new LanesError("lane_title_requires_remote_control", "--title is only supported with --remote-control", {});
|
|
3502
|
+
}
|
|
3457
3503
|
const continuityEnabled = opts.remoteControl !== true && opts.worker !== undefined && await readLanesRegistryFlagFailOpen(LANE_WORKER_CONTINUITY_FLAG, { company: company ?? meshCompany, env: ctx.env, defaultValue: true });
|
|
3458
3504
|
let workerContinuity = continuityEnabled
|
|
3459
3505
|
? findWorkerContinuityLane(loadAllLanes(hqRoot), {
|
|
@@ -4017,7 +4063,7 @@ async function runCreate(ctx, opts) {
|
|
|
4017
4063
|
...(opts.loop === true ? { loop_mode: true } : {}),
|
|
4018
4064
|
...(keepAlive ? { keep_alive_opted_in_at: createdAt } : {}),
|
|
4019
4065
|
provider,
|
|
4020
|
-
...(opts.remoteControl === true ? { remote_control: true } : {}),
|
|
4066
|
+
...(opts.remoteControl === true ? { remote_control: true, remote_control_title: remoteControlTitle } : {}),
|
|
4021
4067
|
...(workerContinuity.resumable && workerContinuity.previous
|
|
4022
4068
|
? {
|
|
4023
4069
|
provider_session_id: workerContinuity.previous.provider_session_id,
|
|
@@ -9732,6 +9778,7 @@ export function registerLanesCommand(parent, deps = {}) {
|
|
|
9732
9778
|
.option("--loop", "Keep one worker lane registered to process queued phase envelopes")
|
|
9733
9779
|
.option("--provider <name>", "claude | codex | grok")
|
|
9734
9780
|
.option("--remote-control", "Open a Claude lane in Remote Control using account a for login and the selected account for inference")
|
|
9781
|
+
.option("--title <text>", "Human-readable Claude Remote Control session title; required with --remote-control")
|
|
9735
9782
|
.option("--account <id>", "Provider account id, or 'auto' to pick the account with the most room (all accounts are one pool across companies)")
|
|
9736
9783
|
.option("--model <id>", "Model id for the provider CLI")
|
|
9737
9784
|
.option("--effort <level>", "Effort level; claude: low|medium|high|xhigh|max, codex: minimal|low|medium|high|xhigh|max|ultra, grok: low|medium|high|xhigh")
|
package/dist/fast-scaffold.js
CHANGED
|
@@ -160,6 +160,54 @@ export function isDefaultOnFastFamily(flagKey) {
|
|
|
160
160
|
}
|
|
161
161
|
/** The relocated scripts that qualify for the entrypoint fast path. */
|
|
162
162
|
export const FAST_SCAFFOLD_SCRIPTS = [
|
|
163
|
+
{
|
|
164
|
+
name: "handoff-sync-prefetch",
|
|
165
|
+
kind: "native",
|
|
166
|
+
modulePath: "./commands/core-bucket-c-handoff-sync-fast.js",
|
|
167
|
+
exportName: "runHandoffSyncPrefetchFast",
|
|
168
|
+
flagKey: "hq-core-native-fast-route",
|
|
169
|
+
familyFlagKey: "core-native-bucket-c",
|
|
170
|
+
asset: "core/scripts/handoff-sync-prefetch.sh",
|
|
171
|
+
root: "live",
|
|
172
|
+
shellCwd: "live",
|
|
173
|
+
shellHqRoot: "live",
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
name: "knowledge-pulse-lock",
|
|
177
|
+
kind: "native",
|
|
178
|
+
modulePath: "./commands/core-bucket-c-small-fast.js",
|
|
179
|
+
exportName: "runKnowledgePulseLockFast",
|
|
180
|
+
flagKey: "hq-core-native-fast-route",
|
|
181
|
+
familyFlagKey: "core-native-bucket-c",
|
|
182
|
+
asset: "core/scripts/knowledge-pulse-lock.sh",
|
|
183
|
+
root: "live",
|
|
184
|
+
shellCwd: "live",
|
|
185
|
+
shellHqRoot: "live",
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
name: "handoff-sync-publish",
|
|
189
|
+
kind: "native",
|
|
190
|
+
modulePath: "./commands/core-bucket-c-handoff-sync-fast.js",
|
|
191
|
+
exportName: "runHandoffSyncPublishFast",
|
|
192
|
+
flagKey: "hq-core-native-fast-route",
|
|
193
|
+
familyFlagKey: "core-native-bucket-c",
|
|
194
|
+
asset: "core/scripts/handoff-sync-publish.sh",
|
|
195
|
+
root: "live",
|
|
196
|
+
shellCwd: "live",
|
|
197
|
+
shellHqRoot: "live",
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
name: "skill-installed",
|
|
201
|
+
kind: "native",
|
|
202
|
+
modulePath: "./commands/core-bucket-c-small-fast.js",
|
|
203
|
+
exportName: "runSkillInstalledFast",
|
|
204
|
+
flagKey: "hq-core-native-fast-route",
|
|
205
|
+
familyFlagKey: "core-native-bucket-c",
|
|
206
|
+
asset: "core/scripts/skill-installed.sh",
|
|
207
|
+
root: "live",
|
|
208
|
+
shellCwd: "live",
|
|
209
|
+
shellHqRoot: "live",
|
|
210
|
+
},
|
|
163
211
|
{
|
|
164
212
|
name: "sentry report",
|
|
165
213
|
kind: "native",
|
|
@@ -339,7 +339,7 @@ interface RawAccountRow {
|
|
|
339
339
|
* Falls back to `hq` on PATH when this process is not the hq CLI (tests,
|
|
340
340
|
* embedders). Exported for tests.
|
|
341
341
|
*/
|
|
342
|
-
export declare function resolveHqInvocation(argv?: readonly string[], execPath?: string): {
|
|
342
|
+
export declare function resolveHqInvocation(argv?: readonly string[], execPath?: string, execArgv?: readonly string[]): {
|
|
343
343
|
command: string;
|
|
344
344
|
args: string[];
|
|
345
345
|
};
|