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/bin/ai-obs.js ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+ // HARD RULE (BRIEF §5.6): the collector's own summarizer runs a headless harness with
3
+ // AI_OBS_SUMMARIZING=1; every hook invocation inside it must exit immediately, before any work,
4
+ // or summarizing would recurse. Keep this the first statement of the entry file.
5
+ if (process.env.AI_OBS_SUMMARIZING) process.exit(0);
6
+
7
+ const { main } = await import('../dist/cli.js');
8
+ process.exitCode = await main(process.argv.slice(2));
@@ -0,0 +1,189 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { addPhaseTotals, attributeTime, emptyPhaseTotals } from '../../analysis/phases.js';
3
+ import { mergeUsage, sumUsage } from '../../analysis/tokens.js';
4
+ import { addMcp, addMcpResult, addSkill, mergeMcp, mergeMcpStats, mergeSkills, parseMcpTool } from '../../analysis/usage.js';
5
+ import { toolKey } from '../../events.js';
6
+ /** Stored caps: state files stay small even for very long sessions. */
7
+ const MAX_IDS = 400;
8
+ const MAX_FP = 1000;
9
+ const MAX_FILE_KEYS = 500;
10
+ /** `agentCalls` key of a Workflow launch (its sub-agents are linked to the key, not to a tool_use id). */
11
+ export const workflowKey = (runId) => `wf:${runId}`;
12
+ export const isWorkflowKey = (key) => typeof key === 'string' && key.startsWith('wf:');
13
+ const pathKey = (p) => createHash('sha256').update(p).digest('base64url').slice(0, 16);
14
+ const uniqCap = (xs, cap) => [...new Set(xs)].slice(-cap);
15
+ export function emptyAgg(at) {
16
+ return {
17
+ startedAt: at,
18
+ endedAt: at,
19
+ usage: [],
20
+ responseIds: [],
21
+ phases: emptyPhaseTotals(),
22
+ tools: {},
23
+ skills: {},
24
+ mcp: {},
25
+ mcpStats: {},
26
+ toolNames: [],
27
+ fileKeys: [],
28
+ linesAdded: 0,
29
+ linesRemoved: 0,
30
+ fp: { added: [], removed: [] },
31
+ interrupted: false,
32
+ lastCheck: null,
33
+ agentCalls: {},
34
+ lastMessage: '',
35
+ active: false,
36
+ };
37
+ }
38
+ /**
39
+ * Analyzes entries of one stretch in transcript order. Tokens: usage per assistant entry, de-duplicated
40
+ * per API response (Claude Code writes one entry per content block, each repeating the usage). Phases:
41
+ * the shared time-attribution rules over prompt / output / tool_call / tool_result moments.
42
+ */
43
+ export function analyzeEntries(entries, opts = {}) {
44
+ const first = entries[0];
45
+ const start = opts.startAt ?? first?.at ?? 0;
46
+ const agg = emptyAgg(start);
47
+ const timeline = [{ at: start, type: 'prompt' }];
48
+ const records = [];
49
+ const toolNames = [];
50
+ const toolCalls = [];
51
+ const pendingEdits = new Map();
52
+ const checks = new Map();
53
+ /** open MCP calls by tool_use id, paired with their result for errors and latency */
54
+ const mcpCalls = new Map();
55
+ const files = new Set();
56
+ const fpAdded = [];
57
+ const fpRemoved = [];
58
+ let end = start;
59
+ /** a typed slash command waiting for its expansion (only skills / custom commands have one) */
60
+ let command = null;
61
+ for (const e of entries) {
62
+ if (e.k === 'stop')
63
+ continue;
64
+ // A command's expansion is written with the prompt; it is not activity and does not move the turn's end.
65
+ if (e.k === 'expansion') {
66
+ if (command)
67
+ addSkill(agg.skills, command, 'user');
68
+ command = null;
69
+ continue;
70
+ }
71
+ end = Math.max(end, e.at);
72
+ if (e.k === 'prompt') {
73
+ if (e.at > start)
74
+ timeline.push({ at: e.at, type: 'prompt' });
75
+ command = e.command;
76
+ continue;
77
+ }
78
+ if (e.k === 'interrupt') {
79
+ agg.interrupted = true;
80
+ timeline.push({ at: e.at, type: 'output' });
81
+ continue;
82
+ }
83
+ if (e.k === 'assistant') {
84
+ agg.active = true;
85
+ command = null;
86
+ if (e.usage && !(e.usage.responseId && opts.skipResponseIds?.has(e.usage.responseId)))
87
+ records.push(e.usage);
88
+ for (const b of e.blocks) {
89
+ if (b.t === 'output') {
90
+ timeline.push({ at: e.at, type: 'output' });
91
+ if (b.text?.trim())
92
+ agg.lastMessage = b.text;
93
+ continue;
94
+ }
95
+ timeline.push({ at: e.at, type: 'tool_call', id: b.id, phase: b.phase });
96
+ toolCalls.push(b.name);
97
+ toolNames.push(b.name);
98
+ if (b.skill)
99
+ addSkill(agg.skills, b.skill, 'model');
100
+ const mcp = parseMcpTool(b.name);
101
+ if (mcp) {
102
+ addMcp(agg.mcp, mcp.server, mcp.tool);
103
+ if (b.id)
104
+ mcpCalls.set(b.id, { ...mcp, at: e.at });
105
+ }
106
+ if (b.edit && b.filePath)
107
+ pendingEdits.set(b.id, { filePath: b.filePath, estimate: b.edit.fp, added: b.edit.added, removed: b.edit.removed });
108
+ if (b.phase === 'testing' || b.phase === 'validating')
109
+ checks.set(b.id, b.phase);
110
+ if (b.agent)
111
+ agg.agentCalls[b.id] = { type: b.agent.type, background: b.agent.background, completed: false };
112
+ }
113
+ continue;
114
+ }
115
+ if (e.userInterrupt)
116
+ agg.interrupted = true;
117
+ for (const r of e.results) {
118
+ timeline.push({ at: e.at, type: 'tool_result', id: r.id });
119
+ applyResult(r, e.at);
120
+ }
121
+ }
122
+ function applyResult(r, at) {
123
+ const call = mcpCalls.get(r.id);
124
+ if (call) {
125
+ addMcpResult(agg.mcpStats, call.server, call.tool, { error: r.isError, denied: r.denied, ms: at - call.at });
126
+ mcpCalls.delete(r.id);
127
+ }
128
+ const edit = pendingEdits.get(r.id);
129
+ if (edit && !r.isError) {
130
+ const exact = r.edit;
131
+ agg.linesAdded += exact ? exact.added : edit.added;
132
+ agg.linesRemoved += exact ? exact.removed : edit.removed;
133
+ const fp = exact?.fp ?? edit.estimate;
134
+ if (fp) {
135
+ fpAdded.push(...fp.added);
136
+ fpRemoved.push(...fp.removed);
137
+ }
138
+ files.add(pathKey(edit.filePath));
139
+ }
140
+ pendingEdits.delete(r.id);
141
+ const kind = checks.get(r.id);
142
+ if (kind && r.exitCode !== null && !r.interrupted)
143
+ agg.lastCheck = { kind, exitCode: r.exitCode };
144
+ if (r.workflowRunId)
145
+ agg.agentCalls[workflowKey(r.workflowRunId)] = { type: 'workflow', background: true, completed: false };
146
+ const agent = agg.agentCalls[r.id];
147
+ if (agent)
148
+ agent.completed = !r.isError && r.agentStatus !== 'async_launched' && !agent.background;
149
+ }
150
+ agg.endedAt = end;
151
+ agg.phases = attributeTime(timeline, end);
152
+ agg.usage = sumUsage(records);
153
+ agg.responseIds = uniqCap(records.flatMap((r) => (r.responseId ? [r.responseId] : [])), MAX_IDS);
154
+ for (const n of toolCalls)
155
+ agg.tools[toolKey(n)] = (agg.tools[toolKey(n)] ?? 0) + 1;
156
+ agg.toolNames = [...new Set(toolNames)].slice(0, 30);
157
+ agg.fileKeys = uniqCap(files, MAX_FILE_KEYS);
158
+ agg.fp = { added: uniqCap(fpAdded, MAX_FP), removed: uniqCap(fpRemoved, MAX_FP) };
159
+ return agg;
160
+ }
161
+ /** Adds a later stretch (continuation) to an earlier one. */
162
+ export function mergeAgg(a, b) {
163
+ const tools = { ...a.tools };
164
+ for (const [k, v] of Object.entries(b.tools))
165
+ tools[k] = (tools[k] ?? 0) + v;
166
+ const calls = { ...a.agentCalls, ...b.agentCalls };
167
+ return {
168
+ startedAt: Math.min(a.startedAt, b.startedAt),
169
+ endedAt: Math.max(a.endedAt, b.endedAt),
170
+ usage: mergeUsage(a.usage, b.usage),
171
+ responseIds: uniqCap([...a.responseIds, ...b.responseIds], MAX_IDS),
172
+ phases: addPhaseTotals(a.phases, b.phases),
173
+ tools,
174
+ skills: mergeSkills(a.skills, b.skills),
175
+ mcp: mergeMcp(a.mcp, b.mcp),
176
+ mcpStats: mergeMcpStats(a.mcpStats, b.mcpStats),
177
+ toolNames: [...new Set([...a.toolNames, ...b.toolNames])].slice(0, 30),
178
+ fileKeys: uniqCap([...a.fileKeys, ...b.fileKeys], MAX_FILE_KEYS),
179
+ linesAdded: a.linesAdded + b.linesAdded,
180
+ linesRemoved: a.linesRemoved + b.linesRemoved,
181
+ fp: { added: uniqCap([...a.fp.added, ...b.fp.added], MAX_FP), removed: uniqCap([...a.fp.removed, ...b.fp.removed], MAX_FP) },
182
+ interrupted: a.interrupted || b.interrupted,
183
+ lastCheck: b.lastCheck ?? a.lastCheck,
184
+ agentCalls: calls,
185
+ lastMessage: b.lastMessage || a.lastMessage,
186
+ active: a.active || b.active,
187
+ };
188
+ }
189
+ //# sourceMappingURL=analyze.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyze.js","sourceRoot":"","sources":["../../../src/adapters/claude-code/analyze.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ import { execFile } from 'node:child_process';
2
+ import { existsSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ import { readJsonFile, writeJsonAtomic } from '../../fsutil.js';
5
+ import { compareVersions } from '../../version.js';
6
+ import { hooksDisabledAt, hooksInstalledAt, settingsPath } from './settings.js';
7
+ /** Oldest version whose hooks / transcript format this adapter was built against (FORMAT.md). */
8
+ export const MIN_SUPPORTED_VERSION = '2.1.0';
9
+ const VERSION_TTL_MS = 6 * 3600_000;
10
+ /** `claude --version` → "2.1.289" (null when the binary is missing or silent). */
11
+ export const probeClaudeVersion = () => new Promise((resolve) => {
12
+ try {
13
+ execFile('claude', ['--version'], { timeout: 10_000, windowsHide: true, env: { ...process.env, AI_OBS_SUMMARIZING: '1' } }, (err, stdout) => {
14
+ if (err)
15
+ return resolve(null);
16
+ resolve(/(\d+\.\d+\.\d+)/.exec(String(stdout))?.[1] ?? null);
17
+ });
18
+ }
19
+ catch {
20
+ resolve(null);
21
+ }
22
+ });
23
+ /**
24
+ * Version for session_start events, cached in <state>/claude-code.version.json for a few hours, so
25
+ * the worker does not start the claude binary on every SessionStart.
26
+ */
27
+ export async function cachedVersion(stateDir, probe, now) {
28
+ const file = join(stateDir, 'claude-code.version.json');
29
+ const cached = readJsonFile(file);
30
+ if (cached && now - cached.at < VERSION_TTL_MS && cached.version)
31
+ return cached.version;
32
+ const version = await probe();
33
+ try {
34
+ writeJsonAtomic(file, { version, at: now });
35
+ }
36
+ catch {
37
+ /* cache only */
38
+ }
39
+ return version;
40
+ }
41
+ export async function detectClaudeCode(opts) {
42
+ const version = await opts.probe().catch(() => null);
43
+ const userSettings = settingsPath('user', { claudeDir: opts.claudeDir });
44
+ const installed = version !== null || existsSync(opts.claudeDir);
45
+ const projectSettings = opts.projectDir ? settingsPath('project', { projectDir: opts.projectDir }) : null;
46
+ const notes = [];
47
+ if (version === null && installed)
48
+ notes.push('`claude` not found on PATH; hooks will only fire once Claude Code is installed');
49
+ if (hooksDisabledAt(userSettings) || (projectSettings && hooksDisabledAt(projectSettings)))
50
+ notes.push('disableAllHooks is set; no hooks run');
51
+ return {
52
+ installed,
53
+ version,
54
+ versionSupported: version ? compareVersions(version, MIN_SUPPORTED_VERSION) >= 0 : null,
55
+ hooksInstalled: { user: hooksInstalledAt(userSettings), project: projectSettings ? hooksInstalledAt(projectSettings) : null },
56
+ configPath: userSettings,
57
+ ...(notes.length ? { notes } : {}),
58
+ };
59
+ }
60
+ //# sourceMappingURL=detect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect.js","sourceRoot":"","sources":["../../../src/adapters/claude-code/detect.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,183 @@
1
+ import { statSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { looksLikeCorrection } from '../../analysis/corrections.js';
4
+ import { summariesDue } from '../../analysis/summaries.js';
5
+ import { sessionEndEvent, sessionStartEvent, turnStartedEvent } from '../../events.js';
6
+ import { cachedVersion } from './detect.js';
7
+ import { collectWorkflowRuns, emitSessionTitle, Emitter, flushOpenRuns, followUpTurns, processTranscript, settleLastTurn, settleTurns, subagentFailed, subagentFinished, } from './session.js';
8
+ import { evictedUnsettledTurns, loadSession, newSessionState, saveSession } from './state.js';
9
+ /** A session silent for this long without SessionEnd is considered crashed. */
10
+ export const CRASH_AFTER_MS = 24 * 3600_000;
11
+ /** Ended sessions' state is kept this long (a resumed session continues from its cursor). */
12
+ export const KEEP_ENDED_MS = 30 * 24 * 3600_000;
13
+ const str = (v) => (typeof v === 'string' && v ? v : null);
14
+ /** A transcript prompt matched by time is at most this long before the UserPromptSubmit hook fired … */
15
+ export const PROMPT_MATCH_BEFORE_MS = 10_000;
16
+ /** … and at most this long after it. */
17
+ export const PROMPT_MATCH_AFTER_MS = 1_000;
18
+ /** Whether a transcript prompt is the one this UserPromptSubmit announced: prompt_id = promptId when both exist, else by time. */
19
+ export function isHookPrompt(p, promptId, receivedAt) {
20
+ if (promptId && p.promptId)
21
+ return p.promptId === promptId;
22
+ return p.at >= receivedAt - PROMPT_MATCH_BEFORE_MS && p.at <= receivedAt + PROMPT_MATCH_AFTER_MS;
23
+ }
24
+ /** Where Claude Code keeps a session transcript when the payload does not say. */
25
+ export function defaultTranscriptPath(claudeDir, cwd, sessionId) {
26
+ return join(claudeDir, 'projects', cwd.replace(/[^A-Za-z0-9]/g, '-'), `${sessionId}.jsonl`);
27
+ }
28
+ function fileSize(path) {
29
+ try {
30
+ return statSync(path).size;
31
+ }
32
+ catch {
33
+ return 0;
34
+ }
35
+ }
36
+ export async function handleHook(event, ctx, deps) {
37
+ const p = (event.payload && typeof event.payload === 'object' ? event.payload : {});
38
+ const sessionId = str(p.session_id);
39
+ if (!sessionId) {
40
+ ctx.log.warn('claude-code: hook without session_id', { hook: event.hook });
41
+ return;
42
+ }
43
+ const receivedAt = Number.isFinite(Date.parse(event.receivedAt)) ? Date.parse(event.receivedAt) : ctx.now().getTime();
44
+ const transcriptPath = str(p.transcript_path) ?? defaultTranscriptPath(deps.claudeDir, event.cwd, sessionId);
45
+ let st = loadSession(ctx.state, sessionId);
46
+ if (!st) {
47
+ st = newSessionState(sessionId, transcriptPath, event.cwd, receivedAt);
48
+ // A resumed / compacted / forked session we never saw: do not back-fill its history. A fork's
49
+ // transcript starts with a copy of the parent conversation, already counted under the parent.
50
+ if (event.hook === 'SessionStart' && (p.source === 'resume' || p.source === 'compact' || p.source === 'fork')) {
51
+ st.offset = fileSize(transcriptPath);
52
+ }
53
+ }
54
+ else {
55
+ st.transcriptPath = transcriptPath;
56
+ st.pkCwd ??= st.cwd; // state written by 0.1.x: pin the session's own cwd before it is overwritten
57
+ st.cwd = event.cwd;
58
+ }
59
+ if (st.ended && event.hook !== 'SessionEnd')
60
+ st.ended = false; // resumed
61
+ st.lastSeen = Math.max(st.lastSeen, receivedAt);
62
+ const em = new Emitter(ctx.harness, st);
63
+ // Turn-scoped hooks fired inside a sub-agent carry `agent_id`: they are not about the main turn.
64
+ const subagent = str(p.agent_id);
65
+ switch (event.hook) {
66
+ case 'UserPromptSubmit': {
67
+ if (subagent)
68
+ break;
69
+ const promptId = str(p.prompt_id);
70
+ const own = (q) => isHookPrompt(q, promptId, receivedAt);
71
+ const { prompts } = processTranscript(em, { mode: 'prompt', receivedAt, ownPrompt: own });
72
+ const prompt = typeof p.prompt === 'string' ? p.prompt : null;
73
+ if (prompt !== null) {
74
+ const human = !/^\s*<task-notification>/.test(prompt);
75
+ followUpTurns(em, { human, correction: human && looksLikeCorrection(prompt), revertOf: () => false }, receivedAt);
76
+ }
77
+ // live status (ADR-0027): the session is working until this turn's `turn` arrives
78
+ em.events.push(turnStartedEvent({ harness: ctx.harness, sessionId, turnId: prompts.filter(own).at(-1)?.uuid ?? null, startedAt: receivedAt }));
79
+ break;
80
+ }
81
+ case 'Stop':
82
+ if (subagent)
83
+ break;
84
+ processTranscript(em, { mode: 'stop', receivedAt });
85
+ break;
86
+ case 'StopFailure':
87
+ // An API error inside a sub-agent fails that run only; the main turn keeps running.
88
+ if (subagent)
89
+ subagentFailed(em, subagent);
90
+ else
91
+ processTranscript(em, { mode: 'stop', receivedAt, stopFailure: true });
92
+ break;
93
+ case 'SubagentStop': {
94
+ const agentId = str(p.agent_id);
95
+ if (agentId)
96
+ subagentFinished(em, agentId);
97
+ break;
98
+ }
99
+ case 'SessionEnd':
100
+ endSession(em, str(p.reason) ?? 'other', receivedAt);
101
+ break;
102
+ default:
103
+ break; // SessionStart: only session_start below
104
+ }
105
+ if (event.hook !== 'SessionEnd')
106
+ collectWorkflowRuns(em);
107
+ if (!st.startedSent) {
108
+ const firstTurn = st.turns[0]?.agg.startedAt;
109
+ const at = firstTurn !== undefined ? Math.min(firstTurn, receivedAt) : receivedAt;
110
+ const harnessVersion = await cachedVersion(ctx.paths.state, deps.probe, ctx.now().getTime());
111
+ const project = await ctx.projectKey(st.pkCwd ?? st.cwd);
112
+ em.events.unshift(sessionStartEvent({ harness: ctx.harness, sessionId, at, harnessVersion, project }));
113
+ st.startedSent = true;
114
+ }
115
+ await finish(em, ctx, receivedAt);
116
+ }
117
+ /** Ends a session: remaining turns, open sub-agents, final outcome of every unsettled turn, session_end. */
118
+ function endSession(em, reason, at) {
119
+ processTranscript(em, { mode: 'end', receivedAt: at });
120
+ flushOpenRuns(em);
121
+ const lastActivity = em.state.turns.at(-1)?.agg.endedAt ?? 0;
122
+ const endAt = Math.max(at, lastActivity);
123
+ settleLastTurn(em, endAt);
124
+ em.events.push(sessionEndEvent({ harness: em.harness, sessionId: em.state.sessionId, reason, at: endAt }));
125
+ em.state.ended = true;
126
+ }
127
+ /**
128
+ * Enqueue into the session's stream (pinned at its first hook, which always carries `session_start`;
129
+ * `capturedAt` = that job's received_at; C12, C15), hand the waiting turns to the summariser when they are
130
+ * due (session over, 10 waiting, or the first has waited 10 minutes; ADR-0023), then save the cursor and the
131
+ * pin. The digests are staged durably before the state forgets them; the worker summarises them after its
132
+ * flush, so a slow summary never delays the next hook's events (ADR-0027).
133
+ */
134
+ async function finish(em, ctx, capturedAt) {
135
+ const st = em.state;
136
+ // Turns about to fall out of the state file never see a follow-up: settle them now.
137
+ settleTurns(em, evictedUnsettledTurns(st), st.lastSeen);
138
+ emitSessionTitle(em);
139
+ if (st.digests.length > 0 && st.digestsSince === undefined)
140
+ st.digestsSince = capturedAt;
141
+ const summarize = summariesDue({ ended: st.ended, pending: st.digests.length, since: st.digestsSince, now: capturedAt });
142
+ const key = em.events.length || summarize ? await ctx.streamFor(st, capturedAt) : null;
143
+ if (em.events.length)
144
+ ctx.queue.enqueue(em.events, key);
145
+ // durable before the state forgets them (ADR-0027); the worker summarises after its flush
146
+ if (summarize && ctx.scheduleSummaries(st.digests, key)) {
147
+ st.digests = [];
148
+ delete st.digestsSince;
149
+ }
150
+ saveSession(ctx.state, st);
151
+ }
152
+ /** SessionStart sweep: sessions silent for 24 h without SessionEnd get session_end "crashed". */
153
+ export async function sweepCrashedSessions(ctx) {
154
+ const now = ctx.now().getTime();
155
+ for (const { sessionId, updatedAt } of ctx.state.list()) {
156
+ if (now - updatedAt < CRASH_AFTER_MS)
157
+ continue;
158
+ let st;
159
+ try {
160
+ st = loadSession(ctx.state, sessionId);
161
+ }
162
+ catch {
163
+ st = null;
164
+ }
165
+ if (!st)
166
+ continue;
167
+ if (st.ended) {
168
+ if (now - updatedAt > KEEP_ENDED_MS)
169
+ ctx.state.delete(sessionId);
170
+ continue;
171
+ }
172
+ try {
173
+ st.pkCwd ??= st.cwd;
174
+ const em = new Emitter(ctx.harness, st);
175
+ endSession(em, 'crashed', st.lastSeen);
176
+ await finish(em, ctx, now);
177
+ }
178
+ catch (err) {
179
+ ctx.log.warn('claude-code: sweep failed for a session', { error: String(err).slice(0, 200) });
180
+ }
181
+ }
182
+ }
183
+ //# sourceMappingURL=handlers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handlers.js","sourceRoot":"","sources":["../../../src/adapters/claude-code/handlers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ import { tmpdir } from 'node:os';
2
+ import { summarizeWithCommand } from '../../analysis/summaries.js';
3
+ import { detectClaudeCode, probeClaudeVersion } from './detect.js';
4
+ import { handleHook, sweepCrashedSessions } from './handlers.js';
5
+ import { claudeDir as defaultClaudeDir, installHooksAt, ourCommandsAt, settingsPath, uninstallHooksAt } from './settings.js';
6
+ /**
7
+ * Headless summary call: cheapest model, JSON envelope, no tools, no saved session. The prompt goes
8
+ * on stdin; the core adds AI_OBS_SUMMARIZING=1 so our own hooks exit at once inside it.
9
+ */
10
+ export const SUMMARY_ARGV = ['claude', '-p', '--model', 'haiku', '--output-format', 'json', '--no-session-persistence', '--tools', ''];
11
+ /** `--output-format json` prints `{ "type": "result", "is_error": false, "result": "<text>", … }`. */
12
+ export function extractResultText(stdout) {
13
+ try {
14
+ const o = JSON.parse(stdout);
15
+ if (o.is_error === true)
16
+ throw new Error('claude reported an error');
17
+ return typeof o.result === 'string' ? o.result : '';
18
+ }
19
+ catch (err) {
20
+ if (err instanceof SyntaxError)
21
+ return stdout;
22
+ throw err;
23
+ }
24
+ }
25
+ export function createClaudeCodeAdapter(opts = {}) {
26
+ const dir = () => opts.claudeDir ?? defaultClaudeDir();
27
+ const probe = opts.probe ?? probeClaudeVersion;
28
+ const argv = [...(opts.summaryArgv ?? SUMMARY_ARGV)];
29
+ return {
30
+ name: 'claude-code',
31
+ displayName: 'Claude Code',
32
+ sessionStartHooks: ['SessionStart'],
33
+ detect: (d = {}) => detectClaudeCode({ ...d, claudeDir: dir(), probe }),
34
+ async installedHookCommands(d = {}) {
35
+ const paths = [settingsPath('user', { claudeDir: dir() }), ...(d.projectDir ? [settingsPath('project', { claudeDir: dir(), projectDir: d.projectDir })] : [])];
36
+ return paths.flatMap(ourCommandsAt);
37
+ },
38
+ async installHooks(o) {
39
+ const path = settingsPath(o.scope, { claudeDir: dir(), ...(o.projectDir ? { projectDir: o.projectDir } : {}) });
40
+ installHooksAt(path, o.hookCommand, o.scope === 'project' ? 0o644 : 0o600);
41
+ },
42
+ async uninstallHooks(o) {
43
+ uninstallHooksAt(settingsPath(o.scope, { claudeDir: dir(), ...(o.projectDir ? { projectDir: o.projectDir } : {}) }));
44
+ },
45
+ handleHook: (event, ctx) => handleHook(event, ctx, { claudeDir: dir(), probe }),
46
+ sweepCrashedSessions: (ctx) => sweepCrashedSessions(ctx),
47
+ summarize: (digests) => summarizeWithCommand(digests, {
48
+ command: (prompt) => ({ argv, input: prompt }),
49
+ extractText: extractResultText,
50
+ cwd: tmpdir(),
51
+ }),
52
+ };
53
+ }
54
+ export const adapter = createClaudeCodeAdapter();
55
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/adapters/claude-code/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAEnE,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAqB,MAAM,aAAa,CAAC;AACtF,OAAO,EAAE,UAAU,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AACjE,OAAO,EAAE,SAAS,IAAI,gBAAgB,EAAE,cAAc,EAAE,aAAa,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAgB7H;;;GAGG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,EAAE,0BAA0B,EAAE,SAAS,EAAE,EAAE,CAAU,CAAC;AAEhJ,sGAAsG;AACtG,MAAM,UAAU,iBAAiB,CAAC,MAAc;IAC9C,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAA6C,CAAC;QACzE,IAAI,CAAC,CAAC,QAAQ,KAAK,IAAI;YAAE,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;QACrE,OAAO,OAAO,CAAC,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;IACtD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,WAAW;YAAE,OAAO,MAAM,CAAC;QAC9C,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,IAAI,GAA6B,EAAE;IACzE,MAAM,GAAG,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,SAAS,IAAI,gBAAgB,EAAE,CAAC;IACvD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,kBAAkB,CAAC;IAC/C,MAAM,IAAI,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,IAAI,YAAY,CAAC,CAAC,CAAC;IACrD,OAAO;QACL,IAAI,EAAE,aAAa;QACnB,WAAW,EAAE,aAAa;QAC1B,iBAAiB,EAAE,CAAC,cAAc,CAAC;QACnC,MAAM,EAAE,CAAC,CAAC,GAAG,EAAE,EAAE,EAAE,CAAC,gBAAgB,CAAC,EAAE,GAAG,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,CAAC;QACvE,KAAK,CAAC,qBAAqB,CAAC,CAAC,GAAG,EAAE;YAChC,MAAM,KAAK,GAAG,CAAC,YAAY,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,EAAE,UAAU,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YAC/J,OAAO,KAAK,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;QACtC,CAAC;QACD,KAAK,CAAC,YAAY,CAAC,CAAC;YAClB,MAAM,IAAI,GAAG,YAAY,CAAC,CAAC,CAAC,KAAK,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;YAChH,cAAc,CAAC,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QAC7E,CAAC;QACD,KAAK,CAAC,cAAc,CAAC,CAAC;YACpB,gBAAgB,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QACvH,CAAC;QACD,UAAU,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,CAAC;QAC/E,oBAAoB,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,oBAAoB,CAAC,GAAG,CAAC;QACxD,SAAS,EAAE,CAAC,OAAO,EAAE,EAAE,CACrB,oBAAoB,CAAC,OAAO,EAAE;YAC5B,OAAO,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;YAC9C,WAAW,EAAE,iBAAiB;YAC9B,GAAG,EAAE,MAAM,EAAE;SACd,CAAC;KACL,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,OAAO,GAAmB,uBAAuB,EAAE,CAAC"}
@@ -0,0 +1,53 @@
1
+ export function computeRunLinks(runs) {
2
+ const byId = new Map();
3
+ for (const r of runs)
4
+ if (!byId.has(r.runId))
5
+ byId.set(r.runId, r);
6
+ const out = new Map();
7
+ const add = (to, fromRunId, kind) => {
8
+ if (to === fromRunId)
9
+ return;
10
+ const list = out.get(to) ?? [];
11
+ if (!list.some((l) => l.fromRunId === fromRunId && l.kind === kind))
12
+ list.push({ fromRunId, kind });
13
+ out.set(to, list);
14
+ };
15
+ const byRunId = (a, b) => (a.runId < b.runId ? -1 : a.runId > b.runId ? 1 : 0);
16
+ const items = new Map();
17
+ const siblings = new Map();
18
+ for (const r of byId.values()) {
19
+ if (r.orchestrationId) {
20
+ if (!r.flowKey)
21
+ continue;
22
+ const k = JSON.stringify([r.orchestrationId, r.flowKey]);
23
+ items.set(k, [...(items.get(k) ?? []), r]);
24
+ }
25
+ else {
26
+ const k = r.parentRunId ?? '';
27
+ siblings.set(k, [...(siblings.get(k) ?? []), r]);
28
+ }
29
+ }
30
+ for (const chain of items.values()) {
31
+ chain.sort((a, b) => a.startedMs - b.startedMs || byRunId(a, b));
32
+ for (let i = 1; i < chain.length; i++)
33
+ add(chain[i].runId, chain[i - 1].runId, 'item');
34
+ }
35
+ for (const group of siblings.values()) {
36
+ for (const b of group) {
37
+ let best = null;
38
+ for (const a of group) {
39
+ if (a === b || a.endedMs > b.startedMs)
40
+ continue;
41
+ // two zero-length runs at the same instant would link both ways: only the lower run id leads
42
+ if (a.startedMs === b.startedMs && byRunId(a, b) > 0)
43
+ continue;
44
+ if (!best || a.endedMs > best.endedMs || (a.endedMs === best.endedMs && byRunId(a, best) > 0))
45
+ best = a;
46
+ }
47
+ if (best)
48
+ add(b.runId, best.runId, 'sequence');
49
+ }
50
+ }
51
+ return out;
52
+ }
53
+ //# sourceMappingURL=run-links.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-links.js","sourceRoot":"","sources":["../../../src/adapters/claude-code/run-links.ts"],"names":[],"mappings":"AAuBA,MAAM,UAAU,eAAe,CAAC,IAA4B;IAC1D,MAAM,IAAI,GAAG,IAAI,GAAG,EAAuB,CAAC;IAC5C,KAAK,MAAM,CAAC,IAAI,IAAI;QAAE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC;YAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IACnE,MAAM,GAAG,GAAG,IAAI,GAAG,EAA0B,CAAC;IAC9C,MAAM,GAAG,GAAG,CAAC,EAAU,EAAE,SAAiB,EAAE,IAA0B,EAAE,EAAE;QACxE,IAAI,EAAE,KAAK,SAAS;YAAE,OAAO;QAC7B,MAAM,IAAI,GAAG,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC;QAC/B,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,KAAK,SAAS,IAAI,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC;YAAE,IAAI,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACpG,GAAG,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;IACpB,CAAC,CAAC;IACF,MAAM,OAAO,GAAG,CAAC,CAAc,EAAE,CAAc,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAEzG,MAAM,KAAK,GAAG,IAAI,GAAG,EAAyB,CAAC;IAC/C,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAyB,CAAC;IAClD,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;QAC9B,IAAI,CAAC,CAAC,eAAe,EAAE,CAAC;YACtB,IAAI,CAAC,CAAC,CAAC,OAAO;gBAAE,SAAS;YACzB,MAAM,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,eAAe,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;YACzD,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAC7C,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,GAAG,CAAC,CAAC,WAAW,IAAI,EAAE,CAAC;YAC9B,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACnD,CAAC;IACH,CAAC;IAED,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;QACnC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,SAAS,IAAI,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACjE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE;YAAE,GAAG,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,GAAG,CAAC,CAAE,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IAC3F,CAAC;IAED,KAAK,MAAM,KAAK,IAAI,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC;QACtC,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;YACtB,IAAI,IAAI,GAAuB,IAAI,CAAC;YACpC,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;gBACtB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,SAAS;oBAAE,SAAS;gBACjD,6FAA6F;gBAC7F,IAAI,CAAC,CAAC,SAAS,KAAK,CAAC,CAAC,SAAS,IAAI,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC;oBAAE,SAAS;gBAC/D,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC,OAAO,KAAK,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;oBAAE,IAAI,GAAG,CAAC,CAAC;YAC1G,CAAC;YACD,IAAI,IAAI;gBAAE,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;QACjD,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}