@indigoai-us/hq-cli 5.77.14 → 5.78.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 (308) hide show
  1. package/CHANGELOG.md +23 -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/members.js +16 -5
  31. package/dist/commands/pack-install.d.ts +14 -0
  32. package/dist/commands/pack-install.js +42 -2
  33. package/dist/commands/pkg-install.js +39 -2
  34. package/dist/commands/run.js +6 -2
  35. package/dist/commands/secrets.js +120 -65
  36. package/dist/main.js +6 -0
  37. package/dist/utils/api-key-command-gate.d.ts +45 -0
  38. package/dist/utils/api-key-command-gate.js +51 -0
  39. package/dist/utils/hq-roots.d.ts +91 -0
  40. package/dist/utils/hq-roots.js +212 -0
  41. package/dist/utils/resolve-vault-credential.d.ts +63 -3
  42. package/dist/utils/resolve-vault-credential.js +152 -6
  43. package/dist/utils/run-bundled-script.d.ts +66 -0
  44. package/dist/utils/run-bundled-script.js +80 -0
  45. package/dist/utils/vault-api.d.ts +21 -0
  46. package/dist/utils/vault-api.js +74 -3
  47. package/package.json +7 -1
  48. package/.claude/policies/hq-cli-interactive-reads-use-sts-vend.md +0 -49
  49. package/.github/workflows/ci.yml +0 -46
  50. package/.github/workflows/publish.yml +0 -36
  51. package/.github/workflows/scripts/smoke-test-pkg.sh +0 -97
  52. package/e2e/cli.test.ts +0 -128
  53. package/eslint.config.js +0 -37
  54. package/pnpm-workspace.yaml +0 -4
  55. package/scripts/chmod-bins.mjs +0 -49
  56. package/scripts/generate-dsn.mjs +0 -26
  57. package/scripts/generate-scan-packages-table.mjs +0 -113
  58. package/scripts/smoke-sources-signals.sh +0 -103
  59. package/src/bin/hq-auth-refresh.ts +0 -43
  60. package/src/cli-version.ts +0 -13
  61. package/src/commands/__fixtures__/make-tar.ts +0 -126
  62. package/src/commands/_patterns.ts +0 -10
  63. package/src/commands/add.ts +0 -75
  64. package/src/commands/agents.test.ts +0 -527
  65. package/src/commands/agents.ts +0 -923
  66. package/src/commands/api-keys.test.ts +0 -291
  67. package/src/commands/api-keys.ts +0 -382
  68. package/src/commands/artifact-verify.test.ts +0 -177
  69. package/src/commands/auth.test.ts +0 -82
  70. package/src/commands/auth.ts +0 -213
  71. package/src/commands/billing.test.ts +0 -158
  72. package/src/commands/billing.ts +0 -146
  73. package/src/commands/channels.test.ts +0 -74
  74. package/src/commands/channels.ts +0 -91
  75. package/src/commands/cloud-demote.test.ts +0 -401
  76. package/src/commands/cloud-demote.ts +0 -278
  77. package/src/commands/cloud-provision.test.ts +0 -1117
  78. package/src/commands/cloud-provision.ts +0 -942
  79. package/src/commands/cloud.pull-all.test.ts +0 -711
  80. package/src/commands/cloud.pull-per-company.test.ts +0 -188
  81. package/src/commands/cloud.push-all.test.ts +0 -485
  82. package/src/commands/cloud.scope-excluded-warning.test.ts +0 -22
  83. package/src/commands/cloud.selectors.test.ts +0 -208
  84. package/src/commands/cloud.status.test.ts +0 -160
  85. package/src/commands/cloud.test.ts +0 -41
  86. package/src/commands/cloud.ts +0 -2130
  87. package/src/commands/company.test.ts +0 -202
  88. package/src/commands/company.ts +0 -148
  89. package/src/commands/creators.test.ts +0 -60
  90. package/src/commands/creators.ts +0 -117
  91. package/src/commands/crm.test.ts +0 -179
  92. package/src/commands/crm.ts +0 -236
  93. package/src/commands/db-migrate.ts +0 -55
  94. package/src/commands/db-provision.ts +0 -114
  95. package/src/commands/db-sql.ts +0 -124
  96. package/src/commands/db-status.ts +0 -108
  97. package/src/commands/db.ts +0 -26
  98. package/src/commands/dm.test.ts +0 -748
  99. package/src/commands/dm.ts +0 -1226
  100. package/src/commands/feedback.test.ts +0 -413
  101. package/src/commands/feedback.ts +0 -169
  102. package/src/commands/files-browse.test.ts +0 -1249
  103. package/src/commands/files-browse.ts +0 -1506
  104. package/src/commands/files-delete.test.ts +0 -484
  105. package/src/commands/files-recovery.test.ts +0 -370
  106. package/src/commands/files.test.ts +0 -722
  107. package/src/commands/files.ts +0 -1446
  108. package/src/commands/group-grants.test.ts +0 -330
  109. package/src/commands/group-grants.ts +0 -455
  110. package/src/commands/groups.test.ts +0 -44
  111. package/src/commands/groups.ts +0 -368
  112. package/src/commands/integrations.test.ts +0 -633
  113. package/src/commands/integrations.ts +0 -507
  114. package/src/commands/list.ts +0 -85
  115. package/src/commands/login.ts +0 -52
  116. package/src/commands/logout.ts +0 -30
  117. package/src/commands/marketplace-install.test.ts +0 -543
  118. package/src/commands/marketplace-security.test.ts +0 -646
  119. package/src/commands/mcp-registration.test.ts +0 -2787
  120. package/src/commands/mcp-registration.ts +0 -2612
  121. package/src/commands/mcp-status.test.ts +0 -483
  122. package/src/commands/mcp-status.ts +0 -575
  123. package/src/commands/mcp-status.us011.test.ts +0 -243
  124. package/src/commands/meetings.test.ts +0 -522
  125. package/src/commands/meetings.ts +0 -789
  126. package/src/commands/members.test.ts +0 -1474
  127. package/src/commands/members.ts +0 -1181
  128. package/src/commands/onboard-identity-guard.test.ts +0 -99
  129. package/src/commands/onboard-identity-guard.ts +0 -103
  130. package/src/commands/onboard-join.test.ts +0 -96
  131. package/src/commands/onboard-join.ts +0 -101
  132. package/src/commands/onboard-warning.test.ts +0 -26
  133. package/src/commands/onboard-warning.ts +0 -12
  134. package/src/commands/onboard.ts +0 -267
  135. package/src/commands/outposts-heartbeat.test.ts +0 -299
  136. package/src/commands/outposts-heartbeat.ts +0 -310
  137. package/src/commands/outposts-replica-sync.test.ts +0 -272
  138. package/src/commands/outposts-self-deploy.test.ts +0 -243
  139. package/src/commands/outposts.test.ts +0 -1039
  140. package/src/commands/outposts.ts +0 -1935
  141. package/src/commands/pack-install-secret-authorization.test.ts +0 -115
  142. package/src/commands/pack-install.test.ts +0 -1469
  143. package/src/commands/pack-install.ts +0 -2256
  144. package/src/commands/pack-update-cache.test.ts +0 -149
  145. package/src/commands/packs-update-api-key.test.ts +0 -105
  146. package/src/commands/packs.test.ts +0 -88
  147. package/src/commands/packs.ts +0 -622
  148. package/src/commands/people.test.ts +0 -807
  149. package/src/commands/people.ts +0 -422
  150. package/src/commands/pkg-install.dispatch.test.ts +0 -103
  151. package/src/commands/pkg-install.ts +0 -221
  152. package/src/commands/pkg-list.test.ts +0 -79
  153. package/src/commands/pkg-list.ts +0 -13
  154. package/src/commands/pkg-remove.ts +0 -71
  155. package/src/commands/pkg-update.ts +0 -189
  156. package/src/commands/publish.test.ts +0 -650
  157. package/src/commands/publish.ts +0 -580
  158. package/src/commands/reindex.test.ts +0 -259
  159. package/src/commands/reindex.ts +0 -274
  160. package/src/commands/rescue.test.ts +0 -39
  161. package/src/commands/rescue.ts +0 -210
  162. package/src/commands/run.env-local.test.ts +0 -88
  163. package/src/commands/run.test.ts +0 -45
  164. package/src/commands/run.ts +0 -190
  165. package/src/commands/safe-extract.test.ts +0 -459
  166. package/src/commands/safe-extract.ts +0 -444
  167. package/src/commands/secrets-scope.test.ts +0 -56
  168. package/src/commands/secrets-scope.ts +0 -32
  169. package/src/commands/secrets.parse-destination.test.ts +0 -38
  170. package/src/commands/secrets.test.ts +0 -2050
  171. package/src/commands/secrets.ts +0 -2249
  172. package/src/commands/signals.ts +0 -351
  173. package/src/commands/skill.test.ts +0 -770
  174. package/src/commands/skill.ts +0 -796
  175. package/src/commands/sources.ts +0 -362
  176. package/src/commands/sync-mode.test.ts +0 -366
  177. package/src/commands/sync-mode.ts +0 -387
  178. package/src/commands/sync-narrow.test.ts +0 -633
  179. package/src/commands/sync-narrow.ts +0 -555
  180. package/src/commands/sync.ts +0 -165
  181. package/src/commands/team-sync.ts +0 -628
  182. package/src/commands/update.ts +0 -71
  183. package/src/commands/whoami.ts +0 -83
  184. package/src/commands/workers.test.ts +0 -158
  185. package/src/commands/workers.ts +0 -301
  186. package/src/index.test.ts +0 -32
  187. package/src/index.ts +0 -20
  188. package/src/lib/db/control-plane.test.ts +0 -59
  189. package/src/lib/db/control-plane.ts +0 -113
  190. package/src/lib/db/local.test.ts +0 -81
  191. package/src/lib/db/local.ts +0 -148
  192. package/src/lib/db/migrate.test.ts +0 -133
  193. package/src/lib/db/migrate.ts +0 -137
  194. package/src/lib/db/paths.test.ts +0 -112
  195. package/src/lib/db/paths.ts +0 -128
  196. package/src/lib/db/remote-engine.test.ts +0 -44
  197. package/src/lib/db/remote-engine.ts +0 -148
  198. package/src/lib/db/remote-sql.test.ts +0 -32
  199. package/src/lib/db/remote-sql.ts +0 -62
  200. package/src/lib/db/sql.test.ts +0 -106
  201. package/src/lib/db/sql.ts +0 -192
  202. package/src/lib/hq-cloud-dep.smoke.test.ts +0 -75
  203. package/src/lib/local-tree-diff.test.ts +0 -301
  204. package/src/lib/local-tree-diff.ts +0 -362
  205. package/src/lib/narrow-hint-banner.test.ts +0 -235
  206. package/src/lib/narrow-hint-banner.ts +0 -212
  207. package/src/lib/plan-limit-nag.test.ts +0 -317
  208. package/src/lib/plan-limit-nag.ts +0 -264
  209. package/src/main.ts +0 -371
  210. package/src/node-preflight.test.ts +0 -60
  211. package/src/node-preflight.ts +0 -67
  212. package/src/outpost/session-heartbeat-bounds.test.ts +0 -195
  213. package/src/outpost/session-heartbeat-guard.test.ts +0 -105
  214. package/src/outpost/session-heartbeat-publisher.test.ts +0 -178
  215. package/src/outpost/session-heartbeat-publisher.ts +0 -186
  216. package/src/outpost/session-heartbeat-retain-guard.test.ts +0 -126
  217. package/src/outpost/session-heartbeat.test.ts +0 -459
  218. package/src/outpost/session-heartbeat.ts +0 -877
  219. package/src/packaging.test.ts +0 -109
  220. package/src/run/__fixtures__/discover-schemas/example.env.schema +0 -4
  221. package/src/run/discover-schemas.test.ts +0 -153
  222. package/src/run/discover-schemas.ts +0 -79
  223. package/src/run/hq-plugin.test.ts +0 -371
  224. package/src/run/hq-plugin.ts +0 -277
  225. package/src/run/varlock-shape.test.ts +0 -57
  226. package/src/schemas/hq-package.schema.json +0 -155
  227. package/src/sentry-before-send.test.ts +0 -359
  228. package/src/sentry-before-send.ts +0 -221
  229. package/src/sentry-epipe.test.ts +0 -37
  230. package/src/sentry-release.test.ts +0 -54
  231. package/src/sentry.test.ts +0 -24
  232. package/src/sentry.ts +0 -54
  233. package/src/strategies/link.ts +0 -62
  234. package/src/strategies/merge.ts +0 -142
  235. package/src/types.ts +0 -146
  236. package/src/utils/__fixtures__/scan-packages.generated-block.sh +0 -23
  237. package/src/utils/auth-error.test.ts +0 -40
  238. package/src/utils/auth-error.ts +0 -42
  239. package/src/utils/billing-gate.test.ts +0 -95
  240. package/src/utils/billing-gate.ts +0 -228
  241. package/src/utils/breadcrumb-buffer.ts +0 -18
  242. package/src/utils/cli-telemetry.test.ts +0 -153
  243. package/src/utils/cli-telemetry.ts +0 -61
  244. package/src/utils/cognito-session.machine.test.ts +0 -109
  245. package/src/utils/cognito-session.refresh.test.ts +0 -84
  246. package/src/utils/cognito-session.test.ts +0 -328
  247. package/src/utils/cognito-session.ts +0 -448
  248. package/src/utils/company-selection-error.test.ts +0 -42
  249. package/src/utils/company-selection-error.ts +0 -45
  250. package/src/utils/contribution-table.ts +0 -83
  251. package/src/utils/environmental-error.test.ts +0 -45
  252. package/src/utils/environmental-error.ts +0 -39
  253. package/src/utils/epipe.test.ts +0 -28
  254. package/src/utils/epipe.ts +0 -29
  255. package/src/utils/expected-cli-error.test.ts +0 -28
  256. package/src/utils/expected-cli-error.ts +0 -39
  257. package/src/utils/feedback-diagnostics.test.ts +0 -183
  258. package/src/utils/feedback-diagnostics.ts +0 -123
  259. package/src/utils/feedback-screenshots.test.ts +0 -134
  260. package/src/utils/feedback-screenshots.ts +0 -124
  261. package/src/utils/feedback-versions.test.ts +0 -98
  262. package/src/utils/feedback-versions.ts +0 -68
  263. package/src/utils/git.ts +0 -74
  264. package/src/utils/integrity.ts +0 -59
  265. package/src/utils/intercepted-process-exit.test.ts +0 -37
  266. package/src/utils/intercepted-process-exit.ts +0 -36
  267. package/src/utils/login-provider.test.ts +0 -42
  268. package/src/utils/login-provider.ts +0 -30
  269. package/src/utils/manifest.test.ts +0 -167
  270. package/src/utils/manifest.ts +0 -131
  271. package/src/utils/pack-contributions.test.ts +0 -603
  272. package/src/utils/pack-contributions.ts +0 -450
  273. package/src/utils/people.ts +0 -215
  274. package/src/utils/registry-client.ts +0 -204
  275. package/src/utils/registry.ts +0 -90
  276. package/src/utils/resolve-vault-credential.test.ts +0 -69
  277. package/src/utils/resolve-vault-credential.ts +0 -60
  278. package/src/utils/sandbox-runner-client.test.ts +0 -279
  279. package/src/utils/sandbox-runner-client.ts +0 -260
  280. package/src/utils/secrets-cache.ts +0 -183
  281. package/src/utils/sentry-identity.ts +0 -45
  282. package/src/utils/settle-with-timeout.test.ts +0 -21
  283. package/src/utils/settle-with-timeout.ts +0 -22
  284. package/src/utils/user-yaml-error.test.ts +0 -24
  285. package/src/utils/user-yaml-error.ts +0 -30
  286. package/src/utils/vault-api.test.ts +0 -536
  287. package/src/utils/vault-api.ts +0 -382
  288. package/src/utils/version-check.test.ts +0 -176
  289. package/src/utils/version-check.ts +0 -155
  290. package/src/utils/version-gate.test.ts +0 -1024
  291. package/src/utils/version-gate.ts +0 -702
  292. package/test/commands/db-tenant-isolation.test.ts +0 -94
  293. package/test/commands/db.test.ts +0 -85
  294. package/test/commands/signals.test.ts +0 -207
  295. package/test/commands/sources.test.ts +0 -231
  296. package/test/e2e/smoke-install-mcp.sh +0 -113
  297. package/test/fixtures/hq-pack-smoke-mcp/mcp/smoke-http.json +0 -1
  298. package/test/fixtures/hq-pack-smoke-mcp/package.yaml +0 -11
  299. package/test/fixtures/signals/action_item/sample.md +0 -16
  300. package/test/fixtures/signals/summary/sample.md +0 -12
  301. package/test/fixtures/sources/meetings/sample.md +0 -25
  302. package/test/helpers/cli-runner.ts +0 -150
  303. package/test/helpers/s3-list-mock.ts +0 -79
  304. package/test/helpers/vault-service-mock.ts +0 -295
  305. package/test/sources-signals/smoke.test.ts +0 -228
  306. package/tsconfig.json +0 -20
  307. package/vitest.config.ts +0 -11
  308. 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.78.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
- );