@indigoai-us/hq-cli 5.301.0 → 5.303.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 (65) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/assets/scaffold/core/scripts/rebuild-projects-index.sh +99 -12
  3. package/assets/scaffold/core/scripts/token-usage-report.sh +72 -20
  4. package/dist/command-catalog.generated.d.ts +4 -1
  5. package/dist/command-catalog.generated.js +5 -1
  6. package/dist/commands/bot.js +1 -0
  7. package/dist/commands/core-checkpoint.js +1 -0
  8. package/dist/commands/core-handoff-fast.js +1 -0
  9. package/dist/commands/core-handoff.js +2 -0
  10. package/dist/commands/deploy-comments.js +5 -2
  11. package/dist/commands/integrations-connect.d.ts +3 -0
  12. package/dist/commands/integrations-connect.js +21 -2
  13. package/dist/commands/lanes-message.js +33 -3
  14. package/dist/commands/lanes-questions.d.ts +4 -2
  15. package/dist/commands/lanes-questions.js +123 -2
  16. package/dist/commands/lanes-resume.js +25 -4
  17. package/dist/commands/lanes-shared.d.ts +13 -1
  18. package/dist/commands/lanes-watch.js +5 -1
  19. package/dist/commands/lanes.js +91 -9
  20. package/dist/commands/monitor.js +17 -2
  21. package/dist/commands/report.js +5 -2
  22. package/dist/commands/rescue.d.ts +4 -0
  23. package/dist/commands/rescue.js +27 -17
  24. package/dist/lib/agent-kit/fallback.d.ts +1 -0
  25. package/dist/lib/agent-kit/fallback.js +1 -0
  26. package/dist/lib/bot/cli-update.d.ts +0 -8
  27. package/dist/lib/bot/cli-update.js +5 -5
  28. package/dist/lib/bot/daemon.d.ts +5 -1
  29. package/dist/lib/bot/daemon.js +4 -4
  30. package/dist/lib/bot/local-jobs.d.ts +1 -21
  31. package/dist/lib/bot/local-jobs.js +12 -12
  32. package/dist/lib/core-utils/soft-timeout.js +1 -1
  33. package/dist/lib/daemon/config.d.ts +0 -1
  34. package/dist/lib/daemon/config.js +1 -1
  35. package/dist/lib/deploy-apps.d.ts +13 -0
  36. package/dist/lib/deploy-apps.js +24 -0
  37. package/dist/lib/index-render/projects.js +82 -5
  38. package/dist/lib/lanes/delivery.d.ts +7 -3
  39. package/dist/lib/lanes/delivery.js +18 -8
  40. package/dist/lib/lanes/index.d.ts +1 -1
  41. package/dist/lib/lanes/keep-alive.d.ts +13 -3
  42. package/dist/lib/lanes/keep-alive.js +29 -5
  43. package/dist/lib/lanes/outpost-dispatch.d.ts +5 -0
  44. package/dist/lib/lanes/outpost-dispatch.js +12 -0
  45. package/dist/lib/lanes/reconcile.d.ts +1 -0
  46. package/dist/lib/lanes/reconcile.js +358 -38
  47. package/dist/lib/lanes/spawn.d.ts +1 -0
  48. package/dist/lib/lanes/spawn.js +20 -10
  49. package/dist/lib/lanes/store.js +24 -0
  50. package/dist/lib/lanes/story-ledger.d.ts +2 -0
  51. package/dist/lib/lanes/story-ledger.js +8 -0
  52. package/dist/lib/lanes/types.d.ts +26 -4
  53. package/dist/lib/lanes/types.js +33 -1
  54. package/dist/lib/lanes/watch.d.ts +1 -0
  55. package/dist/lib/lanes/watch.js +19 -6
  56. package/dist/lib/lanes/watcher.js +139 -9
  57. package/dist/lib/mesh/live/daemon/run.js +36 -2
  58. package/dist/lib/report-snapshot.d.ts +0 -2
  59. package/dist/lib/report-snapshot.js +2 -2
  60. package/dist/lib/search-index/background.d.ts +1 -0
  61. package/dist/lib/search-index/background.js +1 -0
  62. package/dist/utils/run-bundled-script.js +103 -1
  63. package/dist/utils/update-command-supervisor.cjs +1 -0
  64. package/dist/utils/version-gate.js +1 -1
  65. package/package.json +1 -1
@@ -1,7 +1,5 @@
1
1
  /** File name of the snapshot inside the published report. */
2
2
  export declare const REPORT_PREVIEW_FILE = "hq-preview.png";
3
- export declare const REPORT_PREVIEW_WIDTH = 1280;
4
- export declare const REPORT_PREVIEW_HEIGHT = 720;
5
3
  /** First installed browser that can take a snapshot, or null. */
6
4
  export declare function findSnapshotBrowser(env?: NodeJS.ProcessEnv, platform?: string, exists?: (file: string) => boolean): string | null;
7
5
  export declare function snapshotArgs(indexFile: string, outFile: string, profileDir: string): string[];
