@indigoai-us/hq-cli 5.77.14 → 5.79.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 (309) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/assets/scaffold/core/scripts/archive-old-threads.sh +86 -0
  3. package/assets/scaffold/core/scripts/backfill-company-skill-mirrors.sh +73 -0
  4. package/assets/scaffold/core/scripts/backfill-workspace-mirror.sh +51 -0
  5. package/assets/scaffold/core/scripts/codex-skill-bridge.sh +550 -0
  6. package/assets/scaffold/core/scripts/detect-stale-core-policy-mirror.sh +185 -0
  7. package/assets/scaffold/core/scripts/hq-status-summary.sh +187 -0
  8. package/assets/scaffold/core/scripts/ontology-readme-drift.sh +264 -0
  9. package/assets/scaffold/core/scripts/qmd-reindex-after-sync.sh +93 -0
  10. package/assets/scaffold/core/scripts/rebuild-all-indexes.sh +69 -0
  11. package/assets/scaffold/core/scripts/rebuild-companies-index.sh +206 -0
  12. package/assets/scaffold/core/scripts/rebuild-company-knowledge-index.sh +127 -0
  13. package/assets/scaffold/core/scripts/rebuild-orchestrator-index.sh +86 -0
  14. package/assets/scaffold/core/scripts/rebuild-projects-index.sh +105 -0
  15. package/assets/scaffold/core/scripts/rebuild-public-knowledge-index.sh +83 -0
  16. package/assets/scaffold/core/scripts/rebuild-reports-index.sh +114 -0
  17. package/assets/scaffold/core/scripts/rebuild-social-drafts-index.sh +135 -0
  18. package/assets/scaffold/core/scripts/rebuild-threads-index.sh +82 -0
  19. package/assets/scaffold/core/scripts/rebuild-workers-index.sh +97 -0
  20. package/assets/scaffold/core/scripts/resize-screenshot.sh +47 -0
  21. package/assets/scaffold/core/scripts/token-usage-report.sh +254 -0
  22. package/assets/scaffold/core/scripts/worktree.sh +136 -0
  23. package/dist/commands/agents.js +28 -12
  24. package/dist/commands/api-keys.js +100 -20
  25. package/dist/commands/core.d.ts +90 -0
  26. package/dist/commands/core.js +279 -0
  27. package/dist/commands/files-browse.d.ts +21 -0
  28. package/dist/commands/files-browse.js +145 -24
  29. package/dist/commands/files.js +33 -7
  30. package/dist/commands/meetings.js +16 -9
  31. package/dist/commands/members.js +16 -5
  32. package/dist/commands/pack-install.d.ts +14 -0
  33. package/dist/commands/pack-install.js +42 -2
  34. package/dist/commands/pkg-install.js +39 -2
  35. package/dist/commands/run.js +6 -2
  36. package/dist/commands/secrets.js +120 -65
  37. package/dist/main.js +6 -0
  38. package/dist/utils/api-key-command-gate.d.ts +45 -0
  39. package/dist/utils/api-key-command-gate.js +51 -0
  40. package/dist/utils/hq-roots.d.ts +91 -0
  41. package/dist/utils/hq-roots.js +212 -0
  42. package/dist/utils/resolve-vault-credential.d.ts +63 -3
  43. package/dist/utils/resolve-vault-credential.js +152 -6
  44. package/dist/utils/run-bundled-script.d.ts +66 -0
  45. package/dist/utils/run-bundled-script.js +80 -0
  46. package/dist/utils/vault-api.d.ts +21 -0
  47. package/dist/utils/vault-api.js +74 -3
  48. package/package.json +7 -1
  49. package/.claude/policies/hq-cli-interactive-reads-use-sts-vend.md +0 -49
  50. package/.github/workflows/ci.yml +0 -46
  51. package/.github/workflows/publish.yml +0 -36
  52. package/.github/workflows/scripts/smoke-test-pkg.sh +0 -97
  53. package/e2e/cli.test.ts +0 -128
  54. package/eslint.config.js +0 -37
  55. package/pnpm-workspace.yaml +0 -4
  56. package/scripts/chmod-bins.mjs +0 -49
  57. package/scripts/generate-dsn.mjs +0 -26
  58. package/scripts/generate-scan-packages-table.mjs +0 -113
  59. package/scripts/smoke-sources-signals.sh +0 -103
  60. package/src/bin/hq-auth-refresh.ts +0 -43
  61. package/src/cli-version.ts +0 -13
  62. package/src/commands/__fixtures__/make-tar.ts +0 -126
  63. package/src/commands/_patterns.ts +0 -10
  64. package/src/commands/add.ts +0 -75
  65. package/src/commands/agents.test.ts +0 -527
  66. package/src/commands/agents.ts +0 -923
  67. package/src/commands/api-keys.test.ts +0 -291
  68. package/src/commands/api-keys.ts +0 -382
  69. package/src/commands/artifact-verify.test.ts +0 -177
  70. package/src/commands/auth.test.ts +0 -82
  71. package/src/commands/auth.ts +0 -213
  72. package/src/commands/billing.test.ts +0 -158
  73. package/src/commands/billing.ts +0 -146
  74. package/src/commands/channels.test.ts +0 -74
  75. package/src/commands/channels.ts +0 -91
  76. package/src/commands/cloud-demote.test.ts +0 -401
  77. package/src/commands/cloud-demote.ts +0 -278
  78. package/src/commands/cloud-provision.test.ts +0 -1117
  79. package/src/commands/cloud-provision.ts +0 -942
  80. package/src/commands/cloud.pull-all.test.ts +0 -711
  81. package/src/commands/cloud.pull-per-company.test.ts +0 -188
  82. package/src/commands/cloud.push-all.test.ts +0 -485
  83. package/src/commands/cloud.scope-excluded-warning.test.ts +0 -22
  84. package/src/commands/cloud.selectors.test.ts +0 -208
  85. package/src/commands/cloud.status.test.ts +0 -160
  86. package/src/commands/cloud.test.ts +0 -41
  87. package/src/commands/cloud.ts +0 -2130
  88. package/src/commands/company.test.ts +0 -202
  89. package/src/commands/company.ts +0 -148
  90. package/src/commands/creators.test.ts +0 -60
  91. package/src/commands/creators.ts +0 -117
  92. package/src/commands/crm.test.ts +0 -179
  93. package/src/commands/crm.ts +0 -236
  94. package/src/commands/db-migrate.ts +0 -55
  95. package/src/commands/db-provision.ts +0 -114
  96. package/src/commands/db-sql.ts +0 -124
  97. package/src/commands/db-status.ts +0 -108
  98. package/src/commands/db.ts +0 -26
  99. package/src/commands/dm.test.ts +0 -748
  100. package/src/commands/dm.ts +0 -1226
  101. package/src/commands/feedback.test.ts +0 -413
  102. package/src/commands/feedback.ts +0 -169
  103. package/src/commands/files-browse.test.ts +0 -1249
  104. package/src/commands/files-browse.ts +0 -1506
  105. package/src/commands/files-delete.test.ts +0 -484
  106. package/src/commands/files-recovery.test.ts +0 -370
  107. package/src/commands/files.test.ts +0 -722
  108. package/src/commands/files.ts +0 -1446
  109. package/src/commands/group-grants.test.ts +0 -330
  110. package/src/commands/group-grants.ts +0 -455
  111. package/src/commands/groups.test.ts +0 -44
  112. package/src/commands/groups.ts +0 -368
  113. package/src/commands/integrations.test.ts +0 -633
  114. package/src/commands/integrations.ts +0 -507
  115. package/src/commands/list.ts +0 -85
  116. package/src/commands/login.ts +0 -52
  117. package/src/commands/logout.ts +0 -30
  118. package/src/commands/marketplace-install.test.ts +0 -543
  119. package/src/commands/marketplace-security.test.ts +0 -646
  120. package/src/commands/mcp-registration.test.ts +0 -2787
  121. package/src/commands/mcp-registration.ts +0 -2612
  122. package/src/commands/mcp-status.test.ts +0 -483
  123. package/src/commands/mcp-status.ts +0 -575
  124. package/src/commands/mcp-status.us011.test.ts +0 -243
  125. package/src/commands/meetings.test.ts +0 -522
  126. package/src/commands/meetings.ts +0 -789
  127. package/src/commands/members.test.ts +0 -1474
  128. package/src/commands/members.ts +0 -1181
  129. package/src/commands/onboard-identity-guard.test.ts +0 -99
  130. package/src/commands/onboard-identity-guard.ts +0 -103
  131. package/src/commands/onboard-join.test.ts +0 -96
  132. package/src/commands/onboard-join.ts +0 -101
  133. package/src/commands/onboard-warning.test.ts +0 -26
  134. package/src/commands/onboard-warning.ts +0 -12
  135. package/src/commands/onboard.ts +0 -267
  136. package/src/commands/outposts-heartbeat.test.ts +0 -299
  137. package/src/commands/outposts-heartbeat.ts +0 -310
  138. package/src/commands/outposts-replica-sync.test.ts +0 -272
  139. package/src/commands/outposts-self-deploy.test.ts +0 -243
  140. package/src/commands/outposts.test.ts +0 -1039
  141. package/src/commands/outposts.ts +0 -1935
  142. package/src/commands/pack-install-secret-authorization.test.ts +0 -115
  143. package/src/commands/pack-install.test.ts +0 -1469
  144. package/src/commands/pack-install.ts +0 -2256
  145. package/src/commands/pack-update-cache.test.ts +0 -149
  146. package/src/commands/packs-update-api-key.test.ts +0 -105
  147. package/src/commands/packs.test.ts +0 -88
  148. package/src/commands/packs.ts +0 -622
  149. package/src/commands/people.test.ts +0 -807
  150. package/src/commands/people.ts +0 -422
  151. package/src/commands/pkg-install.dispatch.test.ts +0 -103
  152. package/src/commands/pkg-install.ts +0 -221
  153. package/src/commands/pkg-list.test.ts +0 -79
  154. package/src/commands/pkg-list.ts +0 -13
  155. package/src/commands/pkg-remove.ts +0 -71
  156. package/src/commands/pkg-update.ts +0 -189
  157. package/src/commands/publish.test.ts +0 -650
  158. package/src/commands/publish.ts +0 -580
  159. package/src/commands/reindex.test.ts +0 -259
  160. package/src/commands/reindex.ts +0 -274
  161. package/src/commands/rescue.test.ts +0 -39
  162. package/src/commands/rescue.ts +0 -210
  163. package/src/commands/run.env-local.test.ts +0 -88
  164. package/src/commands/run.test.ts +0 -45
  165. package/src/commands/run.ts +0 -190
  166. package/src/commands/safe-extract.test.ts +0 -459
  167. package/src/commands/safe-extract.ts +0 -444
  168. package/src/commands/secrets-scope.test.ts +0 -56
  169. package/src/commands/secrets-scope.ts +0 -32
  170. package/src/commands/secrets.parse-destination.test.ts +0 -38
  171. package/src/commands/secrets.test.ts +0 -2050
  172. package/src/commands/secrets.ts +0 -2249
  173. package/src/commands/signals.ts +0 -351
  174. package/src/commands/skill.test.ts +0 -770
  175. package/src/commands/skill.ts +0 -796
  176. package/src/commands/sources.ts +0 -362
  177. package/src/commands/sync-mode.test.ts +0 -366
  178. package/src/commands/sync-mode.ts +0 -387
  179. package/src/commands/sync-narrow.test.ts +0 -633
  180. package/src/commands/sync-narrow.ts +0 -555
  181. package/src/commands/sync.ts +0 -165
  182. package/src/commands/team-sync.ts +0 -628
  183. package/src/commands/update.ts +0 -71
  184. package/src/commands/whoami.ts +0 -83
  185. package/src/commands/workers.test.ts +0 -158
  186. package/src/commands/workers.ts +0 -301
  187. package/src/index.test.ts +0 -32
  188. package/src/index.ts +0 -20
  189. package/src/lib/db/control-plane.test.ts +0 -59
  190. package/src/lib/db/control-plane.ts +0 -113
  191. package/src/lib/db/local.test.ts +0 -81
  192. package/src/lib/db/local.ts +0 -148
  193. package/src/lib/db/migrate.test.ts +0 -133
  194. package/src/lib/db/migrate.ts +0 -137
  195. package/src/lib/db/paths.test.ts +0 -112
  196. package/src/lib/db/paths.ts +0 -128
  197. package/src/lib/db/remote-engine.test.ts +0 -44
  198. package/src/lib/db/remote-engine.ts +0 -148
  199. package/src/lib/db/remote-sql.test.ts +0 -32
  200. package/src/lib/db/remote-sql.ts +0 -62
  201. package/src/lib/db/sql.test.ts +0 -106
  202. package/src/lib/db/sql.ts +0 -192
  203. package/src/lib/hq-cloud-dep.smoke.test.ts +0 -75
  204. package/src/lib/local-tree-diff.test.ts +0 -301
  205. package/src/lib/local-tree-diff.ts +0 -362
  206. package/src/lib/narrow-hint-banner.test.ts +0 -235
  207. package/src/lib/narrow-hint-banner.ts +0 -212
  208. package/src/lib/plan-limit-nag.test.ts +0 -317
  209. package/src/lib/plan-limit-nag.ts +0 -264
  210. package/src/main.ts +0 -371
  211. package/src/node-preflight.test.ts +0 -60
  212. package/src/node-preflight.ts +0 -67
  213. package/src/outpost/session-heartbeat-bounds.test.ts +0 -195
  214. package/src/outpost/session-heartbeat-guard.test.ts +0 -105
  215. package/src/outpost/session-heartbeat-publisher.test.ts +0 -178
  216. package/src/outpost/session-heartbeat-publisher.ts +0 -186
  217. package/src/outpost/session-heartbeat-retain-guard.test.ts +0 -126
  218. package/src/outpost/session-heartbeat.test.ts +0 -459
  219. package/src/outpost/session-heartbeat.ts +0 -877
  220. package/src/packaging.test.ts +0 -109
  221. package/src/run/__fixtures__/discover-schemas/example.env.schema +0 -4
  222. package/src/run/discover-schemas.test.ts +0 -153
  223. package/src/run/discover-schemas.ts +0 -79
  224. package/src/run/hq-plugin.test.ts +0 -371
  225. package/src/run/hq-plugin.ts +0 -277
  226. package/src/run/varlock-shape.test.ts +0 -57
  227. package/src/schemas/hq-package.schema.json +0 -155
  228. package/src/sentry-before-send.test.ts +0 -359
  229. package/src/sentry-before-send.ts +0 -221
  230. package/src/sentry-epipe.test.ts +0 -37
  231. package/src/sentry-release.test.ts +0 -54
  232. package/src/sentry.test.ts +0 -24
  233. package/src/sentry.ts +0 -54
  234. package/src/strategies/link.ts +0 -62
  235. package/src/strategies/merge.ts +0 -142
  236. package/src/types.ts +0 -146
  237. package/src/utils/__fixtures__/scan-packages.generated-block.sh +0 -23
  238. package/src/utils/auth-error.test.ts +0 -40
  239. package/src/utils/auth-error.ts +0 -42
  240. package/src/utils/billing-gate.test.ts +0 -95
  241. package/src/utils/billing-gate.ts +0 -228
  242. package/src/utils/breadcrumb-buffer.ts +0 -18
  243. package/src/utils/cli-telemetry.test.ts +0 -153
  244. package/src/utils/cli-telemetry.ts +0 -61
  245. package/src/utils/cognito-session.machine.test.ts +0 -109
  246. package/src/utils/cognito-session.refresh.test.ts +0 -84
  247. package/src/utils/cognito-session.test.ts +0 -328
  248. package/src/utils/cognito-session.ts +0 -448
  249. package/src/utils/company-selection-error.test.ts +0 -42
  250. package/src/utils/company-selection-error.ts +0 -45
  251. package/src/utils/contribution-table.ts +0 -83
  252. package/src/utils/environmental-error.test.ts +0 -45
  253. package/src/utils/environmental-error.ts +0 -39
  254. package/src/utils/epipe.test.ts +0 -28
  255. package/src/utils/epipe.ts +0 -29
  256. package/src/utils/expected-cli-error.test.ts +0 -28
  257. package/src/utils/expected-cli-error.ts +0 -39
  258. package/src/utils/feedback-diagnostics.test.ts +0 -183
  259. package/src/utils/feedback-diagnostics.ts +0 -123
  260. package/src/utils/feedback-screenshots.test.ts +0 -134
  261. package/src/utils/feedback-screenshots.ts +0 -124
  262. package/src/utils/feedback-versions.test.ts +0 -98
  263. package/src/utils/feedback-versions.ts +0 -68
  264. package/src/utils/git.ts +0 -74
  265. package/src/utils/integrity.ts +0 -59
  266. package/src/utils/intercepted-process-exit.test.ts +0 -37
  267. package/src/utils/intercepted-process-exit.ts +0 -36
  268. package/src/utils/login-provider.test.ts +0 -42
  269. package/src/utils/login-provider.ts +0 -30
  270. package/src/utils/manifest.test.ts +0 -167
  271. package/src/utils/manifest.ts +0 -131
  272. package/src/utils/pack-contributions.test.ts +0 -603
  273. package/src/utils/pack-contributions.ts +0 -450
  274. package/src/utils/people.ts +0 -215
  275. package/src/utils/registry-client.ts +0 -204
  276. package/src/utils/registry.ts +0 -90
  277. package/src/utils/resolve-vault-credential.test.ts +0 -69
  278. package/src/utils/resolve-vault-credential.ts +0 -60
  279. package/src/utils/sandbox-runner-client.test.ts +0 -279
  280. package/src/utils/sandbox-runner-client.ts +0 -260
  281. package/src/utils/secrets-cache.ts +0 -183
  282. package/src/utils/sentry-identity.ts +0 -45
  283. package/src/utils/settle-with-timeout.test.ts +0 -21
  284. package/src/utils/settle-with-timeout.ts +0 -22
  285. package/src/utils/user-yaml-error.test.ts +0 -24
  286. package/src/utils/user-yaml-error.ts +0 -30
  287. package/src/utils/vault-api.test.ts +0 -536
  288. package/src/utils/vault-api.ts +0 -382
  289. package/src/utils/version-check.test.ts +0 -176
  290. package/src/utils/version-check.ts +0 -155
  291. package/src/utils/version-gate.test.ts +0 -1024
  292. package/src/utils/version-gate.ts +0 -702
  293. package/test/commands/db-tenant-isolation.test.ts +0 -94
  294. package/test/commands/db.test.ts +0 -85
  295. package/test/commands/signals.test.ts +0 -207
  296. package/test/commands/sources.test.ts +0 -231
  297. package/test/e2e/smoke-install-mcp.sh +0 -113
  298. package/test/fixtures/hq-pack-smoke-mcp/mcp/smoke-http.json +0 -1
  299. package/test/fixtures/hq-pack-smoke-mcp/package.yaml +0 -11
  300. package/test/fixtures/signals/action_item/sample.md +0 -16
  301. package/test/fixtures/signals/summary/sample.md +0 -12
  302. package/test/fixtures/sources/meetings/sample.md +0 -25
  303. package/test/helpers/cli-runner.ts +0 -150
  304. package/test/helpers/s3-list-mock.ts +0 -79
  305. package/test/helpers/vault-service-mock.ts +0 -295
  306. package/test/sources-signals/smoke.test.ts +0 -228
  307. package/tsconfig.json +0 -20
  308. package/vitest.config.ts +0 -11
  309. package/vitest.e2e.config.ts +0 -7
