@indigoai-us/hq-cli 5.325.0 → 5.327.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.
Files changed (77) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/dist/bin/hq-auth-refresh.js +2 -3
  3. package/dist/command-catalog.generated.d.ts +19 -1
  4. package/dist/command-catalog.generated.js +21 -1
  5. package/dist/commands/anywhere-runtime-flag.d.ts +2 -2
  6. package/dist/commands/anywhere-runtime-flag.js +2 -2
  7. package/dist/commands/auth.js +3 -1
  8. package/dist/commands/core-detect-stale-review-base-fast.d.ts +2 -0
  9. package/dist/commands/core-detect-stale-review-base-fast.js +23 -0
  10. package/dist/commands/core-job-remote-launcher.js +2 -3
  11. package/dist/commands/core-register-project-native.js +1 -1
  12. package/dist/commands/core-repo-run-registry-fast.d.ts +2 -0
  13. package/dist/commands/core-repo-run-registry-fast.js +35 -0
  14. package/dist/commands/core-rrr-worktree-scope-fix-fast-flag.d.ts +7 -0
  15. package/dist/commands/core-rrr-worktree-scope-fix-fast-flag.js +25 -0
  16. package/dist/commands/core-session-journal-native.js +1 -1
  17. package/dist/commands/core-share-suggestion-state-fast.d.ts +2 -0
  18. package/dist/commands/core-share-suggestion-state-fast.js +25 -0
  19. package/dist/commands/daemon.js +1 -1
  20. package/dist/commands/install-global.d.ts +10 -0
  21. package/dist/commands/install-global.js +96 -41
  22. package/dist/commands/logout.js +2 -0
  23. package/dist/commands/mcp-serve.d.ts +28 -0
  24. package/dist/commands/mcp-serve.js +165 -0
  25. package/dist/commands/mcp-status.js +14 -0
  26. package/dist/fast-core.js +3 -6
  27. package/dist/fast-scaffold.js +5 -1
  28. package/dist/index.d.ts +3 -0
  29. package/dist/index.js +9 -0
  30. package/dist/lanes-drain-hook.js +2 -2
  31. package/dist/lib/anywhere-runtime-fast-flag.d.ts +3 -0
  32. package/dist/lib/anywhere-runtime-fast-flag.js +23 -0
  33. package/dist/lib/anywhere-runtime-flag-key.d.ts +3 -0
  34. package/dist/lib/anywhere-runtime-flag-key.js +3 -0
  35. package/dist/lib/daemon/mcp-endpoint.d.ts +8 -0
  36. package/dist/lib/daemon/mcp-endpoint.js +30 -0
  37. package/dist/lib/daemon/mcp-oauth.d.ts +24 -0
  38. package/dist/lib/daemon/mcp-oauth.js +298 -0
  39. package/dist/lib/daemon/ops/mcp.d.ts +53 -0
  40. package/dist/lib/daemon/ops/mcp.js +217 -0
  41. package/dist/lib/daemon/protocol.d.ts +2 -1
  42. package/dist/lib/daemon/protocol.js +3 -1
  43. package/dist/lib/daemon/server.d.ts +5 -0
  44. package/dist/lib/daemon/server.js +78 -11
  45. package/dist/lib/install/claude-targets.d.ts +11 -4
  46. package/dist/lib/install/claude-targets.js +21 -9
  47. package/dist/lib/install/codex-targets.d.ts +8 -4
  48. package/dist/lib/install/codex-targets.js +18 -9
  49. package/dist/lib/lanes/watcher-main.js +2 -4
  50. package/dist/lib/mcp/hosted-search-tools.d.ts +4 -0
  51. package/dist/lib/mcp/hosted-search-tools.js +28 -0
  52. package/dist/lib/mcp/hq-mcp-tools.generated.d.ts +3 -0
  53. package/dist/lib/mcp/hq-mcp-tools.generated.js +538 -0
  54. package/dist/lib/mcp/prompts.d.ts +30 -0
  55. package/dist/lib/mcp/prompts.js +48 -0
  56. package/dist/lib/mcp/tools.d.ts +22 -0
  57. package/dist/lib/mcp/tools.js +82 -0
  58. package/dist/lib/mcp/types.d.ts +6 -0
  59. package/dist/lib/mcp/types.js +2 -0
  60. package/dist/lib/process-flag-company-context-fast.d.ts +4 -0
  61. package/dist/lib/process-flag-company-context-fast.js +20 -0
  62. package/dist/lib/process-flag-company-context-light.d.ts +9 -0
  63. package/dist/lib/process-flag-company-context-light.js +81 -0
  64. package/dist/lib/process-flag-company-context.d.ts +2 -4
  65. package/dist/lib/process-flag-company-context.js +2 -46
  66. package/dist/utils/hq-roots-core.d.ts +130 -0
  67. package/dist/utils/hq-roots-core.js +354 -0
  68. package/dist/utils/hq-roots.d.ts +2 -129
  69. package/dist/utils/hq-roots.js +2 -353
  70. package/dist/utils/is-main-module.d.ts +3 -0
  71. package/dist/utils/is-main-module.js +19 -0
  72. package/dist/utils/package-root-diagnostics.d.ts +5 -36
  73. package/dist/utils/package-root-diagnostics.js +4 -83
  74. package/dist/utils/package-root-resolution-error.d.ts +32 -0
  75. package/dist/utils/package-root-resolution-error.js +79 -0
  76. package/dist/utils/staged-npm-install.js +2 -1
  77. package/package.json +3 -1
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Tool surface of `hq mcp serve` (hq-anywhere US-011).
3
+ *
4
+ * The hq-mcp tools come from src/lib/mcp/hq-mcp-tools.generated.ts, which
5
+ * scripts/generate-hq-mcp-tools.mjs builds from repos/public/hq-mcp. The four
6
+ * daemon-native tools are defined here. Names use underscores because
7
+ * Anthropic and OpenAI tool names reject dots (hq.resolve_company is exposed
8
+ * as hq_resolve_company).
9
+ *
10
+ * hqd answers every one of these through the `mcp.call` op, so a subagent
11
+ * without MCP can call the same tool with
12
+ * `hq daemon call mcp.call --json '{"name":"hq_journal_append","arguments":{...}}'`.
13
+ */
14
+ import { HQ_MCP_TOOLS } from "./hq-mcp-tools.generated.js";
15
+ import { HOSTED_SEARCH_FETCH_TOOLS } from "./hosted-search-tools.js";
16
+ const companyProp = { type: "string", description: "Company slug. Defaults to the company linked to cwd." };
17
+ const cwdProp = { type: "string", description: "Directory to resolve the company from. Defaults to the server's working directory." };
18
+ export const HQD_NATIVE_TOOLS = [
19
+ {
20
+ name: "hq_resolve_company",
21
+ description: "Returns the HQ company linked to a directory (registry from `hq link`), with the matched repo path.",
22
+ inputSchema: { type: "object", properties: { cwd: cwdProp }, additionalProperties: false },
23
+ },
24
+ {
25
+ name: "hq_policy_check",
26
+ description: "Runs the HQ policy engine for a proposed tool call and returns allow/block plus any policy context to inject. Fails closed when the engine errors.",
27
+ inputSchema: {
28
+ type: "object",
29
+ properties: {
30
+ tool: { type: "string", description: "Tool name the policy is checked for, e.g. Bash or Write" },
31
+ input: { type: "object", description: "The tool input, e.g. {\"command\": \"git push\"}" },
32
+ event: { type: "string", description: "Hook event, default PreToolUse" },
33
+ company: companyProp,
34
+ cwd: cwdProp,
35
+ sessionId: { type: "string" },
36
+ },
37
+ required: ["tool"],
38
+ additionalProperties: false,
39
+ },
40
+ },
41
+ {
42
+ name: "hq_journal_append",
43
+ description: "Appends a line to a project's active HQ journal under a section heading.",
44
+ inputSchema: {
45
+ type: "object",
46
+ properties: {
47
+ project: { type: "string", description: "Project slug under companies/<company>/projects" },
48
+ section: { type: "string", enum: ["decisions", "open", "findings", "rejected"], description: "Journal section" },
49
+ text: { type: "string", description: "The line to append" },
50
+ company: companyProp,
51
+ cwd: cwdProp,
52
+ },
53
+ required: ["project", "section", "text"],
54
+ additionalProperties: false,
55
+ },
56
+ },
57
+ {
58
+ name: "hq_run_worker",
59
+ description: "Dispatches an HQ worker skill through the /run command in a detached headless session. Returns the pid and log path; it does not wait for the worker to finish.",
60
+ inputSchema: {
61
+ type: "object",
62
+ properties: {
63
+ worker: { type: "string", description: "Worker id from core/workers/registry.yaml or a company registry" },
64
+ skill: { type: "string", description: "Skill name on that worker" },
65
+ args: { type: "string", description: "Free-text arguments passed to the skill" },
66
+ company: companyProp,
67
+ cwd: cwdProp,
68
+ },
69
+ required: ["worker"],
70
+ additionalProperties: false,
71
+ },
72
+ },
73
+ ];
74
+ export const HQD_NATIVE_TOOL_NAMES = new Set(HQD_NATIVE_TOOLS.map((t) => t.name));
75
+ /** Every tool `hq mcp serve` lists: the four native tools, then the hq-mcp set. */
76
+ export const HQ_MCP_HOSTED_TOOLS = [...HQ_MCP_TOOLS, ...HOSTED_SEARCH_FETCH_TOOLS];
77
+ export const MCP_TOOLS = [
78
+ ...HQD_NATIVE_TOOLS,
79
+ ...HQ_MCP_HOSTED_TOOLS.filter((t) => !HQD_NATIVE_TOOL_NAMES.has(t.name)),
80
+ ];
81
+ export const HQ_MCP_TOOL_NAMES = new Set(HQ_MCP_HOSTED_TOOLS.map((t) => t.name));
82
+ //# sourceMappingURL=tools.js.map
@@ -0,0 +1,6 @@
1
+ export interface McpToolDefinition {
2
+ name: string;
3
+ description: string;
4
+ inputSchema: Record<string, unknown>;
5
+ }
6
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1,4 @@
1
+ /** Fast scope resolver; it loads manifest and HQ-root code only for slug scopes. */
2
+ import { type ProcessFlagCompanyContext } from "./process-flag-company-context-light.js";
3
+ export declare function resolveFastProcessFlagCompanyContext(env?: NodeJS.ProcessEnv): Promise<ProcessFlagCompanyContext>;
4
+ //# sourceMappingURL=process-flag-company-context-fast.d.ts.map
@@ -0,0 +1,20 @@
1
+ /** Fast scope resolver; it loads manifest and HQ-root code only for slug scopes. */
2
+ import { normalizedCompanyUid, resolveLightProcessFlagCompanyContext, } from "./process-flag-company-context-light.js";
3
+ export async function resolveFastProcessFlagCompanyContext(env = process.env) {
4
+ const context = resolveLightProcessFlagCompanyContext(env);
5
+ let companyUid = context.companyUid;
6
+ if (!companyUid && context.companySlug) {
7
+ const [{ resolveDefaultHqRoot }, { readCompaniesManifestMap }] = await Promise.all([
8
+ import("../utils/hq-root-resolver.js"),
9
+ import("./work-context/repo-remote.js"),
10
+ ]);
11
+ const hqRoot = resolveDefaultHqRoot({ env });
12
+ const manifestUid = readCompaniesManifestMap(hqRoot)?.[context.companySlug]?.cloud_uid;
13
+ companyUid = typeof manifestUid === "string" ? normalizedCompanyUid(manifestUid) : undefined;
14
+ }
15
+ return {
16
+ ...(companyUid ? { companyUid } : {}),
17
+ ...(context.companySlug ? { companySlug: context.companySlug } : {}),
18
+ };
19
+ }
20
+ //# sourceMappingURL=process-flag-company-context-fast.js.map
@@ -0,0 +1,9 @@
1
+ /** Lightweight process company context shared by full and fast flag readers. */
2
+ export interface ProcessFlagCompanyContext {
3
+ companyUid?: string;
4
+ companySlug?: string;
5
+ }
6
+ export declare function normalizedCompanyUid(value: string | undefined): string | undefined;
7
+ /** Resolve explicit, machine, or bound-session company scope without defaults. */
8
+ export declare function resolveLightProcessFlagCompanyContext(env?: NodeJS.ProcessEnv): ProcessFlagCompanyContext;
9
+ //# sourceMappingURL=process-flag-company-context-light.d.ts.map
@@ -0,0 +1,81 @@
1
+ /** Lightweight process company context shared by full and fast flag readers. */
2
+ import * as fs from "node:fs";
3
+ import * as os from "node:os";
4
+ import * as path from "node:path";
5
+ const COMPANY_UID_RE = /^cmp_[A-Za-z0-9]{3,128}$/;
6
+ const COMPANY_SLUG_RE = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
7
+ const SESSION_ID_RE = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
8
+ const DEFAULT_AGENT_IDENTITY_FILE = "/var/lib/hq-agent/identity.json";
9
+ export function normalizedCompanyUid(value) {
10
+ const candidate = value?.trim() ?? "";
11
+ return COMPANY_UID_RE.test(candidate) ? candidate : undefined;
12
+ }
13
+ function normalizedCompanySlug(value) {
14
+ const candidate = value?.trim() ?? "";
15
+ return COMPANY_SLUG_RE.test(candidate) ? candidate : undefined;
16
+ }
17
+ function record(value) {
18
+ return value && typeof value === "object" && !Array.isArray(value)
19
+ ? value
20
+ : undefined;
21
+ }
22
+ function readAgentIdentity(env) {
23
+ const configured = env.HQ_AGENT_IDENTITY_FILE;
24
+ const file = configured === undefined ? DEFAULT_AGENT_IDENTITY_FILE : configured.trim();
25
+ if (!file)
26
+ return undefined;
27
+ try {
28
+ const identity = record(JSON.parse(fs.readFileSync(file, "utf8")));
29
+ const companyUid = normalizedCompanyUid(typeof identity?.companyUid === "string" ? identity.companyUid : undefined);
30
+ const companySlug = normalizedCompanySlug(typeof identity?.companySlug === "string" ? identity.companySlug : undefined);
31
+ return companyUid || companySlug ? {
32
+ ...(companyUid ? { companyUid } : {}),
33
+ ...(companySlug ? { companySlug } : {}),
34
+ } : undefined;
35
+ }
36
+ catch {
37
+ return undefined;
38
+ }
39
+ }
40
+ function readSessionCompany(env) {
41
+ const sessionId = env.HQ_SESSION_ID?.trim();
42
+ if (!sessionId || sessionId.includes("..") || !SESSION_ID_RE.test(sessionId))
43
+ return undefined;
44
+ const contextRoot = env.HQ_WORK_CONTEXT_ROOT?.trim() || path.join(os.homedir(), ".hq", "work-context");
45
+ try {
46
+ const sessionPath = path.join(contextRoot, "sessions", sessionId + ".json");
47
+ const session = record(JSON.parse(fs.readFileSync(sessionPath, "utf8")));
48
+ if (session?.sessionId !== sessionId ||
49
+ session.contextStatus !== "bound" ||
50
+ session.companyConfidence === "device_default")
51
+ return undefined;
52
+ const companyUid = normalizedCompanyUid(typeof session.companyUid === "string" ? session.companyUid : undefined);
53
+ const companySlug = normalizedCompanySlug(typeof session.companySlug === "string" ? session.companySlug : undefined);
54
+ return companyUid || companySlug ? {
55
+ ...(companyUid ? { companyUid } : {}),
56
+ ...(companySlug ? { companySlug } : {}),
57
+ } : undefined;
58
+ }
59
+ catch {
60
+ return undefined;
61
+ }
62
+ }
63
+ /** Resolve explicit, machine, or bound-session company scope without defaults. */
64
+ export function resolveLightProcessFlagCompanyContext(env = process.env) {
65
+ const explicitUid = normalizedCompanyUid(env.HQ_COMPANY_UID);
66
+ const explicitSlug = normalizedCompanySlug(env.HQ_COMPANY_SLUG);
67
+ if (explicitUid || explicitSlug) {
68
+ return { companyUid: explicitUid, companySlug: explicitSlug };
69
+ }
70
+ const spawnValue = env.HQ_SPAWN_COMPANY?.trim();
71
+ if (spawnValue && COMPANY_UID_RE.test(spawnValue))
72
+ return { companyUid: spawnValue };
73
+ const spawnSlug = normalizedCompanySlug(spawnValue);
74
+ if (spawnSlug)
75
+ return { companySlug: spawnSlug };
76
+ const identity = readAgentIdentity(env);
77
+ if (identity)
78
+ return identity;
79
+ return readSessionCompany(env) ?? {};
80
+ }
81
+ //# sourceMappingURL=process-flag-company-context-light.js.map
@@ -1,8 +1,6 @@
1
1
  /** Company scope shared by the full flag registry and its fast-path reader. */
