ai-obs-cli 0.0.0-stage → 0.5.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 (155) hide show
  1. package/README.md +666 -2
  2. package/bin/ai-obs.js +8 -0
  3. package/dist/adapters/claude-code/analyze.js +189 -0
  4. package/dist/adapters/claude-code/analyze.js.map +1 -0
  5. package/dist/adapters/claude-code/detect.js +60 -0
  6. package/dist/adapters/claude-code/detect.js.map +1 -0
  7. package/dist/adapters/claude-code/handlers.js +183 -0
  8. package/dist/adapters/claude-code/handlers.js.map +1 -0
  9. package/dist/adapters/claude-code/index.js +55 -0
  10. package/dist/adapters/claude-code/index.js.map +1 -0
  11. package/dist/adapters/claude-code/run-links.js +53 -0
  12. package/dist/adapters/claude-code/run-links.js.map +1 -0
  13. package/dist/adapters/claude-code/session.js +427 -0
  14. package/dist/adapters/claude-code/session.js.map +1 -0
  15. package/dist/adapters/claude-code/settings.js +161 -0
  16. package/dist/adapters/claude-code/settings.js.map +1 -0
  17. package/dist/adapters/claude-code/state.js +66 -0
  18. package/dist/adapters/claude-code/state.js.map +1 -0
  19. package/dist/adapters/claude-code/subagents.js +246 -0
  20. package/dist/adapters/claude-code/subagents.js.map +1 -0
  21. package/dist/adapters/claude-code/transcript.js +309 -0
  22. package/dist/adapters/claude-code/transcript.js.map +1 -0
  23. package/dist/adapters/codex/accumulator.js +135 -0
  24. package/dist/adapters/codex/accumulator.js.map +1 -0
  25. package/dist/adapters/codex/detect.js +93 -0
  26. package/dist/adapters/codex/detect.js.map +1 -0
  27. package/dist/adapters/codex/hooks-config.js +158 -0
  28. package/dist/adapters/codex/hooks-config.js.map +1 -0
  29. package/dist/adapters/codex/index.js +270 -0
  30. package/dist/adapters/codex/index.js.map +1 -0
  31. package/dist/adapters/codex/locate.js +72 -0
  32. package/dist/adapters/codex/locate.js.map +1 -0
  33. package/dist/adapters/codex/records.js +194 -0
  34. package/dist/adapters/codex/records.js.map +1 -0
  35. package/dist/adapters/codex/rollout.js +72 -0
  36. package/dist/adapters/codex/rollout.js.map +1 -0
  37. package/dist/adapters/codex/session.js +212 -0
  38. package/dist/adapters/codex/session.js.map +1 -0
  39. package/dist/adapters/codex/subagents.js +139 -0
  40. package/dist/adapters/codex/subagents.js.map +1 -0
  41. package/dist/adapters/codex/summarize.js +84 -0
  42. package/dist/adapters/codex/summarize.js.map +1 -0
  43. package/dist/adapters/codex/tools.js +145 -0
  44. package/dist/adapters/codex/tools.js.map +1 -0
  45. package/dist/adapters/hook-command.js +94 -0
  46. package/dist/adapters/hook-command.js.map +1 -0
  47. package/dist/adapters/index.js +12 -0
  48. package/dist/adapters/index.js.map +1 -0
  49. package/dist/adapters/types.js +2 -0
  50. package/dist/adapters/types.js.map +1 -0
  51. package/dist/analysis/corrections.js +79 -0
  52. package/dist/analysis/corrections.js.map +1 -0
  53. package/dist/analysis/digest.js +16 -0
  54. package/dist/analysis/digest.js.map +1 -0
  55. package/dist/analysis/outcome.js +76 -0
  56. package/dist/analysis/outcome.js.map +1 -0
  57. package/dist/analysis/phases.js +203 -0
  58. package/dist/analysis/phases.js.map +1 -0
  59. package/dist/analysis/summaries.js +350 -0
  60. package/dist/analysis/summaries.js.map +1 -0
  61. package/dist/analysis/tokens.js +67 -0
  62. package/dist/analysis/tokens.js.map +1 -0
  63. package/dist/analysis/usage.js +229 -0
  64. package/dist/analysis/usage.js.map +1 -0
  65. package/dist/cc-cache.js +81 -0
  66. package/dist/cc-cache.js.map +1 -0
  67. package/dist/cli.js +128 -0
  68. package/dist/cli.js.map +1 -0
  69. package/dist/commands/common.js +235 -0
  70. package/dist/commands/common.js.map +1 -0
  71. package/dist/commands/doctor.js +193 -0
  72. package/dist/commands/doctor.js.map +1 -0
  73. package/dist/commands/flush.js +131 -0
  74. package/dist/commands/flush.js.map +1 -0
  75. package/dist/commands/init.js +119 -0
  76. package/dist/commands/init.js.map +1 -0
  77. package/dist/commands/link.js +171 -0
  78. package/dist/commands/link.js.map +1 -0
  79. package/dist/commands/live.js +130 -0
  80. package/dist/commands/live.js.map +1 -0
  81. package/dist/commands/login.js +397 -0
  82. package/dist/commands/login.js.map +1 -0
  83. package/dist/commands/status.js +155 -0
  84. package/dist/commands/status.js.map +1 -0
  85. package/dist/commands/token.js +92 -0
  86. package/dist/commands/token.js.map +1 -0
  87. package/dist/commands/uninstall.js +56 -0
  88. package/dist/commands/uninstall.js.map +1 -0
  89. package/dist/config.js +305 -0
  90. package/dist/config.js.map +1 -0
  91. package/dist/context.js +109 -0
  92. package/dist/context.js.map +1 -0
  93. package/dist/delivery.js +151 -0
  94. package/dist/delivery.js.map +1 -0
  95. package/dist/dotfile.js +187 -0
  96. package/dist/dotfile.js.map +1 -0
  97. package/dist/events.js +259 -0
  98. package/dist/events.js.map +1 -0
  99. package/dist/fsutil.js +50 -0
  100. package/dist/fsutil.js.map +1 -0
  101. package/dist/git.js +139 -0
  102. package/dist/git.js.map +1 -0
  103. package/dist/hook.js +147 -0
  104. package/dist/hook.js.map +1 -0
  105. package/dist/http.js +35 -0
  106. package/dist/http.js.map +1 -0
  107. package/dist/jobs.js +53 -0
  108. package/dist/jobs.js.map +1 -0
  109. package/dist/live/claude-code.js +226 -0
  110. package/dist/live/claude-code.js.map +1 -0
  111. package/dist/live/codex.js +91 -0
  112. package/dist/live/codex.js.map +1 -0
  113. package/dist/live/monitor.js +229 -0
  114. package/dist/live/monitor.js.map +1 -0
  115. package/dist/live/render.js +92 -0
  116. package/dist/live/render.js.map +1 -0
  117. package/dist/lock.js +93 -0
  118. package/dist/lock.js.map +1 -0
  119. package/dist/log.js +36 -0
  120. package/dist/log.js.map +1 -0
  121. package/dist/migrate.js +109 -0
  122. package/dist/migrate.js.map +1 -0
  123. package/dist/nudge.js +231 -0
  124. package/dist/nudge.js.map +1 -0
  125. package/dist/paths.js +73 -0
  126. package/dist/paths.js.map +1 -0
  127. package/dist/pk-cache.js +110 -0
  128. package/dist/pk-cache.js.map +1 -0
  129. package/dist/prices.js +45 -0
  130. package/dist/prices.js.map +1 -0
  131. package/dist/project-key.js +144 -0
  132. package/dist/project-key.js.map +1 -0
  133. package/dist/protocol-types.js +30 -0
  134. package/dist/protocol-types.js.map +1 -0
  135. package/dist/queue.js +649 -0
  136. package/dist/queue.js.map +1 -0
  137. package/dist/routing.js +122 -0
  138. package/dist/routing.js.map +1 -0
  139. package/dist/runtime.js +54 -0
  140. package/dist/runtime.js.map +1 -0
  141. package/dist/sender.js +559 -0
  142. package/dist/sender.js.map +1 -0
  143. package/dist/state.js +59 -0
  144. package/dist/state.js.map +1 -0
  145. package/dist/ulid.js +73 -0
  146. package/dist/ulid.js.map +1 -0
  147. package/dist/version.js +26 -0
  148. package/dist/version.js.map +1 -0
  149. package/dist/warnings.js +71 -0
  150. package/dist/warnings.js.map +1 -0
  151. package/dist/worker-main.js +14 -0
  152. package/dist/worker-main.js.map +1 -0
  153. package/dist/worker.js +295 -0
  154. package/dist/worker.js.map +1 -0
  155. package/package.json +25 -4