@@ -62,8 +62,65 @@ async function peekPlanLimitStatus(response) {
62
62
  return response;
63
63
  }
64
64
  }
65
+ /**
66
+ * Map Cognito JWT paths onto parallel Bearer `hqk_` routes under `/v1/keys/…`.
67
+ * Returns null when no keyed route exists (caller must fail closed).
68
+ *
69
+ * The table mirrors hq-pro's gateway routes, NOT its path shapes: a rewrite is
70
+ * listed only where an `hqk_`-authorized route actually exists. Two surfaces
71
+ * are therefore unmapped ON PURPOSE, and adding a rewrite for them would turn
72
+ * an explicit fail-closed error into a 404/401 that reads like a login problem:
73
+ *
74
+ * - the unversioned file ACL + share surfaces (`/files/{companyUid}/acl…`,
75
+ * `/files/{companyUid}/share-session`) — hq-pro serves these under JWT
76
+ * only. `/v1/keys/files/…` exists but covers the VERSIONED family
77
+ * (`list`, `versions`, `versions-list`, `grants`, `tombstones`, `presign`,
78
+ * `delete`, `restore`), which is a different set of handlers.
79
+ * - the notify surface (`/v1/notify/dm`, `/v1/notify/thread`) behind
80
+ * `hq agents message|thread` — there is no `/v1/keys/notify…` route.
81
+ *
82
+ * Both are additionally gated at the command layer so they fail before any
83
+ * network call; this stays the backstop for a new call site that forgets to.
84
+ */
85
+ export function rewritePathForApiKey(path) {
86
+ if (path.startsWith("/v1/keys/") || path === "/v1/keys/secrets/fetch") {
87
+ return path;
88
+ }
89
+ const rewrites = [
90
+ [/^\/v1\/files(\/|$)/, "/v1/keys/files$1"],
91
+ [/^\/v1\/agents(\/|$)/, "/v1/keys/agents$1"],
92
+ [/^\/v1\/search(\/|$)/, "/v1/keys/search$1"],
93
+ [/^\/v1\/listings(\/|$)/, "/v1/keys/listings$1"],
94
+ [/^\/v1\/fleet(\/|$)/, "/v1/keys/fleet$1"],
95
+ [/^\/v1\/outposts(\/|$)/, "/v1/keys/outposts$1"],
96
+ [/^\/v1\/integrations(\/|$)/, "/v1/keys/integrations$1"],
97
+ [/^\/v1\/work-mesh(\/|$)/, "/v1/keys/work-mesh$1"],
98
+ [/^\/v1\/memberships(\/|$)/, "/v1/keys/memberships$1"],
99
+ [/^\/v1\/companies(\/|$)/, "/v1/keys/companies$1"],
100
+ [/^\/membership(\/|$)/, "/v1/keys/membership$1"],
101
+ [/^\/company-settings(\/|$)/, "/v1/keys/company-settings$1"],
102
+ [/^\/sts(\/|$)/, "/v1/keys/sts$1"],
103
+ // Secrets Cognito routes → keyed family (list/set/get/delete/acl).
104
+ [/^\/secrets(\/|$)/, "/v1/keys/secrets$1"],
105
+ ];
106
+ for (const [pattern, replacement] of rewrites) {
107
+ if (pattern.test(path))
108
+ return path.replace(pattern, replacement);
109
+ }
110
+ return null;
111
+ }
65
112
  export async function vaultApiFetch(opts) {
66
- const url = new URL(opts.path, opts.baseUrl ?? DEFAULT_VAULT_API_URL);
113
+ let path = opts.path;
114
+ if (opts.token.startsWith("hqk_")) {
115
+ const rewritten = rewritePathForApiKey(path);
116
+ if (rewritten === null) {
117
+ throw Object.assign(new Error(`HQ_API_KEY cannot call '${path}' — hq-pro has no Bearer hqk_ route ` +
118
+ `for this surface. Use a Cognito session (unset HQ_API_KEY), or a ` +
119
+ `keyed route under /v1/keys/… when available.`), { expected: true });
120
+ }
121
+ path = rewritten;
122
+ }
123
+ const url = new URL(path, opts.baseUrl ?? DEFAULT_VAULT_API_URL);
67
124
  if (opts.query) {
68
125
  for (const [k, v] of Object.entries(opts.query)) {
69
126
  url.searchParams.set(k, v);
@@ -73,7 +130,7 @@ export async function vaultApiFetch(opts) {
73
130
  const safeUrl = url.search ? `${url.origin}${url.pathname}?<redacted>` : `${url.origin}${url.pathname}`;
74
131
  Sentry.addBreadcrumb({
75
132
  category: "http",
76
- message: `${method} ${opts.path}`,
133
+ message: `${method} ${path}`,
77
134
  level: "info",
78
135
  data: { url: safeUrl, method },
79
136
  });
@@ -89,7 +146,7 @@ export async function vaultApiFetch(opts) {
89
146
  if (!response.ok) {
90
147
  Sentry.addBreadcrumb({
91
148
  category: "http",
92
- message: `${method} ${opts.path} → ${response.status}`,
149
+ message: `${method} ${path} → ${response.status}`,
93
150
  level: "warning",
94
151
  data: { url: safeUrl, status: response.status },
95
152
  });
@@ -267,6 +324,20 @@ async function resolveCompanyFromMemberships(token) {
267
324
  uids.map((u) => ` --company ${u}`).join('\n'));
268
325
  }
269
326
  export async function getCompanyUid(token, companySlug) {
327
+ // Vault API keys are company-bound. Entity slug resolution has no keyed
328
+ // route, so under hqk_ we accept an explicit cmp_ uid (or HQ_COMPANY_UID)
329
+ // and otherwise fall through to keyed GET /v1/keys/membership/me.
330
+ if (token.startsWith("hqk_")) {
331
+ const ref = companySlug ?? process.env.HQ_COMPANY_UID?.trim();
332
+ if (ref) {
333
+ if (!looksLikeCompanyUid(ref)) {
334
+ throw Object.assign(new Error(`HQ_API_KEY is set; --company must be a company uid (cmp_…) — ` +
335
+ `resolving a slug needs a Cognito session. Got '${ref}'.`), { expected: true });
336
+ }
337
+ return ref;
338
+ }
339
+ return resolveCompanyFromMemberships(token);
340
+ }
270
341
  if (companySlug) {
271
342
  return resolveCompanyUid(token, companySlug);
272
343
  }
package/package.json CHANGED
@@ -1,12 +1,18 @@
1
1
  {
2
2
  "name": "@indigoai-us/hq-cli",
3
- "version": "5.77.14",
3
+ "version": "5.79.0",
4
4
  "description": "HQ by Indigo management CLI — modules and cloud sync",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
7
7
  "hq": "dist/index.js",
8
8
  "hq-auth-refresh": "dist/bin/hq-auth-refresh.js"
9
9
  },
10
+ "files": [
11
+ "dist",
12
+ "!dist/**/*.map",
13
+ "assets/scaffold",
14
+ "CHANGELOG.md"
15
+ ],
10
16
  "scripts": {
11
17
  "build": "node scripts/generate-dsn.mjs && tsc && node scripts/chmod-bins.mjs",
12
18
  "prepublishOnly": "npm run build",
@@ -1,49 +0,0 @@
1
- ---
2
- id: hq-cli-interactive-reads-use-sts-vend
3
- title: Interactive vault reads vend via /sts/vend, never the legacy POST /vend
4
- scope: repo
5
- trigger: any hq-cli command that vends vault credentials to read/list company objects (files browse, files cat, files get/search, or any new interactive read surface)
6
- enforcement: hard
7
- public: false
8
- version: 1
9
- created: 2026-05-29
10
- updated: 2026-05-29
11
- source: back-pressure-failure
12
- applies_to: [aws]
13
- ---
14
-
15
- ## Rule
16
-
17
- Interactive vault reads in hq-cli MUST vend through the multi-tenant STS
18
- routes — `VaultClient.sts.vend({ companyUid })` (`POST /sts/vend`, company) or
19
- `VaultClient.sts.vendSelf({ personUid })` (`POST /sts/vend-self`, personal).
20
- NEVER vend through the legacy `VaultClient.vend(...)` (`POST /vend`).
21
-
22
- The legacy `POST /vend` (hq-pro `VaultVendFunction` → `vend.handler`) builds
23
- its IAM policy against a static `process.env.BUCKET_ARN`, but the hq-pro infra
24
- (`infra/vault-service.ts`) deliberately does NOT set `BUCKET_ARN` — production
25
- is multi-tenant with one bucket per company. At runtime `BUCKET_ARN` is
26
- `undefined`, so the session policy contains `"Resource":[null,"undefined/…"]`
27
- and STS rejects it with `MalformedPolicyDocument: Syntax error at position
28
- (-1,-1)` → the client sees a 500 "Failed to generate credentials". Only
29
- `/sts/vend{,-self,-child}` resolve the per-entity bucket (`entity.bucketArn`)
30
- and apply role/ACL scoping server-side (owner/admin → full access; member/
31
- guest → per-prefix). `policy-builder.ts` even documents that `POST /vend` "has
32
- no production callers" — treat it as dead.
33
-
34
- Related namespace rule: company vault bucket keys are **company-relative**
35
- (`knowledge/foo.md`, NOT `companies/<slug>/knowledge/foo.md`). Translate the
36
- CLI's anchored `companies/<slug>/…` form to the bucket-relative key at the S3
37
- boundary (`toBucketRelative` / `toCompanyAnchored` in `files-browse.ts`), and
38
- normalize ACL grant paths with `grantPathToPrefix` before `startsWith`
39
- classification. Listing/getting with the anchored prefix returns nothing.
40
-
41
- ## Rationale
42
-
43
- `hq files browse`/`cat` (US-009) were wired to `POST /vend`, which 500'd on
44
- every multi-tenant call. The root cause was an undefined `BUCKET_ARN` env on
45
- the vend Lambda, not a stale deploy — redeploying clean source did not fix it.
46
- The working fix routed both commands through `/sts/vend` + `/sts/vend-self`
47
- (client-only, hq-cloud 5.43.0 / hq-cli 5.29.0) and fixed the company-relative
48
- namespace translation. Captured so future interactive-read surfaces reach for
49
- the STS routes from the start and don't resurrect the dead `POST /vend`.
@@ -1,46 +0,0 @@
1
- name: CI
2
- on:
3
- pull_request:
4
- branches: [main]
5
- push:
6
- branches: [main]
7
-
8
- concurrency:
9
- group: ${{ github.workflow }}-${{ github.ref }}
10
- cancel-in-progress: true
11
-
12
- jobs:
13
- build:
14
- name: build (node ${{ matrix.node-version }})
15
- strategy:
16
- fail-fast: false
17
- matrix:
18
- # 20 is the declared engines floor (package.json engines.node >=20),
19
- # 22 is the current dev/publish baseline.
20
- node-version: ["20", "22"]
21
- uses: indigoai-us/.github/.github/workflows/_node-ci.yml@main
22
- with:
23
- package-manager: pnpm
24
- pnpm-version: "10"
25
- node-version: ${{ matrix.node-version }}
26
- run-build: true
27
- run-lint: true
28
- run-coverage: true
29
- secrets: inherit
30
-
31
- e2e:
32
- name: e2e (node 22)
33
- runs-on: ubuntu-latest
34
- timeout-minutes: 10
35
- steps:
36
- - uses: actions/checkout@v4
37
- - uses: pnpm/action-setup@v4
38
- with:
39
- version: "10"
40
- - uses: actions/setup-node@v4
41
- with:
42
- node-version: "22"
43
- cache: pnpm
44
- - run: pnpm install --frozen-lockfile
45
- - run: pnpm build
46
- - run: pnpm test:e2e
@@ -1,36 +0,0 @@
1
- name: Publish to npm
2
- on:
3
- push:
4
- tags: ["v*"]
5
- # Manual dry-run: validate the build/pack/smoke pipeline without publishing.
6
- workflow_dispatch:
7
- inputs:
8
- dry_run:
9
- description: "Dry-run (validate build/pack/smoke; npm publish --dry-run, no Sentry upload)"
10
- type: boolean
11
- default: true
12
-
13
- jobs:
14
- publish:
15
- permissions:
16
- contents: read
17
- id-token: write
18
- uses: indigoai-us/.github/.github/workflows/_npm-publish.yml@main
19
- with:
20
- package-manager: pnpm
21
- pnpm-version: "10"
22
- node-version: "24"
23
- build-command: "pnpm run build"
24
- dsn-env-name: "HQ_CLI_PUBLISH_SENTRY_DSN"
25
- sentry-inject-dir: "dist/"
26
- smoke-test-arg: "hq"
27
- sentry-release-prefix: "hq-cli"
28
- sentry-upload-paths: "dist/ node_modules/@indigoai-us/hq-cloud/dist/"
29
- sentry-org: "indigo-d0"
30
- sentry-project: "hq-cli"
31
- # Prerelease versions (e.g. 5.x.y-rc.0) ship to the rc dist-tag, not latest.
32
- prerelease-dist-tag: "rc"
33
- dry-run: ${{ github.event_name == 'workflow_dispatch' && inputs.dry_run }}
34
- secrets:
35
- sentry-dsn: ${{ secrets.HQ_CLI_PUBLISH_SENTRY_DSN }}
36
- sentry-auth-token: ${{ secrets.SENTRY_AUTH_TOKEN }}
@@ -1,97 +0,0 @@
1
- #!/bin/bash
2
- # smoke-test-pkg.sh — pre-publish cross-package import smoke test (Bug A guard).
3
- #
4
- # Single-package adaptation of the same script used in the legacy hq monorepo.
5
- # The monorepo version operated on `packages/$PKG/package.json`; this version
6
- # reads `./package.json` because each extracted repo is a single package at
7
- # its root.
8
- #
9
- # Install the package in an isolated tmpdir — using a freshly-packed tarball
10
- # when the package.json version is new, or fetching the existing name@version
11
- # from npm when it is already published — then boot the binary with
12
- # `--version`. The boot exercises the full module-load graph and the
13
- # transitive `@indigoai-us/*` resolution path a customer's `npm install`
14
- # would take. If the boot fails the script exits non-zero and the workflow
15
- # aborts before any further publish steps run.
16
- #
17
- # Why we don't skip when the consumer's version is already on npm:
18
- # @indigoai-us/hq-cli depends on @indigoai-us/hq-cloud via a caret range
19
- # (^5.1.0). A producer bump (published from indigoai-us/hq-cloud) re-resolves
20
- # this consumer's transitive deps on the next fresh install, so an already-
21
- # published consumer is NOT actually "locked." If the new producer drops or
22
- # renames a symbol the published consumer imports, `hq --version` crashes
23
- # on every fresh install starting the moment the producer publishes.
24
- #
25
- # Usage:
26
- # smoke-test-pkg.sh <bin-name>
27
- # Example:
28
- # smoke-test-pkg.sh hq
29
-
30
- set -uo pipefail
31
-
32
- BIN=${1:?usage: smoke-test-pkg.sh <bin-name>}
33
-
34
- PKG_JSON="package.json"
35
- if [ ! -f "$PKG_JSON" ]; then
36
- echo "::error::smoke-test-pkg.sh: $PKG_JSON not found (cwd: $(pwd))"
37
- exit 2
38
- fi
39
-
40
- NAME=$(jq -r .name "$PKG_JSON")
41
- VER=$(jq -r .version "$PKG_JSON")
42
-
43
- # Pick the install target. Already on npm → install by name@version so the
44
- # smoke matches what a customer would actually receive. Not yet on npm →
45
- # pack the local repo; the next publish step will push that exact byte-for-
46
- # byte content. Either way, `npm install` happens OUTSIDE this repo so
47
- # transitive @indigoai-us/* deps resolve from the registry.
48
- INSTALL_SOURCE=""
49
- if npm view "$NAME@$VER" version >/dev/null 2>&1; then
50
- INSTALL_TARGET="$NAME@$VER"
51
- INSTALL_SOURCE="npm registry (consumer version already published)"
52
- else
53
- TARBALL_RELATIVE=$(npm pack --silent --pack-destination /tmp)
54
- if [ -z "$TARBALL_RELATIVE" ]; then
55
- echo "::error::npm pack produced no tarball for $NAME"
56
- exit 1
57
- fi
58
- INSTALL_TARGET="/tmp/$TARBALL_RELATIVE"
59
- if [ ! -f "$INSTALL_TARGET" ]; then
60
- echo "::error::expected tarball at $INSTALL_TARGET not found"
61
- exit 1
62
- fi
63
- INSTALL_SOURCE="packed tarball ($TARBALL_RELATIVE)"
64
- fi
65
-
66
- echo "::group::smoke test: $NAME@$VER via $INSTALL_SOURCE"
67
-
68
- SMOKE=$(mktemp -d)
69
- pushd "$SMOKE" >/dev/null
70
-
71
- printf '%s' '{"name":"smoke","version":"0.0.0","private":true}' > package.json
72
-
73
- if ! npm install --no-audit --no-fund --no-package-lock "$INSTALL_TARGET" >/tmp/smoke-install.log 2>&1; then
74
- echo "::error::pre-publish smoke install FAILED for $NAME@$VER:"
75
- tail -50 /tmp/smoke-install.log
76
- popd >/dev/null
77
- echo "::endgroup::"
78
- exit 1
79
- fi
80
-
81
- set +e
82
- OUT=$("./node_modules/.bin/$BIN" --version 2>&1)
83
- CODE=$?
84
- set -e
85
-
86
- popd >/dev/null
87
-
88
- if [ "$CODE" -ne 0 ]; then
89
- echo "::error::pre-publish smoke FAILED for $NAME@$VER (exit $CODE):"
90
- echo "::error::$OUT"
91
- echo "::error::Likely cause: a cross-package symbol was changed (added, removed, renamed) in another @indigoai-us/* package without keeping this consumer's import in sync. Bump this consumer (or revert the producer change) and re-tag, OR set the repo/workflow variable WORKFLOW_ALLOW_BROKEN_PUBLISH=1 to override (audited)."
92
- echo "::endgroup::"
93
- exit 1
94
- fi
95
-
96
- echo "✓ smoke ok: $NAME@$VER → $BIN --version → $OUT (via $INSTALL_SOURCE)"
97
- echo "::endgroup::"
package/e2e/cli.test.ts DELETED
@@ -1,128 +0,0 @@
1
- import { mkdtemp, rm } from "node:fs/promises";
2
- import { tmpdir } from "node:os";
3
- import path from "node:path";
4
- import { spawn } from "node:child_process";
5
- import { afterEach, describe, expect, it } from "vitest";
6
- import { version } from "../package.json";
7
-
8
- const cliEntry = path.resolve("dist/index.js");
9
- const tempDirs: string[] = [];
10
-
11
- interface CliResult {
12
- code: number | null;
13
- stdout: string;
14
- stderr: string;
15
- }
16
-
17
- function runHq(args: string[], options: { cwd?: string; env?: NodeJS.ProcessEnv } = {}) {
18
- return new Promise<CliResult>((resolve, reject) => {
19
- const child = spawn(process.execPath, [cliEntry, ...args], {
20
- cwd: options.cwd,
21
- env: {
22
- ...process.env,
23
- HQ_NO_UPDATE_CHECK: "1",
24
- ...options.env,
25
- },
26
- stdio: ["ignore", "pipe", "pipe"],
27
- });
28
-
29
- let stdout = "";
30
- let stderr = "";
31
- child.stdout.setEncoding("utf8");
32
- child.stderr.setEncoding("utf8");
33
- child.stdout.on("data", (chunk) => {
34
- stdout += chunk;
35
- });
36
- child.stderr.on("data", (chunk) => {
37
- stderr += chunk;
38
- });
39
- child.on("error", reject);
40
- child.on("close", (code) => resolve({ code, stdout, stderr }));
41
- });
42
- }
43
-
44
- // Spawn the built CLI with its stdout read-end closed immediately, so the
45
- // child's first write to stdout hits EPIPE — the `hq … | head` / `source <(hq
46
- // …)` scenario behind HQ-6B. Returns the child's own exit code + stderr.
47
- function runHqWithClosedStdout(args: string[]) {
48
- return new Promise<{ code: number | null; stderr: string }>(
49
- (resolve, reject) => {
50
- const child = spawn(process.execPath, [cliEntry, ...args], {
51
- env: { ...process.env, HQ_NO_UPDATE_CHECK: "1" },
52
- stdio: ["ignore", "pipe", "pipe"],
53
- });
54
- let stderr = "";
55
- child.stderr.setEncoding("utf8");
56
- child.stderr.on("data", (chunk) => {
57
- stderr += chunk;
58
- });
59
- // Close the read end up front (and again on any byte that slips through)
60
- // so subsequent writes by the child fail with EPIPE.
61
- child.stdout.on("data", () => child.stdout.destroy());
62
- child.stdout.destroy();
63
- child.on("error", reject);
64
- child.on("close", (code) => resolve({ code, stderr }));
65
- },
66
- );
67
- }
68
-
69
- async function makeTempDir(prefix: string) {
70
- const dir = await mkdtemp(path.join(tmpdir(), prefix));
71
- tempDirs.push(dir);
72
- return dir;
73
- }
74
-
75
- afterEach(async () => {
76
- await Promise.all(tempDirs.splice(0).map((dir) => rm(dir, { recursive: true, force: true })));
77
- });
78
-
79
- describe("built hq CLI", () => {
80
- it("prints help from the built entrypoint", async () => {
81
- const result = await runHq(["--help"]);
82
-
83
- expect(result.code).toBe(0);
84
- expect(result.stderr).toBe("");
85
- expect(result.stdout).toContain("Usage: hq [options] [command]");
86
- expect(result.stdout).toContain("HQ management CLI");
87
- expect(result.stdout).toContain("whoami");
88
- });
89
-
90
- it("exits cleanly when the downstream reader closes the pipe (HQ-6B)", async () => {
91
- // Regression for HQ-6B: a closed stdout reader must NOT crash the CLI with
92
- // a fatal `write EPIPE`. The process should exit 0 with no EPIPE traceback.
93
- const { code, stderr } = await runHqWithClosedStdout(["--help"]);
94
-
95
- expect(code).toBe(0);
96
- expect(stderr).not.toMatch(/EPIPE/);
97
- expect(stderr).not.toMatch(/Error:/);
98
- });
99
-
100
- it("prints the package version from the built entrypoint", async () => {
101
- const result = await runHq(["--version"]);
102
-
103
- expect(result.code).toBe(0);
104
- expect(result.stderr).toBe("");
105
- expect(result.stdout.trim()).toBe(version);
106
- });
107
-
108
- it("reports logged-out state without network or credentials", async () => {
109
- const home = await makeTempDir("hq-cli-e2e-home-");
110
- const cwd = await makeTempDir("hq-cli-e2e-cwd-");
111
-
112
- const result = await runHq(["whoami"], {
113
- cwd,
114
- env: {
115
- HOME: home,
116
- USERPROFILE: home,
117
- XDG_CONFIG_HOME: path.join(home, ".config"),
118
- XDG_CACHE_HOME: path.join(home, ".cache"),
119
- HQ_MACHINE_IDENTITY: undefined,
120
- HQ_MACHINE_CREDS: undefined,
121
- },
122
- });
123
-
124
- expect(result.code).toBe(0);
125
- expect(result.stderr).toBe("");
126
- expect(result.stdout.trim()).toBe("Not logged in. Run 'hq login' to authenticate.");
127
- });
128
- });
package/eslint.config.js DELETED
@@ -1,37 +0,0 @@
1
- import js from "@eslint/js";
2
- import tseslint from "typescript-eslint";
3
-
4
- const sourceFiles = ["src/**/*.ts"];
5
- const recommended = tseslint
6
- .config(js.configs.recommended, ...tseslint.configs.recommended)
7
- .map((config) => ({
8
- ...config,
9
- files: sourceFiles,
10
- }));
11
-
12
- export default [
13
- {
14
- ignores: ["dist/**", "generated/**", "node_modules/**"],
15
- },
16
- ...recommended,
17
- {
18
- files: sourceFiles,
19
- rules: {
20
- "no-undef": "off",
21
- "no-useless-assignment": "warn",
22
- "no-useless-escape": "warn",
23
- "prefer-const": "warn",
24
- "preserve-caught-error": "off",
25
- "@typescript-eslint/no-explicit-any": "warn",
26
- "@typescript-eslint/no-require-imports": "warn",
27
- "@typescript-eslint/no-unused-vars": [
28
- "warn",
29
- {
30
- argsIgnorePattern: "^_",
31
- caughtErrorsIgnorePattern: "^_",
32
- varsIgnorePattern: "^_",
33
- },
34
- ],
35
- },
36
- },
37
- ];
@@ -1,4 +0,0 @@
1
- allowBuilds:
2
- better-sqlite3: true
3
- minimumReleaseAgeExclude:
4
- - '@indigoai-us/hq-cloud@6.14.14 || 6.14.18 || 6.14.19 || 6.14.27'
@@ -1,49 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * Make every declared `bin` executable after `tsc` emits it.
4
- *
5
- * WHY: the build is plain `tsc`, and TypeScript does NOT set the executable
6
- * bit on its output — `dist/index.js` lands as 0644 despite carrying a
7
- * `#!/usr/bin/env node` shebang. Most `npm install` paths re-chmod bin targets
8
- * to 0755 while linking, but not all do: a root global install on a fresh
9
- * Amazon Linux outpost (`npm install -g @indigoai-us/hq-cli`) has been observed
10
- * to leave the linked target at 0644, so `/usr/bin/hq` resolves to a
11
- * non-executable file and EVERY `hq …` invocation on the box dies with
12
- * "Permission denied" — the outpost never becomes CLI-ready.
13
- *
14
- * Fixing it here means the published tarball ships its bins already 0755, so
15
- * the runnable bit no longer depends on the installer re-chmod'ing. Runs from
16
- * `build` (local + CI) and `prepublishOnly` (guarantees a fresh publish is
17
- * always executable, whatever state the publisher's dist was in).
18
- *
19
- * Cross-platform: uses fs.chmod (no `chmod` shell dependency); a no-op on
20
- * Windows where the mode bits are ignored anyway.
21
- */
22
- import { chmodSync, existsSync, readFileSync } from "node:fs";
23
- import { dirname, resolve } from "node:path";
24
- import { fileURLToPath } from "node:url";
25
-
26
- const here = dirname(fileURLToPath(import.meta.url));
27
- const pkgPath = resolve(here, "..", "package.json");
28
- const pkg = JSON.parse(readFileSync(pkgPath, "utf8"));
29
-
30
- const bins =
31
- typeof pkg.bin === "string"
32
- ? { [pkg.name]: pkg.bin }
33
- : (pkg.bin ?? {});
34
-
35
- let touched = 0;
36
- for (const [name, relPath] of Object.entries(bins)) {
37
- const target = resolve(here, "..", relPath);
38
- if (!existsSync(target)) {
39
- // Build not run yet / stale bin map — surface it loudly so a publish that
40
- // would ship a missing bin fails fast instead of silently.
41
- console.error(`chmod-bins: declared bin "${name}" not found at ${relPath}`);
42
- process.exitCode = 1;
43
- continue;
44
- }
45
- chmodSync(target, 0o755);
46
- touched += 1;
47
- }
48
-
49
- console.log(`chmod-bins: made ${touched} bin(s) executable (0755)`);
@@ -1,26 +0,0 @@
1
- import { writeFileSync } from "fs";
2
- import { join, dirname } from "path";
3
- import { fileURLToPath } from "url";
4
-
5
- const __dirname = dirname(fileURLToPath(import.meta.url));
6
-
7
- const isGitHubActions = process.env.GITHUB_ACTIONS === "true";
8
- const isPublishJob = process.env.GITHUB_JOB === "publish";
9
- const dsn = process.env.HQ_CLI_PUBLISH_SENTRY_DSN ?? "";
10
-
11
- if (isGitHubActions && isPublishJob && !dsn) {
12
- process.stderr.write(
13
- "[generate-dsn] FATAL: GITHUB_ACTIONS=true, GITHUB_JOB=publish, " +
14
- "but HQ_CLI_PUBLISH_SENTRY_DSN is not set. " +
15
- "Add the repo secret HQ_CLI_PUBLISH_SENTRY_DSN before publishing.\n",
16
- );
17
- process.exit(1);
18
- }
19
-
20
- const outPath = join(__dirname, "../src/sentry-dsn.generated.ts");
21
- const content = `export const BUNDLED_DSN = "${dsn}";\n`;
22
-
23
- writeFileSync(outPath, content, "utf8");
24
- process.stdout.write(
25
- `[generate-dsn] Wrote BUNDLED_DSN="${dsn ? "[DSN set]" : ""}" to ${outPath}\n`,
26
- );