2
- export interface ProcessFlagCompanyContext {
3
- companyUid?: string;
4
- companySlug?: string;
5
- }
2
+ import { type ProcessFlagCompanyContext } from "./process-flag-company-context-light.js";
3
+ export type { ProcessFlagCompanyContext } from "./process-flag-company-context-light.js";
6
4
  /** Resolve the same company identity the process-wide flag reader uses. */
7
5
  export declare function resolveProcessFlagCompanyContext(env?: NodeJS.ProcessEnv): ProcessFlagCompanyContext;
8
6
  //# sourceMappingURL=process-flag-company-context.d.ts.map
@@ -1,51 +1,7 @@
1
1
  /** Company scope shared by the full flag registry and its fast-path reader. */
2
- import { readMachineCompanyBinding } from "./work-context/company.js";
3
- import { readSessionState } from "./work-context/state.js";
4
- import { workContextRoot } from "./work-context/paths.js";
5
2
  import { readCompaniesManifestMap } from "./work-context/repo-remote.js";
6
3
  import { resolveDefaultHqRoot } from "../utils/hq-root-resolver.js";
7
- const COMPANY_UID_RE = /^cmp_[A-Za-z0-9]{3,128}$/;
8
- const COMPANY_SLUG_RE = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
9
- function normalizedCompanyUid(value) {
10
- const candidate = value?.trim() ?? "";
11
- return COMPANY_UID_RE.test(candidate) ? candidate : undefined;
12
- }
13
- function normalizedCompanySlug(value) {
14
- const candidate = value?.trim() ?? "";
15
- return COMPANY_SLUG_RE.test(candidate) ? candidate : undefined;
16
- }
17
- /** Resolve explicit, machine, or bound-session company scope without defaults. */
18
- function processCompanyContext(env = process.env) {
19
- const explicitUid = normalizedCompanyUid(env.HQ_COMPANY_UID);
20
- const explicitSlug = normalizedCompanySlug(env.HQ_COMPANY_SLUG);
21
- if (explicitUid || explicitSlug) {
22
- return { companyUid: explicitUid, companySlug: explicitSlug };
23
- }
24
- const machine = readMachineCompanyBinding(env);
25
- const spawnValue = env.HQ_SPAWN_COMPANY?.trim();
26
- const spawnSlug = normalizedCompanySlug(spawnValue);
27
- const machineContext = spawnValue && COMPANY_UID_RE.test(spawnValue)
28
- ? { companyUid: spawnValue }
29
- : spawnSlug
30
- ? { companySlug: spawnSlug }
31
- : {
32
- companyUid: normalizedCompanyUid(machine?.uid),
33
- companySlug: normalizedCompanySlug(machine?.slug),
34
- };
35
- if (machineContext.companyUid || machineContext.companySlug)
36
- return machineContext;
37
- const sessionId = env.HQ_SESSION_ID?.trim();
38
- if (!sessionId)
39
- return {};
40
- const session = readSessionState(sessionId, workContextRoot(undefined, env));
41
- if (session?.contextStatus !== "bound" || session.companyConfidence === "device_default") {
42
- return {};
43
- }
44
- return {
45
- companyUid: normalizedCompanyUid(session.companyUid),
46
- companySlug: normalizedCompanySlug(session.companySlug),
47
- };
48
- }
4
+ import { normalizedCompanyUid, resolveLightProcessFlagCompanyContext, } from "./process-flag-company-context-light.js";
49
5
  function companyUidForContext(context, env = process.env) {
50
6
  if (context.companyUid)
51
7
  return context.companyUid;
@@ -57,7 +13,7 @@ function companyUidForContext(context, env = process.env) {
57
13
  }
58
14
  /** Resolve the same company identity the process-wide flag reader uses. */
59
15
  export function resolveProcessFlagCompanyContext(env = process.env) {
60
- const context = processCompanyContext(env);
16
+ const context = resolveLightProcessFlagCompanyContext(env);
61
17
  const companyUid = companyUidForContext(context, env);
62
18
  return {
63
19
  ...(companyUid ? { companyUid } : {}),
@@ -0,0 +1,130 @@
1
+ /**
2
+ * Root resolution for CLI-hosted HQ scaffold code.
3
+ *
4
+ * When shell that used to live inside the HQ scaffold moves into this npm
5
+ * package, it loses the one thing it relied on: `BASH_SOURCE`/`$0` pointed at
6
+ * the user's live HQ tree, so "where am I" and "where is HQ" were the same
7
+ * answer. Inside a globally installed package they are three different answers,
8
+ * and conflating any two of them silently corrupts the wrong tree.
9
+ *
10
+ * liveRoot The user's HQ installation — companies/, workspace/, personal/,
11
+ * the installed .claude/ and core/. This is runtime state. Hidden
12
+ * runtime commands operate here.
13
+ *
14
+ * packageRoot This npm package's own directory, where bundled scaffold assets
15
+ * ship. Read-only in practice: a global install may sit in a
16
+ * root-owned prefix. NEVER usable as liveRoot.
17
+ *
18
+ * There is deliberately no third "source root". Release-source tooling — the
19
+ * linters, generators, and validators that rewrite checked-in artifacts — stays
20
+ * scaffold-owned, so nothing here ever needs to resolve an hq-core checkout. See
21
+ * the scaffold-vs-cli-code-ownership policy for why.
22
+ *
23
+ * The invariant that matters most: `resolveLiveRoot` never consults
24
+ * `import.meta.url`. A relocated script asking "where is HQ" must get the live
25
+ * tree, not the package it happens to be bundled in.
26
+ */
27
+ import * as fs from "fs";
28
+ /** Where bundled scaffold assets live, relative to the package root. */
29
+ export declare const BUNDLED_ASSET_DIR: string;
30
+ /**
31
+ * Does this directory look like an HQ tree root?
32
+ *
33
+ * `companies/` is the load-bearing marker — it is the source of truth for
34
+ * tenants and exists in every real install. The second clause tolerates the
35
+ * three shapes a tree can legitimately be in: a full install, a scaffold
36
+ * checkout without a personal overlay, and a personal-only overlay.
37
+ */
38
+ export declare function isHqRoot(dir: string): boolean;
39
+ export type PackageRootFs = Pick<typeof fs, "existsSync" | "readFileSync" | "realpathSync" | "statSync">;
40
+ export type PackageRootResolverOptions = {
41
+ /** Directory containing the currently-running compiled module. */
42
+ moduleDir: string;
43
+ /** Full module path used only in safe diagnostic output. */
44
+ modulePath?: string;
45
+ /** Injectable filesystem seam for resolver tests. */
46
+ fs?: PackageRootFs;
47
+ };
48
+ /**
49
+ * Make a resolver for this package's root. It caches only a successful lookup:
50
+ * a concurrently replaced manifest must be retried by the next command, not
51
+ * converted into a permanent process failure.
52
+ */
53
+ export declare function createPackageRootResolver(options: PackageRootResolverOptions): () => string;
54
+ /**
55
+ * This package's installed root — the directory holding its `package.json`.
56
+ *
57
+ * Walks up from the compiled module (`dist/utils/hq-roots.js`) until it finds a
58
+ * `package.json` whose name matches, rather than hard-coding `..` hops, so the
59
+ * answer survives a change in output layout.
60
+ */
61
+ export declare function packageRoot(): string;
62
+ /**
63
+ * Derive this package's installed root from the running module's OWN path using
64
+ * STRING operations only — no `readFileSync`, `realpathSync`, or `existsSync`.
65
+ *
66
+ * {@link packageRoot} must read `<dir>/package.json` and `realpathSync` the
67
+ * module directory to answer, so it THROWS in exactly the situation that most
68
+ * needs an answer: a concurrent global install has renamed the installed
69
+ * package directory aside (`.hq-cli-<rand>`) and is re-extracting it file by
70
+ * file, so both the manifest walk and the dist-owner fallback fail on a
71
+ * directory that is momentarily gone. This walks the compiled module's
72
+ * ancestors as strings and returns the DEEPEST one whose trailing segments are
73
+ * `node_modules/@indigoai-us/hq-cli`, which stays correct while that directory
74
+ * does not exist on disk.
75
+ *
76
+ * It is a FALLBACK only — {@link packageRoot} validates the manifest name and
77
+ * is authoritative whenever it succeeds. Returns null for a dev checkout or any
78
+ * layout without that segment triple, so a caller that falls back to it can
79
+ * only ever degrade to today's behaviour (no resolution), never widen it.
80
+ *
81
+ * The deepest match is deliberate: a nested `node_modules/@indigoai-us/hq-cli`
82
+ * inside another package resolves to ITSELF (the copy the module belongs to),
83
+ * never an outer decoy. Case is folded only for a Windows-shaped path, matching
84
+ * the POSIX case-sensitivity the rest of this module assumes.
85
+ */
86
+ export declare function stringDerivedPackageRoot(moduleFilePath?: string): string | null;
87
+ export type LiveRootOptions = {
88
+ /** Explicit `--hq-root` value. Highest precedence. */
89
+ hqRoot?: string;
90
+ /** Start the walk-up here instead of `process.cwd()`. Tests only. */
91
+ cwd?: string;
92
+ /** Environment to read. Tests only. */
93
+ env?: NodeJS.ProcessEnv;
94
+ };
95
+ /**
96
+ * Resolve the user's live HQ installation.
97
+ *
98
+ * Precedence: `--hq-root` → `HQ_ROOT` → `CLAUDE_PROJECT_DIR` → walk up from cwd.
99
+ *
100
+ * ## An explicit root is trusted; a discovered one must be recognized
101
+ *
102
+ * The FIRST explicit candidate present wins outright — there is no fall-through
103
+ * past it, because silently operating on a different tree than the caller named
104
+ * is the worst available outcome.
105
+ *
106
+ * That explicit candidate is checked only for the two things that are always
107
+ * wrong: it must be a directory, and it must not be inside {@link packageRoot}
108
+ * (that is this package, not anyone's HQ). It is deliberately NOT required to
109
+ * satisfy {@link isHqRoot}.
110
+ *
111
+ * Requiring markers here was tried and was wrong: the scripts these roots feed
112
+ * accepted any `HQ_ROOT` before they moved, and several callers legitimately pass
113
+ * a minimal tree — e.g. `rebuild-threads-index` against a fixture holding nothing
114
+ * but `workspace/threads/`. Enforcing markers on an explicit value turned a
115
+ * relocation into a silent contract change and broke those callers.
116
+ *
117
+ * The cwd walk is the opposite case: there the marker check is the only thing
118
+ * that can identify a root at all, so it stays mandatory.
119
+ */
120
+ export declare function resolveLiveRoot(opts?: LiveRootOptions): string;
121
+ /**
122
+ * Absolute path to a scaffold asset bundled in this package.
123
+ *
124
+ * Refuses to resolve outside the asset directory so a manifest entry can never
125
+ * be coaxed into executing an arbitrary path, and fails loudly when the asset
126
+ * is missing — an absent asset means the packlist dropped it, which is a
127
+ * packaging bug worth surfacing rather than a runtime fallback.
128
+ */
129
+ export declare function resolveBundledAsset(relativePath: string): string;
130
+ //# sourceMappingURL=hq-roots-core.d.ts.map