@indigoai-us/hq-cli 5.109.6 → 5.109.7

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.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,15 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [5.109.7] — 2026-09-10
6
+
7
+ ### Fixed
8
+
9
+ - Add `whoami --json`, structured `files acl --json` with explicit absence,
10
+ and `people resolve --membership-only` with canonical company/person IDs.
11
+ Delegation helpers can now verify exact grants without parsing display tables
12
+ or treating a missing ACL as a transport failure. Existing human output stays available.
13
+
5
14
  ## [5.109.6] — 2026-09-10
6
15
 
7
16
  ### Fixed
@@ -276,7 +276,8 @@ export function registerFilesCommand(program) {
276
276
  files
277
277
  .command("acl <prefix>")
278
278
  .description("Show the ACL (access control list) for a file prefix")
279
- .action(async (prefix) => {
279
+ .option("--json", "Output structured ACL data, including explicit absence")
280
+ .action(async (prefix, opts) => {
280
281
  try {
281
282
  // Read-only, so stripping is safe — but a mismatched anchor would show
282
283
  // a DIFFERENT company's ACL than the one the operator pasted.
@@ -321,7 +322,16 @@ export function registerFilesCommand(program) {
321
322
  process.exit(1);
322
323
  }
323
324
  const tree = (await treeRes.json());
325
+ if (!tree || typeof tree.prefix !== 'string' || !Array.isArray(tree.direct)
326
+ || !Array.isArray(tree.inherited) || !Array.isArray(tree.children)
327
+ || !(tree.directRow === null || (typeof tree.directRow === 'object' && tree.directRow))) {
328
+ throw new Error('Invalid ACL tree response');
329
+ }
324
330
  const row = tree.directRow;
331
+ if (opts.json) {
332
+ console.log(JSON.stringify({ ...tree, schemaVersion: 1, companyUid, exists: row !== null }, null, 2));
333
+ return;
334
+ }
325
335
  // No own row AND nothing inherited or granted below — preserve the
326
336
  // original "no ACL record" exit path.
327
337
  if (!row && tree.inherited.length === 0 && tree.children.length === 0) {
@@ -20,6 +20,7 @@ interface PeopleCommandDeps {
20
20
  }
21
21
  interface PeopleLookupOpts {
22
22
  localOnly?: boolean;
23
+ membershipOnly?: boolean;
23
24
  json?: boolean;
24
25
  }
25
26
  export declare function activeMemberToPersonRecord(m: ActiveMember): PersonRecord | null;
@@ -41,6 +41,8 @@ export function activeMemberToPersonRecord(m) {
41
41
  slug,
42
42
  name,
43
43
  email,
44
+ personUid: m.personUid,
45
+ companyUid: m.companyUid,
44
46
  role: m.role || undefined,
45
47
  type: "internal",
46
48
  source: `hq-pro membership: /membership/company/${m.companyUid}`,
@@ -147,6 +149,13 @@ async function tryFetchRoster(fetchRoster, hqRoot, slug) {
147
149
  }
148
150
  }
149
151
  export async function resolvePersonWithRosterFallback(input) {
152
+ if (input.opts?.membershipOnly) {
153
+ if (input.opts.localOnly)
154
+ throw new Error('--membership-only cannot be combined with --local-only');
155
+ // No local fallback: callers need authoritative IDs and must see transport errors.
156
+ const roster = await (input.fetchRoster ?? fetchMembershipRoster)(input.hqRoot, input.slug);
157
+ return resolveNameToEmail(roster, input.name);
158
+ }
150
159
  const localPeople = listCompanyPeople(input.hqRoot, input.slug);
151
160
  const local = resolveNameToEmail(localPeople, input.name);
152
161
  if (local.status !== "not_found" || input.opts?.localOnly)
@@ -239,6 +248,7 @@ export function registerPeopleCommand(program, deps = {}) {
239
248
  people
240
249
  .command("resolve <name>")
241
250
  .description("Resolve a person name to their email address")
251
+ .option("--membership-only", "Resolve from authoritative company membership, ignoring local records")
242
252
  .option("--json", "Output JSON instead of plain text")
243
253
  .option("--local-only", "Skip network fallback; resolve only from the local people roster")
244
254
  .action(async (name, opts) => {
@@ -1,17 +1,3 @@
1
- /**
2
- * hq packages install <slug> — download, verify, and extract a package (US-005)
3
- *
4
- * Flow:
5
- * 1. Check auth (prompt login if needed)
6
- * 2. Check entitlement via API
7
- * 3. Download tarball via presigned URL
8
- * 4. Verify SHA256 hash
9
- * 5. Verify RSA signature (if provided)
10
- * 6. Extract to packages/installed/<slug>/
11
- * 7. Validate extracted package.yaml slug matches
12
- * 8. Update packages/registry.yaml
13
- * 9. Print next-step message
14
- */
15
1
  import { Command } from 'commander';
16
2
  export declare function registerPackageInstallCommand(parent: Command): void;
17
3
  //# sourceMappingURL=pkg-install.d.ts.map
@@ -1,28 +1,4 @@
1
- /**
2
- * hq packages install <slug> — download, verify, and extract a package (US-005)
3
- *
4
- * Flow:
5
- * 1. Check auth (prompt login if needed)
6
- * 2. Check entitlement via API
7
- * 3. Download tarball via presigned URL
8
- * 4. Verify SHA256 hash
9
- * 5. Verify RSA signature (if provided)
10
- * 6. Extract to packages/installed/<slug>/
11
- * 7. Validate extracted package.yaml slug matches
12
- * 8. Update packages/registry.yaml
13
- * 9. Print next-step message
14
- */
15
- import * as fs from 'fs';
16
- import * as os from 'os';
17
- import * as path from 'path';
18
- import { parseUserYaml } from '../utils/user-yaml-error.js';
19
- import { execSync } from 'child_process';
20
1
  import chalk from 'chalk';
21
- import { ensureCognitoToken } from '../utils/cognito-session.js';
22
- import { resolveDefaultHqRoot } from '../utils/cognito-session.js';
23
- import { getRegistryUrl, RegistryClient, } from '../utils/registry-client.js';
24
- import { verifySha256, verifyRsaSignature } from '../utils/integrity.js';
25
- import { addToRegistry } from '../utils/registry.js';
26
2
  import { peekHqApiKey, requireApiKeyCapability, } from '../utils/resolve-vault-credential.js';
27
3
  import { MARKETPLACE_PREFIX, installPack, sourceMatchesPackPattern, } from './pack-install.js';
28
4
  /**
@@ -105,107 +81,4 @@ export function registerPackageInstallCommand(parent) {
105
81
  }
106
82
  });
107
83
  }
108
- async function installPackage(slug, company) {
109
- // 1. Auth
110
- const accessToken = await ensureCognitoToken();
111
- const registryUrl = getRegistryUrl();
112
- const client = new RegistryClient(registryUrl, accessToken);
113
- // 2. Check entitlement
114
- console.log(chalk.dim(`Checking entitlement for ${slug}...`));
115
- const entitlement = await client.checkEntitlement(slug);
116
- if (!entitlement.entitled) {
117
- throw new Error(`You are not entitled to package "${slug}". Visit the registry to purchase or request access.`);
118
- }
119
- // 3. Get download URL
120
- console.log(chalk.dim('Fetching download URL...'));
121
- const download = await client.getDownloadUrl(slug);
122
- // 4. Download to temp file
123
- const tmpDir = os.tmpdir();
124
- const tmpFile = path.resolve(tmpDir, `hq-pkg-${slug}-${Date.now()}.tar.gz`);
125
- try {
126
- console.log(chalk.dim('Downloading package...'));
127
- const response = await fetch(download.url, {
128
- signal: AbortSignal.timeout(120_000),
129
- });
130
- if (!response.ok) {
131
- throw new Error(`Download failed (${response.status})`);
132
- }
133
- const buffer = Buffer.from(await response.arrayBuffer());
134
- fs.writeFileSync(tmpFile, buffer);
135
- // 5. Verify SHA256
136
- console.log(chalk.dim('Verifying integrity...'));
137
- const hashValid = await verifySha256(tmpFile, download.sha256);
138
- if (!hashValid) {
139
- throw new Error('SHA256 hash mismatch — the downloaded file may be corrupted or tampered with.');
140
- }
141
- // 6. Verify RSA signature (if provided)
142
- if (download.signature) {
143
- const sigValid = verifyRsaSignature(download.sha256, download.signature);
144
- if (!sigValid) {
145
- throw new Error('RSA signature verification failed — the package may have been tampered with or the public key is missing/invalid. Aborting install.');
146
- }
147
- }
148
- // 7. Extract
149
- const hqRoot = resolveDefaultHqRoot({ onMissing: 'throw' });
150
- const installDir = path.resolve(hqRoot, 'packages', 'installed', slug);
151
- // Clean existing installation
152
- if (fs.existsSync(installDir)) {
153
- fs.rmSync(installDir, { recursive: true, force: true });
154
- }
155
- fs.mkdirSync(installDir, { recursive: true });
156
- execSync(`tar -xzf "${tmpFile}" -C "${installDir}"`, {
157
- stdio: 'pipe',
158
- });
159
- // 8. Validate package.yaml slug
160
- const packageYamlPath = path.resolve(installDir, 'package.yaml');
161
- if (fs.existsSync(packageYamlPath)) {
162
- const pkgContent = fs.readFileSync(packageYamlPath, 'utf-8');
163
- const pkgMeta = parseUserYaml(pkgContent, packageYamlPath);
164
- if (pkgMeta?.slug && pkgMeta.slug !== slug) {
165
- // Mismatch — clean up and abort
166
- fs.rmSync(installDir, { recursive: true, force: true });
167
- throw new Error(`Package slug mismatch: expected "${slug}", got "${pkgMeta.slug}"`);
168
- }
169
- }
170
- // 9. Get package info for registry entry
171
- let version = 'unknown';
172
- let name = slug;
173
- try {
174
- const pkgInfo = await client.getPackage(slug);
175
- version = pkgInfo.package.latest_version;
176
- name = pkgInfo.package.name;
177
- }
178
- catch {
179
- // Best-effort — fall back to package.yaml if present
180
- const packageYaml = path.resolve(installDir, 'package.yaml');
181
- if (fs.existsSync(packageYaml)) {
182
- const content = fs.readFileSync(packageYaml, 'utf-8');
183
- const meta = parseUserYaml(content, packageYaml);
184
- if (meta?.version)
185
- version = meta.version;
186
- if (meta?.name)
187
- name = meta.name;
188
- }
189
- }
190
- // 10. Update registry.yaml
191
- const now = new Date().toISOString();
192
- addToRegistry(hqRoot, {
193
- name,
194
- slug,
195
- version,
196
- source: registryUrl,
197
- scope: company,
198
- installed_at: now,
199
- updated_at: now,
200
- });
201
- console.log(chalk.green(`\nInstalled ${slug}@${version} to packages/installed/${slug}/`));
202
- console.log(chalk.cyan('Run /package-install ' + slug + ' in Claude to merge into your HQ.'));
203
- }
204
- finally {
205
- // Clean up temp file — never leave partial downloads
206
- if (fs.existsSync(tmpFile)) {
207
- fs.unlinkSync(tmpFile);
208
- }
209
- }
210
- }
211
84
  //# sourceMappingURL=pkg-install.js.map
@@ -4,7 +4,7 @@
4
4
  import chalk from 'chalk';
5
5
  import { loadCachedTokens, isExpiring, loadMachineCreds, } from '@indigoai-us/hq-cloud';
6
6
  import { peekIdToken as decodeIdToken } from "../utils/id-token.js";
7
- import { resolveCognitoTokenSource } from "../utils/cognito-session.js";
7
+ import { loadMachineCachedTokens, resolveCognitoTokenSource } from "../utils/cognito-session.js";
8
8
  function peekIdToken(idToken) {
9
9
  const decoded = decodeIdToken(idToken);
10
10
  return {
@@ -22,13 +22,39 @@ export function registerWhoamiCommand(program) {
22
22
  program
23
23
  .command('whoami')
24
24
  .description('Show the currently authenticated user')
25
- .action(async () => {
25
+ .option('--json', 'Output identity metadata as JSON (never tokens)')
26
+ .action(async (opts) => {
26
27
  try {
27
28
  // Effective source (same as auth status / ensureCognitoToken): env
28
29
  // opt-in, fresh-box default-creds when no usable person session, or
29
30
  // after a definitive person-refresh rejection marked the session rejected.
30
31
  const machine = resolveCognitoTokenSource() === "machine";
31
32
  const cached = loadCachedTokens();
33
+ if (opts.json) {
34
+ const machineCreds = machine ? loadMachineCreds() : null;
35
+ const identityCache = machine ? loadMachineCachedTokens() : cached;
36
+ const identity = identityCache ? peekIdToken(identityCache.idToken) : {};
37
+ const claims = identityCache ? decodeIdToken(identityCache.idToken) : {};
38
+ // Modern credentials carry the canonical UID. Legacy caches may only
39
+ // supply a UID when their subject is bound to the selected username.
40
+ const boundLegacyAgent = machineCreds && identity.entityType === 'agent'
41
+ && (claims['cognito:username'] === machineCreds.username
42
+ || claims.username === machineCreds.username || claims.sub === machineCreds.username)
43
+ ? identity.entityUid ?? null : null;
44
+ const agentUid = machineCreds?.entityUid !== undefined
45
+ ? (machineCreds.entityUid.startsWith('agt_') ? machineCreds.entityUid : null)
46
+ : boundLegacyAgent;
47
+ console.log(JSON.stringify({
48
+ schemaVersion: 1,
49
+ authenticated: machine ? Boolean(machineCreds) : Boolean(cached && !isExpiring(cached, 0)),
50
+ tokenSource: machine ? 'machine' : 'person',
51
+ email: machine ? null : identity.email ?? null,
52
+ personUid: !machine && identity.entityType === 'person' ? identity.entityUid ?? null : null,
53
+ agentUid,
54
+ username: machineCreds?.username ?? null,
55
+ }, null, 2));
56
+ return;
57
+ }
32
58
  if (machine) {
33
59
  // Machine identities (company agents) mint sessions on demand from
34
60
  // long-lived creds — report the machine identity honestly even when
@@ -50,7 +50,7 @@ export declare const POLICY_TRIGGER_LEDGER_RELPATH = "workspace/orchestrator/pol
50
50
  /** The two lifecycle events `check-hq-hooks.sh` requires a command hook on. */
51
51
  export declare const REQUIRED_HOOK_EVENTS: readonly ["SessionStart", "PreToolUse"];
52
52
  /**
53
- * Default runtime marker path an agents-v2 (hermes) box writes its runtime mode
53
+ * Default runtime marker path an agents-v2 (hq-fleet) box writes its runtime mode
54
54
  * to. Overridable via `HQ_RUNTIME_MARKER_FILE`, exactly as the shell reads
55
55
  * `${HQ_RUNTIME_MARKER_FILE:-/var/lib/hq-agent/runtime.json}`.
56
56
  */
@@ -129,31 +129,31 @@ export interface AgentsV2AttestationOptions {
129
129
  */
130
130
  export declare function isAgentsV2Runtime(hqRoot: string, env?: NodeJS.ProcessEnv): boolean;
131
131
  /**
132
- * Env var overriding the agents-v2 runtime (hermes) config path (chiefly for
132
+ * Env var overriding the agents-v2 runtime (hq-fleet) config path (chiefly for
133
133
  * tests), mirroring `HQ_RUNTIME_MARKER_FILE` and the shell's
134
- * `HQ_HERMES_CONFIG_FILE`.
134
+ * `HQ_FLEET_CONFIG_FILE`.
135
135
  */
136
- export declare const HQ_HERMES_CONFIG_ENV = "HQ_HERMES_CONFIG_FILE";
136
+ export declare const HQ_FLEET_CONFIG_ENV = "HQ_FLEET_CONFIG_FILE";
137
137
  /**
138
- * The agents-v2 runtime (hermes) config whose `hooks:` block wires the on-box
139
- * adapter into every lifecycle event — the env override, else `~/.hermes/config.yaml`
138
+ * The agents-v2 runtime (hq-fleet) config whose `hooks:` block wires the on-box
139
+ * adapter into every lifecycle event — the env override, else `~/.hq-fleet/config.yaml`
140
140
  * (where `provision/render-config.sh` renders it). Mirrors the shell's
141
- * `HQ_HERMES_CONFIG_FILE="${HQ_HERMES_CONFIG_FILE:-$HOME/.hermes/config.yaml}"`.
141
+ * `HQ_FLEET_CONFIG_FILE="${HQ_FLEET_CONFIG_FILE:-$HOME/.hq-fleet/config.yaml}"`.
142
142
  */
143
- export declare function resolveHermesConfigPath(env?: NodeJS.ProcessEnv): string;
143
+ export declare function resolveHqFleetConfigPath(env?: NodeJS.ProcessEnv): string;
144
144
  /**
145
145
  * Whether the agents-v2 runtime actually wires the on-box hook adapter.
146
146
  *
147
147
  * The wiring lives in the RUNTIME's hook config, not `.claude/settings.json`. On
148
148
  * a real box the v2 runtime's shell-hook dispatcher (`agent/shell_hooks.py`)
149
- * reads a `hooks:` block from `~/.hermes/config.yaml` with one entry per
149
+ * reads a `hooks:` block from `~/.hq-fleet/config.yaml` with one entry per
150
150
  * lifecycle event, each invoking `hq-agents-v2-hook-adapter.sh`; the adapter in
151
151
  * turn READS `.claude/settings.json` (via `hook-adapter-core.sh`) to fan out to
152
152
  * the classic `.claude/hooks` set. So `.claude/settings.json` never NAMES the
153
153
  * adapter — it wires the classic `hook-gate.sh` hooks — and grepping it for the
154
154
  * adapter always fails on a real box (verified on the v2.17 canary
155
155
  * i-0277243ad3aed8109, 2026-09-05: settings.json had 0 adapter refs / 94
156
- * hook-gate.sh refs, while ~/.hermes/config.yaml wired the adapter across 7
156
+ * hook-gate.sh refs, while ~/.hq-fleet/config.yaml wired the adapter across 7
157
157
  * events). Require BOTH the adapter installed under the tree at
158
158
  * {@link AGENTS_V2_ADAPTER_RELPATH} AND the runtime config invoking it. Mirrors
159
159
  * `hq_runtime_config_wires_v2_adapter` in `check-hq-hooks.sh`.
@@ -169,7 +169,7 @@ export declare function runtimeConfigWiresV2Adapter(hqRoot: string, env?: NodeJS
169
169
  export declare function v2LedgerPresent(opts: AgentsV2AttestationOptions): boolean;
170
170
  /**
171
171
  * All three agents-v2 self-attestation conditions. Used only to GRANT PASS to a
172
- * hermes box that host detection leaves platform-unknown; never to withhold it.
172
+ * hq-fleet box that host detection leaves platform-unknown; never to withhold it.
173
173
  * The exact conjunction of `agents_v2_attested` in `check-hq-hooks.sh`.
174
174
  */
175
175
  export declare function agentsV2Attested(opts: AgentsV2AttestationOptions): boolean;
@@ -53,7 +53,7 @@ export const POLICY_TRIGGER_LEDGER_RELPATH = "workspace/orchestrator/policy-trig
53
53
  /** The two lifecycle events `check-hq-hooks.sh` requires a command hook on. */
54
54
  export const REQUIRED_HOOK_EVENTS = ["SessionStart", "PreToolUse"];
55
55
  /**
56
- * Default runtime marker path an agents-v2 (hermes) box writes its runtime mode
56
+ * Default runtime marker path an agents-v2 (hq-fleet) box writes its runtime mode
57
57
  * to. Overridable via `HQ_RUNTIME_MARKER_FILE`, exactly as the shell reads
58
58
  * `${HQ_RUNTIME_MARKER_FILE:-/var/lib/hq-agent/runtime.json}`.
59
59
  */
@@ -161,36 +161,36 @@ function readRuntimeMarkerMode(markerPath) {
161
161
  }
162
162
  }
163
163
  /**
164
- * Env var overriding the agents-v2 runtime (hermes) config path (chiefly for
164
+ * Env var overriding the agents-v2 runtime (hq-fleet) config path (chiefly for
165
165
  * tests), mirroring `HQ_RUNTIME_MARKER_FILE` and the shell's
166
- * `HQ_HERMES_CONFIG_FILE`.
166
+ * `HQ_FLEET_CONFIG_FILE`.
167
167
  */
168
- export const HQ_HERMES_CONFIG_ENV = "HQ_HERMES_CONFIG_FILE";
168
+ export const HQ_FLEET_CONFIG_ENV = "HQ_FLEET_CONFIG_FILE";
169
169
  /**
170
- * The agents-v2 runtime (hermes) config whose `hooks:` block wires the on-box
171
- * adapter into every lifecycle event — the env override, else `~/.hermes/config.yaml`
170
+ * The agents-v2 runtime (hq-fleet) config whose `hooks:` block wires the on-box
171
+ * adapter into every lifecycle event — the env override, else `~/.hq-fleet/config.yaml`
172
172
  * (where `provision/render-config.sh` renders it). Mirrors the shell's
173
- * `HQ_HERMES_CONFIG_FILE="${HQ_HERMES_CONFIG_FILE:-$HOME/.hermes/config.yaml}"`.
173
+ * `HQ_FLEET_CONFIG_FILE="${HQ_FLEET_CONFIG_FILE:-$HOME/.hq-fleet/config.yaml}"`.
174
174
  */
175
- export function resolveHermesConfigPath(env = process.env) {
176
- const override = env[HQ_HERMES_CONFIG_ENV]?.trim();
175
+ export function resolveHqFleetConfigPath(env = process.env) {
176
+ const override = env[HQ_FLEET_CONFIG_ENV]?.trim();
177
177
  if (override)
178
178
  return override;
179
- return path.join(os.homedir(), ".hermes", "config.yaml");
179
+ return path.join(os.homedir(), ".hq-fleet", "config.yaml");
180
180
  }
181
181
  /**
182
182
  * Whether the agents-v2 runtime actually wires the on-box hook adapter.
183
183
  *
184
184
  * The wiring lives in the RUNTIME's hook config, not `.claude/settings.json`. On
185
185
  * a real box the v2 runtime's shell-hook dispatcher (`agent/shell_hooks.py`)
186
- * reads a `hooks:` block from `~/.hermes/config.yaml` with one entry per
186
+ * reads a `hooks:` block from `~/.hq-fleet/config.yaml` with one entry per
187
187
  * lifecycle event, each invoking `hq-agents-v2-hook-adapter.sh`; the adapter in
188
188
  * turn READS `.claude/settings.json` (via `hook-adapter-core.sh`) to fan out to
189
189
  * the classic `.claude/hooks` set. So `.claude/settings.json` never NAMES the
190
190
  * adapter — it wires the classic `hook-gate.sh` hooks — and grepping it for the
191
191
  * adapter always fails on a real box (verified on the v2.17 canary
192
192
  * i-0277243ad3aed8109, 2026-09-05: settings.json had 0 adapter refs / 94
193
- * hook-gate.sh refs, while ~/.hermes/config.yaml wired the adapter across 7
193
+ * hook-gate.sh refs, while ~/.hq-fleet/config.yaml wired the adapter across 7
194
194
  * events). Require BOTH the adapter installed under the tree at
195
195
  * {@link AGENTS_V2_ADAPTER_RELPATH} AND the runtime config invoking it. Mirrors
196
196
  * `hq_runtime_config_wires_v2_adapter` in `check-hq-hooks.sh`.
@@ -201,7 +201,7 @@ export function runtimeConfigWiresV2Adapter(hqRoot, env = process.env) {
201
201
  return false;
202
202
  let raw;
203
203
  try {
204
- raw = fs.readFileSync(resolveHermesConfigPath(env), "utf8");
204
+ raw = fs.readFileSync(resolveHqFleetConfigPath(env), "utf8");
205
205
  }
206
206
  catch {
207
207
  return false;
@@ -265,7 +265,7 @@ function ledgerDirHasFreshTxt(dir, cutoffMs) {
265
265
  }
266
266
  /**
267
267
  * All three agents-v2 self-attestation conditions. Used only to GRANT PASS to a
268
- * hermes box that host detection leaves platform-unknown; never to withhold it.
268
+ * hq-fleet box that host detection leaves platform-unknown; never to withhold it.
269
269
  * The exact conjunction of `agents_v2_attested` in `check-hq-hooks.sh`.
270
270
  */
271
271
  export function agentsV2Attested(opts) {
@@ -286,7 +286,7 @@ export function checkRuntimeProbe(context) {
286
286
  const checkId = `${RUNTIME_PROBE_PREFIX}.enforcement`;
287
287
  const target = POLICY_TRIGGER_LEDGER_RELPATH;
288
288
  const scope = sessionId ? ` for session ${sessionId}` : "";
289
- // agents-v2 (hermes) self-attestation. hq doctor leaves the hermes host
289
+ // agents-v2 (hq-fleet) self-attestation. hq doctor leaves the hq-fleet host
290
290
  // platform-unknown and, on an unknown host, the probe would report UNKNOWN
291
291
  // below. But the on-box adapter provably wrote the ledger through the same
292
292
  // .claude hooks, so grant PASS — and report platform "agents-v2" — when, and
@@ -75,12 +75,12 @@ export interface DeriveVerdictOptions {
75
75
  */
76
76
  requireLedger?: boolean;
77
77
  /**
78
- * Whether this is an attested agents-v2 (hermes) box: the runtime is
78
+ * Whether this is an attested agents-v2 (hq-fleet) box: the runtime is
79
79
  * agents-v2, `.claude/settings.json` wires the on-box adapter, and a
80
80
  * policy-trigger ledger exists (the exact session's when a session id is
81
81
  * given; otherwise a ledger fresh within the freshness window). When true,
82
82
  * OBSERVED is granted even though the doctor's runtime check did not report
83
- * PASS — because hq doctor leaves the hermes host platform-unknown, yet the
83
+ * PASS — because hq doctor leaves the hq-fleet host platform-unknown, yet the
84
84
  * on-box adapter provably wrote the ledger through the same .claude hooks.
85
85
  *
86
86
  * This is the exact twin of the `agents_v2_attested` override in
@@ -81,7 +81,7 @@ export function deriveCheckHqHooksVerdict(doc, options = {}) {
81
81
  // ledger" contract.
82
82
  const runtimeResult = doc.results.find((result) => result.checkId === RUNTIME_ENFORCEMENT_CHECK_ID);
83
83
  let runtime = observeRuntime(runtimeResult?.status, requireLedger);
84
- // agents-v2 self-attestation: hq doctor leaves the hermes host
84
+ // agents-v2 self-attestation: hq doctor leaves the hq-fleet host
85
85
  // platform-unknown and so does not report the runtime check as PASS, but the
86
86
  // on-box adapter provably wrote the ledger through the same .claude hooks.
87
87
  // Grant the identical OBSERVED verdict rather than relaying the host-unknown
@@ -22,6 +22,9 @@ export interface PersonRecord {
22
22
  name: string;
23
23
  /** Contact email, when recorded. */
24
24
  email?: string;
25
+ /** Canonical identity from authoritative company membership, never local YAML. */
26
+ personUid?: string;
27
+ companyUid?: string;
25
28
  /** "internal" (team member) | "external" (client, vendor, …). */
26
29
  type?: string;
27
30
  /** Role/title inside (or relative to) the company. */
@@ -31,11 +31,6 @@ export interface EntitlementEntry {
31
31
  export interface EntitlementListResponse {
32
32
  entitlements: EntitlementEntry[];
33
33
  }
34
- export interface EntitlementCheckResponse {
35
- entitled: boolean;
36
- tier?: string;
37
- expires_at?: string;
38
- }
39
34
  export interface DownloadResponse {
40
35
  url: string;
41
36
  sha256: string;
@@ -59,7 +54,6 @@ export declare class RegistryClient {
59
54
  }): Promise<PackageListResponse>;
60
55
  getPackage(slug: string): Promise<PackageResponse>;
61
56
  getMyEntitlements(): Promise<EntitlementListResponse>;
62
- checkEntitlement(slug: string): Promise<EntitlementCheckResponse>;
63
57
  getDownloadUrl(slug: string, version?: string): Promise<DownloadResponse>;
64
58
  }
65
59
  //# sourceMappingURL=registry-client.d.ts.map
@@ -88,9 +88,6 @@ export class RegistryClient {
88
88
  auth: true,
89
89
  });
90
90
  }
91
- async checkEntitlement(slug) {
92
- return this.request('GET', `/entitlements/${encodeURIComponent(slug)}`, { auth: true });
93
- }
94
91
  async getDownloadUrl(slug, version) {
95
92
  const params = new URLSearchParams();
96
93
  if (version)
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@indigoai-us/hq-cli",
3
- "version": "5.109.6",
4
- "description": "HQ by Indigo management CLI modules and cloud sync",
3
+ "version": "5.109.7",
4
+ "description": "HQ by Indigo management CLI \u2014 modules and cloud sync",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
7
7
  "hq": "dist/index.js",
@@ -26,7 +26,8 @@
26
26
  "coverage": "vitest run --coverage --coverage.reporter=text-summary --coverage.reporter=json-summary",
27
27
  "vitest": "vitest",
28
28
  "clean": "rm -rf dist",
29
- "prepare": "husky || true"
29
+ "prepare": "husky || true",
30
+ "check:no-hermes": "bash scripts/check-no-hermes.sh"
30
31
  },
31
32
  "dependencies": {
32
33
  "@aws-sdk/client-iot-data-plane": "^3.1096.0",