@scrylog/cli 0.3.0 → 0.3.1

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 (195) hide show
  1. package/dist/assets/highlights-eq9cgrbb.scm +604 -0
  2. package/dist/assets/highlights-ghv9g403.scm +205 -0
  3. package/dist/assets/highlights-hk7bwhj4.scm +284 -0
  4. package/dist/assets/highlights-r812a2qc.scm +150 -0
  5. package/dist/assets/highlights-x6tmsnaa.scm +115 -0
  6. package/dist/assets/injections-73j83es3.scm +27 -0
  7. package/dist/assets/parser.worker-xyhf83rf.js +4563 -0
  8. package/dist/assets/tree-sitter-3jzf13jk.wasm +0 -0
  9. package/dist/assets/tree-sitter-javascript-nd0q4pe9.wasm +0 -0
  10. package/dist/assets/tree-sitter-markdown-411r6y9b.wasm +0 -0
  11. package/dist/assets/tree-sitter-markdown_inline-j5349f42.wasm +0 -0
  12. package/dist/assets/tree-sitter-typescript-zxjzwt75.wasm +0 -0
  13. package/dist/assets/tree-sitter-zig-e78zbjpm.wasm +0 -0
  14. package/dist/cli/index.js +499 -0
  15. package/dist/cli/index.js.map +61 -0
  16. package/dist/daemon/index.js +670 -0
  17. package/dist/daemon/index.js.map +1475 -0
  18. package/dist/hooks/claude.js +6 -0
  19. package/dist/hooks/claude.js.map +11 -0
  20. package/dist/hooks/codex.js +10 -0
  21. package/dist/hooks/codex.js.map +11 -0
  22. package/dist/mcp/index.js +100 -0
  23. package/dist/mcp/index.js.map +231 -0
  24. package/dist/oc/index.js +21 -0
  25. package/dist/oc/index.js.map +10 -0
  26. package/package.json +16 -13
  27. package/src/api/docs/sessions.keys.ts +0 -6
  28. package/src/api/docs/sessions.ts +0 -82
  29. package/src/api/docs/system.keys.ts +0 -5
  30. package/src/api/docs/system.ts +0 -69
  31. package/src/api/docs/usage.keys.ts +0 -3
  32. package/src/api/docs/usage.ts +0 -24
  33. package/src/api/docs/webhooks.keys.ts +0 -5
  34. package/src/api/docs/webhooks.ts +0 -78
  35. package/src/api/index.ts +0 -18
  36. package/src/api/lib/auth.ts +0 -43
  37. package/src/api/lib/errors.ts +0 -28
  38. package/src/api/lib/route.ts +0 -18
  39. package/src/api/models/claude.ts +0 -4
  40. package/src/api/models/codex.ts +0 -4
  41. package/src/api/models/opencode.ts +0 -11
  42. package/src/api/routes/sessions.ts +0 -51
  43. package/src/api/routes/system.ts +0 -106
  44. package/src/api/routes/usage.ts +0 -15
  45. package/src/api/routes/webhooks/claude.ts +0 -149
  46. package/src/api/routes/webhooks/codex.ts +0 -175
  47. package/src/api/routes/webhooks/opencode.ts +0 -112
  48. package/src/api/routes.ts +0 -93
  49. package/src/api/schemas/common.ts +0 -29
  50. package/src/api/schemas/sessions.ts +0 -86
  51. package/src/api/schemas/usage.ts +0 -51
  52. package/src/api/schemas/webhooks/claude.ts +0 -32
  53. package/src/api/schemas/webhooks/codex.ts +0 -34
  54. package/src/api/schemas/webhooks/opencode.ts +0 -29
  55. package/src/api/services/claude-session.ts +0 -9
  56. package/src/api/services/codex-session.ts +0 -8
  57. package/src/api/services/opencode-session.ts +0 -73
  58. package/src/classifier.ts +0 -206
  59. package/src/cli/commands.ts +0 -714
  60. package/src/cli/index.ts +0 -18
  61. package/src/cli/program.ts +0 -175
  62. package/src/cli/prompt.ts +0 -44
  63. package/src/daemon/cli.ts +0 -27
  64. package/src/daemon/collectors/claude/README.md +0 -108
  65. package/src/daemon/collectors/claude/collector.ts +0 -423
  66. package/src/daemon/collectors/claude/discovery.ts +0 -127
  67. package/src/daemon/collectors/claude/hooks.ts +0 -181
  68. package/src/daemon/collectors/claude/index.ts +0 -8
  69. package/src/daemon/collectors/claude/jsonl.ts +0 -85
  70. package/src/daemon/collectors/claude/transcript.ts +0 -246
  71. package/src/daemon/collectors/codex/README.md +0 -147
  72. package/src/daemon/collectors/codex/collector.ts +0 -661
  73. package/src/daemon/collectors/codex/discovery.ts +0 -104
  74. package/src/daemon/collectors/codex/hooks.ts +0 -179
  75. package/src/daemon/collectors/codex/index.ts +0 -7
  76. package/src/daemon/collectors/codex/jsonl.ts +0 -108
  77. package/src/daemon/collectors/codex/transcript.ts +0 -299
  78. package/src/daemon/collectors/git.ts +0 -353
  79. package/src/daemon/collectors/herdr/collector.ts +0 -128
  80. package/src/daemon/collectors/herdr/index.ts +0 -2
  81. package/src/daemon/collectors/herdr/normalization.ts +0 -111
  82. package/src/daemon/collectors/opencode/README.md +0 -106
  83. package/src/daemon/collectors/opencode/collector.ts +0 -545
  84. package/src/daemon/collectors/opencode/discovery.ts +0 -257
  85. package/src/daemon/collectors/opencode/index.ts +0 -5
  86. package/src/daemon/collectors/opencode/session-builder.ts +0 -59
  87. package/src/daemon/collectors/opencode-db.ts +0 -294
  88. package/src/daemon/collectors/process.ts +0 -201
  89. package/src/daemon/collectors/tmux/README.md +0 -128
  90. package/src/daemon/collectors/tmux/collector.ts +0 -492
  91. package/src/daemon/collectors/tmux/enrichment.ts +0 -242
  92. package/src/daemon/collectors/tmux/index.ts +0 -4
  93. package/src/daemon/collectors/tmux/parse.ts +0 -128
  94. package/src/daemon/collectors/usage.ts +0 -259
  95. package/src/daemon/index.ts +0 -209
  96. package/src/daemon/scheduler.ts +0 -86
  97. package/src/daemon/store.ts +0 -630
  98. package/src/detect.ts +0 -143
  99. package/src/hooks/claude.ts +0 -596
  100. package/src/hooks/codex.ts +0 -517
  101. package/src/legacy/classifier.ts +0 -215
  102. package/src/legacy/detect.ts +0 -143
  103. package/src/mcp/client-server.ts +0 -21
  104. package/src/mcp/http-handler.ts +0 -126
  105. package/src/mcp/index.ts +0 -61
  106. package/src/mcp/resources/config-current.ts +0 -19
  107. package/src/mcp/resources/index.ts +0 -11
  108. package/src/mcp/resources/sessions-active.ts +0 -19
  109. package/src/mcp/resources/sessions-all.ts +0 -19
  110. package/src/mcp/schemas/sessions.ts +0 -3
  111. package/src/mcp/server.ts +0 -17
  112. package/src/mcp/services/api-adapter.ts +0 -48
  113. package/src/mcp/services/data-source.ts +0 -22
  114. package/src/mcp/services/store-adapter.ts +0 -40
  115. package/src/mcp/tools/get-active-sessions.ts +0 -16
  116. package/src/mcp/tools/get-session-children.ts +0 -24
  117. package/src/mcp/tools/get-session-messages.ts +0 -24
  118. package/src/mcp/tools/get-session.ts +0 -23
  119. package/src/mcp/tools/index.ts +0 -15
  120. package/src/mcp/tools/list-sessions.ts +0 -16
  121. package/src/oc/index.ts +0 -302
  122. package/src/service/manager.ts +0 -284
  123. package/src/shared/config.ts +0 -511
  124. package/src/shared/ipc.ts +0 -80
  125. package/src/shared/logger.ts +0 -248
  126. package/src/shared/paths.ts +0 -73
  127. package/src/shared/platform.ts +0 -110
  128. package/src/shared/session-exclusions.ts +0 -5
  129. package/src/shared/session-view.ts +0 -302
  130. package/src/shared/terminal-capabilities.ts +0 -130
  131. package/src/shared/types.ts +0 -330
  132. package/src/shared/utils.ts +0 -339
  133. package/src/shared/version.ts +0 -44
  134. package/src/tui/App.tsx +0 -240
  135. package/src/tui/client.ts +0 -163
  136. package/src/tui/components/BindingsModal.tsx +0 -82
  137. package/src/tui/components/DashboardHeader.tsx +0 -256
  138. package/src/tui/components/KeyBar.tsx +0 -67
  139. package/src/tui/components/SessionDetailModal.tsx +0 -169
  140. package/src/tui/components/SessionsView.tsx +0 -184
  141. package/src/tui/components/TabBar.tsx +0 -40
  142. package/src/tui/components/UsageSummaryPane.tsx +0 -272
  143. package/src/tui/components/UsageView.tsx +0 -242
  144. package/src/tui/components/tool-icons.ts +0 -24
  145. package/src/tui/index.tsx +0 -106
  146. package/src/tui/keybindings.ts +0 -49
  147. package/src/tui/model.ts +0 -295
  148. package/src/tui/state.ts +0 -77
  149. package/src/tui/theme.ts +0 -110
  150. package/src/types.ts +0 -113
  151. package/src/usage/README.md +0 -323
  152. package/src/usage/api.ts +0 -99
  153. package/src/usage/client.ts +0 -3
  154. package/src/usage/clients/anthropic-oauth-usage.ts +0 -258
  155. package/src/usage/clients/anthropic-web-usage.ts +0 -329
  156. package/src/usage/clients/claude-cli-probe.ts +0 -513
  157. package/src/usage/clients/codex-app-server.ts +0 -354
  158. package/src/usage/clients/codex-oauth-usage.ts +0 -240
  159. package/src/usage/clients/opencode-go-api.ts +0 -100
  160. package/src/usage/clients/opencode-go-usage.ts +0 -577
  161. package/src/usage/errors.ts +0 -33
  162. package/src/usage/index.ts +0 -20
  163. package/src/usage/local/opencode-go-local.ts +0 -194
  164. package/src/usage/mappers.ts +0 -282
  165. package/src/usage/planner.ts +0 -118
  166. package/src/usage/providers/claude.ts +0 -233
  167. package/src/usage/providers/codex.ts +0 -115
  168. package/src/usage/providers/opencode-go.ts +0 -115
  169. package/src/usage/resolver.ts +0 -4
  170. package/src/usage/resolvers/browser-cookies.ts +0 -808
  171. package/src/usage/resolvers/claude-auth.ts +0 -208
  172. package/src/usage/resolvers/claude-cli.ts +0 -24
  173. package/src/usage/resolvers/claude-desktop-auth.ts +0 -170
  174. package/src/usage/resolvers/claude-web.ts +0 -82
  175. package/src/usage/resolvers/codex-auth.ts +0 -174
  176. package/src/usage/resolvers/keychain-coordinator.ts +0 -397
  177. package/src/usage/resolvers/opencode-go-web.ts +0 -55
  178. package/src/usage/types.ts +0 -225
  179. package/src/usage/web-session-cache.ts +0 -37
  180. /package/{src/tui → dist/cli}/assets/providers/SOURCES.md +0 -0
  181. /package/{src/tui → dist/cli}/assets/providers/claude-terminal.png +0 -0
  182. /package/{src/tui → dist/cli}/assets/providers/claude-terminal.svg +0 -0
  183. /package/{src/tui → dist/cli}/assets/providers/claude.png +0 -0
  184. /package/{src/tui → dist/cli}/assets/providers/copilot.png +0 -0
  185. /package/{src/tui → dist/cli}/assets/providers/copilot.svg +0 -0
  186. /package/{src/tui → dist/cli}/assets/providers/openai-terminal.png +0 -0
  187. /package/{src/tui → dist/cli}/assets/providers/openai-terminal.svg +0 -0
  188. /package/{src/tui → dist/cli}/assets/providers/openai.png +0 -0
  189. /package/{src/tui → dist/cli}/assets/providers/opencode-terminal.png +0 -0
  190. /package/{src/tui → dist/cli}/assets/providers/opencode-terminal.svg +0 -0
  191. /package/{src/tui → dist/cli}/assets/providers/opencode.png +0 -0
  192. /package/{src/tui → dist/cli}/assets/providers/shell.png +0 -0
  193. /package/{src/tui → dist/cli}/assets/providers/shell.svg +0 -0
  194. /package/{src/tui → dist/cli}/assets/providers/unknown.png +0 -0
  195. /package/{src/tui → dist/cli}/assets/providers/unknown.svg +0 -0
