@indigoai-us/hq-cli 5.345.199 → 5.345.200
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 +26 -0
- package/assets/scaffold/core/scripts/lib/session-scope-capability.sh +6 -4
- package/dist/command-catalog.generated.d.ts +44 -0
- package/dist/command-catalog.generated.js +52 -0
- package/dist/commands/bot-runtime.d.ts +35 -0
- package/dist/commands/bot-runtime.js +115 -0
- package/dist/commands/bot.d.ts +6 -0
- package/dist/commands/bot.js +39 -10
- package/dist/commands/creators.js +2 -1
- package/dist/commands/library-remove.js +2 -1
- package/dist/commands/library.js +5 -4
- package/dist/commands/mesh.d.ts +0 -7
- package/dist/commands/mesh.js +5 -1
- package/dist/commands/sync-held.js +2 -2
- package/dist/lib/bot/fleet-download.d.ts +27 -0
- package/dist/lib/bot/fleet-download.js +162 -0
- package/dist/lib/bot/fleet-local.d.ts +51 -2
- package/dist/lib/bot/fleet-local.js +177 -74
- package/dist/lib/bot/fleet-python.d.ts +2 -0
- package/dist/lib/bot/fleet-python.js +29 -0
- package/dist/lib/lanes/mesh-events.js +3 -1
- package/dist/lib/mesh/api.js +2 -1
- package/dist/lib/mesh/live/daemon/run.d.ts +0 -10
- package/dist/lib/mesh/live/daemon/run.js +3 -0
- package/dist/lib/mesh/live/emit.d.ts +2 -11
- package/dist/lib/mesh/live/emit.js +20 -2
- package/dist/lib/mesh/live/flush.d.ts +2 -0
- package/dist/lib/mesh/live/flush.js +34 -3
- package/dist/lib/mesh/live/reporting-privacy.d.ts +7 -0
- package/dist/lib/mesh/live/reporting-privacy.js +47 -0
- package/dist/lib/work-context/company.d.ts +2 -3
- package/dist/lib/work-context/company.js +4 -22
- package/dist/secrets-env-action.js +5 -2
- package/dist/utils/cognito-callback-port.d.ts +2 -0
- package/dist/utils/cognito-callback-port.js +10 -5
- package/dist/utils/cognito-config.js +6 -1
- package/dist/utils/cognito-session.js +6 -1
- package/dist/utils/interactive-caller.d.ts +8 -0
- package/dist/utils/interactive-caller.js +10 -0
- package/dist/utils/login-browser.js +2 -1
- package/package.json +7 -7
|
@@ -9,9 +9,10 @@
|
|
|
9
9
|
* 2xx responses are accounted per eventId (accepted / duplicates / rejected).
|
|
10
10
|
*/
|
|
11
11
|
import * as fs from "node:fs";
|
|
12
|
+
import { reportingLocallyDisabled } from "./reporting-privacy.js";
|
|
12
13
|
import * as path from "node:path";
|
|
13
14
|
import { readMetaCompanySlug, resolveCompany } from "../../work-context/company.js";
|
|
14
|
-
import { companyBindingChanged, reboundSessionProjection, } from "../../work-context/company-rebind.js";
|
|
15
|
+
import { companyBindingChanged, isNonCloudCompanySlug, reboundSessionProjection, } from "../../work-context/company-rebind.js";
|
|
15
16
|
import { deriveRemoteOwnerSlug, deriveRepoIdentityKey, } from "../../work-context/repo-remote.js";
|
|
16
17
|
import { rebindNeedsProjectOnPrompt } from "../../work-context/prompt-rebind.js";
|
|
17
18
|
import { readSessionState, updateSessionState, writeSessionState } from "../../work-context/state.js";
|
|
@@ -172,6 +173,12 @@ async function postBatchWithRetries(poster, body, deps) {
|
|
|
172
173
|
* Recovers orphan `*.claimed` files first; restores unprocessed lines on throw.
|
|
173
174
|
*/
|
|
174
175
|
export async function flushSessionEvents(inputDeps) {
|
|
176
|
+
const env = inputDeps.env ?? process.env;
|
|
177
|
+
if (reportingLocallyDisabled(env) ||
|
|
178
|
+
(inputDeps.reportingAllowed && !(await inputDeps.reportingAllowed()))) {
|
|
179
|
+
return { claimed: 0, posted: 0, held: 0, dropped: 0, deadLettered: 0,
|
|
180
|
+
restored: 0, batches: 0, heldClaimed: false, heldOverflow: 0 };
|
|
181
|
+
}
|
|
175
182
|
// One resolver per flush: git lookups are cached per cwd for this flush only.
|
|
176
183
|
const deps = {
|
|
177
184
|
...inputDeps,
|
|
@@ -268,6 +275,30 @@ export async function flushSessionEvents(inputDeps) {
|
|
|
268
275
|
break sessionLoop;
|
|
269
276
|
let state = readSessionState(sessionId, deps.workContextRoot);
|
|
270
277
|
state = applySessionMetaCompanyRebind(sessionId, items, state, deps, now);
|
|
278
|
+
// Personal is the documented non-cloud scope, even if an old projection
|
|
279
|
+
// still contains a company UID or a pending presence leave.
|
|
280
|
+
if (isNonCloudCompanySlug(state?.companySlug) || items.some(item => isNonCloudCompanySlug(eventText(item.event, "companySlug")))) {
|
|
281
|
+
summary.dropped += items.length;
|
|
282
|
+
for (const item of items)
|
|
283
|
+
markDisposed(item.event);
|
|
284
|
+
continue;
|
|
285
|
+
}
|
|
286
|
+
if (state?.companyConfidence === "device_default" && deps.authorizeDeviceDefaultTenant) {
|
|
287
|
+
await deps.authorizeDeviceDefaultTenant(state);
|
|
288
|
+
state = readSessionState(sessionId, deps.workContextRoot) ?? state;
|
|
289
|
+
}
|
|
290
|
+
if (state?.companyConfidence === "device_default") {
|
|
291
|
+
summary.held += appendHeldLinesIfAbsent(items.map(item => heldEnvelope(item.event, "NEEDS_COMPANY", item.heldAt ?? now().toISOString())), deps.workMeshRoot);
|
|
292
|
+
for (const item of items)
|
|
293
|
+
markDisposed(item.event);
|
|
294
|
+
continue;
|
|
295
|
+
}
|
|
296
|
+
if (isNonCloudCompanySlug(state?.companySlug)) {
|
|
297
|
+
summary.dropped += items.length;
|
|
298
|
+
for (const item of items)
|
|
299
|
+
markDisposed(item.event);
|
|
300
|
+
continue;
|
|
301
|
+
}
|
|
271
302
|
const leaveResult = await postPresenceLeaveIfNeeded({
|
|
272
303
|
sessionId,
|
|
273
304
|
items,
|
|
@@ -726,7 +757,7 @@ function bindHeldCompanyIfResolved(sessionId, items, state, deps, now, uidCache)
|
|
|
726
757
|
// Stay synchronous unless a uid lookup is needed: the flush loop's
|
|
727
758
|
// microtask ordering is relied on by retry/back-pressure timing.
|
|
728
759
|
const company = resolveHeldCompany(sessionId, items, state, deps);
|
|
729
|
-
if (!company)
|
|
760
|
+
if (!company || isNonCloudCompanySlug(company.slug))
|
|
730
761
|
return state;
|
|
731
762
|
if (company.uid) {
|
|
732
763
|
return writeHeldCompanyBinding(sessionId, state, { uid: company.uid, slug: company.slug, source: company.source }, deps, now);
|
|
@@ -996,7 +1027,7 @@ function classifySession(state) {
|
|
|
996
1027
|
state.companyUid === state.ownerMismatch.companyUid) {
|
|
997
1028
|
return { action: "drop", reason: "owner_mismatch" };
|
|
998
1029
|
}
|
|
999
|
-
if (state.contextStatus === "needs_company") {
|
|
1030
|
+
if (state.companyConfidence === "device_default" || state.contextStatus === "needs_company") {
|
|
1000
1031
|
return { action: "hold", heldReason: "NEEDS_COMPANY" };
|
|
1001
1032
|
}
|
|
1002
1033
|
if (state.contextStatus === "company_conflict") {
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** Match the off controls used by the hook and handoff command. */
|
|
2
|
+
export declare function reportingLocallyDisabled(env?: NodeJS.ProcessEnv): boolean;
|
|
3
|
+
/** Legacy emit must not let the server infer a company for conversation text. */
|
|
4
|
+
export declare function mayEmitConversation(event: Record<string, unknown>, env?: NodeJS.ProcessEnv): boolean;
|
|
5
|
+
/** Fleet identities have no person preference; operator and local controls still apply. */
|
|
6
|
+
export declare function reportingRuntimeAllowed(machine: boolean, env?: NodeJS.ProcessEnv): Promise<boolean>;
|
|
7
|
+
//# sourceMappingURL=reporting-privacy.d.ts.map
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { anywhereRuntimeAllowed } from "../../anywhere-person-setting.js";
|
|
2
|
+
import { anywhereRuntimeEnabledFromSnapshot } from "../../anywhere-runtime-fast-flag.js";
|
|
3
|
+
import { hqAnywhereRuntimeLocallyDisabled } from "../../anywhere-runtime-flag-key.js";
|
|
4
|
+
import { isNonCloudCompanySlug } from "../../work-context/company-rebind.js";
|
|
5
|
+
import { readMetaCompanySlug, resolveCompany } from "../../work-context/company.js";
|
|
6
|
+
import { deriveRemoteOwnerSlug, deriveRepoIdentityKey } from "../../work-context/repo-remote.js";
|
|
7
|
+
import { workContextRoot } from "../../work-context/paths.js";
|
|
8
|
+
import { readSessionState } from "../../work-context/state.js";
|
|
9
|
+
/** Match the off controls used by the hook and handoff command. */
|
|
10
|
+
export function reportingLocallyDisabled(env = process.env) {
|
|
11
|
+
const hooks = (env.HQ_DISABLED_HOOKS ?? "").split(",").map(value => value.trim());
|
|
12
|
+
return ["1", "true", "TRUE", "yes", "YES", "on", "ON"].includes(env.HQ_WORK_MESH_DISABLED ?? "") ||
|
|
13
|
+
hooks.some(value => ["*", "work-mesh", "work-mesh-live"].includes(value)) ||
|
|
14
|
+
hqAnywhereRuntimeLocallyDisabled(env);
|
|
15
|
+
}
|
|
16
|
+
/** Legacy emit must not let the server infer a company for conversation text. */
|
|
17
|
+
export function mayEmitConversation(event, env = process.env) {
|
|
18
|
+
if (event.kind !== "session_end" && typeof event.summary !== "string")
|
|
19
|
+
return true;
|
|
20
|
+
if (typeof event.sessionId !== "string" || !event.sessionId.trim())
|
|
21
|
+
return false;
|
|
22
|
+
const evidence = event.evidence && typeof event.evidence === "object"
|
|
23
|
+
? event.evidence : {};
|
|
24
|
+
const text = (key) => typeof evidence[key] === "string" ? evidence[key] : undefined;
|
|
25
|
+
const root = workContextRoot(undefined, env);
|
|
26
|
+
const state = readSessionState(event.sessionId, root);
|
|
27
|
+
const meta = readMetaCompanySlug(event.sessionId, text("hqRoot"));
|
|
28
|
+
if (isNonCloudCompanySlug(meta) || isNonCloudCompanySlug(state?.companySlug) || isNonCloudCompanySlug(text("companySlug")) ||
|
|
29
|
+
state?.companyConfidence === "device_default" || state?.contextStatus === "untracked")
|
|
30
|
+
return false;
|
|
31
|
+
// The flushing process is not the originating session. Its spawn/company
|
|
32
|
+
// identity cannot authorize historical conversation text.
|
|
33
|
+
const resolved = resolveCompany({ root, sessionId: event.sessionId,
|
|
34
|
+
env: { HQ_AGENT_IDENTITY_FILE: "" },
|
|
35
|
+
cwd: text("cwd"), hqRoot: text("hqRoot"),
|
|
36
|
+
remoteOwnerSlug: deriveRemoteOwnerSlug({ cwd: text("cwd"), hqRoot: text("hqRoot") }) ?? undefined,
|
|
37
|
+
repoIdentityKey: text("cwd") ? deriveRepoIdentityKey({ cwd: text("cwd") }) ?? undefined : undefined,
|
|
38
|
+
trusted: { companySlug: text("companySlug") }, existingState: state });
|
|
39
|
+
return resolved.status === "resolved" && !isNonCloudCompanySlug(resolved.company.slug);
|
|
40
|
+
}
|
|
41
|
+
/** Fleet identities have no person preference; operator and local controls still apply. */
|
|
42
|
+
export async function reportingRuntimeAllowed(machine, env = process.env) {
|
|
43
|
+
if (reportingLocallyDisabled(env))
|
|
44
|
+
return false;
|
|
45
|
+
return machine ? anywhereRuntimeEnabledFromSnapshot(env) : anywhereRuntimeAllowed(env);
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=reporting-privacy.js.map
|
|
@@ -12,11 +12,10 @@
|
|
|
12
12
|
* 4b. persisted per-repo company map (gap 4 — person "always ask per repo",
|
|
13
13
|
* remembered by repoIdentityKey; above the git-remote heuristic + device
|
|
14
14
|
* default, below the identity file so an agent box always wins)
|
|
15
|
-
* 5.
|
|
16
|
-
* 6. exactly one deterministic mapping (cwd under companies/{slug}/ or repo remote)
|
|
15
|
+
* 5. exactly one deterministic mapping (cwd under companies/{slug}/ or repo remote)
|
|
17
16
|
*
|
|
18
17
|
* Prompt-text matching is never used.
|
|
19
|
-
* Device
|
|
18
|
+
* Device defaults never attribute a session; explicit evidence is required.
|
|
20
19
|
*/
|
|
21
20
|
import type { TrustedExplicitContext } from "./contract.js";
|
|
22
21
|
import { type SessionStateFile } from "./state.js";
|
|
@@ -12,15 +12,14 @@
|
|
|
12
12
|
* 4b. persisted per-repo company map (gap 4 — person "always ask per repo",
|
|
13
13
|
* remembered by repoIdentityKey; above the git-remote heuristic + device
|
|
14
14
|
* default, below the identity file so an agent box always wins)
|
|
15
|
-
* 5.
|
|
16
|
-
* 6. exactly one deterministic mapping (cwd under companies/{slug}/ or repo remote)
|
|
15
|
+
* 5. exactly one deterministic mapping (cwd under companies/{slug}/ or repo remote)
|
|
17
16
|
*
|
|
18
17
|
* Prompt-text matching is never used.
|
|
19
|
-
* Device
|
|
18
|
+
* Device defaults never attribute a session; explicit evidence is required.
|
|
20
19
|
*/
|
|
21
20
|
import * as fs from "node:fs";
|
|
22
21
|
import * as path from "node:path";
|
|
23
|
-
import {
|
|
22
|
+
import { getRepoCompany } from "./config.js";
|
|
24
23
|
import { authoritativeCompanyFromState, readSessionState, } from "./state.js";
|
|
25
24
|
/** Pointer to the US-017B correction client (never auto-switches). */
|
|
26
25
|
const COMPANY_CORRECTION_PATH_PREFIX = "hq mesh context correct --session";
|
|
@@ -333,8 +332,7 @@ export function resolveCompany(input) {
|
|
|
333
332
|
};
|
|
334
333
|
}
|
|
335
334
|
}
|
|
336
|
-
//
|
|
337
|
-
const deviceDefault = input.allowDeviceDefault === false ? null : getDefaultCompany({ root: input.root });
|
|
335
|
+
// Membership and device preferences are not session attribution evidence.
|
|
338
336
|
const deterministic = resolveDeterministicCompany({
|
|
339
337
|
cwd: input.cwd,
|
|
340
338
|
hqRoot: input.hqRoot,
|
|
@@ -354,22 +352,6 @@ export function resolveCompany(input) {
|
|
|
354
352
|
evidenceCompany: deterministicConflict.remote,
|
|
355
353
|
};
|
|
356
354
|
}
|
|
357
|
-
if (deviceDefault?.enabled && deviceDefault.slug) {
|
|
358
|
-
const def = {
|
|
359
|
-
slug: deviceDefault.slug,
|
|
360
|
-
uid: deviceDefault.uid,
|
|
361
|
-
source: "device_default",
|
|
362
|
-
};
|
|
363
|
-
if (deterministic &&
|
|
364
|
-
!sameCompany(def, deterministic)) {
|
|
365
|
-
return {
|
|
366
|
-
status: "company_conflict",
|
|
367
|
-
defaultCompany: def,
|
|
368
|
-
evidenceCompany: deterministic,
|
|
369
|
-
};
|
|
370
|
-
}
|
|
371
|
-
return { status: "resolved", company: def };
|
|
372
|
-
}
|
|
373
355
|
if (deterministic) {
|
|
374
356
|
return { status: "resolved", company: deterministic };
|
|
375
357
|
}
|
|
@@ -2,6 +2,7 @@ import chalk from "chalk";
|
|
|
2
2
|
import { writeSync } from "node:fs";
|
|
3
3
|
import * as nodePath from "node:path";
|
|
4
4
|
import { cognitoCachePrincipalUid } from "./utils/cognito-session.js";
|
|
5
|
+
import { gatedInteractiveLogin } from "./utils/interactive-caller.js";
|
|
5
6
|
import { DEFAULT_SECRETS_CACHE_TTL_MS, hasCacheEntry, readCache, removeCacheEntry, writeCache, } from "./utils/secrets-cache.js";
|
|
6
7
|
import { computeSha256 } from "./utils/integrity.js";
|
|
7
8
|
import { SECRET_NAME_PATTERN } from "./commands/_patterns.js";
|
|
@@ -21,10 +22,12 @@ const SECRET_LOAD_TIMEOUT_MS = 30_000;
|
|
|
21
22
|
* stdin and stderr must be TTYs, and CI is always non-interactive.
|
|
22
23
|
*/
|
|
23
24
|
export function secretsCredentialOptions() {
|
|
25
|
+
// The shared gate also refuses lanes, daemons, bot runtimes, launchd
|
|
26
|
+
// tasks, and HQ_NO_BROWSER_LOGIN children that happen to hold a TTY.
|
|
24
27
|
return {
|
|
25
|
-
interactive: process.stdin.isTTY === true &&
|
|
28
|
+
interactive: gatedInteractiveLogin(process.stdin.isTTY === true &&
|
|
26
29
|
process.stderr.isTTY === true &&
|
|
27
|
-
!process.env.CI,
|
|
30
|
+
!process.env.CI),
|
|
28
31
|
};
|
|
29
32
|
}
|
|
30
33
|
export function scopeOpts(opts) {
|
|
@@ -4,6 +4,8 @@ export declare const DEFAULT_COGNITO_CALLBACK_PORT = 8765;
|
|
|
4
4
|
/** Ports registered as callback URLs on the HQ CLI Cognito app client. */
|
|
5
5
|
export declare const REGISTERED_COGNITO_CALLBACK_PORTS: readonly number[];
|
|
6
6
|
export type PortWarn = (message: string) => void;
|
|
7
|
+
/** Test hook: forget that the stray-port warning was printed. */
|
|
8
|
+
export declare function resetStrayPortWarningForTests(): void;
|
|
7
9
|
/**
|
|
8
10
|
* Resolve a callback port value, a string from the environment or a number,
|
|
9
11
|
* to a registered port. Unset resolves to 8765 silently; an unregistered value
|
|
@@ -11,18 +11,23 @@
|
|
|
11
11
|
export const DEFAULT_COGNITO_CALLBACK_PORT = 8765;
|
|
12
12
|
/** Ports registered as callback URLs on the HQ CLI Cognito app client. */
|
|
13
13
|
export const REGISTERED_COGNITO_CALLBACK_PORTS = [8765, 3000, 53682];
|
|
14
|
-
|
|
14
|
+
/** One stray-port warning per process: config and session both resolve the env value. */
|
|
15
|
+
let warnedStrayPort = false;
|
|
15
16
|
function defaultWarn(message) {
|
|
16
17
|
console.error(message);
|
|
17
18
|
}
|
|
18
|
-
function warnOnce(
|
|
19
|
+
function warnOnce(message, warn) {
|
|
19
20
|
if (warn === defaultWarn) {
|
|
20
|
-
if (
|
|
21
|
+
if (warnedStrayPort)
|
|
21
22
|
return;
|
|
22
|
-
|
|
23
|
+
warnedStrayPort = true;
|
|
23
24
|
}
|
|
24
25
|
warn(message);
|
|
25
26
|
}
|
|
27
|
+
/** Test hook: forget that the stray-port warning was printed. */
|
|
28
|
+
export function resetStrayPortWarningForTests() {
|
|
29
|
+
warnedStrayPort = false;
|
|
30
|
+
}
|
|
26
31
|
/**
|
|
27
32
|
* Resolve a callback port value, a string from the environment or a number,
|
|
28
33
|
* to a registered port. Unset resolves to 8765 silently; an unregistered value
|
|
@@ -35,7 +40,7 @@ export function resolveCognitoCallbackPort(raw, warn = defaultWarn) {
|
|
|
35
40
|
const port = typeof raw === "number" ? raw : Number(raw.trim());
|
|
36
41
|
if (REGISTERED_COGNITO_CALLBACK_PORTS.includes(port))
|
|
37
42
|
return port;
|
|
38
|
-
warnOnce(
|
|
43
|
+
warnOnce(`hq: ignoring callback port ${String(raw)}: it is not a registered Cognito callback ` +
|
|
39
44
|
`(${REGISTERED_COGNITO_CALLBACK_PORTS.join(", ")}). Using ${DEFAULT_COGNITO_CALLBACK_PORT}. ` +
|
|
40
45
|
"Unset HQ_COGNITO_CALLBACK_PORT or set it to a registered port.", warn);
|
|
41
46
|
return DEFAULT_COGNITO_CALLBACK_PORT;
|
|
@@ -4,7 +4,12 @@ export const DEFAULT_COGNITO = {
|
|
|
4
4
|
region: process.env.AWS_REGION ?? "us-east-1",
|
|
5
5
|
userPoolDomain: process.env.HQ_COGNITO_DOMAIN ?? "vault-indigo-hq-prod",
|
|
6
6
|
clientId: process.env.HQ_COGNITO_CLIENT_ID ?? "7acei2c8v870enheptb1j5foln",
|
|
7
|
-
|
|
7
|
+
// Resolved on read, not at module load: main.ts imports this for every
|
|
8
|
+
// command, and a stray HQ_COGNITO_CALLBACK_PORT should warn only when a
|
|
9
|
+
// sign-in actually reads the port.
|
|
10
|
+
get port() {
|
|
11
|
+
return resolveCognitoCallbackPort(process.env.HQ_COGNITO_CALLBACK_PORT);
|
|
12
|
+
},
|
|
8
13
|
identityProvider: process.env.HQ_COGNITO_IDENTITY_PROVIDER !== undefined
|
|
9
14
|
? process.env.HQ_COGNITO_IDENTITY_PROVIDER || undefined
|
|
10
15
|
: "Google",
|
|
@@ -51,7 +51,12 @@ export const DEFAULT_COGNITO = {
|
|
|
51
51
|
region: process.env.AWS_REGION ?? "us-east-1",
|
|
52
52
|
userPoolDomain: process.env.HQ_COGNITO_DOMAIN ?? "vault-indigo-hq-prod",
|
|
53
53
|
clientId: process.env.HQ_COGNITO_CLIENT_ID ?? "7acei2c8v870enheptb1j5foln",
|
|
54
|
-
|
|
54
|
+
// Resolved on read, not at module load: main.ts imports this for every
|
|
55
|
+
// command, and a stray HQ_COGNITO_CALLBACK_PORT should warn only when a
|
|
56
|
+
// sign-in actually reads the port.
|
|
57
|
+
get port() {
|
|
58
|
+
return resolveCognitoCallbackPort(process.env.HQ_COGNITO_CALLBACK_PORT);
|
|
59
|
+
},
|
|
55
60
|
// Skip Cognito's Hosted UI — go straight to Google OAuth. The Cognito
|
|
56
61
|
// /oauth2/authorize endpoint honors `identity_provider` and performs an
|
|
57
62
|
// internal redirect, so the user never sees the (un-styleable) Hosted UI.
|
|
@@ -12,4 +12,12 @@ export type InteractiveCallerInput = {
|
|
|
12
12
|
export declare function nonInteractiveReason(input?: InteractiveCallerInput): string | null;
|
|
13
13
|
/** True only when a person is at a terminal and may complete a browser sign-in. */
|
|
14
14
|
export declare function isInteractiveCaller(input?: InteractiveCallerInput): boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Gate a call site's request for an implicit browser sign-in. A command that
|
|
17
|
+
* asks for `interactive: true` gets it only when a person is at a terminal, so
|
|
18
|
+
* the same command run from a lane, daemon, bot, launchd task, or piped child
|
|
19
|
+
* fails with the `hq login` remedy instead of opening a sign-in tab. Explicit
|
|
20
|
+
* `false` stays false. `hq login` calls browserLogin directly and is not gated.
|
|
21
|
+
*/
|
|
22
|
+
export declare function gatedInteractiveLogin(requested?: boolean, input?: InteractiveCallerInput): boolean;
|
|
15
23
|
//# sourceMappingURL=interactive-caller.d.ts.map
|
|
@@ -67,4 +67,14 @@ export function nonInteractiveReason(input = {}) {
|
|
|
67
67
|
export function isInteractiveCaller(input = {}) {
|
|
68
68
|
return nonInteractiveReason(input) === null;
|
|
69
69
|
}
|
|
70
|
+
/**
|
|
71
|
+
* Gate a call site's request for an implicit browser sign-in. A command that
|
|
72
|
+
* asks for `interactive: true` gets it only when a person is at a terminal, so
|
|
73
|
+
* the same command run from a lane, daemon, bot, launchd task, or piped child
|
|
74
|
+
* fails with the `hq login` remedy instead of opening a sign-in tab. Explicit
|
|
75
|
+
* `false` stays false. `hq login` calls browserLogin directly and is not gated.
|
|
76
|
+
*/
|
|
77
|
+
export function gatedInteractiveLogin(requested = true, input = {}) {
|
|
78
|
+
return requested && isInteractiveCaller(input);
|
|
79
|
+
}
|
|
70
80
|
//# sourceMappingURL=interactive-caller.js.map
|
|
@@ -15,7 +15,8 @@ export async function loginWithBrowserPreference(config, browser = true) {
|
|
|
15
15
|
if (browser && !isHeadless())
|
|
16
16
|
return browserLogin(withRegisteredCallbackPort(config));
|
|
17
17
|
assertHumanLoginAllowed();
|
|
18
|
-
|
|
18
|
+
// The manual URL path builds the same redirect_uri, so it needs the same guard.
|
|
19
|
+
const port = withRegisteredCallbackPort(config).port ?? 3000;
|
|
19
20
|
const redirectUri = `http://localhost:${port}/callback`;
|
|
20
21
|
const base = `https://${config.userPoolDomain}.auth.${config.region}.amazoncognito.com`;
|
|
21
22
|
const verifier = randomBytes(32).toString("base64url");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@indigoai-us/hq-cli",
|
|
3
|
-
"version": "5.345.
|
|
3
|
+
"version": "5.345.200",
|
|
4
4
|
"description": "HQ by Indigo management CLI — modules and cloud sync",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -116,11 +116,11 @@
|
|
|
116
116
|
"*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}": "eslint --cache --no-error-on-unmatched-pattern"
|
|
117
117
|
},
|
|
118
118
|
"optionalDependencies": {
|
|
119
|
-
"@indigoai-us/hq-hook-win32-x64": "5.345.
|
|
120
|
-
"@indigoai-us/hq-hook-win32-arm64": "5.345.
|
|
121
|
-
"@indigoai-us/hq-hook-darwin-x64": "5.345.
|
|
122
|
-
"@indigoai-us/hq-hook-darwin-arm64": "5.345.
|
|
123
|
-
"@indigoai-us/hq-hook-linux-x64": "5.345.
|
|
124
|
-
"@indigoai-us/hq-hook-linux-arm64": "5.345.
|
|
119
|
+
"@indigoai-us/hq-hook-win32-x64": "5.345.200",
|
|
120
|
+
"@indigoai-us/hq-hook-win32-arm64": "5.345.200",
|
|
121
|
+
"@indigoai-us/hq-hook-darwin-x64": "5.345.200",
|
|
122
|
+
"@indigoai-us/hq-hook-darwin-arm64": "5.345.200",
|
|
123
|
+
"@indigoai-us/hq-hook-linux-x64": "5.345.200",
|
|
124
|
+
"@indigoai-us/hq-hook-linux-arm64": "5.345.200"
|
|
125
125
|
}
|
|
126
126
|
}
|