package/dist/paths.js ADDED
@@ -0,0 +1,73 @@
1
+ import { homedir } from 'node:os';
2
+ import { join } from 'node:path';
3
+ /** Resolves the collector home: explicit arg, then AI_OBS_HOME, then ~/.ai-obs. */
4
+ export function resolveHome(home) {
5
+ return home ?? process.env.AI_OBS_HOME ?? join(homedir(), '.ai-obs');
6
+ }
7
+ /** Local collector files (BRIEF §5.1). AI_OBS_HOME overrides the base dir (tests, sandboxes). */
8
+ export function aiObsPaths(home = resolveHome()) {
9
+ const state = join(home, 'state');
10
+ return {
11
+ root: home,
12
+ /** config v3: machine_id and one entry per server with its token (mode 0600) */
13
+ config: join(home, 'config.json'),
14
+ /** 0.2 – 0.4 per-repository token choice: no longer read; renamed to projects.json.v2 by the migration */
15
+ legacyProjects: join(home, 'projects.json'),
16
+ /** random local secret for path-based project keys (mode 0600; never sent) */
17
+ projectSecret: join(home, 'project-secret'),
18
+ /** per-session cursors (state/<harness>/<session>.json), delivery + collector-config caches */
19
+ state,
20
+ /** cached GET /api/v1/collector-config, one file per server: <host>.json (':' → '_') */
21
+ collectorConfigDir: join(state, 'collector-config'),
22
+ /** cwd → plain project key, written by the worker, read by the hook */
23
+ projectKeyCache: join(state, 'project-keys.json'),
24
+ /** cwd → dot-file lookup (.ai-obs.json / .ai-obs.local.json), written by the worker, read by the hook */
25
+ dotFileCache: join(state, 'dot-files.json'),
26
+ /** latest ingest warning per project key (team_not_member / team_unknown) */
27
+ warnings: join(state, 'warnings.json'),
28
+ /** SessionStart nudge markers, one file per session id */
29
+ nudged: join(state, 'nudged'),
30
+ /** size-cap drop counters */
31
+ dropped: join(state, 'dropped.json'),
32
+ /** per-server delivery state (keyed by host): last attempt / success / backoff / blocked / repositories */
33
+ delivery: join(state, 'delivery.json'),
34
+ /** event queue, capped ~50 MB / 30 days; root *.ndjson = pre-upgrade stream (frozen, never sent) */
35
+ queue: join(home, 'queue'),
36
+ /** project streams p/s-<id>/ keyed by (project key, server endpoint, team) */
37
+ queueProjects: join(home, 'queue', 'p'),
38
+ /** unresolved streams u/s-<id>/ (git timed out at capture) */
39
+ queueUnresolved: join(home, 'queue', 'u'),
40
+ /** batches the server refused as a whole (HTTP 400), kept locally for inspection */
41
+ deadLetter: join(home, 'queue', 'dead'),
42
+ /** pre-upgrade root segments moved here by 0.2 – 0.4 (never sent; left as is) */
43
+ deadPreUpgrade: join(home, 'queue', 'dead', 'pre-upgrade'),
44
+ /** hook invocations waiting for the detached worker */
45
+ jobs: join(home, 'jobs'),
46
+ /** collector log (errors from hooks and the worker go here, never to the harness) */
47
+ logDir: join(home, 'log'),
48
+ logFile: join(home, 'log', 'collector.log'),
49
+ /** stable copy of the collector that installed hooks point to */
50
+ app: join(home, 'app'),
51
+ /** held by the single worker / flush process */
52
+ workerLock: join(home, 'worker.lock'),
53
+ /** held while turn summaries are written (worker summary phase after its flush, or `ai-obs flush`; ADR-0027) */
54
+ summariesLock: join(home, 'summaries.lock'),
55
+ /** digests due for summarising, staged/<harness>/<ulid>.json (local only, mode 0600; ADR-0027) */
56
+ stagedSummaries: join(state, 'summaries', 'staged'),
57
+ };
58
+ }
59
+ /** Per-server collector-config cache file: `<host>.json` with ':' → '_' (a host is never a path). */
60
+ export function collectorConfigPath(paths, host) {
61
+ if (!/^[a-z0-9.\-\[\]:]{1,255}$/.test(host))
62
+ throw new Error(`invalid host: ${JSON.stringify(host)}`);
63
+ return join(paths.collectorConfigDir, `${host.replace(/[:[\]]/g, '_')}.json`);
64
+ }
65
+ /** Nudge marker of one session; null unless the id is a plain token (no path tricks). */
66
+ export function nudgeMarkerPath(paths, sessionId) {
67
+ return typeof sessionId === 'string' && /^[A-Za-z0-9-]{1,100}$/.test(sessionId) ? join(paths.nudged, sessionId) : null;
68
+ }
69
+ /** Directory for one harness's session state. */
70
+ export function harnessStateDir(paths, harness) {
71
+ return join(paths.state, harness);
72
+ }
73
+ //# sourceMappingURL=paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,110 @@
1
+ import { readFileSync, statSync } from 'node:fs';
2
+ import { dirname, join, resolve } from 'node:path';
3
+ import { readJsonFile, writeJsonAtomic } from './fsutil.js';
4
+ /** Entries kept in state/project-keys.json (least recently resolved dropped first). */
5
+ export const PK_CACHE_MAX = 500;
6
+ /** A cache hit younger than this is not rewritten (the worker resolves on every job). */
7
+ const REFRESH_MS = 60_000;
8
+ /** The cache; empty when missing or unreadable. Never throws. */
9
+ export function readPkCache(paths) {
10
+ const raw = readJsonFile(paths.projectKeyCache);
11
+ const out = Object.create(null);
12
+ if (typeof raw !== 'object' || raw === null || Array.isArray(raw))
13
+ return out;
14
+ for (const [cwd, v] of Object.entries(raw)) {
15
+ const e = v;
16
+ if (e && typeof e.pk === 'string' && e.pk && typeof e.at === 'number' && Number.isFinite(e.at)) {
17
+ out[cwd] = { pk: e.pk, at: e.at, ...(typeof e.stamp === 'string' ? { stamp: e.stamp } : {}) };
18
+ }
19
+ }
20
+ return out;
21
+ }
22
+ /** Records a resolution (LRU, 0600, atomic). Never throws: the cache is an optimisation only. */
23
+ export function rememberPk(paths, cwd, pk, now = Date.now()) {
24
+ try {
25
+ const cache = readPkCache(paths);
26
+ const hit = cache[cwd];
27
+ const stamp = repoStamp(cwd);
28
+ if (hit && hit.pk === pk && hit.stamp === stamp && now - hit.at >= 0 && now - hit.at < REFRESH_MS)
29
+ return;
30
+ cache[cwd] = { pk, at: now, stamp };
31
+ const kept = Object.entries(cache)
32
+ .sort((a, b) => b[1].at - a[1].at)
33
+ .slice(0, PK_CACHE_MAX);
34
+ writeJsonAtomic(paths.projectKeyCache, Object.fromEntries(kept), 0o600);
35
+ }
36
+ catch {
37
+ /* read-only home */
38
+ }
39
+ }
40
+ /** Distinct keys resolved at or after `sinceMs` (a timestamp), most recent first. */
41
+ export function recentKeys(paths, sinceMs) {
42
+ const seen = new Set();
43
+ for (const [, e] of Object.entries(readPkCache(paths)).sort((a, b) => b[1].at - a[1].at)) {
44
+ if (e.at >= sinceMs)
45
+ seen.add(e.pk);
46
+ }
47
+ return [...seen];
48
+ }
49
+ /**
50
+ * The cached key of `cwd` when it still describes the same repository: the entry's stamp equals the
51
+ * current repoStamp (no re-clone, no `git remote set-url`, no `git init` since). Null otherwise: the
52
+ * caller resolves again (the hook trusts nothing older, §4.2).
53
+ */
54
+ export function cachedPk(cache, cwd) {
55
+ const hit = cache[cwd];
56
+ return hit?.stamp !== undefined && hit.stamp !== 'unknown' && hit.stamp === repoStamp(cwd) ? hit.pk : null;
57
+ }
58
+ /**
59
+ * What identifies the repository a directory belongs to, from a few `stat`s and no git: the git config
60
+ * file that holds its remotes (path, mtime, inode), found by walking up to the nearest `.git` (a linked
61
+ * worktree's `.git` file is followed to the common directory); `none` outside a repository. Any change
62
+ * of the remote rewrites that file, a re-clone replaces it. Never throws.
63
+ */
64
+ export function repoStamp(cwd) {
65
+ try {
66
+ let dir = resolve(cwd);
67
+ for (let depth = 0; depth < 128; depth++) {
68
+ const dotgit = join(dir, '.git');
69
+ let st = null;
70
+ try {
71
+ st = statSync(dotgit);
72
+ }
73
+ catch {
74
+ st = null;
75
+ }
76
+ if (st) {
77
+ let gitdir = dotgit;
78
+ if (!st.isDirectory()) {
79
+ const m = /^gitdir:\s*(.+)$/m.exec(readFileSync(dotgit, 'utf8'));
80
+ if (!m?.[1])
81
+ return `file:${dotgit}:${st.mtimeMs}:${st.ino}`;
82
+ gitdir = resolve(dir, m[1].trim());
83
+ try {
84
+ gitdir = resolve(gitdir, readFileSync(join(gitdir, 'commondir'), 'utf8').trim());
85
+ }
86
+ catch {
87
+ /* a submodule or a plain gitdir file: its own config */
88
+ }
89
+ }
90
+ const cfg = join(gitdir, 'config');
91
+ try {
92
+ const c = statSync(cfg);
93
+ return `${cfg}:${c.mtimeMs}:${c.ino}`;
94
+ }
95
+ catch {
96
+ return `${cfg}:missing`;
97
+ }
98
+ }
99
+ const parent = dirname(dir);
100
+ if (parent === dir)
101
+ break;
102
+ dir = parent;
103
+ }
104
+ }
105
+ catch {
106
+ return 'unknown';
107
+ }
108
+ return 'none';
109
+ }
110
+ //# sourceMappingURL=pk-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pk-cache.js","sourceRoot":"","sources":["../src/pk-cache.ts"],"names":[],"mappings":"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"}
package/dist/prices.js ADDED
@@ -0,0 +1,45 @@
1
+ const p = (model, input, output, cacheRead, cacheWrite) => ({ model, input, output, cacheRead, cacheWrite });
2
+ /**
3
+ * Copy of DEFAULT_MODEL_PRICES in packages/db/src/prices.ts (USD/Mtok); test/prices.test.ts keeps them equal.
4
+ * Operator-edited rows are not visible locally, so `ai-obs live` shows "≈ at default list prices" (ADR-0027).
5
+ */
6
+ export const DEFAULT_MODEL_PRICES = [
7
+ p('claude-fable-5-1', 10, 50, 0.25, 12.5),
8
+ p('claude-fable-5', 10, 50, 1, 12.5),
9
+ p('claude-opus-5-5', 4, 20, 0.2, 5),
10
+ p('claude-opus-5', 5, 25, 0.5, 6.25),
11
+ p('claude-opus-4-8', 5, 25, 0.5, 6.25),
12
+ p('claude-opus-4-7', 5, 25, 0.5, 6.25),
13
+ p('claude-opus-4-6', 5, 25, 0.5, 6.25),
14
+ p('claude-sonnet-5-5', 2, 10, 0.2, 2.5),
15
+ p('claude-sonnet-5', 2, 10, 0.2, 2.5),
16
+ p('claude-sonnet-4-6', 3, 15, 0.3, 3.75),
17
+ p('claude-haiku-4-5', 1, 5, 0.1, 1.25),
18
+ p('gpt-5.5', 5, 30, 0.5, 0),
19
+ p('gpt-5.4', 2.5, 15, 0.25, 0),
20
+ p('gpt-5.4-mini', 0.75, 4.5, 0.075, 0),
21
+ ];
22
+ const BY_MODEL = new Map(DEFAULT_MODEL_PRICES.map((r) => [r.model, r]));
23
+ /**
24
+ * ≈ cost, same formula as db estimateCostUsd (prices.ts); reasoning is part of output, not billed again.
25
+ * Exact model match. `usd` is null when every model is unknown (and there is usage), `partial` when some are.
26
+ */
27
+ export function estimateUsageCost(usage) {
28
+ let usd = 0;
29
+ let known = 0;
30
+ const unknown = new Set();
31
+ for (const u of usage) {
32
+ const price = BY_MODEL.get(u.model);
33
+ if (!price) {
34
+ unknown.add(u.model);
35
+ continue;
36
+ }
37
+ known++;
38
+ usd += (u.input * price.input + u.output * price.output + u.cache_read * price.cacheRead + u.cache_write * price.cacheWrite) / 1_000_000;
39
+ }
40
+ const unknownModels = [...unknown].sort();
41
+ if (usage.length && !known)
42
+ return { usd: null, partial: false, unknownModels };
43
+ return { usd, partial: unknownModels.length > 0, unknownModels };
44
+ }
45
+ //# sourceMappingURL=prices.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prices.js","sourceRoot":"","sources":["../src/prices.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,144 @@
1
+ import { createHash, createHmac, randomBytes } from 'node:crypto';
2
+ import { linkSync, readFileSync, realpathSync, rmSync, writeFileSync } from 'node:fs';
3
+ import { basename, dirname, isAbsolute, resolve as resolvePath } from 'node:path';
4
+ import { ensureDir } from './fsutil.js';
5
+ import { gitRemoteUrlResult, gitRepoRootResult } from './git.js';
6
+ const sha256 = (s) => createHash('sha256').update(s).digest('hex');
7
+ const hmac = (key, s) => createHmac('sha256', key).update(s).digest('hex');
8
+ /**
9
+ * Normalizes a git remote to `host/path`: strips protocol, credentials / `user@`, port, `.git` and
10
+ * trailing slashes; lowercases the host. Returns null for local remotes (paths, file://), which
11
+ * would leak a file path.
12
+ *
13
+ * git@github.com:Acme/billing.git → github.com/Acme/billing
14
+ * https://u:p@GitHub.com:443/acme/x.git/ → github.com/acme/x
15
+ */
16
+ export function normalizeRemote(remote) {
17
+ let s = remote.trim();
18
+ if (!s)
19
+ return null;
20
+ let host;
21
+ let path;
22
+ const urlMatch = /^([a-z][a-z0-9+.-]*):\/\/(.*)$/i.exec(s);
23
+ if (urlMatch) {
24
+ const scheme = (urlMatch[1] ?? '').toLowerCase();
25
+ if (scheme === 'file')
26
+ return null;
27
+ s = urlMatch[2] ?? '';
28
+ const slash = s.indexOf('/');
29
+ const authority = slash < 0 ? s : s.slice(0, slash);
30
+ path = slash < 0 ? '' : s.slice(slash + 1);
31
+ host = authority.slice(authority.lastIndexOf('@') + 1);
32
+ // ssh://git@host:org/repo (scp-ish inside a URL): a non-numeric "port" is really the path start.
33
+ const colon = host.lastIndexOf(':');
34
+ if (colon >= 0 && !host.startsWith('[')) {
35
+ const port = host.slice(colon + 1);
36
+ if (port && !/^\d+$/.test(port))
37
+ path = `${port}/${path}`;
38
+ host = host.slice(0, colon);
39
+ }
40
+ }
41
+ else {
42
+ // scp-like: [user@]host:path — but not a Windows drive (C:\…) or a plain local path.
43
+ const scp = /^(?:[^@/\\]+@)?([^:/\\\s]+):(?!\/\/)(.+)$/.exec(s);
44
+ if (!scp || /^[a-z]$/i.test(scp[1] ?? ''))
45
+ return null;
46
+ host = scp[1] ?? '';
47
+ path = scp[2] ?? '';
48
+ }
49
+ host = host.toLowerCase().replace(/\.$/, '');
50
+ path = path
51
+ .replace(/\\/g, '/')
52
+ .replace(/^\/+|\/+$/g, '')
53
+ .replace(/\.git$/i, '')
54
+ .replace(/\/+$/, '');
55
+ if (!host || !path || !/^[a-z0-9.-]+$/.test(host) || /\s/.test(path))
56
+ return null;
57
+ return `${host}/${path}`;
58
+ }
59
+ /** Default git budget of a key resolution outside the hook (worker, sender, `use`): latency does not matter there (C16). */
60
+ export const RESOLVE_TIMEOUT_MS = 5000;
61
+ /**
62
+ * The plain project key of a working directory (Q4, C2): the normalized git remote, else the git
63
+ * top-level (of the main checkout, for a linked worktree), else `realpath(cwd)` outside a repo
64
+ * (`path.resolve(cwd)` when the directory is gone). Local only, never sent as such (sendRef). Null only
65
+ * when git timed out. `bounded` (the hook) kills git at the deadline instead of waiting for it (C26).
66
+ * Never throws.
67
+ */
68
+ export async function resolveProjectKey(cwd, opts = {}) {
69
+ const d = { until: Date.now() + (opts.timeoutMs ?? RESOLVE_TIMEOUT_MS), bounded: opts.bounded === true };
70
+ const [top, remote] = await Promise.all([gitRepoRootResult(cwd, d), gitRemoteUrlResult(cwd, d)]);
71
+ if (top.timedOut || remote.timedOut)
72
+ return null;
73
+ const normalized = remote.out ? normalizeRemote(remote.out) : null;
74
+ if (normalized)
75
+ return normalized;
76
+ if (top.out && isAbsolute(top.out))
77
+ return top.out;
78
+ try {
79
+ return realpathSync(cwd);
80
+ }
81
+ catch {
82
+ return resolvePath(cwd);
83
+ }
84
+ }
85
+ /** A key that is a local path (no usable remote): always sent as a keyed hash. */
86
+ export function isPathKey(pk) {
87
+ return isAbsolute(pk);
88
+ }
89
+ /**
90
+ * Send-time project reference for the receiving token (C3, contract §5.5). Path key →
91
+ * `sha256:` + HMAC(local path secret, `path:` + path) (plain sha256 without a secret); hashed →
92
+ * `sha256:` + HMAC(deployment salt, key) (plain sha256 without a salt), no name; plain → the key and its
93
+ * last segment as name.
94
+ */
95
+ export function sendRef(pk, o) {
96
+ if (isPathKey(pk)) {
97
+ const path = `path:${pk}`;
98
+ return { key: `sha256:${o.pathSecret ? hmac(o.pathSecret, path) : sha256(path)}` };
99
+ }
100
+ if (o.naming === 'hashed')
101
+ return { key: `sha256:${o.salt ? hmac(o.salt, pk) : sha256(pk)}` };
102
+ const name = basename(pk).slice(0, 200);
103
+ return name ? { key: pk, name } : { key: pk };
104
+ }
105
+ /** What `ctx.projectKey` returns at capture (plain naming); the sender overwrites it from the stream key. */
106
+ export function localRef(pk, pathSecret) {
107
+ return sendRef(pk, { naming: 'plain', pathSecret });
108
+ }
109
+ /**
110
+ * The machine's path secret (32 random bytes, hex), created on first use. Creation is atomic (temp
111
+ * file + hard link), so concurrent workers agree on one value. Null when the file cannot be read or
112
+ * created (the caller then falls back to the unsalted key).
113
+ */
114
+ export function loadPathSecret(file) {
115
+ const read = () => {
116
+ try {
117
+ const v = readFileSync(file, 'utf8').trim();
118
+ return /^[0-9a-f]{64}$/.test(v) ? v : null;
119
+ }
120
+ catch {
121
+ return null;
122
+ }
123
+ };
124
+ const existing = read();
125
+ if (existing)
126
+ return existing;
127
+ const tmp = `${file}.${process.pid}.${randomBytes(4).toString('hex')}.tmp`;
128
+ try {
129
+ ensureDir(dirname(file));
130
+ writeFileSync(tmp, `${randomBytes(32).toString('hex')}\n`, { mode: 0o600 });
131
+ linkSync(tmp, file); // fails with EEXIST if another process won the race
132
+ }
133
+ catch {
134
+ /* lost the race, or read-only home */
135
+ }
136
+ try {
137
+ rmSync(tmp, { force: true });
138
+ }
139
+ catch {
140
+ /* nothing was written */
141
+ }
142
+ return read();
143
+ }
144
+ //# sourceMappingURL=project-key.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-key.js","sourceRoot":"","sources":["../src/project-key.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Minimal copy of the ingest schema v1 (`@ai-obs/protocol`) for the collector. The collector has ZERO
3
+ * runtime dependencies, so it cannot import zod; test/protocol-conformance.test.ts type-checks these
4
+ * types against @ai-obs/protocol and validates builder output with its validateBatch().
5
+ */
6
+ export const SCHEMA_VERSION = 1;
7
+ export const MAX_BATCH_EVENTS = 500;
8
+ export const MAX_BATCH_BYTES = 1_000_000;
9
+ export const MAX_SUMMARY_LENGTH = 140;
10
+ export const MAX_USAGE_NAME_LENGTH = 128;
11
+ export const MAX_SKILLS_PER_EVENT = 100;
12
+ export const MAX_MCP_SERVERS_PER_EVENT = 50;
13
+ export const MAX_MCP_TOOLS_PER_SERVER = 100;
14
+ /** MCP latency bucket upper bounds (ms); the last of the 5 buckets is open. */
15
+ export const MCP_LATENCY_BUCKETS_MS = [1_000, 5_000, 30_000, 120_000];
16
+ /** Incoming links a run event may carry (ADR-0020). */
17
+ export const MAX_RUN_LINKS = 32;
18
+ /** Upper bound of `stage_index`. */
19
+ export const MAX_STAGE_INDEX = 10_000;
20
+ /** The one ingest token prefix: person and service users (ADR-0029). */
21
+ export const USER_TOKEN_PREFIX = 'aiobs_u_';
22
+ /** Retired prefixes (company `aiobs_c_`, team `aiobs_t_`): never accepted, kept to name them in messages and maskToken. */
23
+ export const RETIRED_TOKEN_PREFIXES = ['aiobs_c_', 'aiobs_t_'];
24
+ /** Team slug (dot file `team`, `session_start.project.team`): 1–63 of a-z0-9-. */
25
+ export const TEAM_SLUG_RE = /^[a-z0-9-]{1,63}$/;
26
+ /** Recursion guard for the collector's own summarizer child process (BRIEF §5.6). */
27
+ export const SUMMARIZING_ENV = 'AI_OBS_SUMMARIZING';
28
+ /** Reported phases. `delegating` is never reported: it is counted in the child run instead. */
29
+ export const PHASES = ['thinking', 'exploring', 'coding', 'documenting', 'testing', 'validating', 'other'];
30
+ //# sourceMappingURL=protocol-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol-types.js","sourceRoot":"","sources":["../src/protocol-types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAU,CAAC;AACzC,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAG,CAAC;AACpC,MAAM,CAAC,MAAM,eAAe,GAAG,SAAS,CAAC;AACzC,MAAM,CAAC,MAAM,kBAAkB,GAAG,GAAG,CAAC;AACtC,MAAM,CAAC,MAAM,qBAAqB,GAAG,GAAG,CAAC;AACzC,MAAM,CAAC,MAAM,oBAAoB,GAAG,GAAG,CAAC;AACxC,MAAM,CAAC,MAAM,yBAAyB,GAAG,EAAE,CAAC;AAC5C,MAAM,CAAC,MAAM,wBAAwB,GAAG,GAAG,CAAC;AAC5C,+EAA+E;AAC/E,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAU,CAAC;AAC/E,uDAAuD;AACvD,MAAM,CAAC,MAAM,aAAa,GAAG,EAAE,CAAC;AAChC,oCAAoC;AACpC,MAAM,CAAC,MAAM,eAAe,GAAG,MAAM,CAAC;AACtC,wEAAwE;AACxE,MAAM,CAAC,MAAM,iBAAiB,GAAG,UAAmB,CAAC;AACrD,2HAA2H;AAC3H,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,UAAU,EAAE,UAAU,CAAU,CAAC;AACxE,kFAAkF;AAClF,MAAM,CAAC,MAAM,YAAY,GAAG,mBAAmB,CAAC;AAChD,qFAAqF;AACrF,MAAM,CAAC,MAAM,eAAe,GAAG,oBAA6B,CAAC;AAE7D,+FAA+F;AAC/F,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,UAAU,EAAE,WAAW,EAAE,QAAQ,EAAE,aAAa,EAAE,SAAS,EAAE,YAAY,EAAE,OAAO,CAAU,CAAC"}