@@ -1,104 +0,0 @@
1
- import { existsSync, readdirSync, statSync } from "node:fs";
2
- import { homedir } from "node:os";
3
- import { join, basename } from "node:path";
4
- import type { ScrylogConfig } from "../../../shared/config";
5
- import type { Logger } from "../../../shared/logger";
6
- import { maybeRunCommand } from "../../../shared/utils";
7
-
8
- export interface DiscoveredTranscript {
9
- sessionId: string;
10
- path: string;
11
- lastModified: number;
12
- size: number;
13
- }
14
-
15
- export function getCodexDir(config: ScrylogConfig): string {
16
- if (process.env.CODEX_HOME) return process.env.CODEX_HOME;
17
- return config.codex.codexDir ?? join(homedir(), ".codex");
18
- }
19
-
20
- export function discoverTranscripts(codexDir: string, hookManagedIds?: ReadonlySet<string>): DiscoveredTranscript[] {
21
- const results: DiscoveredTranscript[] = [];
22
- const cutoff = Date.now() - 24 * 60 * 60 * 1000;
23
-
24
- // Date-partitioned sessions: sessions/YYYY/MM/DD/*.jsonl
25
- const sessionsDir = join(codexDir, "sessions");
26
- if (existsSync(sessionsDir)) {
27
- try {
28
- for (const year of readdirSync(sessionsDir)) {
29
- const yearPath = join(sessionsDir, year);
30
- if (!statSync(yearPath).isDirectory()) continue;
31
- for (const month of readdirSync(yearPath)) {
32
- const monthPath = join(yearPath, month);
33
- if (!statSync(monthPath).isDirectory()) continue;
34
- for (const day of readdirSync(monthPath)) {
35
- const dayPath = join(monthPath, day);
36
- if (!statSync(dayPath).isDirectory()) continue;
37
- for (const file of readdirSync(dayPath)) {
38
- if (!file.endsWith(".jsonl")) continue;
39
- const fullPath = join(dayPath, file);
40
- try {
41
- const stat = statSync(fullPath);
42
- const sessionId = basename(file, ".jsonl");
43
- if (stat.mtimeMs < cutoff && !hookManagedIds?.has(sessionId)) continue;
44
- results.push({ sessionId, path: fullPath, lastModified: stat.mtimeMs, size: stat.size });
45
- } catch {
46
- // Skip unreadable files
47
- }
48
- }
49
- }
50
- }
51
- }
52
- } catch {
53
- // sessions dir not accessible
54
- }
55
- }
56
-
57
- // Archived sessions: archived_sessions/*.jsonl
58
- const archivedDir = join(codexDir, "archived_sessions");
59
- if (existsSync(archivedDir)) {
60
- try {
61
- for (const file of readdirSync(archivedDir)) {
62
- if (!file.endsWith(".jsonl")) continue;
63
- const fullPath = join(archivedDir, file);
64
- try {
65
- const stat = statSync(fullPath);
66
- const sessionId = basename(file, ".jsonl");
67
- if (stat.mtimeMs < cutoff && !hookManagedIds?.has(sessionId)) continue;
68
- results.push({ sessionId, path: fullPath, lastModified: stat.mtimeMs, size: stat.size });
69
- } catch {
70
- // Skip unreadable files
71
- }
72
- }
73
- } catch {
74
- // archived dir not accessible
75
- }
76
- }
77
-
78
- return results;
79
- }
80
-
81
- export function getCodexProcessPids(logger: Logger, timeoutMs?: number, processes?: { pid: number; command: string }[]): number[] {
82
- const result = maybeRunCommand(["pgrep", "-f", "codex"], timeoutMs);
83
- if (result.ok) {
84
- return result.output
85
- .split(/\r?\n/)
86
- .filter(Boolean)
87
- .map((s) => Number.parseInt(s, 10))
88
- .filter((n) => !Number.isNaN(n));
89
- }
90
-
91
- logger.debug("codex", "pgrep failed — falling back to process collector data", { error: result.error });
92
-
93
- if (processes && processes.length > 0) {
94
- return processes
95
- .filter((p) => isCodexProcessCommand(p.command))
96
- .map((p) => p.pid);
97
- }
98
-
99
- return [];
100
- }
101
-
102
- export function isCodexProcessCommand(command: string): boolean {
103
- return /(?:^|[\\/])codex(?:\.exe)?(?:\s|$)/i.test(command) && !/(scrylog|hook)/i.test(command);
104
- }
@@ -1,179 +0,0 @@
1
- import { existsSync, readFileSync } from "node:fs";
2
- import { join } from "node:path";
3
- import type { SessionModel, SessionState, CodexSessionMeta } from "../../../shared/types";
4
-
5
- export interface CodexHookFileData {
6
- eventType?: string;
7
- eventTime?: number;
8
- hookSeq?: number;
9
- state?: SessionState;
10
- hasAttention?: boolean;
11
- attentionKind?: "permission" | "question" | "turn" | "none";
12
- summary?: string;
13
- activeTool?: string;
14
- toolName?: string;
15
- toolInputSummary?: string;
16
- toolResultStatus?: "started" | "completed" | "error" | "blocked" | "denied" | "unknown";
17
- permissionMode?: string;
18
- startSource?: string;
19
- model?: string;
20
- endReason?: string;
21
- transcriptPath?: string;
22
- currentPath?: string;
23
- turnId?: string;
24
- agentId?: string;
25
- agentType?: string;
26
- lastActivity?: number;
27
- parentSessionId?: string;
28
- detectionSource?: "codex-hook";
29
- }
30
-
31
- export function isValidHookData(data: CodexHookFileData): boolean {
32
- return typeof data.eventType === "string"
33
- && data.eventType.length > 0
34
- && typeof data.eventTime === "number"
35
- && Number.isFinite(data.eventTime)
36
- && typeof data.hookSeq === "number"
37
- && Number.isFinite(data.hookSeq)
38
- && data.state !== undefined
39
- && typeof data.hasAttention === "boolean"
40
- && typeof data.attentionKind === "string";
41
- }
42
-
43
- export function readHookData(hooksDir: string, sessionId: string): Partial<SessionModel> | null {
44
- if (!existsSync(hooksDir)) return null;
45
- const hookFile = join(hooksDir, `${sessionId}.json`);
46
- if (!existsSync(hookFile)) return null;
47
- try {
48
- const raw = readFileSync(hookFile, "utf8");
49
- const data = JSON.parse(raw) as CodexHookFileData;
50
- if (!isValidHookData(data)) return null;
51
- return {
52
- ...(data.state !== undefined ? { state: data.state } : {}),
53
- ...(data.hasAttention !== undefined ? { hasAttention: data.hasAttention } : {}),
54
- ...(data.summary !== undefined ? { summary: data.summary } : {}),
55
- ...(data.activeTool !== undefined ? { activeTool: data.activeTool } : {}),
56
- ...(data.currentPath !== undefined ? { currentPath: data.currentPath } : {}),
57
- ...(data.lastActivity !== undefined ? { lastActivity: data.lastActivity } : {}),
58
- ...(data.parentSessionId !== undefined ? { parentSessionId: data.parentSessionId } : {}),
59
- ...(data.detectionSource !== undefined ? { detectionSource: data.detectionSource } : {}),
60
- codex: {
61
- sessionId,
62
- transcriptPath: data.transcriptPath ?? "",
63
- ...(data.eventType !== undefined ? { hookEventType: data.eventType } : {}),
64
- ...(data.eventTime !== undefined ? { hookEventTime: data.eventTime } : {}),
65
- ...(data.hookSeq !== undefined ? { hookSeq: data.hookSeq } : {}),
66
- ...(data.permissionMode !== undefined ? { permissionMode: data.permissionMode } : {}),
67
- ...(data.startSource !== undefined ? { startSource: data.startSource } : {}),
68
- ...(data.model !== undefined ? { model: data.model } : {}),
69
- ...(data.endReason !== undefined ? { endReason: data.endReason } : {}),
70
- ...(data.toolName !== undefined ? { toolName: data.toolName } : {}),
71
- ...(data.toolInputSummary !== undefined ? { toolInputSummary: data.toolInputSummary } : {}),
72
- ...(data.toolResultStatus !== undefined ? { toolResultStatus: data.toolResultStatus } : {}),
73
- ...(data.agentId !== undefined ? { agentId: data.agentId } : {}),
74
- ...(data.agentType !== undefined ? { agentType: data.agentType } : {}),
75
- ...(data.turnId !== undefined ? { turnId: data.turnId } : {}),
76
- ...(data.parentSessionId !== undefined ? { parentSessionId: data.parentSessionId } : {}),
77
- },
78
- };
79
- } catch {
80
- return null;
81
- }
82
- }
83
-
84
- export function isHookNewer(existing: SessionModel | undefined, hookData: Partial<SessionModel>): boolean {
85
- const incomingSeq = hookData.codex?.hookSeq;
86
- const existingSeq = existing?.codex?.hookSeq;
87
- if (typeof incomingSeq === "number" && typeof existingSeq === "number") {
88
- return incomingSeq >= existingSeq;
89
- }
90
-
91
- const incomingTime = hookData.codex?.hookEventTime ?? hookData.lastActivity ?? 0;
92
- const existingTime = existing?.codex?.hookEventTime ?? existing?.lastActivity ?? 0;
93
- return incomingTime >= existingTime;
94
- }
95
-
96
- export function getHookTime(session: Partial<SessionModel> | undefined): number {
97
- return session?.codex?.hookEventTime ?? session?.lastActivity ?? 0;
98
- }
99
-
100
- export function getExistingHookData(existing: SessionModel | undefined): Partial<SessionModel> | null {
101
- if (!existing) return null;
102
- if (existing.detectionSource !== "codex-hook") return null;
103
- if (!existing.codex?.hookEventType || typeof existing.codex.hookEventTime !== "number" || typeof existing.codex.hookSeq !== "number") {
104
- return null;
105
- }
106
-
107
- return {
108
- state: existing.state,
109
- hasAttention: existing.hasAttention,
110
- summary: existing.summary,
111
- activeTool: existing.activeTool,
112
- currentPath: existing.currentPath,
113
- lastActivity: existing.lastActivity,
114
- parentSessionId: existing.parentSessionId,
115
- detectionSource: "codex-hook",
116
- codex: {
117
- sessionId: existing.codex.sessionId,
118
- transcriptPath: existing.codex.transcriptPath,
119
- hookEventType: existing.codex.hookEventType,
120
- hookEventTime: existing.codex.hookEventTime,
121
- hookSeq: existing.codex.hookSeq,
122
- ...(existing.codex.permissionMode ? { permissionMode: existing.codex.permissionMode } : {}),
123
- ...(existing.codex.startSource ? { startSource: existing.codex.startSource } : {}),
124
- ...(existing.codex.model ? { model: existing.codex.model } : {}),
125
- ...(existing.codex.endReason ? { endReason: existing.codex.endReason } : {}),
126
- ...(existing.codex.toolName ? { toolName: existing.codex.toolName } : {}),
127
- ...(existing.codex.toolInputSummary ? { toolInputSummary: existing.codex.toolInputSummary } : {}),
128
- ...(existing.codex.toolResultStatus ? { toolResultStatus: existing.codex.toolResultStatus } : {}),
129
- ...(existing.codex.agentId ? { agentId: existing.codex.agentId } : {}),
130
- ...(existing.codex.agentType ? { agentType: existing.codex.agentType } : {}),
131
- ...(existing.codex.parentSessionId ? { parentSessionId: existing.codex.parentSessionId } : {}),
132
- ...(existing.codex.forkedFromId ? { forkedFromId: existing.codex.forkedFromId } : {}),
133
- },
134
- };
135
- }
136
-
137
- const MERGEABLE_FIELDS: (keyof CodexSessionMeta)[] = [
138
- "hookEventType", "hookEventTime", "hookSeq",
139
- "permissionMode", "startSource", "endReason",
140
- "toolName", "toolInputSummary", "toolResultStatus",
141
- "model", "parentSessionId", "forkedFromId",
142
- "turnId", "attentionKind", "agentId", "agentType", "agentNickname", "agentRole",
143
- ];
144
-
145
- export function mergeCodexMeta(
146
- base: CodexSessionMeta,
147
- incoming: Partial<CodexSessionMeta>,
148
- ): CodexSessionMeta {
149
- const result = { ...base };
150
- for (const key of MERGEABLE_FIELDS) {
151
- if (incoming[key] !== undefined) {
152
- (result as Record<string, unknown>)[key] = incoming[key];
153
- }
154
- }
155
- return result;
156
- }
157
-
158
- export function mergeHookIntoModel(model: SessionModel, hookData: Partial<SessionModel>, transcriptPath: string): SessionModel {
159
- const hookCodex = hookData.codex ?? { sessionId: model.codex?.sessionId ?? model.id.replace(/^codex:/, ""), transcriptPath };
160
- return {
161
- ...model,
162
- ...hookData,
163
- state: (hookData.state as SessionState | undefined) ?? model.state,
164
- hasAttention: hookData.hasAttention ?? model.hasAttention,
165
- id: model.id,
166
- source: model.source,
167
- summary: hookData.summary ?? model.summary,
168
- lastActivity: typeof hookData.lastActivity === "number" ? hookData.lastActivity : model.lastActivity,
169
- activeTool: hookData.activeTool ?? model.activeTool,
170
- detectionSource: "codex-hook",
171
- codex: mergeCodexMeta(
172
- {
173
- sessionId: hookCodex.sessionId ?? model.codex?.sessionId ?? model.id.replace(/^codex:/, ""),
174
- transcriptPath: hookCodex.transcriptPath || transcriptPath,
175
- },
176
- hookCodex,
177
- ),
178
- };
179
- }
@@ -1,7 +0,0 @@
1
- export { CodexCollector } from "./collector";
2
- export type { CodexHookFileData } from "./hooks";
3
-
4
- // Test-accessible pure functions (not part of collector public API,
5
- // but exported for direct unit testing without replicating logic)
6
- export { extractMeta } from "./transcript";
7
- export { mergeCodexMeta } from "./hooks";
@@ -1,108 +0,0 @@
1
- import { closeSync, openSync, readFileSync, readSync, statSync } from "node:fs";
2
-
3
- export interface CodexJsonlEntry {
4
- type?: string;
5
- timestamp?: string;
6
- model?: string;
7
- payload?: Record<string, unknown>;
8
- session_id?: string;
9
- sessionId?: string;
10
- id?: string;
11
- }
12
-
13
- export interface CodexResponseItem extends CodexJsonlEntry {
14
- type: "response_item";
15
- payload: {
16
- type: string;
17
- role?: string;
18
- name?: string;
19
- content?: unknown;
20
- phase?: string;
21
- [key: string]: unknown;
22
- };
23
- }
24
-
25
- export interface CodexEventMsg extends CodexJsonlEntry {
26
- type: "event_msg";
27
- payload: {
28
- type: string;
29
- message?: string;
30
- [key: string]: unknown;
31
- };
32
- }
33
-
34
- export function isResponseItem(entry: CodexJsonlEntry): entry is CodexResponseItem {
35
- return entry.type === "response_item";
36
- }
37
-
38
- export function isEventMsg(entry: CodexJsonlEntry): entry is CodexEventMsg {
39
- return entry.type === "event_msg";
40
- }
41
-
42
- export function getResponseItemText(item: CodexResponseItem): string | undefined {
43
- const content = item.payload.content;
44
- if (!Array.isArray(content)) return undefined;
45
- for (const block of content) {
46
- if (
47
- typeof block === "object" && block !== null
48
- && ("type" in block)
49
- && (
50
- (block as { type: string }).type === "output_text"
51
- || (block as { type: string }).type === "input_text"
52
- )
53
- && typeof (block as { text?: string }).text === "string"
54
- ) {
55
- return (block as { text: string }).text;
56
- }
57
- }
58
- return undefined;
59
- }
60
-
61
- export function getResponseItemRole(item: CodexResponseItem): string | undefined {
62
- return item.payload.role;
63
- }
64
-
65
- export function getFunctionCallName(item: CodexResponseItem): string | undefined {
66
- if (item.payload.type !== "function_call") return undefined;
67
- return typeof item.payload.name === "string" ? item.payload.name : undefined;
68
- }
69
-
70
- export function parseJsonlFile(path: string, maxBytes?: number): CodexJsonlEntry[] {
71
- try {
72
- const content = readTextTail(path, maxBytes);
73
- return parseJsonlContent(content);
74
- } catch {
75
- return [];
76
- }
77
- }
78
-
79
- export function parseJsonlContent(content: string): CodexJsonlEntry[] {
80
- return content
81
- .split(/\r?\n/)
82
- .filter(Boolean)
83
- .map((line) => {
84
- try {
85
- return JSON.parse(line) as CodexJsonlEntry;
86
- } catch {
87
- return null;
88
- }
89
- })
90
- .filter((entry): entry is CodexJsonlEntry => entry !== null);
91
- }
92
-
93
- export function readTextTail(path: string, maxBytes?: number): string {
94
- if (!maxBytes || maxBytes <= 0) return readFileSync(path, "utf8");
95
- const stat = statSync(path);
96
- if (stat.size <= maxBytes) return readFileSync(path, "utf8");
97
-
98
- const fd = openSync(path, "r");
99
- try {
100
- const buffer = Buffer.allocUnsafe(maxBytes);
101
- readSync(fd, buffer, 0, maxBytes, stat.size - maxBytes);
102
- const text = buffer.toString("utf8");
103
- const firstNewline = text.indexOf("\n");
104
- return firstNewline >= 0 ? text.slice(firstNewline + 1) : text;
105
- } finally {
106
- closeSync(fd);
107
- }
108
- }