/** * cwd → owning-company resolution for telemetry edge attribution * (surface-hq-console-telemetry US-002). * * Both telemetry collectors (`./telemetry.ts`, `./skill-telemetry.ts`) stamp an * optional `companyUid` on each event so the server can attribute usage to the * company that owns the repo the event was produced in. The mapping comes from * `/companies/manifest.yaml`, whose shape is: * * companies: * indigo: * repos: * - repos/private/hq-cloud * - repos/public/hq-core * cloud_uid: cmp_01KQWRSQTCTES1SEFKXKDZAAK1 * liverecover: * repos: * - repos/private/liverecover-site * # (no cloud_uid — not cloud-backed) * * companyUid source: the value stamped is the manifest's `cloud_uid`. That is a * `cmp_*` entity uid — the SAME value the server membership-keys on * (`membershipKey = '#'`, where companyUid is the cmp_* * uid; see hq-pro `vault-service/handlers/usage.ts` + `skill-invocations.ts`). * So no slug→uid round-trip is needed: the manifest already carries the uid the * server expects. A company entry WITHOUT a `cloud_uid` (not cloud-backed, e.g. * `liverecover`/`temple`) contributes no mapping — its repos resolve to no * companyUid and the event is sent unattributed (field omitted). * * The reserved sentinel `unattributed` is NEVER produced here — "no match" * means "return undefined / omit the field", which the server treats as * unattributed/personal. * * Cost: `buildRepoCompanyMap()` parses the manifest ONCE per sync run; the * resulting map is reused for every event via `resolveCompanyForCwd()`. No * per-event manifest reads. * * Privacy: this module only ever returns a `cmp_*` uid (or undefined). It never * adds a raw path to any payload — the collectors add exactly one new field, * `companyUid`. */ /** * A repo-path → companyUid lookup, built once per run. Keys are ABSOLUTE, * normalized repo roots (`/repos/private/hq-cloud`); values are the * owning company's `cmp_*` uid. An event `cwd` is attributed to the entry whose * repo root is the longest prefix of (or equal to) the cwd. */ export interface RepoCompanyMap { /** * Absolute, normalized repo root → owning company `cmp_*` uid. `matchKey` is * the precomputed `canonicalPath(repoRoot)` used for the containment test, so * per-event matching stays a plain string compare. */ entries: Array<{ repoRoot: string; matchKey: string; companyUid: string; }>; /** * Company SLUG → owning company `cmp_*` uid, from the manifest keys. Backs * skill-based attribution: a company skill is invoked as `:` * (mirroring `companies//skills/`), so its usage belongs to the company * named by that slug regardless of the cwd it ran in. Manifest keys are unique, * so a slug resolves to exactly one cloud-backed company here. */ bySlug: Map; /** * Whether the HQ filesystem folds case, PROBED at build time rather than * inferred from `process.platform`. APFS can be case-sensitive on macOS and * Windows supports per-directory case sensitivity, so the OS is only a hint; * getting this wrong in the folding direction risks cross-tenant * misattribution. Defaults to `false` (exact matching) when the probe fails. */ foldsCase: boolean; /** * Match keys that two or more companies claimed. They are excluded from * `entries` (fail closed), and resolution must ALSO refuse to reach them via * the worktree fallback — otherwise an ambiguous `foo-wt-team` would collapse * to `foo` and hand the event to whichever company owns `foo`, quietly * undoing the protection. */ ambiguous: Set; } /** * Parse `/companies/manifest.yaml` ONCE and build the repo-path → * companyUid lookup. Best-effort: a missing/unparseable manifest yields an * empty map (every event then resolves to no company → unattributed), so a * telemetry run never fails on a manifest problem. * * Only companies that carry a `cloud_uid` (`cmp_*`) contribute entries — a * company without one is not cloud-backed and its repos stay unattributed. */ export declare function buildRepoCompanyMap(hqRoot: string): Promise; /** * Resolve a skill INVOCATION to its owning company's `cmp_*` uid, or `undefined` * when the skill is not a cloud-backed company's skill. * * A company skill is invoked as `:` (the namespaced form of * `companies//skills/`); the leading `` names the owning * company. We look that slug up in the manifest's slug→uid map, so a company * skill attributes to ITS company no matter which cwd it ran in — this is what * surfaces company-skill usage in the company console. A core / `personal:` / * `hq-pack-*:` / `anthropic-skills:` skill has no matching manifest company, so * it resolves to `undefined` (the cwd resolver remains the fallback). */ export declare function resolveCompanyForSkill(skill: string | undefined, map: RepoCompanyMap): string | undefined; /** * Resolve an event's `cwd` to the owning company's `cmp_*` uid, or `undefined` * when the cwd is inside no cloud-backed company repo (→ omit `companyUid`; * the server treats absence as unattributed/personal). * * Matching is by path containment: the cwd must equal a repo root or sit * beneath it (`/...`). A trailing-slash boundary prevents a sibling * that merely shares a string prefix (`-other`) from matching. * Entries are pre-sorted longest-first, so the first match is the most * specific. * * If nothing matches, one lexical retry strips HQ's `-wt-` worktree * suffix from the path. `buildRepoCompanyMap` discovers worktrees by reading * the directory, which only sees the ones that exist RIGHT NOW — but telemetry * is read from a cursor and a branch worktree is routinely deleted before the * next pass. Those pending rows still carry the worktree cwd, and because a * successful POST advances the cursor permanently, failing to resolve them * loses that attribution for good. The suffix is documented convention, so * deriving it from the recorded path needs no directory to still exist. */ export declare function resolveCompanyForCwd(cwd: string | undefined, map: RepoCompanyMap): string | undefined; //# sourceMappingURL=company-resolver.d.ts.map