@indigoai-us/hq-cli 5.324.0 → 5.326.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 (46) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/dist/bin/hq-auth-refresh.js +2 -3
  3. package/dist/command-catalog.generated.d.ts +10 -1
  4. package/dist/command-catalog.generated.js +11 -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/core-derive-trigger-facts-native.js +37 -3
  8. package/dist/commands/core-job-remote-launcher.js +2 -3
  9. package/dist/commands/daemon.js +1 -1
  10. package/dist/commands/install-global.d.ts +10 -0
  11. package/dist/commands/install-global.js +96 -41
  12. package/dist/commands/mcp-serve.d.ts +28 -0
  13. package/dist/commands/mcp-serve.js +165 -0
  14. package/dist/commands/mcp-status.js +7 -0
  15. package/dist/index.d.ts +3 -0
  16. package/dist/index.js +9 -0
  17. package/dist/lanes-drain-hook.js +2 -2
  18. package/dist/lib/anywhere-runtime-fast-flag.d.ts +3 -0
  19. package/dist/lib/anywhere-runtime-fast-flag.js +23 -0
  20. package/dist/lib/anywhere-runtime-flag-key.d.ts +3 -0
  21. package/dist/lib/anywhere-runtime-flag-key.js +3 -0
  22. package/dist/lib/daemon/ops/mcp.d.ts +54 -0
  23. package/dist/lib/daemon/ops/mcp.js +217 -0
  24. package/dist/lib/daemon/protocol.d.ts +2 -1
  25. package/dist/lib/daemon/protocol.js +3 -1
  26. package/dist/lib/daemon/server.d.ts +5 -0
  27. package/dist/lib/daemon/server.js +78 -11
  28. package/dist/lib/install/claude-targets.d.ts +11 -4
  29. package/dist/lib/install/claude-targets.js +21 -9
  30. package/dist/lib/install/codex-targets.d.ts +8 -4
  31. package/dist/lib/install/codex-targets.js +18 -9
  32. package/dist/lib/lanes/watcher-main.js +2 -4
  33. package/dist/lib/mcp/hosted-search-tools.d.ts +4 -0
  34. package/dist/lib/mcp/hosted-search-tools.js +28 -0
  35. package/dist/lib/mcp/hq-mcp-tools.generated.d.ts +3 -0
  36. package/dist/lib/mcp/hq-mcp-tools.generated.js +538 -0
  37. package/dist/lib/mcp/prompts.d.ts +30 -0
  38. package/dist/lib/mcp/prompts.js +48 -0
  39. package/dist/lib/mcp/tools.d.ts +22 -0
  40. package/dist/lib/mcp/tools.js +82 -0
  41. package/dist/lib/mcp/types.d.ts +6 -0
  42. package/dist/lib/mcp/types.js +2 -0
  43. package/dist/utils/is-main-module.d.ts +3 -0
  44. package/dist/utils/is-main-module.js +19 -0
  45. package/dist/utils/staged-npm-install.js +2 -1
  46. package/package.json +3 -1
@@ -11,12 +11,15 @@ import * as net from "node:net";
11
11
  import * as path from "node:path";
12
12
  import { CLI_VERSION } from "../../cli-version.js";
13
13
  import { canonicalDir, readRegistry, registryFile, resolveCompanyForDir } from "../registry/registry.js";
14
- import { createLineSplitter, encodeMessage, parseRequestLine } from "./protocol.js";
14
+ import { createLineSplitter, encodeMessage, HQD_DEFAULT_REQUEST_TIMEOUT_MS, HQD_MAX_LINE_BYTES, parseRequestLine } from "./protocol.js";
15
15
  import { SessionRegistry } from "./session-registry.js";
16
16
  import { journalAppend, JournalOpError } from "./ops/journal.js";
17
17
  import { memoryGet, memoryPut, MemoryOpError } from "./ops/memory.js";
18
18
  import { meshPresence, MeshOpError } from "./ops/mesh.js";
19
19
  import { PolicyIndex, PolicyOpError, policyCheck } from "./ops/policy.js";
