@indigoai-us/hq-cli 5.345.187 → 5.345.189
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 +111 -0
- package/dist/command-catalog.generated.d.ts +34 -0
- package/dist/command-catalog.generated.js +42 -0
- package/dist/commands/agent-inbox.js +43 -11
- package/dist/commands/agent-mcp.js +5 -2
- package/dist/commands/bot.js +15 -3
- package/dist/commands/core-company-index-scope-flag.d.ts +2 -1
- package/dist/commands/core-company-index-scope-flag.js +2 -1
- package/dist/commands/core.js +0 -5
- package/dist/commands/dm-attach.d.ts +73 -0
- package/dist/commands/dm-attach.js +104 -0
- package/dist/commands/dm.d.ts +10 -0
- package/dist/commands/dm.js +114 -2
- package/dist/commands/sources.js +15 -0
- package/dist/hq-cloud-sync-runner/bin/sync-runner.js +57330 -63803
- package/dist/hq-cloud-sync-runner/package.json +1 -1
- package/dist/lib/agent-kit/inbox-fetch.d.ts +92 -0
- package/dist/lib/agent-kit/inbox-fetch.js +135 -0
- package/dist/lib/agent-kit/mcp/tools.d.ts +11 -2
- package/dist/lib/agent-kit/mcp/tools.js +17 -3
- package/dist/lib/bot/fleet-local.d.ts +3 -1
- package/dist/lib/bot/fleet-local.js +9 -3
- package/dist/lib/bot/fleet-python.d.ts +6 -0
- package/dist/lib/bot/fleet-python.js +24 -5
- package/dist/lib/bot/probe.d.ts +7 -1
- package/dist/lib/bot/probe.js +11 -3
- package/dist/lib/bot/run.d.ts +9 -0
- package/dist/lib/bot/run.js +114 -8
- package/dist/lib/bot/runtime-failure.d.ts +3 -0
- package/dist/lib/bot/runtime-failure.js +20 -2
- package/dist/lib/flag-registry-worker-source.generated.d.ts +1 -1
- package/dist/lib/flag-registry-worker-source.generated.js +1 -1
- package/dist/lib/index-render/session-scope.d.ts +3 -3
- package/dist/lib/index-render/session-scope.js +11 -9
- package/dist/lib/index-render/shared.d.ts +6 -4
- package/dist/lib/index-render/shared.js +33 -4
- package/dist/utils/cognito-session.d.ts +5 -3
- package/dist/utils/cognito-session.js +43 -46
- package/dist/utils/hq-root-resolver.d.ts +27 -1
- package/dist/utils/hq-root-resolver.js +65 -33
- package/package.json +15 -15
|
@@ -60,9 +60,9 @@ export interface PlanOptions {
|
|
|
60
60
|
* - Unbound session: an explicit company is used as given; otherwise every
|
|
61
61
|
* company is rebuilt, with a warning unless --all-companies was passed.
|
|
62
62
|
* - Indeterminate session state: refused.
|
|
63
|
-
* -
|
|
64
|
-
*
|
|
65
|
-
*
|
|
63
|
+
* - Bound isolation is not optional. The kill switch may restore every-company
|
|
64
|
+
* writes only for an unbound session (automation). A bound session never
|
|
65
|
+
* writes another company's INDEX.md (feedback_31a4e992).
|
|
66
66
|
* - Every company is checked to be a real directory before anything runs.
|
|
67
67
|
*/
|
|
68
68
|
export declare function planScopedRebuild(target: IndexTarget, args: readonly string[], root: string, env: NodeJS.ProcessEnv, options: PlanOptions): RebuildPlan;
|
|
@@ -196,9 +196,9 @@ function companyArgs(target, slug) {
|
|
|
196
196
|
* - Unbound session: an explicit company is used as given; otherwise every
|
|
197
197
|
* company is rebuilt, with a warning unless --all-companies was passed.
|
|
198
198
|
* - Indeterminate session state: refused.
|
|
199
|
-
* -
|
|
200
|
-
*
|
|
201
|
-
*
|
|
199
|
+
* - Bound isolation is not optional. The kill switch may restore every-company
|
|
200
|
+
* writes only for an unbound session (automation). A bound session never
|
|
201
|
+
* writes another company's INDEX.md (feedback_31a4e992).
|
|
202
202
|
* - Every company is checked to be a real directory before anything runs.
|
|
203
203
|
*/
|
|
204
204
|
export function planScopedRebuild(target, args, root, env, options) {
|
|
@@ -261,17 +261,19 @@ export function planScopedRebuild(target, args, root, env, options) {
|
|
|
261
261
|
}
|
|
262
262
|
}
|
|
263
263
|
}
|
|
264
|
-
// cli.rebuild-index-company-scope is a kill switch (default on). Off,
|
|
265
|
-
// companies
|
|
266
|
-
//
|
|
264
|
+
// cli.rebuild-index-company-scope is a kill switch (default on). Off, an
|
|
265
|
+
// unbound `companies` rebuild goes back to every company (automation). A
|
|
266
|
+
// bound session still rebuilds only its bound companies.
|
|
267
267
|
const gateOff = !options.companyIndexScopeEnabled;
|
|
268
|
-
|
|
268
|
+
const bound = state.kind === "bound";
|
|
269
|
+
if (target === "companies" && gateOff && explicit.length === 0 && !bound) {
|
|
269
270
|
return { runs: [{ target, args: [] }], warning: COMPANY_SCOPE_FLAG_OFF_WARNING };
|
|
270
271
|
}
|
|
271
272
|
if (target === "all") {
|
|
273
|
+
const unscoped = gateOff && !bound;
|
|
272
274
|
return {
|
|
273
|
-
runs: [{ target, args: [...companies.flatMap((slug) => ["--company", slug]), ...(
|
|
274
|
-
warning:
|
|
275
|
+
runs: [{ target, args: [...companies.flatMap((slug) => ["--company", slug]), ...(unscoped ? [UNSCOPED_COMPANIES_INDEX] : [])] }],
|
|
276
|
+
warning: unscoped ? COMPANY_SCOPE_FLAG_OFF_WARNING : warning,
|
|
275
277
|
};
|
|
276
278
|
}
|
|
277
279
|
return { runs: companies.map((slug) => ({ target, args: companyArgs(target, slug) })), warning };
|
|
@@ -54,10 +54,12 @@ export declare function generatedStamp(content: string): string | undefined;
|
|
|
54
54
|
export declare function log(context: RenderContext, message: string): void;
|
|
55
55
|
export declare function projectStatus(root: string, project: string, prdPath: string, fallback: string, expectedStatePrdPath?: string): string;
|
|
56
56
|
/**
|
|
57
|
-
* Project status from
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
57
|
+
* Project status from files that sync with the company: sibling `state.json`
|
|
58
|
+
* (status written by skills such as demand-test), then prd.json `status` /
|
|
59
|
+
* `metadata.status`, then "complete" when every story passes, otherwise
|
|
60
|
+
* `fallback`. Unlike `projectStatus`, this never reads the machine-local
|
|
61
|
+
* `workspace/orchestrator/<project>/state.json`, so synced output renders
|
|
62
|
+
* the same on every machine.
|
|
61
63
|
*/
|
|
62
64
|
export declare function prdProjectStatus(prdPath: string, fallback: string): string;
|
|
63
65
|
export declare function basename(file: string): string;
|
|
@@ -166,14 +166,43 @@ export function projectStatus(root, project, prdPath, fallback, expectedStatePrd
|
|
|
166
166
|
}
|
|
167
167
|
return prdProjectStatus(prdPath, fallback);
|
|
168
168
|
}
|
|
169
|
+
function normalizeProjectStatus(raw) {
|
|
170
|
+
if (["completed", "complete"].includes(raw))
|
|
171
|
+
return "complete";
|
|
172
|
+
if (["in_progress", "active", "started"].includes(raw))
|
|
173
|
+
return "active";
|
|
174
|
+
return raw;
|
|
175
|
+
}
|
|
176
|
+
function explicitProjectStatus(record) {
|
|
177
|
+
if (!record)
|
|
178
|
+
return undefined;
|
|
179
|
+
if (typeof record.status === "string" && record.status.trim()) {
|
|
180
|
+
return normalizeProjectStatus(record.status.trim());
|
|
181
|
+
}
|
|
182
|
+
const metadata = record.metadata;
|
|
183
|
+
if (metadata && typeof metadata === "object" && !Array.isArray(metadata)) {
|
|
184
|
+
const nested = metadata.status;
|
|
185
|
+
if (typeof nested === "string" && nested.trim())
|
|
186
|
+
return normalizeProjectStatus(nested.trim());
|
|
187
|
+
}
|
|
188
|
+
return undefined;
|
|
189
|
+
}
|
|
169
190
|
/**
|
|
170
|
-
* Project status from
|
|
171
|
-
*
|
|
172
|
-
*
|
|
173
|
-
*
|
|
191
|
+
* Project status from files that sync with the company: sibling `state.json`
|
|
192
|
+
* (status written by skills such as demand-test), then prd.json `status` /
|
|
193
|
+
* `metadata.status`, then "complete" when every story passes, otherwise
|
|
194
|
+
* `fallback`. Unlike `projectStatus`, this never reads the machine-local
|
|
195
|
+
* `workspace/orchestrator/<project>/state.json`, so synced output renders
|
|
196
|
+
* the same on every machine.
|
|
174
197
|
*/
|
|
175
198
|
export function prdProjectStatus(prdPath, fallback) {
|
|
199
|
+
const localState = explicitProjectStatus(readJson(path.join(path.dirname(prdPath), "state.json")));
|
|
200
|
+
if (localState)
|
|
201
|
+
return localState;
|
|
176
202
|
const prd = readJson(prdPath);
|
|
203
|
+
const declared = explicitProjectStatus(prd);
|
|
204
|
+
if (declared)
|
|
205
|
+
return declared;
|
|
177
206
|
if (prd && Array.isArray(prd.userStories) && prd.userStories.length > 0 && prd.userStories.every((story) => Boolean(story.passes)))
|
|
178
207
|
return "complete";
|
|
179
208
|
return fallback;
|
|
@@ -52,7 +52,7 @@ export declare const DEFAULT_VAULT_API_URL: string;
|
|
|
52
52
|
* 5. Discovery: scan well-known locations (`~/HQ`, `~/hq`, `~/Documents/HQ`,
|
|
53
53
|
* …) for a folder carrying a valid `core.yaml` signature. Safety net for
|
|
54
54
|
* installs that never wrote the path back to menubar.json.
|
|
55
|
-
* 6. Fall back to `~/hq` (
|
|
55
|
+
* 6. Fall back to `~/hq` (`C:\hq` on Windows) — or throw, per
|
|
56
56
|
* `opts.onMissing`.
|
|
57
57
|
*
|
|
58
58
|
* Why tiers 3–5 exist:
|
|
@@ -71,7 +71,7 @@ export declare const DEFAULT_VAULT_API_URL: string;
|
|
|
71
71
|
* the walk from latching onto `<hqRoot>/core/` (Codex P2 on hq#146).
|
|
72
72
|
*
|
|
73
73
|
* `opts.onMissing` controls the final arm:
|
|
74
|
-
* - `'fallback'` (default) — return `~/hq` if nothing resolves. Preserves the
|
|
74
|
+
* - `'fallback'` (default) — return `~/hq` (`C:\hq` on Windows) if nothing resolves. Preserves the
|
|
75
75
|
* module-load contract of `DEFAULT_HQ_ROOT`, pinned by commander.js
|
|
76
76
|
* `.option()` callers at registration time.
|
|
77
77
|
* - `'throw'` — throw a user-actionable error. Used by module-management
|
|
@@ -88,6 +88,8 @@ export declare function resolveDefaultHqRoot(opts?: {
|
|
|
88
88
|
env?: NodeJS.ProcessEnv;
|
|
89
89
|
cwd?: string;
|
|
90
90
|
home?: string;
|
|
91
|
+
/** Defaults to process.platform; injectable so tests can exercise win32. */
|
|
92
|
+
platform?: NodeJS.Platform;
|
|
91
93
|
}): string;
|
|
92
94
|
export declare const DEFAULT_HQ_ROOT: string;
|
|
93
95
|
/**
|
|
@@ -267,7 +269,7 @@ export declare function buildVaultConfig(authToken: string): VaultServiceConfig;
|
|
|
267
269
|
* means no valid session could be ensured non-interactively; the caller gets a
|
|
268
270
|
* reason string and can decide what to do next. Never opens a browser.
|
|
269
271
|
*/
|
|
270
|
-
type MachineRefreshOptions = Pick<EnsureCognitoTokenOptions, "tokenSource"> & MachineTokenValidityOptions & {
|
|
272
|
+
type MachineRefreshOptions = Pick<EnsureCognitoTokenOptions, "tokenSource" | "signal"> & MachineTokenValidityOptions & {
|
|
271
273
|
/** Refresh the person session even when the cached token is still valid. */
|
|
272
274
|
force?: boolean;
|
|
273
275
|
};
|
|
@@ -30,6 +30,7 @@ import { hasPersonCachedSession, isMachineCredsFileEnvSet, probeMachineIdentity,
|
|
|
30
30
|
import { CLI_NAME, CLI_VERSION } from "../cli-version.js";
|
|
31
31
|
import { daemonDir } from "../lib/mesh/live/daemon/paths.js";
|
|
32
32
|
import { workMeshRoot } from "../lib/mesh/live/paths.js";
|
|
33
|
+
import { defaultHqRootFallback, hqDiscoveryCandidates, pathForPlatform, } from "./hq-root-resolver.js";
|
|
33
34
|
import { acquireLockFileExclusively } from "./exclusive-lock.js";
|
|
34
35
|
import { reportNoninteractivePersonRefreshRejection } from "./cognito-refresh-sentry.js";
|
|
35
36
|
import { decodeJwtPayload, loadCachedTokens, personTokenCacheFile, readPersonTokenFile, readTokenFile, } from "./person-token-cache.js";
|
|
@@ -78,7 +79,7 @@ export const DEFAULT_VAULT_API_URL = process.env.HQ_VAULT_API_URL ?? "https://hq
|
|
|
78
79
|
* 5. Discovery: scan well-known locations (`~/HQ`, `~/hq`, `~/Documents/HQ`,
|
|
79
80
|
* …) for a folder carrying a valid `core.yaml` signature. Safety net for
|
|
80
81
|
* installs that never wrote the path back to menubar.json.
|
|
81
|
-
* 6. Fall back to `~/hq` (
|
|
82
|
+
* 6. Fall back to `~/hq` (`C:\hq` on Windows) — or throw, per
|
|
82
83
|
* `opts.onMissing`.
|
|
83
84
|
*
|
|
84
85
|
* Why tiers 3–5 exist:
|
|
@@ -97,7 +98,7 @@ export const DEFAULT_VAULT_API_URL = process.env.HQ_VAULT_API_URL ?? "https://hq
|
|
|
97
98
|
* the walk from latching onto `<hqRoot>/core/` (Codex P2 on hq#146).
|
|
98
99
|
*
|
|
99
100
|
* `opts.onMissing` controls the final arm:
|
|
100
|
-
* - `'fallback'` (default) — return `~/hq` if nothing resolves. Preserves the
|
|
101
|
+
* - `'fallback'` (default) — return `~/hq` (`C:\hq` on Windows) if nothing resolves. Preserves the
|
|
101
102
|
* module-load contract of `DEFAULT_HQ_ROOT`, pinned by commander.js
|
|
102
103
|
* `.option()` callers at registration time.
|
|
103
104
|
* - `'throw'` — throw a user-actionable error. Used by module-management
|
|
@@ -111,32 +112,35 @@ export const DEFAULT_VAULT_API_URL = process.env.HQ_VAULT_API_URL ?? "https://hq
|
|
|
111
112
|
export function resolveDefaultHqRoot(opts = {}) {
|
|
112
113
|
const env = opts.env ?? process.env;
|
|
113
114
|
const home = opts.home ?? os.homedir();
|
|
115
|
+
const platform = opts.platform ?? process.platform;
|
|
116
|
+
const p = pathForPlatform(platform);
|
|
114
117
|
// Tier 1: explicit override.
|
|
115
118
|
if (env.HQ_ROOT)
|
|
116
|
-
return
|
|
119
|
+
return p.resolve(env.HQ_ROOT);
|
|
117
120
|
// Tier 2: working-tree walk-up — operate on the HQ tree you're inside.
|
|
118
|
-
let cur =
|
|
119
|
-
while (cur !==
|
|
120
|
-
if (isHqRoot(cur))
|
|
121
|
+
let cur = p.resolve(opts.cwd ?? process.cwd());
|
|
122
|
+
while (cur !== p.dirname(cur)) {
|
|
123
|
+
if (isHqRoot(cur, p))
|
|
121
124
|
return cur;
|
|
122
|
-
cur =
|
|
125
|
+
cur = p.dirname(cur);
|
|
123
126
|
}
|
|
124
127
|
// Tiers 3–4: the installer/menubar's canonical "where is HQ" records.
|
|
125
|
-
const fromConfig = readHqRootFromHqConfig(
|
|
128
|
+
const fromConfig = readHqRootFromHqConfig(p.join(home, ".hq"), p);
|
|
126
129
|
if (fromConfig)
|
|
127
|
-
return
|
|
128
|
-
// Tier 5: discover a valid HQ root in the well-known locations
|
|
129
|
-
|
|
130
|
+
return p.resolve(fromConfig);
|
|
131
|
+
// Tier 5: discover a valid HQ root in the well-known locations (on Windows
|
|
132
|
+
// the home-relative ones first, then %SystemDrive%\hq and %LOCALAPPDATA%\hq).
|
|
133
|
+
const discovered = hqDiscoveryCandidates({ platform, env, home }).find((dir) => isValidHqRootSignature(dir, p));
|
|
130
134
|
if (discovered)
|
|
131
135
|
return discovered;
|
|
132
|
-
// Tier 6: nothing resolved.
|
|
136
|
+
// Tier 6: nothing resolved. Fallback is ~/hq, or %SystemDrive%\hq on Windows.
|
|
133
137
|
if (opts.onMissing === "throw") {
|
|
134
138
|
throw new Error("Could not find HQ root. Run this command from within your HQ directory " +
|
|
135
139
|
"(must contain core.yaml AND a companies/ subdirectory), set $HQ_ROOT, " +
|
|
136
140
|
"or install HQ via the installer/menubar so ~/.hq/menubar.json records " +
|
|
137
141
|
"its location.");
|
|
138
142
|
}
|
|
139
|
-
return
|
|
143
|
+
return defaultHqRootFallback({ platform, env, home });
|
|
140
144
|
}
|
|
141
145
|
/**
|
|
142
146
|
* Read the configured HQ root from the installer/menubar records under
|
|
@@ -147,11 +151,11 @@ export function resolveDefaultHqRoot(opts = {}) {
|
|
|
147
151
|
* Returns the first non-empty string, or undefined. Best-effort: a missing or
|
|
148
152
|
* malformed file is treated as "not configured" (never throws).
|
|
149
153
|
*/
|
|
150
|
-
function readHqRootFromHqConfig(hqConfigDir) {
|
|
151
|
-
const fromMenubar = readJsonStringField(
|
|
154
|
+
function readHqRootFromHqConfig(hqConfigDir, p = path) {
|
|
155
|
+
const fromMenubar = readJsonStringField(p.join(hqConfigDir, "menubar.json"), "hqPath");
|
|
152
156
|
if (fromMenubar)
|
|
153
157
|
return fromMenubar;
|
|
154
|
-
return readJsonStringField(
|
|
158
|
+
return readJsonStringField(p.join(hqConfigDir, "config.json"), "hqFolderPath");
|
|
155
159
|
}
|
|
156
160
|
/** Read a top-level string field from a JSON file, or undefined on any miss. */
|
|
157
161
|
function readJsonStringField(file, field) {
|
|
@@ -164,25 +168,6 @@ function readJsonStringField(file, field) {
|
|
|
164
168
|
return undefined;
|
|
165
169
|
}
|
|
166
170
|
}
|
|
167
|
-
/** Well-known parent locations an HQ tree commonly lives in (mirrors hq-sync). */
|
|
168
|
-
function hqDiscoveryCandidates(home = os.homedir()) {
|
|
169
|
-
return [
|
|
170
|
-
path.join(home, "HQ"),
|
|
171
|
-
path.join(home, "hq"),
|
|
172
|
-
path.join(home, "Documents", "HQ"),
|
|
173
|
-
path.join(home, "Documents", "hq"),
|
|
174
|
-
path.join(home, "Desktop", "HQ"),
|
|
175
|
-
path.join(home, "Desktop", "hq"),
|
|
176
|
-
];
|
|
177
|
-
}
|
|
178
|
-
/**
|
|
179
|
-
* Scan the well-known locations for a folder carrying a valid `core.yaml`
|
|
180
|
-
* signature. First match wins; returns undefined if none qualify. Cheap — a
|
|
181
|
-
* few stats plus one small YAML parse on a hit.
|
|
182
|
-
*/
|
|
183
|
-
function discoverHqRootViaCoreYaml(home) {
|
|
184
|
-
return hqDiscoveryCandidates(home).find(isValidHqRootSignature);
|
|
185
|
-
}
|
|
186
171
|
/**
|
|
187
172
|
* True iff `dir` carries a valid hq-core `core.yaml` — canonical
|
|
188
173
|
* (`<dir>/core/core.yaml`, hq-core ≥v14) or legacy (`<dir>/core.yaml`) — that
|
|
@@ -190,9 +175,9 @@ function discoverHqRootViaCoreYaml(home) {
|
|
|
190
175
|
* field check (matching hq-sync's `is_valid_hq_root`) stops a stray `core.yaml`
|
|
191
176
|
* from another tool from false-matching.
|
|
192
177
|
*/
|
|
193
|
-
function isValidHqRootSignature(dir) {
|
|
194
|
-
const canonical =
|
|
195
|
-
const legacy =
|
|
178
|
+
function isValidHqRootSignature(dir, p = path) {
|
|
179
|
+
const canonical = p.join(dir, "core", "core.yaml");
|
|
180
|
+
const legacy = p.join(dir, "core.yaml");
|
|
196
181
|
let file;
|
|
197
182
|
if (fileExists(canonical))
|
|
198
183
|
file = canonical;
|
|
@@ -227,13 +212,13 @@ function fileExists(p) {
|
|
|
227
212
|
* the walk from latching onto the inner `core/` subtree, which carries its own
|
|
228
213
|
* `core.yaml` but no `companies/`.
|
|
229
214
|
*/
|
|
230
|
-
function isHqRoot(dir) {
|
|
231
|
-
const hasCoreYaml = fileExists(
|
|
232
|
-
fileExists(
|
|
215
|
+
function isHqRoot(dir, p = path) {
|
|
216
|
+
const hasCoreYaml = fileExists(p.join(dir, "core", "core.yaml")) ||
|
|
217
|
+
fileExists(p.join(dir, "core.yaml"));
|
|
233
218
|
if (!hasCoreYaml)
|
|
234
219
|
return false;
|
|
235
220
|
try {
|
|
236
|
-
return fs.statSync(
|
|
221
|
+
return fs.statSync(p.join(dir, "companies")).isDirectory();
|
|
237
222
|
}
|
|
238
223
|
catch {
|
|
239
224
|
return false;
|
|
@@ -780,11 +765,21 @@ function withTokenStateDirSection(fn) {
|
|
|
780
765
|
return run;
|
|
781
766
|
}
|
|
782
767
|
const MAX_MACHINE_TOKEN_MIN_VALIDITY_SECONDS = 1800;
|
|
783
|
-
|
|
768
|
+
/**
|
|
769
|
+
* `signal` cancels only this caller's wait inside hq-cloud (a mint shared with
|
|
770
|
+
* other callers keeps running). Without it a bounded caller such as `hq agent
|
|
771
|
+
* inbox` timed out, retried, and its retry queued behind the orphaned first
|
|
772
|
+
* mint, which still held the lock.
|
|
773
|
+
*/
|
|
774
|
+
async function ensureMachineTokens(minValiditySeconds, signal) {
|
|
784
775
|
const resolverMinimum = minValiditySeconds === undefined
|
|
785
776
|
? undefined
|
|
786
777
|
: Math.min(minValiditySeconds, MAX_MACHINE_TOKEN_MIN_VALIDITY_SECONDS);
|
|
787
|
-
|
|
778
|
+
const resolverOptions = {
|
|
779
|
+
...(resolverMinimum === undefined ? {} : { minValiditySeconds: resolverMinimum }),
|
|
780
|
+
...(signal ? { signal } : {}),
|
|
781
|
+
};
|
|
782
|
+
return withMachineTokenStateDir(() => getValidMachineTokens(DEFAULT_COGNITO, Object.keys(resolverOptions).length === 0 ? undefined : resolverOptions));
|
|
788
783
|
}
|
|
789
784
|
/**
|
|
790
785
|
* Ensure the current machine identity has a valid session and return only the
|
|
@@ -803,7 +798,7 @@ async function ensureMachineTokensMaybeFallback(options = {}) {
|
|
|
803
798
|
if (isDefaultMachineCredsFallback(options)) {
|
|
804
799
|
logDefaultMachineCredsFallback();
|
|
805
800
|
}
|
|
806
|
-
return ensureMachineTokens(options.minValiditySeconds);
|
|
801
|
+
return ensureMachineTokens(options.minValiditySeconds, options.signal);
|
|
807
802
|
}
|
|
808
803
|
/**
|
|
809
804
|
* After a person-cache miss or refresh failure: if the default machine-creds
|
|
@@ -818,7 +813,7 @@ async function tryDefaultMachineCredsFallback(options = {}) {
|
|
|
818
813
|
if (!isMachineIdentity())
|
|
819
814
|
return null;
|
|
820
815
|
logDefaultMachineCredsFallback();
|
|
821
|
-
return ensureMachineTokens(options.minValiditySeconds);
|
|
816
|
+
return ensureMachineTokens(options.minValiditySeconds, options.signal);
|
|
822
817
|
}
|
|
823
818
|
/**
|
|
824
819
|
* True when a person-token refresh failed with a definitive Cognito auth
|
|
@@ -880,6 +875,8 @@ function resolvePersonSessionAfterRefreshRejection(cached) {
|
|
|
880
875
|
* a browser.
|
|
881
876
|
*/
|
|
882
877
|
export async function ensureCognitoToken(options = {}) {
|
|
878
|
+
if (options.signal?.aborted)
|
|
879
|
+
throw options.signal.reason ?? new Error("Token acquisition was aborted");
|
|
883
880
|
if (wantsMachineCognitoTokens(options))
|
|
884
881
|
return ensureCognitoTokenUnserialized(options);
|
|
885
882
|
return withTokenStateDirSection(() => ensureCognitoTokenUnserialized(options));
|
|
@@ -1,13 +1,39 @@
|
|
|
1
1
|
/** Lightweight HQ-root resolver shared by cloud commands and fast flag scope. */
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
/** Path module matching the target platform's path shapes. */
|
|
4
|
+
export declare function pathForPlatform(platform?: NodeJS.Platform): path.PlatformPath;
|
|
5
|
+
/**
|
|
6
|
+
* The last-resort HQ root when nothing else resolves: `C:\hq` on Windows
|
|
7
|
+
* (`%SystemDrive%\hq`), `~/hq` elsewhere. Pure; all inputs injectable.
|
|
8
|
+
*/
|
|
9
|
+
export declare function defaultHqRootFallback(opts?: {
|
|
10
|
+
platform?: NodeJS.Platform;
|
|
11
|
+
env?: NodeJS.ProcessEnv;
|
|
12
|
+
home?: string;
|
|
13
|
+
}): string;
|
|
14
|
+
/**
|
|
15
|
+
* Well-known locations an HQ tree commonly lives in (mirrors hq-sync). On
|
|
16
|
+
* Windows `%SystemDrive%\hq` then `%LOCALAPPDATA%\hq` come AFTER the
|
|
17
|
+
* home-relative candidates, so an existing unrecorded `%USERPROFILE%\hq`
|
|
18
|
+
* install keeps winning over a stray `C:\hq` (avoids a split root).
|
|
19
|
+
*/
|
|
20
|
+
export declare function hqDiscoveryCandidates(opts?: {
|
|
21
|
+
platform?: NodeJS.Platform;
|
|
22
|
+
env?: NodeJS.ProcessEnv;
|
|
23
|
+
home?: string;
|
|
24
|
+
}): string[];
|
|
2
25
|
/**
|
|
3
26
|
* Resolve the HQ tree root using the same precedence as the Cognito helpers:
|
|
4
27
|
* explicit HQ_ROOT, nearest cwd root, installer records, known locations, then
|
|
5
|
-
* the
|
|
28
|
+
* the platform fallback (`~/hq`, or `C:\hq` on Windows), or an error when
|
|
29
|
+
* requested.
|
|
6
30
|
*/
|
|
7
31
|
export declare function resolveDefaultHqRoot(opts?: {
|
|
8
32
|
onMissing?: "throw" | "fallback";
|
|
9
33
|
env?: NodeJS.ProcessEnv;
|
|
10
34
|
cwd?: string;
|
|
11
35
|
home?: string;
|
|
36
|
+
platform?: NodeJS.Platform;
|
|
12
37
|
}): string;
|
|
38
|
+
export declare function isValidHqRootSignature(dir: string, p?: path.PlatformPath): boolean;
|
|
13
39
|
//# sourceMappingURL=hq-root-resolver.d.ts.map
|
|
@@ -3,26 +3,71 @@ import * as fs from "node:fs";
|
|
|
3
3
|
import * as os from "node:os";
|
|
4
4
|
import * as path from "node:path";
|
|
5
5
|
import * as yaml from "js-yaml";
|
|
6
|
+
/** Path module matching the target platform's path shapes. */
|
|
7
|
+
export function pathForPlatform(platform = process.platform) {
|
|
8
|
+
return platform === "win32" ? path.win32 : path.posix;
|
|
9
|
+
}
|
|
10
|
+
/** `%SystemDrive%` (for example `C:`), defaulting to `C:` when unset. */
|
|
11
|
+
function windowsSystemDrive(env) {
|
|
12
|
+
const drive = env.SystemDrive ?? env.SYSTEMDRIVE;
|
|
13
|
+
return drive && drive.trim().length > 0 ? drive.trim() : "C:";
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* The last-resort HQ root when nothing else resolves: `C:\hq` on Windows
|
|
17
|
+
* (`%SystemDrive%\hq`), `~/hq` elsewhere. Pure; all inputs injectable.
|
|
18
|
+
*/
|
|
19
|
+
export function defaultHqRootFallback(opts = {}) {
|
|
20
|
+
const platform = opts.platform ?? process.platform;
|
|
21
|
+
const env = opts.env ?? process.env;
|
|
22
|
+
if (platform === "win32") {
|
|
23
|
+
return path.win32.join(`${windowsSystemDrive(env)}\\`, "hq");
|
|
24
|
+
}
|
|
25
|
+
return path.posix.join(opts.home ?? os.homedir(), "hq");
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Well-known locations an HQ tree commonly lives in (mirrors hq-sync). On
|
|
29
|
+
* Windows `%SystemDrive%\hq` then `%LOCALAPPDATA%\hq` come AFTER the
|
|
30
|
+
* home-relative candidates, so an existing unrecorded `%USERPROFILE%\hq`
|
|
31
|
+
* install keeps winning over a stray `C:\hq` (avoids a split root).
|
|
32
|
+
*/
|
|
33
|
+
export function hqDiscoveryCandidates(opts = {}) {
|
|
34
|
+
const platform = opts.platform ?? process.platform;
|
|
35
|
+
const env = opts.env ?? process.env;
|
|
36
|
+
const home = opts.home ?? os.homedir();
|
|
37
|
+
const p = pathForPlatform(platform);
|
|
38
|
+
const candidates = [];
|
|
39
|
+
candidates.push(p.join(home, "HQ"), p.join(home, "hq"), p.join(home, "Documents", "HQ"), p.join(home, "Documents", "hq"), p.join(home, "Desktop", "HQ"), p.join(home, "Desktop", "hq"));
|
|
40
|
+
if (platform === "win32") {
|
|
41
|
+
candidates.push(defaultHqRootFallback({ platform, env, home }));
|
|
42
|
+
const localAppData = env.LOCALAPPDATA?.trim();
|
|
43
|
+
if (localAppData)
|
|
44
|
+
candidates.push(p.join(localAppData, "hq"));
|
|
45
|
+
}
|
|
46
|
+
return [...new Set(candidates)];
|
|
47
|
+
}
|
|
6
48
|
/**
|
|
7
49
|
* Resolve the HQ tree root using the same precedence as the Cognito helpers:
|
|
8
50
|
* explicit HQ_ROOT, nearest cwd root, installer records, known locations, then
|
|
9
|
-
* the
|
|
51
|
+
* the platform fallback (`~/hq`, or `C:\hq` on Windows), or an error when
|
|
52
|
+
* requested.
|
|
10
53
|
*/
|
|
11
54
|
export function resolveDefaultHqRoot(opts = {}) {
|
|
12
55
|
const env = opts.env ?? process.env;
|
|
13
56
|
const home = opts.home ?? os.homedir();
|
|
57
|
+
const platform = opts.platform ?? process.platform;
|
|
58
|
+
const p = pathForPlatform(platform);
|
|
14
59
|
if (env.HQ_ROOT)
|
|
15
|
-
return
|
|
16
|
-
let cur =
|
|
17
|
-
while (cur !==
|
|
18
|
-
if (isHqRoot(cur))
|
|
60
|
+
return p.resolve(env.HQ_ROOT);
|
|
61
|
+
let cur = p.resolve(opts.cwd ?? process.cwd());
|
|
62
|
+
while (cur !== p.dirname(cur)) {
|
|
63
|
+
if (isHqRoot(cur, p))
|
|
19
64
|
return cur;
|
|
20
|
-
cur =
|
|
65
|
+
cur = p.dirname(cur);
|
|
21
66
|
}
|
|
22
|
-
const fromConfig = readHqRootFromHqConfig(
|
|
67
|
+
const fromConfig = readHqRootFromHqConfig(p.join(home, ".hq"), p);
|
|
23
68
|
if (fromConfig)
|
|
24
|
-
return
|
|
25
|
-
const discovered =
|
|
69
|
+
return p.resolve(fromConfig);
|
|
70
|
+
const discovered = hqDiscoveryCandidates({ platform, env, home }).find((dir) => isValidHqRootSignature(dir, p));
|
|
26
71
|
if (discovered)
|
|
27
72
|
return discovered;
|
|
28
73
|
if (opts.onMissing === "throw") {
|
|
@@ -31,13 +76,13 @@ export function resolveDefaultHqRoot(opts = {}) {
|
|
|
31
76
|
"or install HQ via the installer/menubar so ~/.hq/menubar.json records " +
|
|
32
77
|
"its location.");
|
|
33
78
|
}
|
|
34
|
-
return
|
|
79
|
+
return defaultHqRootFallback({ platform, env, home });
|
|
35
80
|
}
|
|
36
|
-
function readHqRootFromHqConfig(hqConfigDir) {
|
|
37
|
-
const fromMenubar = readJsonStringField(
|
|
81
|
+
function readHqRootFromHqConfig(hqConfigDir, p = path) {
|
|
82
|
+
const fromMenubar = readJsonStringField(p.join(hqConfigDir, "menubar.json"), "hqPath");
|
|
38
83
|
if (fromMenubar)
|
|
39
84
|
return fromMenubar;
|
|
40
|
-
return readJsonStringField(
|
|
85
|
+
return readJsonStringField(p.join(hqConfigDir, "config.json"), "hqFolderPath");
|
|
41
86
|
}
|
|
42
87
|
function readJsonStringField(file, field) {
|
|
43
88
|
try {
|
|
@@ -49,22 +94,9 @@ function readJsonStringField(file, field) {
|
|
|
49
94
|
return undefined;
|
|
50
95
|
}
|
|
51
96
|
}
|
|
52
|
-
function
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
path.join(home, "hq"),
|
|
56
|
-
path.join(home, "Documents", "HQ"),
|
|
57
|
-
path.join(home, "Documents", "hq"),
|
|
58
|
-
path.join(home, "Desktop", "HQ"),
|
|
59
|
-
path.join(home, "Desktop", "hq"),
|
|
60
|
-
];
|
|
61
|
-
}
|
|
62
|
-
function discoverHqRootViaCoreYaml(home) {
|
|
63
|
-
return hqDiscoveryCandidates(home).find(isValidHqRootSignature);
|
|
64
|
-
}
|
|
65
|
-
function isValidHqRootSignature(dir) {
|
|
66
|
-
const canonical = path.join(dir, "core", "core.yaml");
|
|
67
|
-
const legacy = path.join(dir, "core.yaml");
|
|
97
|
+
export function isValidHqRootSignature(dir, p = path) {
|
|
98
|
+
const canonical = p.join(dir, "core", "core.yaml");
|
|
99
|
+
const legacy = p.join(dir, "core.yaml");
|
|
68
100
|
let file;
|
|
69
101
|
if (fileExists(canonical))
|
|
70
102
|
file = canonical;
|
|
@@ -88,13 +120,13 @@ function fileExists(file) {
|
|
|
88
120
|
return false;
|
|
89
121
|
}
|
|
90
122
|
}
|
|
91
|
-
function isHqRoot(dir) {
|
|
92
|
-
const hasCoreYaml = fileExists(
|
|
93
|
-
fileExists(
|
|
123
|
+
function isHqRoot(dir, p = path) {
|
|
124
|
+
const hasCoreYaml = fileExists(p.join(dir, "core", "core.yaml")) ||
|
|
125
|
+
fileExists(p.join(dir, "core.yaml"));
|
|
94
126
|
if (!hasCoreYaml)
|
|
95
127
|
return false;
|
|
96
128
|
try {
|
|
97
|
-
return fs.statSync(
|
|
129
|
+
return fs.statSync(p.join(dir, "companies")).isDirectory();
|
|
98
130
|
}
|
|
99
131
|
catch {
|
|
100
132
|
return false;
|
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.189",
|
|
4
4
|
"description": "HQ by Indigo management CLI — modules and cloud sync",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -52,9 +52,9 @@
|
|
|
52
52
|
"@aws-sdk/client-iot-data-plane": "^3.1096.0",
|
|
53
53
|
"@aws-sdk/client-s3": "^3.1049.0",
|
|
54
54
|
"@aws-sdk/dsql-signer": "^3.1146.0",
|
|
55
|
-
"@indigoai-us/hq-cloud": "6.18.
|
|
56
|
-
"@indigoai-us/hq-flags-client": "^0.
|
|
57
|
-
"@modelcontextprotocol/sdk": "1.
|
|
55
|
+
"@indigoai-us/hq-cloud": "6.18.107",
|
|
56
|
+
"@indigoai-us/hq-flags-client": "^0.2.0",
|
|
57
|
+
"@modelcontextprotocol/sdk": "1.32.2",
|
|
58
58
|
"@sentry/node": "^10.49.0",
|
|
59
59
|
"@tobilu/qmd": "2.5.3",
|
|
60
60
|
"ajv": "^8.20.0",
|
|
@@ -62,13 +62,13 @@
|
|
|
62
62
|
"chalk": "^5.3.0",
|
|
63
63
|
"commander": "^12.1.0",
|
|
64
64
|
"js-yaml": "^4.1.0",
|
|
65
|
-
"mqtt": "5.
|
|
65
|
+
"mqtt": "5.16.1",
|
|
66
66
|
"open": "^10.1.0",
|
|
67
67
|
"pg": "^8.23.1",
|
|
68
68
|
"semver": "^7.8.5",
|
|
69
69
|
"simple-git": "^3.27.0",
|
|
70
|
-
"smol-toml": "1.
|
|
71
|
-
"varlock": "1.
|
|
70
|
+
"smol-toml": "1.9.1",
|
|
71
|
+
"varlock": "1.23.0"
|
|
72
72
|
},
|
|
73
73
|
"devDependencies": {
|
|
74
74
|
"@eslint/js": "^10.0.1",
|
|
@@ -77,8 +77,8 @@
|
|
|
77
77
|
"@types/node": "^22.0.0",
|
|
78
78
|
"@types/pg": "^8.23.1",
|
|
79
79
|
"@types/semver": "^7.8.0",
|
|
80
|
-
"@vitest/coverage-v8": "4.1.
|
|
81
|
-
"aedes": "1.
|
|
80
|
+
"@vitest/coverage-v8": "4.1.12",
|
|
81
|
+
"aedes": "1.2.0",
|
|
82
82
|
"aws-sdk-client-mock": "^4.1.0",
|
|
83
83
|
"esbuild": "0.28.2",
|
|
84
84
|
"eslint": "^10.5.0",
|
|
@@ -114,11 +114,11 @@
|
|
|
114
114
|
"*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}": "eslint --cache --no-error-on-unmatched-pattern"
|
|
115
115
|
},
|
|
116
116
|
"optionalDependencies": {
|
|
117
|
-
"@indigoai-us/hq-hook-win32-x64": "5.345.
|
|
118
|
-
"@indigoai-us/hq-hook-win32-arm64": "5.345.
|
|
119
|
-
"@indigoai-us/hq-hook-darwin-x64": "5.345.
|
|
120
|
-
"@indigoai-us/hq-hook-darwin-arm64": "5.345.
|
|
121
|
-
"@indigoai-us/hq-hook-linux-x64": "5.345.
|
|
122
|
-
"@indigoai-us/hq-hook-linux-arm64": "5.345.
|
|
117
|
+
"@indigoai-us/hq-hook-win32-x64": "5.345.189",
|
|
118
|
+
"@indigoai-us/hq-hook-win32-arm64": "5.345.189",
|
|
119
|
+
"@indigoai-us/hq-hook-darwin-x64": "5.345.189",
|
|
120
|
+
"@indigoai-us/hq-hook-darwin-arm64": "5.345.189",
|
|
121
|
+
"@indigoai-us/hq-hook-linux-x64": "5.345.189",
|
|
122
|
+
"@indigoai-us/hq-hook-linux-arm64": "5.345.189"
|
|
123
123
|
}
|
|
124
124
|
}
|