@@ -13,8 +13,8 @@ import * as path from "node:path";
13
13
  import { pathToFileURL } from "node:url";
14
14
  /** File name of the snapshot inside the published report. */
15
15
  export const REPORT_PREVIEW_FILE = "hq-preview.png";
16
- export const REPORT_PREVIEW_WIDTH = 1280;
17
- export const REPORT_PREVIEW_HEIGHT = 720;
16
+ const REPORT_PREVIEW_WIDTH = 1280;
17
+ const REPORT_PREVIEW_HEIGHT = 720;
18
18
  const SNAPSHOT_TIMEOUT_MS = 30_000;
19
19
  const PNG_MAGIC = Buffer.from([0x89, 0x50, 0x4e, 0x47]);
20
20
  const BROWSER_PATHS = {
@@ -47,6 +47,7 @@ export type SpawnWorkerIo = {
47
47
  closeSync: (fd: number) => void;
48
48
  spawn: (command: string, args: string[], options: {
49
49
  detached: boolean;
50
+ windowsHide: boolean;
50
51
  stdio: StdioOptions;
51
52
  }) => {
52
53
  pid?: number;
@@ -92,6 +92,7 @@ export function defaultSpawnWorker({ logPath, fallbackLogPath }, io = defaultSpa
92
92
  : ['ignore', opened.fd, opened.fd];
93
93
  const child = io.spawn(process.execPath, [entry, 'index', 'background', '--worker', ...logArgs], {
94
94
  detached: true,
95
+ windowsHide: true,
95
96
  stdio,
96
97
  });
97
98
  if (opened.fd !== null)
@@ -29,6 +29,7 @@
29
29
  * script needs to see termination, not a success code.
30
30
  */
31
31
  import { spawnSync } from "child_process";
32
+ import * as fs from "node:fs";
32
33
  import * as path from "path";
33
34
  import { resolveBundledAsset } from "./hq-roots.js";
34
35
  /**
@@ -41,6 +42,93 @@ export function interpreterFor(asset) {
41
42
  const ext = path.extname(asset).toLowerCase();
42
43
  return ext === ".mjs" || ext === ".js" || ext === ".cjs" ? "node" : "bash";
43
44
  }
45
+ function envValue(env, name) {
46
+ const key = Object.keys(env).find((candidate) => candidate.toLowerCase() === name.toLowerCase());
47
+ return key ? env[key] : undefined;
48
+ }
49
+ function isFile(file, lookupErrors) {
50
+ try {
51
+ return fs.statSync(file).isFile();
52
+ }
53
+ catch (error) {
54
+ // Missing PATH candidates are expected during lookup; retain the cause so
55
+ // the final actionable error can expose why no interpreter was resolved.
56
+ lookupErrors.push(error);
57
+ return false;
58
+ }
59
+ }
60
+ function isWithinWindowsDirectory(file, directory) {
61
+ const normalizedFile = path.win32.resolve(file).toLowerCase();
62
+ const normalizedDirectory = path.win32.resolve(directory).toLowerCase();
63
+ return (normalizedFile === normalizedDirectory ||
64
+ normalizedFile.startsWith(`${normalizedDirectory}${path.win32.sep}`));
65
+ }
66
+ function isExcludedWindowsBash(file, env) {
67
+ if (path.win32.basename(file).toLowerCase() !== "bash.exe")
68
+ return false;
69
+ const windowsDir = envValue(env, "SystemRoot") ?? envValue(env, "WINDIR") ?? "C:\\Windows";
70
+ const systemBash = path.win32.resolve(windowsDir, "System32", "bash.exe");
71
+ if (path.win32.resolve(file).toLowerCase() === systemBash.toLowerCase())
72
+ return true;
73
+ const localAppData = envValue(env, "LOCALAPPDATA");
74
+ return Boolean(localAppData &&
75
+ isWithinWindowsDirectory(file, path.win32.resolve(localAppData, "Microsoft", "WindowsApps")));
76
+ }
77
+ function findOnWindowsPath(executable, env, lookupErrors) {
78
+ const pathValue = envValue(env, "PATH") ?? "";
79
+ const extensions = executable.includes(".")
80
+ ? [""]
81
+ : (envValue(env, "PATHEXT") ?? ".COM;.EXE;.BAT;.CMD")
82
+ .split(";")
83
+ .filter(Boolean)
84
+ .map((ext) => ext.toLowerCase());
85
+ for (const entry of pathValue.split(";").filter(Boolean)) {
86
+ const directory = entry.trim().replace(/^"|"$/g, "");
87
+ for (const extension of extensions) {
88
+ const candidate = path.win32.join(directory, `${executable}${extension}`);
89
+ if (!isExcludedWindowsBash(candidate, env) && isFile(candidate, lookupErrors))
90
+ return candidate;
91
+ }
92
+ }
93
+ return undefined;
94
+ }
95
+ function resolveWindowsBash(env) {
96
+ const lookupErrors = [];
97
+ const configured = envValue(env, "CLAUDE_CODE_GIT_BASH_PATH");
98
+ if (configured && !isExcludedWindowsBash(configured, env) && isFile(configured, lookupErrors)) {
99
+ return { executable: configured, cause: lookupErrors.at(-1) };
100
+ }
101
+ const pathBash = findOnWindowsPath("bash", env, lookupErrors);
102
+ if (pathBash)
103
+ return { executable: pathBash, cause: lookupErrors.at(-1) };
104
+ const gitExe = findOnWindowsPath("git.exe", env, lookupErrors);
105
+ if (gitExe) {
106
+ const derived = path.win32.resolve(path.win32.dirname(gitExe), "..", "bin", "bash.exe");
107
+ if (!isExcludedWindowsBash(derived, env) && isFile(derived, lookupErrors)) {
108
+ return { executable: derived, cause: lookupErrors.at(-1) };
109
+ }
110
+ }
111
+ const programFiles = envValue(env, "ProgramFiles") ?? "C:\\Program Files";
112
+ const localAppData = envValue(env, "LOCALAPPDATA");
113
+ const standardPaths = [
114
+ path.win32.join(programFiles, "Git", "bin", "bash.exe"),
115
+ ...(localAppData ? [path.win32.join(localAppData, "Programs", "Git", "bin", "bash.exe")] : []),
116
+ ];
117
+ const executable = standardPaths.find((candidate) => !isExcludedWindowsBash(candidate, env) && isFile(candidate, lookupErrors));
118
+ return {
119
+ executable,
120
+ cause: lookupErrors.at(-1) ??
121
+ Object.assign(new Error("Bash was not found (ENOENT)"), { code: "ENOENT" }),
122
+ };
123
+ }
124
+ function bashNotFoundError(asset, cause) {
125
+ const isHandoff = asset.replaceAll("\\", "/").endsWith("core/scripts/handoff-finalize.sh");
126
+ const recovery = isHandoff
127
+ ? "The handoff was not saved; rerun the command."
128
+ : "The script did not run; rerun this command.";
129
+ return new Error(`Bash was not found to run bundled script ${asset}. Install Git for Windows or ` +
130
+ `set CLAUDE_CODE_GIT_BASH_PATH. ${recovery}`, { cause });
131
+ }
44
132
  /**
45
133
  * Execute a bundled scaffold script and return its exit code.
46
134
  *
@@ -56,12 +144,26 @@ export function runBundledScript(opts) {
56
144
  env.CLAUDE_PROJECT_DIR = opts.hqRoot;
57
145
  }
58
146
  Object.assign(env, opts.env ?? {});
59
- const result = spawnSync(interpreterFor(opts.asset), [script, ...(opts.args ?? [])], {
147
+ const interpreter = interpreterFor(opts.asset);
148
+ const windowsBash = process.platform === "win32" && interpreter === "bash"
149
+ ? resolveWindowsBash(env)
150
+ : undefined;
151
+ const executable = windowsBash?.executable ?? interpreter;
152
+ if (windowsBash && !windowsBash.executable) {
153
+ throw bashNotFoundError(opts.asset, windowsBash.cause);
154
+ }
155
+ const result = spawnSync(executable, [script, ...(opts.args ?? [])], {
60
156
  cwd: opts.cwd,
61
157
  env,
62
158
  stdio: "inherit",
63
159
  });
64
160
  if (result.error) {
161
+ const spawnError = result.error;
162
+ if (process.platform === "win32" &&
163
+ interpreter === "bash" &&
164
+ spawnError.code === "ENOENT") {
165
+ throw bashNotFoundError(opts.asset, spawnError);
166
+ }
65
167
  throw new Error(`Failed to run bundled script ${opts.asset}: ${result.error.message}`);
66
168
  }
67
169
  if (result.signal) {
@@ -186,6 +186,7 @@ function runUpdateSupervisor(config, dependencies = {}) {
186
186
  try {
187
187
  child = spawn(config.cmd, config.args, {
188
188
  detached: true,
189
+ windowsHide: true,
189
190
  stdio: ["ignore", "inherit", config.diagnosticMarker ? "pipe" : "inherit"],
190
191
  shell: config.shell,
191
192
  });
@@ -637,7 +637,7 @@ export { buildSpawnPlan, quoteForWindowsShell };
637
637
  * protection silently disappearing.
638
638
  */
639
639
  export function inOwnProcessGroup(options) {
640
- return { ...options, detached: true };
640
+ return { ...options, detached: true, windowsHide: true };
641
641
  }
642
642
  /** Tail of captured installer stderr kept to explain a failure. */
643
643
  const INSTALL_DETAIL_MAX_CHARS = 400;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@indigoai-us/hq-cli",
3
- "version": "5.301.0",
3
+ "version": "5.303.0",
4
4
  "description": "HQ by Indigo management CLI — modules and cloud sync",
5
5
  "main": "dist/index.js",
6
6
  "bin": {