20
+ import { HqMcpBridge, jsonResult, McpOpError, runWorker } from "./ops/mcp.js";
21
+ import { HQ_MCP_TOOL_NAMES, HQD_NATIVE_TOOL_NAMES } from "../mcp/tools.js";
22
+ import { anywhereRuntimeEnabled, HQ_ANYWHERE_RUNTIME_FLAG } from "../../commands/anywhere-runtime-flag.js";
20
23
  class OpError extends Error {
21
24
  code;
22
25
  constructor(code, message) {
@@ -87,19 +90,28 @@ export async function startHqdServer(opts) {
87
90
  throw new OpError("no_hq_root", "hqd has no HQ root configured (set hqRoot in daemon config or HQ_ROOT)");
88
91
  return opts.hqRoot;
89
92
  };
90
- /** Company for a call: explicit arg, else the open session's, else the registry's answer for cwd. */
93
+ const assertCompanyMatchesBinding = (explicit, bound) => {
94
+ if (explicit && bound && explicit !== bound) {
95
+ throw new OpError("company_mismatch", `explicit company ${explicit} conflicts with bound company ${bound}`);
96
+ }
97
+ };
98
+ /** Resolve a call's company while keeping any session or cwd binding authoritative. */
91
99
  const companyFor = (args) => {
92
100
  const explicit = stringArg(args, "company", false);
93
- if (explicit)
94
- return explicit;
95
101
  const runtime = stringArg(args, "runtime", false);
96
102
  const sessionId = stringArg(args, "sessionId", false);
97
103
  const session = runtime && sessionId ? sessions.get(runtime, sessionId) : null;
98
- if (session?.company)
99
- return session.company;
100
104
  const cwd = stringArg(args, "cwd", false);
101
- return cwd ? (resolve(cwd).company ?? undefined) : undefined;
105
+ const cwdCompany = cwd ? (resolve(cwd).company ?? undefined) : undefined;
106
+ if (session?.company && cwdCompany && session.company !== cwdCompany) {
107
+ throw new OpError("company_mismatch", `session company ${session.company} conflicts with cwd-bound company ${cwdCompany}`);
108
+ }
109
+ const boundCompany = session?.company ?? cwdCompany;
110
+ assertCompanyMatchesBinding(explicit, boundCompany);
111
+ return explicit ?? boundCompany;
102
112
  };
113
+ let hqMcp = opts.mcpBridge;
114
+ const mcpEnabled = opts.mcpEnabled ?? (() => anywhereRuntimeEnabled(env));
103
115
  if (!isPipe) {
104
116
  fs.mkdirSync(path.dirname(socketPath), { recursive: true, mode: 0o700 });
105
117
  if (fs.existsSync(socketPath)) {
@@ -108,7 +120,7 @@ export async function startHqdServer(opts) {
108
120
  fs.unlinkSync(socketPath);
109
121
  }
110
122
  }
111
- /** Synchronous ops answer in request order; only policy.check returns a promise. */
123
+ /** Synchronous ops answer in request order; policy.check and mcp.call may return a promise. */
112
124
  const handle = (req) => {
113
125
  const args = req.args ?? {};
114
126
  switch (req.op) {
@@ -129,7 +141,9 @@ export async function startHqdServer(opts) {
129
141
  const sessionId = stringArg(args, "sessionId");
130
142
  const cwd = stringArg(args, "cwd");
131
143
  const explicit = stringArg(args, "company", false);
132
- const company = explicit ?? resolve(cwd).company;
144
+ const boundCompany = resolve(cwd).company;
145
+ assertCompanyMatchesBinding(explicit, boundCompany ?? undefined);
146
+ const company = explicit ?? boundCompany;
133
147
  return sessions.open({ runtime, sessionId, cwd: canonicalDir(cwd), company });
134
148
  }
135
149
  case "session.get": {
@@ -197,6 +211,57 @@ export async function startHqdServer(opts) {
197
211
  reason: stringArg(args, "reason", false),
198
212
  }, { hqRoot: opts.hqRoot, workMeshRoot: opts.workMeshRoot, env, now: clock });
199
213
  }
214
+ case "mcp.call": {
215
+ const name = stringArg(args, "name");
216
+ const raw = args.arguments ?? {};
217
+ if (raw === null || typeof raw !== "object" || Array.isArray(raw))
218
+ throw new OpError("bad_args", "arguments must be an object");
219
+ // Preserve the tool cwd for its operation; caller cwd remains the tenant binding.
220
+ const toolArgs = { ...(args.cwd !== undefined ? { cwd: args.cwd } : {}), ...raw };
221
+ const companyArgs = { ...toolArgs, ...(args.cwd !== undefined ? { cwd: args.cwd } : {}) };
222
+ delete companyArgs.runtime;
223
+ delete companyArgs.sessionId;
224
+ const runtime = stringArg(args, "runtime", false);
225
+ const sessionId = stringArg(args, "sessionId", false);
226
+ if (runtime !== undefined)
227
+ companyArgs.runtime = runtime;
228
+ if (sessionId !== undefined)
229
+ companyArgs.sessionId = sessionId;
230
+ const call = (op, a) => handle({ id: req.id, op, args: a });
231
+ const asResult = (value) => (value instanceof Promise ? value.then(jsonResult) : jsonResult(value));
232
+ switch (name) {
233
+ case "hq_resolve_company":
234
+ return asResult(call("resolve", { cwd: toolArgs.cwd ?? process.cwd() }));
235
+ case "hq_policy_check":
236
+ return asResult(call("policy.check", companyArgs));
237
+ case "hq_journal_append":
238
+ return asResult(call("journal.append", companyArgs));
239
+ case "hq_run_worker": {
240
+ const tool = companyArgs;
241
+ return runWorker({
242
+ worker: stringArg(tool, "worker"),
243
+ skill: stringArg(tool, "skill", false),
244
+ args: typeof tool.args === "string" ? tool.args : undefined,
245
+ company: companyFor(tool),
246
+ }, requireRoot(), env, clock()).then(jsonResult);
247
+ }
248
+ default: {
249
+ if (HQD_NATIVE_TOOL_NAMES.has(name) || !HQ_MCP_TOOL_NAMES.has(name))
250
+ throw new OpError("unknown_tool", `unknown tool ${name}`);
251
+ companyFor(companyArgs);
252
+ const timeoutMs = typeof args.timeoutMs === "number" && Number.isFinite(args.timeoutMs)
253
+ ? Math.max(1, Math.min(args.timeoutMs, 120_000))
254
+ : HQD_DEFAULT_REQUEST_TIMEOUT_MS;
255
+ return Promise.resolve(mcpEnabled()).then((enabled) => {
256
+ if (!enabled) {
257
+ throw new McpOpError("hq_mcp_unavailable", `Hosted hq-mcp forwarding is disabled by the ${HQ_ANYWHERE_RUNTIME_FLAG} flag.`);
258
+ }
259
+ hqMcp ??= new HqMcpBridge({ env });
260
+ return hqMcp.callTool(name, raw, timeoutMs);
261
+ });
262
+ }
263
+ }
264
+ }
200
265
  case "shutdown":
201
266
  return { stopping: true };
202
267
  default:
@@ -231,7 +296,8 @@ export async function startHqdServer(opts) {
231
296
  err instanceof PolicyOpError ||
232
297
  err instanceof JournalOpError ||
233
298
  err instanceof MemoryOpError ||
234
- err instanceof MeshOpError
299
+ err instanceof MeshOpError ||
300
+ err instanceof McpOpError
235
301
  ? { code: err.code, message: err.message }
236
302
  : { code: "internal", message: err instanceof Error ? err.message : String(err) };
237
303
  if (error.code === "internal") {
@@ -260,7 +326,7 @@ export async function startHqdServer(opts) {
260
326
  }, () => {
261
327
  respond(socket, { id: null, ok: false, error: { code: "too_large", message: "request line too large" } });
262
328
  socket.end();
263
- });
329
+ }, HQD_MAX_LINE_BYTES);
264
330
  socket.on("data", push);
265
331
  });
266
332
  await new Promise((resolveListen, rejectListen) => {
@@ -287,6 +353,7 @@ export async function startHqdServer(opts) {
287
353
  sessions,
288
354
  close: () => (closing ??= new Promise((done) => {
289
355
  policyIndex?.close();
356
+ hqMcp?.close();
290
357
  server.close(() => done());
291
358
  // Answered-but-idle clients would otherwise hold close() open.
292
359
  for (const client of clients)
@@ -21,10 +21,14 @@ export interface ClaudeTargets {
21
21
  }
22
22
  export declare function claudeTargets(home: string): ClaudeTargets;
23
23
  export declare function masterHookPath(hqRoot: string): string;
24
+ /** hqd hook shim (US-010): registered instead of master-hook.sh once hqd is installed. */
25
+ export declare function shimPath(hqRoot: string): string;
26
+ /** Which HQ hook script the user-scope install registers. */
27
+ export type HookTarget = 'master' | 'shim';
24
28
  export declare function charterPath(hqRoot: string): string;
25
29
  export declare function hqSkillsSource(hqRoot: string): string;
26
30
  /** The exact hook command registered for one event (absolute path, quoted). */
27
- export declare function hookCommand(hqRoot: string, event: string): string;
31
+ export declare function hookCommand(hqRoot: string, event: string, target?: HookTarget): string;
28
32
  export declare function claudeMdBlock(hqRoot: string): string;
29
33
  /** Append the block (replacing any prior HQ block). `null` input = file absent. */
30
34
  export declare function addClaudeMdBlock(current: string | null, hqRoot: string): string;
@@ -32,11 +36,14 @@ export declare function addClaudeMdBlock(current: string | null, hqRoot: string)
32
36
  export declare function removeClaudeMdBlock(current: string): string;
33
37
  export declare function hasClaudeMdBlock(current: string | null): boolean;
34
38
  type Doc = Record<string, unknown>;
35
- /** Add one master-hook group per event; idempotent. Foreign hooks are untouched. */
36
- export declare function addHqHooks(doc: Doc, hqRoot: string): Doc;
39
+ /**
40
+ * Add one HQ hook group per event; idempotent. An HQ entry for the other
41
+ * target (master-hook.sh vs the hqd shim) is swapped out. Foreign hooks are untouched.
42
+ */
43
+ export declare function addHqHooks(doc: Doc, hqRoot: string, target?: HookTarget): Doc;
37
44
  /** Remove only HQ master-hook entries; drop containers this left empty. */
38
45
  export declare function removeHqHooks(doc: Doc, hqRoot: string): Doc;
39
- export declare function hasAllHqHooks(doc: Doc, hqRoot: string): boolean;
46
+ export declare function hasAllHqHooks(doc: Doc, hqRoot: string, target?: HookTarget): boolean;
40
47
  /**
41
48
  * Minimal line diff (LCS) with -/+ prefixes. Only changed lines and `context`
42
49
  * unchanged lines around them are shown, so a dry run never echoes a whole
@@ -37,6 +37,10 @@ export function claudeTargets(home) {
37
37
  export function masterHookPath(hqRoot) {
38
38
  return path.join(hqRoot, '.claude', 'hooks', 'master-hook.sh');
39
39
  }
40
+ /** hqd hook shim (US-010): registered instead of master-hook.sh once hqd is installed. */
41
+ export function shimPath(hqRoot) {
42
+ return path.join(hqRoot, 'core', 'scripts', 'hqd-hook-shim.sh');
43
+ }
40
44
  export function charterPath(hqRoot) {
41
45
  return path.join(hqRoot, '.claude', 'CLAUDE.md');
42
46
  }
@@ -44,7 +48,9 @@ export function hqSkillsSource(hqRoot) {
44
48
  return path.join(hqRoot, '.claude', 'skills');
45
49
  }
46
50
  /** The exact hook command registered for one event (absolute path, quoted). */
47
- export function hookCommand(hqRoot, event) {
51
+ export function hookCommand(hqRoot, event, target = 'master') {
52
+ if (target === 'shim')
53
+ return `/bin/sh ${JSON.stringify(shimPath(hqRoot))} ${event} --runtime claude`;
48
54
  return `bash ${JSON.stringify(masterHookPath(hqRoot))} ${event}`;
49
55
  }
50
56
  // ---------------------------------------------------------------------------
@@ -86,18 +92,24 @@ function isHqHookEntry(entry, hqRoot) {
86
92
  if (!entry || typeof entry !== 'object')
87
93
  return false;
88
94
  const cmd = entry.command;
89
- return typeof cmd === 'string' && cmd.includes(JSON.stringify(masterHookPath(hqRoot)));
95
+ return (typeof cmd === 'string' &&
96
+ (cmd.includes(JSON.stringify(masterHookPath(hqRoot))) || cmd.includes(JSON.stringify(shimPath(hqRoot)))));
90
97
  }
91
- /** Add one master-hook group per event; idempotent. Foreign hooks are untouched. */
92
- export function addHqHooks(doc, hqRoot) {
98
+ /**
99
+ * Add one HQ hook group per event; idempotent. An HQ entry for the other
100
+ * target (master-hook.sh vs the hqd shim) is swapped out. Foreign hooks are untouched.
101
+ */
102
+ export function addHqHooks(doc, hqRoot, target = 'master') {
93
103
  const hooks = { ...(doc.hooks ?? {}) };
94
104
  let changed = false;
95
105
  for (const event of GLOBAL_HOOK_EVENTS) {
96
- const groups = Array.isArray(hooks[event]) ? [...hooks[event]] : [];
97
- const present = groups.some((g) => Array.isArray(g?.hooks) && g.hooks.some((h) => isHqHookEntry(h, hqRoot)));
106
+ const want = hookCommand(hqRoot, event, target);
107
+ let groups = Array.isArray(hooks[event]) ? [...hooks[event]] : [];
108
+ const present = groups.some((g) => Array.isArray(g?.hooks) && g.hooks.some((h) => h.command === want));
98
109
  if (present)
99
110
  continue;
100
- groups.push({ hooks: [{ type: 'command', command: hookCommand(hqRoot, event), timeout: 300 }] });
111
+ groups = removeHqHooks({ hooks: { [event]: groups } }, hqRoot).hooks?.[event] ?? [];
112
+ groups.push({ hooks: [{ type: 'command', command: want, timeout: 300 }] });
101
113
  hooks[event] = groups;
102
114
  changed = true;
103
115
  }
@@ -141,8 +153,8 @@ export function removeHqHooks(doc, hqRoot) {
141
153
  next.hooks = hooks;
142
154
  return next;
143
155
  }
144
- export function hasAllHqHooks(doc, hqRoot) {
145
- return addHqHooks(doc, hqRoot) === doc;
156
+ export function hasAllHqHooks(doc, hqRoot, target = 'master') {
157
+ return addHqHooks(doc, hqRoot, target) === doc;
146
158
  }
147
159
  // ---------------------------------------------------------------------------
148
160
  // Dry-run diff.
@@ -1,3 +1,4 @@
1
+ import { type HookTarget } from './claude-targets.js';
1
2
  /** Events the Codex hook adapter is registered for at user scope. */
2
3
  export declare const CODEX_HOOK_EVENTS: readonly ["SessionStart", "UserPromptSubmit", "PreToolUse", "PostToolUse", "Stop"];
3
4
  export declare const AGENTS_MD_BEGIN = "<!-- hq-anywhere:begin (managed by `hq install --global --runtime codex`; remove with `hq uninstall --global --runtime codex`) -->";
@@ -24,18 +25,21 @@ export declare function codexCharterSource(hqRoot: string): string;
24
25
  * Hook command for every event. The adapter reads the event from
25
26
  * `hook_event_name` and falls back to its own $PWD when Codex sends no `cwd`.
26
27
  */
27
- export declare function codexHookCommand(hqRoot: string): string;
28
+ export declare function codexHookCommand(hqRoot: string, target?: HookTarget): string;
28
29
  export declare function agentsMdBlock(charter: string): string;
29
30
  /** Append the block (replacing any prior HQ block). `null` input = file absent. */
30
31
  export declare function addAgentsMdBlock(current: string | null, charter: string): string;
31
32
  /** Strip the HQ block, plus the separator `addAgentsMdBlock` put before it. */
32
33
  export declare function removeAgentsMdBlock(current: string): string;
33
34
  type Doc = Record<string, unknown>;
34
- /** Add one adapter group per event; idempotent. Foreign hooks are untouched. */
35
- export declare function addCodexHooks(doc: Doc, hqRoot: string): Doc;
35
+ /**
36
+ * Add one HQ hook group per event; idempotent. An HQ entry for the other
37
+ * target (adapter vs the hqd shim) is swapped out. Foreign hooks are untouched.
38
+ */
39
+ export declare function addCodexHooks(doc: Doc, hqRoot: string, target?: HookTarget): Doc;
36
40
  /** Remove only HQ adapter entries; drop containers this left empty. */
37
41
  export declare function removeCodexHooks(doc: Doc, hqRoot: string): Doc;
38
- export declare function hasAllCodexHooks(doc: Doc, hqRoot: string): boolean;
42
+ export declare function hasAllCodexHooks(doc: Doc, hqRoot: string, target?: HookTarget): boolean;
39
43
  export type LegacySkillsMirror = {
40
44
  kind: 'absent';
41
45
  }
@@ -11,6 +11,7 @@
11
11
  */
12
12
  import * as fs from 'fs';
13
13
  import * as path from 'path';
14
+ import { shimPath } from './claude-targets.js';
14
15
  /** Events the Codex hook adapter is registered for at user scope. */
15
16
  export const CODEX_HOOK_EVENTS = [
16
17
  'SessionStart',
@@ -50,7 +51,9 @@ export function codexCharterSource(hqRoot) {
50
51
  * Hook command for every event. The adapter reads the event from
51
52
  * `hook_event_name` and falls back to its own $PWD when Codex sends no `cwd`.
52
53
  */
53
- export function codexHookCommand(hqRoot) {
54
+ export function codexHookCommand(hqRoot, target = 'master') {
55
+ if (target === 'shim')
56
+ return `/bin/sh ${JSON.stringify(shimPath(hqRoot))} --runtime codex`;
54
57
  return `/bin/bash ${JSON.stringify(codexAdapterPath(hqRoot))}`;
55
58
  }
56
59
  // ---------------------------------------------------------------------------
@@ -88,18 +91,24 @@ function isAdapterEntry(entry, hqRoot) {
88
91
  if (!entry || typeof entry !== 'object')
89
92
  return false;
90
93
  const cmd = entry.command;
91
- return typeof cmd === 'string' && cmd.includes(JSON.stringify(codexAdapterPath(hqRoot)));
94
+ return (typeof cmd === 'string' &&
95
+ (cmd.includes(JSON.stringify(codexAdapterPath(hqRoot))) || cmd.includes(JSON.stringify(shimPath(hqRoot)))));
92
96
  }
93
- /** Add one adapter group per event; idempotent. Foreign hooks are untouched. */
94
- export function addCodexHooks(doc, hqRoot) {
97
+ /**
98
+ * Add one HQ hook group per event; idempotent. An HQ entry for the other
99
+ * target (adapter vs the hqd shim) is swapped out. Foreign hooks are untouched.
100
+ */
101
+ export function addCodexHooks(doc, hqRoot, target = 'master') {
95
102
  const hooks = { ...(doc.hooks ?? {}) };
96
103
  let changed = false;
104
+ const want = codexHookCommand(hqRoot, target);
97
105
  for (const event of CODEX_HOOK_EVENTS) {
98
- const groups = Array.isArray(hooks[event]) ? [...hooks[event]] : [];
99
- const present = groups.some((g) => Array.isArray(g?.hooks) && g.hooks.some((h) => isAdapterEntry(h, hqRoot)));
106
+ let groups = Array.isArray(hooks[event]) ? [...hooks[event]] : [];
107
+ const present = groups.some((g) => Array.isArray(g?.hooks) && g.hooks.some((h) => h.command === want));
100
108
  if (present)
101
109
  continue;
102
- groups.push({ hooks: [{ type: 'command', command: codexHookCommand(hqRoot), timeout: 300 }] });
110
+ groups = removeCodexHooks({ hooks: { [event]: groups } }, hqRoot).hooks?.[event] ?? [];
111
+ groups.push({ hooks: [{ type: 'command', command: want, timeout: 300 }] });
103
112
  hooks[event] = groups;
104
113
  changed = true;
105
114
  }
@@ -143,8 +152,8 @@ export function removeCodexHooks(doc, hqRoot) {
143
152
  next.hooks = hooks;
144
153
  return next;
145
154
  }
146
- export function hasAllCodexHooks(doc, hqRoot) {
147
- return addCodexHooks(doc, hqRoot) === doc;
155
+ export function hasAllCodexHooks(doc, hqRoot, target = 'master') {
156
+ return addCodexHooks(doc, hqRoot, target) === doc;
148
157
  }
149
158
  function within(child, parent) {
150
159
  const rel = path.relative(parent, child);
@@ -6,9 +6,9 @@
6
6
  * Requires HQ_ROOT in the environment.
7
7
  */
8
8
  import { spawn, spawnSync } from "node:child_process";
9
- import { existsSync, realpathSync } from "node:fs";
10
9
  import * as path from "node:path";
11
10
  import { fileURLToPath } from "node:url";
11
+ import { isMainModule } from "../../utils/is-main-module.js";
12
12
  import { runWatcherLoop } from "./watcher.js";
13
13
  import { spawnEnvelopeRepairViaCurrentCli, } from "./envelope-repair-dispatch.js";
14
14
  import { LanesError } from "./errors.js";
@@ -100,9 +100,7 @@ function main() {
100
100
  process.exit(1);
101
101
  });
102
102
  }
103
- const invokedEntryPath = process.argv[1] ? path.resolve(process.argv[1]) : undefined;
104
- const currentModule = realpathSync(fileURLToPath(import.meta.url));
105
- if (invokedEntryPath && existsSync(invokedEntryPath) && realpathSync(invokedEntryPath) === currentModule) {
103
+ if (isMainModule(import.meta.url)) {
106
104
  main();
107
105
  }
108
106
  //# sourceMappingURL=watcher-main.js.map
@@ -0,0 +1,4 @@
1
+ import type { McpToolDefinition } from "./types.js";
2
+ /** OpenAI-compatible tools the cloud Lambda adds in place of hq_knowledge_search. */
3
+ export declare const HOSTED_SEARCH_FETCH_TOOLS: readonly McpToolDefinition[];
4
+ //# sourceMappingURL=hosted-search-tools.d.ts.map
@@ -0,0 +1,28 @@
1
+ /** OpenAI-compatible tools the cloud Lambda adds in place of hq_knowledge_search. */
2
+ export const HOSTED_SEARCH_FETCH_TOOLS = [
3
+ {
4
+ name: "search",
5
+ description: "Search the authenticated user's chat-visible HQ knowledge, files, projects, policies, and skills. Returns ranked document references across every company the user is a member of and their personal vault. Use the returned `id` with `fetch` to retrieve the full document body.",
6
+ inputSchema: {
7
+ type: "object",
8
+ properties: {
9
+ query: { type: "string", minLength: 1, description: "Natural-language search query" },
10
+ },
11
+ required: ["query"],
12
+ additionalProperties: false,
13
+ },
14
+ },
15
+ {
16
+ name: "fetch",
17
+ description: "Retrieve the full body of a document returned by `search`. Enforces the same access scope as `search` — an id from a vault the caller no longer has access to is rejected. Skill bodies are returned as document text, not executable local tools.",
18
+ inputSchema: {
19
+ type: "object",
20
+ properties: {
21
+ id: { type: "string", minLength: 1, description: "An `id` from a prior `search` result" },
22
+ },
23
+ required: ["id"],
24
+ additionalProperties: false,
25
+ },
26
+ },
27
+ ];
28
+ //# sourceMappingURL=hosted-search-tools.js.map
@@ -0,0 +1,3 @@
1
+ import type { McpToolDefinition } from "./types.js";
2
+ export declare const HQ_MCP_TOOLS: readonly McpToolDefinition[];
3
+ //# sourceMappingURL=hq-mcp-tools.generated.d.ts.map