@cleocode/adapters 2026.3.74 → 2026.3.76
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +132 -154
- package/dist/index.js.map +4 -4
- package/dist/providers/codex/hooks.d.ts +2 -2
- package/dist/providers/codex/hooks.d.ts.map +1 -1
- package/dist/providers/gemini-cli/hooks.d.ts +2 -2
- package/dist/providers/gemini-cli/hooks.d.ts.map +1 -1
- package/dist/providers/shared/transcript-reader.d.ts +43 -0
- package/dist/providers/shared/transcript-reader.d.ts.map +1 -0
- package/package.json +3 -3
- package/src/providers/codex/hooks.ts +5 -52
- package/src/providers/gemini-cli/hooks.ts +5 -52
- package/src/providers/shared/transcript-reader.ts +123 -0
- package/dist/providers/claude-code/adapter.js +0 -165
- package/dist/providers/claude-code/adapter.js.map +0 -1
- package/dist/providers/claude-code/context-monitor.js +0 -148
- package/dist/providers/claude-code/context-monitor.js.map +0 -1
- package/dist/providers/claude-code/hooks.js +0 -279
- package/dist/providers/claude-code/hooks.js.map +0 -1
- package/dist/providers/claude-code/index.js +0 -26
- package/dist/providers/claude-code/index.js.map +0 -1
- package/dist/providers/claude-code/install.js +0 -234
- package/dist/providers/claude-code/install.js.map +0 -1
- package/dist/providers/claude-code/paths.js +0 -33
- package/dist/providers/claude-code/paths.js.map +0 -1
- package/dist/providers/claude-code/spawn.js +0 -164
- package/dist/providers/claude-code/spawn.js.map +0 -1
- package/dist/providers/claude-code/statusline.js +0 -86
- package/dist/providers/claude-code/statusline.js.map +0 -1
- package/dist/providers/claude-code/task-sync.js +0 -111
- package/dist/providers/claude-code/task-sync.js.map +0 -1
- package/dist/providers/claude-code/transport.js +0 -18
- package/dist/providers/claude-code/transport.js.map +0 -1
- package/dist/providers/codex/adapter.js +0 -134
- package/dist/providers/codex/adapter.js.map +0 -1
- package/dist/providers/codex/hooks.js +0 -155
- package/dist/providers/codex/hooks.js.map +0 -1
- package/dist/providers/codex/index.js +0 -24
- package/dist/providers/codex/index.js.map +0 -1
- package/dist/providers/codex/install.js +0 -183
- package/dist/providers/codex/install.js.map +0 -1
- package/dist/providers/cursor/adapter.js +0 -138
- package/dist/providers/cursor/adapter.js.map +0 -1
- package/dist/providers/cursor/hooks.js +0 -201
- package/dist/providers/cursor/hooks.js.map +0 -1
- package/dist/providers/cursor/index.js +0 -21
- package/dist/providers/cursor/index.js.map +0 -1
- package/dist/providers/cursor/install.js +0 -238
- package/dist/providers/cursor/install.js.map +0 -1
- package/dist/providers/cursor/spawn.js +0 -59
- package/dist/providers/cursor/spawn.js.map +0 -1
- package/dist/providers/gemini-cli/adapter.js +0 -145
- package/dist/providers/gemini-cli/adapter.js.map +0 -1
- package/dist/providers/gemini-cli/hooks.js +0 -169
- package/dist/providers/gemini-cli/hooks.js.map +0 -1
- package/dist/providers/gemini-cli/index.js +0 -24
- package/dist/providers/gemini-cli/index.js.map +0 -1
- package/dist/providers/gemini-cli/install.js +0 -183
- package/dist/providers/gemini-cli/install.js.map +0 -1
- package/dist/providers/kimi/adapter.js +0 -133
- package/dist/providers/kimi/adapter.js.map +0 -1
- package/dist/providers/kimi/hooks.js +0 -73
- package/dist/providers/kimi/hooks.js.map +0 -1
- package/dist/providers/kimi/index.js +0 -24
- package/dist/providers/kimi/index.js.map +0 -1
- package/dist/providers/kimi/install.js +0 -189
- package/dist/providers/kimi/install.js.map +0 -1
- package/dist/providers/opencode/adapter.js +0 -151
- package/dist/providers/opencode/adapter.js.map +0 -1
- package/dist/providers/opencode/hooks.js +0 -197
- package/dist/providers/opencode/hooks.js.map +0 -1
- package/dist/providers/opencode/index.js +0 -22
- package/dist/providers/opencode/index.js.map +0 -1
- package/dist/providers/opencode/install.js +0 -180
- package/dist/providers/opencode/install.js.map +0 -1
- package/dist/providers/opencode/spawn.js +0 -219
- package/dist/providers/opencode/spawn.js.map +0 -1
- package/dist/registry.js +0 -55
- package/dist/registry.js.map +0 -1
|
@@ -71,8 +71,8 @@ export declare class CodexHookProvider implements AdapterHookProvider {
|
|
|
71
71
|
/**
|
|
72
72
|
* Extract a plain-text transcript from Codex CLI session data.
|
|
73
73
|
*
|
|
74
|
-
* Reads the most recent session file under
|
|
75
|
-
*
|
|
74
|
+
* Reads the most recent JSON/JSONL session file under `~/.codex/`
|
|
75
|
+
* and returns its turns as a flat string for brain observation extraction.
|
|
76
76
|
*
|
|
77
77
|
* Returns null when no session data is found or on any read error.
|
|
78
78
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../../src/providers/codex/hooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../../src/providers/codex/hooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAY/D;;;;;;;;;;;;;GAaG;AACH,qBAAa,iBAAkB,YAAW,mBAAmB;IAC3D,OAAO,CAAC,UAAU,CAAS;IAE3B;;;;;;OAMG;IACH,gBAAgB,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAItD;;;;;;;;;;OAUG;IACG,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI7D;;;;;;;OAOG;IACG,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC;IAI5C;;;OAGG;IACH,YAAY,IAAI,OAAO;IAIvB;;;OAGG;IACH,WAAW,IAAI,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAI/C;;;;;;;;;;;OAWG;IACG,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;CAGrF"}
|
|
@@ -78,8 +78,8 @@ export declare class GeminiCliHookProvider implements AdapterHookProvider {
|
|
|
78
78
|
/**
|
|
79
79
|
* Extract a plain-text transcript from Gemini CLI session data.
|
|
80
80
|
*
|
|
81
|
-
* Reads the most recent session file under
|
|
82
|
-
*
|
|
81
|
+
* Reads the most recent JSON/JSONL session file under `~/.gemini/`
|
|
82
|
+
* and returns its turns as a flat string for brain observation extraction.
|
|
83
83
|
*
|
|
84
84
|
* Returns null when no session data is found or on any read error.
|
|
85
85
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../../src/providers/gemini-cli/hooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAIH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../../src/providers/gemini-cli/hooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAIH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAmB/D;;;;;;;;;;;;;GAaG;AACH,qBAAa,qBAAsB,YAAW,mBAAmB;IAC/D,OAAO,CAAC,UAAU,CAAS;IAE3B;;;;;;OAMG;IACH,gBAAgB,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAItD;;;;;;;;;;OAUG;IACG,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI7D;;;;;;;OAOG;IACG,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC;IAI5C;;;OAGG;IACH,YAAY,IAAI,OAAO;IAIvB;;;OAGG;IACH,WAAW,IAAI,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAI/C;;;;;;;;;;;OAWG;IACG,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;CAGrF"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared transcript-reading utility for provider hook adapters.
|
|
3
|
+
*
|
|
4
|
+
* Several providers (Gemini CLI, Codex CLI) store session data in a
|
|
5
|
+
* flat directory of JSON/JSONL files using the same role/content schema.
|
|
6
|
+
* This module centralises the "find most-recent file, parse turns"
|
|
7
|
+
* logic to avoid duplicating it in each hook provider.
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* ```ts
|
|
11
|
+
* import { readLatestTranscript } from '../shared/transcript-reader.js';
|
|
12
|
+
*
|
|
13
|
+
* async getTranscript(_sessionId: string, _projectDir: string) {
|
|
14
|
+
* return readLatestTranscript(join(homedir(), '.gemini'));
|
|
15
|
+
* }
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* @task T161
|
|
19
|
+
* @epic T134
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* Read the most recent JSON or JSONL session file from `providerDir` and
|
|
23
|
+
* return its contents as a flat transcript string.
|
|
24
|
+
*
|
|
25
|
+
* Files are sorted in descending order by filename — this works naturally
|
|
26
|
+
* for providers that embed timestamps in filenames. The most recently named
|
|
27
|
+
* file is read first.
|
|
28
|
+
*
|
|
29
|
+
* Returns `null` when:
|
|
30
|
+
* - `providerDir` does not exist or cannot be read
|
|
31
|
+
* - No JSON/JSONL files are present
|
|
32
|
+
* - The most recent file contains no parseable turns
|
|
33
|
+
*
|
|
34
|
+
* @param providerDir - Absolute path to the provider's session directory
|
|
35
|
+
* (e.g. `~/.gemini` or `~/.codex`).
|
|
36
|
+
* @returns A plain-text transcript with lines of the form `role: content`,
|
|
37
|
+
* or `null` if no transcript could be extracted.
|
|
38
|
+
*
|
|
39
|
+
* @task T161
|
|
40
|
+
* @epic T134
|
|
41
|
+
*/
|
|
42
|
+
export declare function readLatestTranscript(providerDir: string): Promise<string | null>;
|
|
43
|
+
//# sourceMappingURL=transcript-reader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transcript-reader.d.ts","sourceRoot":"","sources":["../../../src/providers/shared/transcript-reader.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAoDH;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA8BtF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cleocode/adapters",
|
|
3
|
-
"version": "2026.3.
|
|
3
|
+
"version": "2026.3.76",
|
|
4
4
|
"description": "Unified provider adapters for CLEO (Claude Code, OpenCode, Cursor)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -12,8 +12,8 @@
|
|
|
12
12
|
}
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@cleocode/caamp": "
|
|
16
|
-
"@cleocode/contracts": "2026.3.
|
|
15
|
+
"@cleocode/caamp": "2026.3.76",
|
|
16
|
+
"@cleocode/contracts": "2026.3.76"
|
|
17
17
|
},
|
|
18
18
|
"license": "MIT",
|
|
19
19
|
"engines": {
|
|
@@ -13,9 +13,10 @@
|
|
|
13
13
|
* @epic T134
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
-
import {
|
|
16
|
+
import { homedir } from 'node:os';
|
|
17
17
|
import { join } from 'node:path';
|
|
18
18
|
import type { AdapterHookProvider } from '@cleocode/contracts';
|
|
19
|
+
import { readLatestTranscript } from '../shared/transcript-reader.js';
|
|
19
20
|
|
|
20
21
|
/**
|
|
21
22
|
* Mapping from Codex CLI native event names to CAAMP canonical event names.
|
|
@@ -100,8 +101,8 @@ export class CodexHookProvider implements AdapterHookProvider {
|
|
|
100
101
|
/**
|
|
101
102
|
* Extract a plain-text transcript from Codex CLI session data.
|
|
102
103
|
*
|
|
103
|
-
* Reads the most recent session file under
|
|
104
|
-
*
|
|
104
|
+
* Reads the most recent JSON/JSONL session file under `~/.codex/`
|
|
105
|
+
* and returns its turns as a flat string for brain observation extraction.
|
|
105
106
|
*
|
|
106
107
|
* Returns null when no session data is found or on any read error.
|
|
107
108
|
*
|
|
@@ -110,54 +111,6 @@ export class CodexHookProvider implements AdapterHookProvider {
|
|
|
110
111
|
* @task T162 @epic T134
|
|
111
112
|
*/
|
|
112
113
|
async getTranscript(_sessionId: string, _projectDir: string): Promise<string | null> {
|
|
113
|
-
|
|
114
|
-
const homeDir = process.env.HOME ?? process.env.USERPROFILE ?? '/root';
|
|
115
|
-
const codexDir = join(homeDir, '.codex');
|
|
116
|
-
|
|
117
|
-
let allFiles: string[] = [];
|
|
118
|
-
try {
|
|
119
|
-
const entries = await readdir(codexDir, { withFileTypes: true });
|
|
120
|
-
for (const entry of entries) {
|
|
121
|
-
if (!entry.isFile()) continue;
|
|
122
|
-
const name = entry.name;
|
|
123
|
-
if (name.endsWith('.json') || name.endsWith('.jsonl')) {
|
|
124
|
-
allFiles.push(join(codexDir, name));
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
} catch {
|
|
128
|
-
return null;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
if (allFiles.length === 0) return null;
|
|
132
|
-
|
|
133
|
-
// Sort descending by filename (timestamps in filenames sort naturally)
|
|
134
|
-
allFiles = allFiles.sort((a, b) => b.localeCompare(a));
|
|
135
|
-
const mostRecent = allFiles[0];
|
|
136
|
-
if (!mostRecent) return null;
|
|
137
|
-
|
|
138
|
-
const raw = await readFile(mostRecent, 'utf-8');
|
|
139
|
-
const turns: string[] = [];
|
|
140
|
-
|
|
141
|
-
// Support both JSONL (one JSON per line) and JSON array formats
|
|
142
|
-
const lines = raw.split('\n').filter((l) => l.trim());
|
|
143
|
-
for (const line of lines) {
|
|
144
|
-
try {
|
|
145
|
-
const entry = JSON.parse(line) as Record<string, unknown>;
|
|
146
|
-
const role = entry.role as string | undefined;
|
|
147
|
-
const content = entry.content;
|
|
148
|
-
if (role === 'assistant' && typeof content === 'string') {
|
|
149
|
-
turns.push(`assistant: ${content}`);
|
|
150
|
-
} else if (role === 'user' && typeof content === 'string') {
|
|
151
|
-
turns.push(`user: ${content}`);
|
|
152
|
-
}
|
|
153
|
-
} catch {
|
|
154
|
-
// Skip malformed lines
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
return turns.length > 0 ? turns.join('\n') : null;
|
|
159
|
-
} catch {
|
|
160
|
-
return null;
|
|
161
|
-
}
|
|
114
|
+
return readLatestTranscript(join(homedir(), '.codex'));
|
|
162
115
|
}
|
|
163
116
|
}
|
|
@@ -20,9 +20,10 @@
|
|
|
20
20
|
* @epic T134
|
|
21
21
|
*/
|
|
22
22
|
|
|
23
|
-
import {
|
|
23
|
+
import { homedir } from 'node:os';
|
|
24
24
|
import { join } from 'node:path';
|
|
25
25
|
import type { AdapterHookProvider } from '@cleocode/contracts';
|
|
26
|
+
import { readLatestTranscript } from '../shared/transcript-reader.js';
|
|
26
27
|
|
|
27
28
|
/**
|
|
28
29
|
* Mapping from Gemini CLI native event names to CAAMP canonical event names.
|
|
@@ -114,8 +115,8 @@ export class GeminiCliHookProvider implements AdapterHookProvider {
|
|
|
114
115
|
/**
|
|
115
116
|
* Extract a plain-text transcript from Gemini CLI session data.
|
|
116
117
|
*
|
|
117
|
-
* Reads the most recent session file under
|
|
118
|
-
*
|
|
118
|
+
* Reads the most recent JSON/JSONL session file under `~/.gemini/`
|
|
119
|
+
* and returns its turns as a flat string for brain observation extraction.
|
|
119
120
|
*
|
|
120
121
|
* Returns null when no session data is found or on any read error.
|
|
121
122
|
*
|
|
@@ -124,54 +125,6 @@ export class GeminiCliHookProvider implements AdapterHookProvider {
|
|
|
124
125
|
* @task T161 @epic T134
|
|
125
126
|
*/
|
|
126
127
|
async getTranscript(_sessionId: string, _projectDir: string): Promise<string | null> {
|
|
127
|
-
|
|
128
|
-
const homeDir = process.env.HOME ?? process.env.USERPROFILE ?? '/root';
|
|
129
|
-
const geminiDir = join(homeDir, '.gemini');
|
|
130
|
-
|
|
131
|
-
let allFiles: string[] = [];
|
|
132
|
-
try {
|
|
133
|
-
const entries = await readdir(geminiDir, { withFileTypes: true });
|
|
134
|
-
for (const entry of entries) {
|
|
135
|
-
if (!entry.isFile()) continue;
|
|
136
|
-
const name = entry.name;
|
|
137
|
-
if (name.endsWith('.json') || name.endsWith('.jsonl')) {
|
|
138
|
-
allFiles.push(join(geminiDir, name));
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
} catch {
|
|
142
|
-
return null;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
if (allFiles.length === 0) return null;
|
|
146
|
-
|
|
147
|
-
// Sort descending by filename (timestamps in filenames sort naturally)
|
|
148
|
-
allFiles = allFiles.sort((a, b) => b.localeCompare(a));
|
|
149
|
-
const mostRecent = allFiles[0];
|
|
150
|
-
if (!mostRecent) return null;
|
|
151
|
-
|
|
152
|
-
const raw = await readFile(mostRecent, 'utf-8');
|
|
153
|
-
const turns: string[] = [];
|
|
154
|
-
|
|
155
|
-
// Support both JSONL (one JSON per line) and JSON array formats
|
|
156
|
-
const lines = raw.split('\n').filter((l) => l.trim());
|
|
157
|
-
for (const line of lines) {
|
|
158
|
-
try {
|
|
159
|
-
const entry = JSON.parse(line) as Record<string, unknown>;
|
|
160
|
-
const role = entry.role as string | undefined;
|
|
161
|
-
const content = entry.content;
|
|
162
|
-
if (role === 'assistant' && typeof content === 'string') {
|
|
163
|
-
turns.push(`assistant: ${content}`);
|
|
164
|
-
} else if (role === 'user' && typeof content === 'string') {
|
|
165
|
-
turns.push(`user: ${content}`);
|
|
166
|
-
}
|
|
167
|
-
} catch {
|
|
168
|
-
// Skip malformed lines
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
return turns.length > 0 ? turns.join('\n') : null;
|
|
173
|
-
} catch {
|
|
174
|
-
return null;
|
|
175
|
-
}
|
|
128
|
+
return readLatestTranscript(join(homedir(), '.gemini'));
|
|
176
129
|
}
|
|
177
130
|
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared transcript-reading utility for provider hook adapters.
|
|
3
|
+
*
|
|
4
|
+
* Several providers (Gemini CLI, Codex CLI) store session data in a
|
|
5
|
+
* flat directory of JSON/JSONL files using the same role/content schema.
|
|
6
|
+
* This module centralises the "find most-recent file, parse turns"
|
|
7
|
+
* logic to avoid duplicating it in each hook provider.
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* ```ts
|
|
11
|
+
* import { readLatestTranscript } from '../shared/transcript-reader.js';
|
|
12
|
+
*
|
|
13
|
+
* async getTranscript(_sessionId: string, _projectDir: string) {
|
|
14
|
+
* return readLatestTranscript(join(homedir(), '.gemini'));
|
|
15
|
+
* }
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* @task T161
|
|
19
|
+
* @epic T134
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import { readdir, readFile } from 'node:fs/promises';
|
|
23
|
+
import { join } from 'node:path';
|
|
24
|
+
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
// Types
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
|
|
29
|
+
/** A single parsed conversation turn from a provider session file. */
|
|
30
|
+
interface TranscriptTurn {
|
|
31
|
+
role: string;
|
|
32
|
+
content: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
// Helpers
|
|
37
|
+
// ---------------------------------------------------------------------------
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Parse a raw JSONL or JSON session file into an array of transcript turns.
|
|
41
|
+
*
|
|
42
|
+
* Lines that are not valid JSON, or that lack a string `role` and string
|
|
43
|
+
* `content`, are silently skipped.
|
|
44
|
+
*
|
|
45
|
+
* @param raw - Raw file contents (UTF-8 string).
|
|
46
|
+
* @returns Array of `{ role, content }` pairs, in file order.
|
|
47
|
+
*/
|
|
48
|
+
function parseTranscriptLines(raw: string): TranscriptTurn[] {
|
|
49
|
+
const turns: TranscriptTurn[] = [];
|
|
50
|
+
const lines = raw.split('\n').filter((l) => l.trim());
|
|
51
|
+
|
|
52
|
+
for (const line of lines) {
|
|
53
|
+
try {
|
|
54
|
+
const entry = JSON.parse(line) as Record<string, unknown>;
|
|
55
|
+
const role = entry.role;
|
|
56
|
+
const content = entry.content;
|
|
57
|
+
if (typeof role === 'string' && typeof content === 'string') {
|
|
58
|
+
turns.push({ role, content });
|
|
59
|
+
}
|
|
60
|
+
} catch {
|
|
61
|
+
// Skip malformed lines
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return turns;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// ---------------------------------------------------------------------------
|
|
69
|
+
// Public API
|
|
70
|
+
// ---------------------------------------------------------------------------
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Read the most recent JSON or JSONL session file from `providerDir` and
|
|
74
|
+
* return its contents as a flat transcript string.
|
|
75
|
+
*
|
|
76
|
+
* Files are sorted in descending order by filename — this works naturally
|
|
77
|
+
* for providers that embed timestamps in filenames. The most recently named
|
|
78
|
+
* file is read first.
|
|
79
|
+
*
|
|
80
|
+
* Returns `null` when:
|
|
81
|
+
* - `providerDir` does not exist or cannot be read
|
|
82
|
+
* - No JSON/JSONL files are present
|
|
83
|
+
* - The most recent file contains no parseable turns
|
|
84
|
+
*
|
|
85
|
+
* @param providerDir - Absolute path to the provider's session directory
|
|
86
|
+
* (e.g. `~/.gemini` or `~/.codex`).
|
|
87
|
+
* @returns A plain-text transcript with lines of the form `role: content`,
|
|
88
|
+
* or `null` if no transcript could be extracted.
|
|
89
|
+
*
|
|
90
|
+
* @task T161
|
|
91
|
+
* @epic T134
|
|
92
|
+
*/
|
|
93
|
+
export async function readLatestTranscript(providerDir: string): Promise<string | null> {
|
|
94
|
+
let allFiles: string[] = [];
|
|
95
|
+
|
|
96
|
+
try {
|
|
97
|
+
const entries = await readdir(providerDir, { withFileTypes: true });
|
|
98
|
+
for (const entry of entries) {
|
|
99
|
+
if (!entry.isFile()) continue;
|
|
100
|
+
const name = entry.name;
|
|
101
|
+
if (name.endsWith('.json') || name.endsWith('.jsonl')) {
|
|
102
|
+
allFiles.push(join(providerDir, name));
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
} catch {
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (allFiles.length === 0) return null;
|
|
110
|
+
|
|
111
|
+
// Sort descending — timestamps in filenames sort naturally
|
|
112
|
+
allFiles = allFiles.sort((a, b) => b.localeCompare(a));
|
|
113
|
+
const mostRecent = allFiles[0];
|
|
114
|
+
if (!mostRecent) return null;
|
|
115
|
+
|
|
116
|
+
try {
|
|
117
|
+
const raw = await readFile(mostRecent, 'utf-8');
|
|
118
|
+
const turns = parseTranscriptLines(raw);
|
|
119
|
+
return turns.length > 0 ? turns.map((t) => `${t.role}: ${t.content}`).join('\n') : null;
|
|
120
|
+
} catch {
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
@@ -1,165 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Claude Code Adapter
|
|
3
|
-
*
|
|
4
|
-
* Main CLEOProviderAdapter implementation for Anthropic's Claude Code CLI.
|
|
5
|
-
* Provides spawn, hooks, and install capabilities for CLEO integration.
|
|
6
|
-
*
|
|
7
|
-
* @task T5240
|
|
8
|
-
*/
|
|
9
|
-
import { exec } from 'node:child_process';
|
|
10
|
-
import { existsSync } from 'node:fs';
|
|
11
|
-
import { homedir } from 'node:os';
|
|
12
|
-
import { join } from 'node:path';
|
|
13
|
-
import { promisify } from 'node:util';
|
|
14
|
-
import { ClaudeCodeContextMonitorProvider } from './context-monitor.js';
|
|
15
|
-
import { ClaudeCodeHookProvider } from './hooks.js';
|
|
16
|
-
import { ClaudeCodeInstallProvider } from './install.js';
|
|
17
|
-
import { ClaudeCodePathProvider } from './paths.js';
|
|
18
|
-
import { ClaudeCodeSpawnProvider } from './spawn.js';
|
|
19
|
-
import { ClaudeCodeTaskSyncProvider } from './task-sync.js';
|
|
20
|
-
import { ClaudeCodeTransportProvider } from './transport.js';
|
|
21
|
-
const execAsync = promisify(exec);
|
|
22
|
-
/**
|
|
23
|
-
* CLEO provider adapter for Anthropic Claude Code CLI.
|
|
24
|
-
*
|
|
25
|
-
* Bridges CLEO's adapter system with Claude Code's native capabilities:
|
|
26
|
-
* - Hooks: Maps Claude Code events (SessionStart, PostToolUse, etc.) to CAAMP events
|
|
27
|
-
* - Spawn: Launches subagent processes via the `claude` CLI
|
|
28
|
-
* - Install: Registers MCP server, instruction files, and brain observation plugin
|
|
29
|
-
*/
|
|
30
|
-
export class ClaudeCodeAdapter {
|
|
31
|
-
id = 'claude-code';
|
|
32
|
-
name = 'Claude Code';
|
|
33
|
-
version = '1.0.0';
|
|
34
|
-
capabilities = {
|
|
35
|
-
supportsHooks: true,
|
|
36
|
-
// 14/16 canonical events — derived from getProviderHookProfile('claude-code') in CAAMP 1.9.1.
|
|
37
|
-
// PreModel and PostModel are not supported by Claude Code.
|
|
38
|
-
supportedHookEvents: [
|
|
39
|
-
'SessionStart',
|
|
40
|
-
'SessionEnd',
|
|
41
|
-
'PromptSubmit',
|
|
42
|
-
'ResponseComplete',
|
|
43
|
-
'PreToolUse',
|
|
44
|
-
'PostToolUse',
|
|
45
|
-
'PostToolUseFailure',
|
|
46
|
-
'PermissionRequest',
|
|
47
|
-
'SubagentStart',
|
|
48
|
-
'SubagentStop',
|
|
49
|
-
'PreCompact',
|
|
50
|
-
'PostCompact',
|
|
51
|
-
'Notification',
|
|
52
|
-
'ConfigChange',
|
|
53
|
-
],
|
|
54
|
-
supportsSpawn: true,
|
|
55
|
-
supportsInstall: true,
|
|
56
|
-
supportsMcp: true,
|
|
57
|
-
supportsInstructionFiles: true,
|
|
58
|
-
instructionFilePattern: 'CLAUDE.md',
|
|
59
|
-
supportsContextMonitor: true,
|
|
60
|
-
supportsStatusline: true,
|
|
61
|
-
supportsProviderPaths: true,
|
|
62
|
-
supportsTransport: true,
|
|
63
|
-
supportsTaskSync: true,
|
|
64
|
-
};
|
|
65
|
-
hooks;
|
|
66
|
-
spawn;
|
|
67
|
-
install;
|
|
68
|
-
paths;
|
|
69
|
-
contextMonitor;
|
|
70
|
-
transport;
|
|
71
|
-
taskSync;
|
|
72
|
-
projectDir = null;
|
|
73
|
-
initialized = false;
|
|
74
|
-
constructor() {
|
|
75
|
-
this.hooks = new ClaudeCodeHookProvider();
|
|
76
|
-
this.spawn = new ClaudeCodeSpawnProvider();
|
|
77
|
-
this.install = new ClaudeCodeInstallProvider();
|
|
78
|
-
this.paths = new ClaudeCodePathProvider();
|
|
79
|
-
this.contextMonitor = new ClaudeCodeContextMonitorProvider();
|
|
80
|
-
this.transport = new ClaudeCodeTransportProvider();
|
|
81
|
-
this.taskSync = new ClaudeCodeTaskSyncProvider();
|
|
82
|
-
}
|
|
83
|
-
/**
|
|
84
|
-
* Initialize the adapter for a given project directory.
|
|
85
|
-
*
|
|
86
|
-
* Validates the environment by checking for the Claude CLI
|
|
87
|
-
* and Claude Code configuration directory.
|
|
88
|
-
*
|
|
89
|
-
* @param projectDir - Root directory of the project
|
|
90
|
-
*/
|
|
91
|
-
async initialize(projectDir) {
|
|
92
|
-
this.projectDir = projectDir;
|
|
93
|
-
this.initialized = true;
|
|
94
|
-
}
|
|
95
|
-
/**
|
|
96
|
-
* Dispose the adapter and clean up resources.
|
|
97
|
-
*
|
|
98
|
-
* Unregisters hooks and releases any tracked state.
|
|
99
|
-
*/
|
|
100
|
-
async dispose() {
|
|
101
|
-
if (this.hooks.isRegistered()) {
|
|
102
|
-
await this.hooks.unregisterNativeHooks();
|
|
103
|
-
}
|
|
104
|
-
this.initialized = false;
|
|
105
|
-
this.projectDir = null;
|
|
106
|
-
}
|
|
107
|
-
/**
|
|
108
|
-
* Run a health check to verify Claude Code is accessible.
|
|
109
|
-
*
|
|
110
|
-
* Checks:
|
|
111
|
-
* 1. Adapter has been initialized
|
|
112
|
-
* 2. Claude CLI is available in PATH
|
|
113
|
-
* 3. ~/.claude/ configuration directory exists
|
|
114
|
-
*
|
|
115
|
-
* @returns Health status with details about each check
|
|
116
|
-
*/
|
|
117
|
-
async healthCheck() {
|
|
118
|
-
const details = {};
|
|
119
|
-
if (!this.initialized) {
|
|
120
|
-
return {
|
|
121
|
-
healthy: false,
|
|
122
|
-
provider: this.id,
|
|
123
|
-
details: { error: 'Adapter not initialized' },
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
// Check Claude CLI availability
|
|
127
|
-
let cliAvailable = false;
|
|
128
|
-
try {
|
|
129
|
-
const { stdout } = await execAsync('which claude');
|
|
130
|
-
cliAvailable = stdout.trim().length > 0;
|
|
131
|
-
details.cliPath = stdout.trim();
|
|
132
|
-
}
|
|
133
|
-
catch {
|
|
134
|
-
details.cliAvailable = false;
|
|
135
|
-
}
|
|
136
|
-
// Check for Claude Code config directory
|
|
137
|
-
const claudeConfigDir = join(homedir(), '.claude');
|
|
138
|
-
const configExists = existsSync(claudeConfigDir);
|
|
139
|
-
details.configDirExists = configExists;
|
|
140
|
-
// Check for CLAUDE_CODE_ENTRYPOINT env var
|
|
141
|
-
const entrypointSet = process.env.CLAUDE_CODE_ENTRYPOINT !== undefined;
|
|
142
|
-
details.entrypointEnvSet = entrypointSet;
|
|
143
|
-
// Healthy if CLI is available (primary requirement)
|
|
144
|
-
const healthy = cliAvailable;
|
|
145
|
-
details.cliAvailable = cliAvailable;
|
|
146
|
-
return {
|
|
147
|
-
healthy,
|
|
148
|
-
provider: this.id,
|
|
149
|
-
details,
|
|
150
|
-
};
|
|
151
|
-
}
|
|
152
|
-
/**
|
|
153
|
-
* Check whether the adapter has been initialized.
|
|
154
|
-
*/
|
|
155
|
-
isInitialized() {
|
|
156
|
-
return this.initialized;
|
|
157
|
-
}
|
|
158
|
-
/**
|
|
159
|
-
* Get the project directory this adapter was initialized with.
|
|
160
|
-
*/
|
|
161
|
-
getProjectDir() {
|
|
162
|
-
return this.projectDir;
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
//# sourceMappingURL=adapter.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../../../src/providers/claude-code/adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAMtC,OAAO,EAAE,gCAAgC,EAAE,MAAM,sBAAsB,CAAC;AACxE,OAAO,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,EAAE,yBAAyB,EAAE,MAAM,cAAc,CAAC;AACzD,OAAO,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,0BAA0B,EAAE,MAAM,gBAAgB,CAAC;AAC5D,OAAO,EAAE,2BAA2B,EAAE,MAAM,gBAAgB,CAAC;AAE7D,MAAM,SAAS,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;AAElC;;;;;;;GAOG;AACH,MAAM,OAAO,iBAAiB;IACnB,EAAE,GAAG,aAAa,CAAC;IACnB,IAAI,GAAG,aAAa,CAAC;IACrB,OAAO,GAAG,OAAO,CAAC;IAE3B,YAAY,GAAwB;QAClC,aAAa,EAAE,IAAI;QACnB,8FAA8F;QAC9F,2DAA2D;QAC3D,mBAAmB,EAAE;YACnB,cAAc;YACd,YAAY;YACZ,cAAc;YACd,kBAAkB;YAClB,YAAY;YACZ,aAAa;YACb,oBAAoB;YACpB,mBAAmB;YACnB,eAAe;YACf,cAAc;YACd,YAAY;YACZ,aAAa;YACb,cAAc;YACd,cAAc;SACf;QACD,aAAa,EAAE,IAAI;QACnB,eAAe,EAAE,IAAI;QACrB,WAAW,EAAE,IAAI;QACjB,wBAAwB,EAAE,IAAI;QAC9B,sBAAsB,EAAE,WAAW;QACnC,sBAAsB,EAAE,IAAI;QAC5B,kBAAkB,EAAE,IAAI;QACxB,qBAAqB,EAAE,IAAI;QAC3B,iBAAiB,EAAE,IAAI;QACvB,gBAAgB,EAAE,IAAI;KACvB,CAAC;IAEF,KAAK,CAAyB;IAC9B,KAAK,CAA0B;IAC/B,OAAO,CAA4B;IACnC,KAAK,CAAyB;IAC9B,cAAc,CAAmC;IACjD,SAAS,CAA8B;IACvC,QAAQ,CAA6B;IAE7B,UAAU,GAAkB,IAAI,CAAC;IACjC,WAAW,GAAG,KAAK,CAAC;IAE5B;QACE,IAAI,CAAC,KAAK,GAAG,IAAI,sBAAsB,EAAE,CAAC;QAC1C,IAAI,CAAC,KAAK,GAAG,IAAI,uBAAuB,EAAE,CAAC;QAC3C,IAAI,CAAC,OAAO,GAAG,IAAI,yBAAyB,EAAE,CAAC;QAC/C,IAAI,CAAC,KAAK,GAAG,IAAI,sBAAsB,EAAE,CAAC;QAC1C,IAAI,CAAC,cAAc,GAAG,IAAI,gCAAgC,EAAE,CAAC;QAC7D,IAAI,CAAC,SAAS,GAAG,IAAI,2BAA2B,EAAE,CAAC;QACnD,IAAI,CAAC,QAAQ,GAAG,IAAI,0BAA0B,EAAE,CAAC;IACnD,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,UAAU,CAAC,UAAkB;QACjC,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;IAC1B,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,OAAO;QACX,IAAI,IAAI,CAAC,KAAK,CAAC,YAAY,EAAE,EAAE,CAAC;YAC9B,MAAM,IAAI,CAAC,KAAK,CAAC,qBAAqB,EAAE,CAAC;QAC3C,CAAC;QACD,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;QACzB,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;IACzB,CAAC;IAED;;;;;;;;;OASG;IACH,KAAK,CAAC,WAAW;QACf,MAAM,OAAO,GAA4B,EAAE,CAAC;QAE5C,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;YACtB,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,QAAQ,EAAE,IAAI,CAAC,EAAE;gBACjB,OAAO,EAAE,EAAE,KAAK,EAAE,yBAAyB,EAAE;aAC9C,CAAC;QACJ,CAAC;QAED,gCAAgC;QAChC,IAAI,YAAY,GAAG,KAAK,CAAC;QACzB,IAAI,CAAC;YACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,SAAS,CAAC,cAAc,CAAC,CAAC;YACnD,YAAY,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;YACxC,OAAO,CAAC,OAAO,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC;QAClC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,CAAC,YAAY,GAAG,KAAK,CAAC;QAC/B,CAAC;QAED,yCAAyC;QACzC,MAAM,eAAe,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,CAAC,CAAC;QACnD,MAAM,YAAY,GAAG,UAAU,CAAC,eAAe,CAAC,CAAC;QACjD,OAAO,CAAC,eAAe,GAAG,YAAY,CAAC;QAEvC,2CAA2C;QAC3C,MAAM,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,sBAAsB,KAAK,SAAS,CAAC;QACvE,OAAO,CAAC,gBAAgB,GAAG,aAAa,CAAC;QAEzC,oDAAoD;QACpD,MAAM,OAAO,GAAG,YAAY,CAAC;QAC7B,OAAO,CAAC,YAAY,GAAG,YAAY,CAAC;QAEpC,OAAO;YACL,OAAO;YACP,QAAQ,EAAE,IAAI,CAAC,EAAE;YACjB,OAAO;SACR,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,aAAa;QACX,OAAO,IAAI,CAAC,WAAW,CAAC;IAC1B,CAAC;IAED;;OAEG;IACH,aAAa;QACX,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;CACF"}
|