@indigoai-us/hq-cli 5.72.0 → 5.73.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.
|
@@ -73,6 +73,13 @@ export declare function listOutposts(token: string): Promise<OutpostSummary[]>;
|
|
|
73
73
|
export declare function getOutpostStatus(token: string, outpostId?: string): Promise<Record<string, unknown>>;
|
|
74
74
|
export declare function enableCodex(token: string, outpostId?: string): Promise<Record<string, unknown>>;
|
|
75
75
|
export declare function regenerateLoginUrl(token: string, outpostId?: string): Promise<Record<string, unknown>>;
|
|
76
|
+
/**
|
|
77
|
+
* Hand the box the one-time Claude sign-in code the operator got from the login
|
|
78
|
+
* URL. hq-pro stores it as the row's pending code; the box polls for it, feeds
|
|
79
|
+
* it to `claude`, and flips itself `awaiting-claude-login → ready`. This is the
|
|
80
|
+
* terminal-native equivalent of pasting the code into the web console.
|
|
81
|
+
*/
|
|
82
|
+
export declare function submitLoginCode(token: string, code: string, outpostId?: string): Promise<Record<string, unknown>>;
|
|
76
83
|
export declare function destroyOutpost(token: string, outpostId?: string): Promise<Record<string, unknown>>;
|
|
77
84
|
/** Result of `POST /outpost/exec` — a terminal SSM invocation on the box. */
|
|
78
85
|
export interface OutpostExecResult {
|
|
@@ -116,6 +116,21 @@ export async function regenerateLoginUrl(token, outpostId) {
|
|
|
116
116
|
query: outpostId ? { outpostId } : undefined,
|
|
117
117
|
});
|
|
118
118
|
}
|
|
119
|
+
/**
|
|
120
|
+
* Hand the box the one-time Claude sign-in code the operator got from the login
|
|
121
|
+
* URL. hq-pro stores it as the row's pending code; the box polls for it, feeds
|
|
122
|
+
* it to `claude`, and flips itself `awaiting-claude-login → ready`. This is the
|
|
123
|
+
* terminal-native equivalent of pasting the code into the web console.
|
|
124
|
+
*/
|
|
125
|
+
export async function submitLoginCode(token, code, outpostId) {
|
|
126
|
+
return outpostRequest({
|
|
127
|
+
token,
|
|
128
|
+
path: "/outpost/login-code",
|
|
129
|
+
method: "POST",
|
|
130
|
+
body: { code },
|
|
131
|
+
query: outpostId ? { outpostId } : undefined,
|
|
132
|
+
});
|
|
133
|
+
}
|
|
119
134
|
export async function destroyOutpost(token, outpostId) {
|
|
120
135
|
return outpostRequest({
|
|
121
136
|
token,
|
|
@@ -1011,8 +1026,40 @@ export function registerOutpostsCommand(program, selfDeployOverrides = {}) {
|
|
|
1011
1026
|
process.stdout.write(JSON.stringify(result, null, 2) + "\n");
|
|
1012
1027
|
return;
|
|
1013
1028
|
}
|
|
1014
|
-
console.log(chalk.green("Login-URL regeneration requested. The box mints a fresh URL shortly
|
|
1015
|
-
|
|
1029
|
+
console.log(chalk.green("Login-URL regeneration requested. The box mints a fresh URL shortly."));
|
|
1030
|
+
console.log(chalk.dim("Next: `hq outposts status" +
|
|
1031
|
+
(opts.id ? ` --id ${opts.id}` : "") +
|
|
1032
|
+
"` to read the login URL, open it and sign in, then paste the code back with " +
|
|
1033
|
+
"`hq outposts login-code <code>" +
|
|
1034
|
+
(opts.id ? ` --id ${opts.id}` : "") +
|
|
1035
|
+
"`."));
|
|
1036
|
+
}
|
|
1037
|
+
catch (err) {
|
|
1038
|
+
fail(err);
|
|
1039
|
+
}
|
|
1040
|
+
});
|
|
1041
|
+
outposts
|
|
1042
|
+
.command("login-code <code>")
|
|
1043
|
+
.description("Submit the Claude sign-in code for an Outpost that is awaiting login")
|
|
1044
|
+
.option("--id <outpostId>", "Outpost id (defaults to your primary box)")
|
|
1045
|
+
.option("--json", "Emit raw JSON")
|
|
1046
|
+
.action(async function (code, opts) {
|
|
1047
|
+
try {
|
|
1048
|
+
const trimmed = code.trim();
|
|
1049
|
+
if (!trimmed) {
|
|
1050
|
+
console.error(chalk.red("Provide the sign-in code: hq outposts login-code <code>"));
|
|
1051
|
+
process.exit(1);
|
|
1052
|
+
}
|
|
1053
|
+
const token = await ensureCognitoToken();
|
|
1054
|
+
const result = await submitLoginCode(token, trimmed, opts.id);
|
|
1055
|
+
if (opts.json) {
|
|
1056
|
+
process.stdout.write(JSON.stringify(result, null, 2) + "\n");
|
|
1057
|
+
return;
|
|
1058
|
+
}
|
|
1059
|
+
console.log(chalk.green("Code submitted — the box will finish signing in shortly."));
|
|
1060
|
+
console.log(chalk.dim("Track it: `hq outposts status" +
|
|
1061
|
+
(opts.id ? ` --id ${opts.id}` : "") +
|
|
1062
|
+
"` (it flips to `ready` once Claude auth completes)."));
|
|
1016
1063
|
}
|
|
1017
1064
|
catch (err) {
|
|
1018
1065
|
fail(err);
|
package/package.json
CHANGED
|
@@ -171,6 +171,38 @@ describe("hq outposts codex-enable / login", () => {
|
|
|
171
171
|
expect(String(url)).toContain("/outpost/regenerate-login-url");
|
|
172
172
|
expect(init?.method).toBe("POST");
|
|
173
173
|
});
|
|
174
|
+
|
|
175
|
+
it("login-code POSTs /outpost/login-code with the code in the body", async () => {
|
|
176
|
+
fetchSpy.mockResolvedValueOnce(jsonResponse(200, { ok: true, userId: "u1" }));
|
|
177
|
+
await run(["outposts", "login-code", "ABC-123"]);
|
|
178
|
+
const [url, init] = fetchSpy.mock.calls[0];
|
|
179
|
+
expect(String(url)).toContain("/outpost/login-code");
|
|
180
|
+
expect(init?.method).toBe("POST");
|
|
181
|
+
expect(JSON.parse(String(init?.body))).toEqual({ code: "ABC-123" });
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
it("login-code targets a specific box via --id (outpostId query)", async () => {
|
|
185
|
+
fetchSpy.mockResolvedValueOnce(jsonResponse(200, { ok: true, userId: "u1" }));
|
|
186
|
+
await run(["outposts", "login-code", "CODE", "--id", "3"]);
|
|
187
|
+
const [url] = fetchSpy.mock.calls[0];
|
|
188
|
+
expect(String(url)).toContain("outpostId=3");
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
it("login-code trims whitespace and refuses an empty code without calling the API", async () => {
|
|
192
|
+
await expect(run(["outposts", "login-code", " "])).rejects.toThrow(
|
|
193
|
+
"process.exit(1)",
|
|
194
|
+
);
|
|
195
|
+
expect(fetchSpy).not.toHaveBeenCalled();
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
it("login-code surfaces an awaiting-login not-found error", async () => {
|
|
199
|
+
fetchSpy.mockResolvedValueOnce(
|
|
200
|
+
jsonResponse(404, { error: true, step: "not-found", message: "no outpost" }),
|
|
201
|
+
);
|
|
202
|
+
await expect(run(["outposts", "login-code", "CODE"])).rejects.toThrow(
|
|
203
|
+
"process.exit(1)",
|
|
204
|
+
);
|
|
205
|
+
});
|
|
174
206
|
});
|
|
175
207
|
|
|
176
208
|
describe("hq outposts destroy", () => {
|
package/src/commands/outposts.ts
CHANGED
|
@@ -182,6 +182,26 @@ export async function regenerateLoginUrl(
|
|
|
182
182
|
});
|
|
183
183
|
}
|
|
184
184
|
|
|
185
|
+
/**
|
|
186
|
+
* Hand the box the one-time Claude sign-in code the operator got from the login
|
|
187
|
+
* URL. hq-pro stores it as the row's pending code; the box polls for it, feeds
|
|
188
|
+
* it to `claude`, and flips itself `awaiting-claude-login → ready`. This is the
|
|
189
|
+
* terminal-native equivalent of pasting the code into the web console.
|
|
190
|
+
*/
|
|
191
|
+
export async function submitLoginCode(
|
|
192
|
+
token: string,
|
|
193
|
+
code: string,
|
|
194
|
+
outpostId?: string,
|
|
195
|
+
): Promise<Record<string, unknown>> {
|
|
196
|
+
return outpostRequest({
|
|
197
|
+
token,
|
|
198
|
+
path: "/outpost/login-code",
|
|
199
|
+
method: "POST",
|
|
200
|
+
body: { code },
|
|
201
|
+
query: outpostId ? { outpostId } : undefined,
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
|
|
185
205
|
export async function destroyOutpost(
|
|
186
206
|
token: string,
|
|
187
207
|
outpostId?: string,
|
|
@@ -1450,8 +1470,58 @@ export function registerOutpostsCommand(
|
|
|
1450
1470
|
}
|
|
1451
1471
|
console.log(
|
|
1452
1472
|
chalk.green(
|
|
1453
|
-
"Login-URL regeneration requested. The box mints a fresh URL shortly
|
|
1454
|
-
|
|
1473
|
+
"Login-URL regeneration requested. The box mints a fresh URL shortly.",
|
|
1474
|
+
),
|
|
1475
|
+
);
|
|
1476
|
+
console.log(
|
|
1477
|
+
chalk.dim(
|
|
1478
|
+
"Next: `hq outposts status" +
|
|
1479
|
+
(opts.id ? ` --id ${opts.id}` : "") +
|
|
1480
|
+
"` to read the login URL, open it and sign in, then paste the code back with " +
|
|
1481
|
+
"`hq outposts login-code <code>" +
|
|
1482
|
+
(opts.id ? ` --id ${opts.id}` : "") +
|
|
1483
|
+
"`.",
|
|
1484
|
+
),
|
|
1485
|
+
);
|
|
1486
|
+
} catch (err) {
|
|
1487
|
+
fail(err);
|
|
1488
|
+
}
|
|
1489
|
+
});
|
|
1490
|
+
|
|
1491
|
+
outposts
|
|
1492
|
+
.command("login-code <code>")
|
|
1493
|
+
.description(
|
|
1494
|
+
"Submit the Claude sign-in code for an Outpost that is awaiting login",
|
|
1495
|
+
)
|
|
1496
|
+
.option("--id <outpostId>", "Outpost id (defaults to your primary box)")
|
|
1497
|
+
.option("--json", "Emit raw JSON")
|
|
1498
|
+
.action(async function (
|
|
1499
|
+
this: Command,
|
|
1500
|
+
code: string,
|
|
1501
|
+
opts: { id?: string; json?: boolean },
|
|
1502
|
+
) {
|
|
1503
|
+
try {
|
|
1504
|
+
const trimmed = code.trim();
|
|
1505
|
+
if (!trimmed) {
|
|
1506
|
+
console.error(chalk.red("Provide the sign-in code: hq outposts login-code <code>"));
|
|
1507
|
+
process.exit(1);
|
|
1508
|
+
}
|
|
1509
|
+
const token = await ensureCognitoToken();
|
|
1510
|
+
const result = await submitLoginCode(token, trimmed, opts.id);
|
|
1511
|
+
if (opts.json) {
|
|
1512
|
+
process.stdout.write(JSON.stringify(result, null, 2) + "\n");
|
|
1513
|
+
return;
|
|
1514
|
+
}
|
|
1515
|
+
console.log(
|
|
1516
|
+
chalk.green(
|
|
1517
|
+
"Code submitted — the box will finish signing in shortly.",
|
|
1518
|
+
),
|
|
1519
|
+
);
|
|
1520
|
+
console.log(
|
|
1521
|
+
chalk.dim(
|
|
1522
|
+
"Track it: `hq outposts status" +
|
|
1523
|
+
(opts.id ? ` --id ${opts.id}` : "") +
|
|
1524
|
+
"` (it flips to `ready` once Claude auth completes).",
|
|
1455
1525
|
),
|
|
1456
1526
|
);
|
|
1457
1527
|
} catch (err) {
|