aemeathcli 1.0.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.
- package/README.md +607 -0
- package/dist/App-P4MYD4QY.js +2719 -0
- package/dist/App-P4MYD4QY.js.map +1 -0
- package/dist/api-key-fallback-YQQBOQIL.js +11 -0
- package/dist/api-key-fallback-YQQBOQIL.js.map +1 -0
- package/dist/chunk-4IJD72YB.js +184 -0
- package/dist/chunk-4IJD72YB.js.map +1 -0
- package/dist/chunk-6PDJ45T4.js +325 -0
- package/dist/chunk-6PDJ45T4.js.map +1 -0
- package/dist/chunk-CARHU3DO.js +562 -0
- package/dist/chunk-CARHU3DO.js.map +1 -0
- package/dist/chunk-CGEV3ARR.js +80 -0
- package/dist/chunk-CGEV3ARR.js.map +1 -0
- package/dist/chunk-CS5X3BWX.js +27 -0
- package/dist/chunk-CS5X3BWX.js.map +1 -0
- package/dist/chunk-CYQNBB25.js +44 -0
- package/dist/chunk-CYQNBB25.js.map +1 -0
- package/dist/chunk-DAHGLHNR.js +657 -0
- package/dist/chunk-DAHGLHNR.js.map +1 -0
- package/dist/chunk-H66O5Z2V.js +305 -0
- package/dist/chunk-H66O5Z2V.js.map +1 -0
- package/dist/chunk-HCIHOHLX.js +322 -0
- package/dist/chunk-HCIHOHLX.js.map +1 -0
- package/dist/chunk-HMJRPNPZ.js +1031 -0
- package/dist/chunk-HMJRPNPZ.js.map +1 -0
- package/dist/chunk-I5PZ4JTS.js +119 -0
- package/dist/chunk-I5PZ4JTS.js.map +1 -0
- package/dist/chunk-IYW62KKR.js +255 -0
- package/dist/chunk-IYW62KKR.js.map +1 -0
- package/dist/chunk-JAXXTYID.js +51 -0
- package/dist/chunk-JAXXTYID.js.map +1 -0
- package/dist/chunk-LSOYPSAT.js +183 -0
- package/dist/chunk-LSOYPSAT.js.map +1 -0
- package/dist/chunk-MFBHNWGV.js +416 -0
- package/dist/chunk-MFBHNWGV.js.map +1 -0
- package/dist/chunk-MXZSI3AY.js +311 -0
- package/dist/chunk-MXZSI3AY.js.map +1 -0
- package/dist/chunk-NBR3GHMT.js +72 -0
- package/dist/chunk-NBR3GHMT.js.map +1 -0
- package/dist/chunk-O3ZF22SW.js +246 -0
- package/dist/chunk-O3ZF22SW.js.map +1 -0
- package/dist/chunk-SUSJPZU2.js +181 -0
- package/dist/chunk-SUSJPZU2.js.map +1 -0
- package/dist/chunk-TEVZS4FA.js +310 -0
- package/dist/chunk-TEVZS4FA.js.map +1 -0
- package/dist/chunk-UY2SYSEZ.js +211 -0
- package/dist/chunk-UY2SYSEZ.js.map +1 -0
- package/dist/chunk-WAHVZH7V.js +260 -0
- package/dist/chunk-WAHVZH7V.js.map +1 -0
- package/dist/chunk-WPP3PEDE.js +234 -0
- package/dist/chunk-WPP3PEDE.js.map +1 -0
- package/dist/chunk-Y5XVD2CD.js +1610 -0
- package/dist/chunk-Y5XVD2CD.js.map +1 -0
- package/dist/chunk-YL5XFHR3.js +56 -0
- package/dist/chunk-YL5XFHR3.js.map +1 -0
- package/dist/chunk-ZGOHARPV.js +122 -0
- package/dist/chunk-ZGOHARPV.js.map +1 -0
- package/dist/claude-adapter-QMLFMSP3.js +6 -0
- package/dist/claude-adapter-QMLFMSP3.js.map +1 -0
- package/dist/claude-login-5WELXPKT.js +324 -0
- package/dist/claude-login-5WELXPKT.js.map +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +703 -0
- package/dist/cli.js.map +1 -0
- package/dist/codex-login-7HHLJHBF.js +164 -0
- package/dist/codex-login-7HHLJHBF.js.map +1 -0
- package/dist/config-store-W6FBCQAQ.js +6 -0
- package/dist/config-store-W6FBCQAQ.js.map +1 -0
- package/dist/executor-6RIKIGXK.js +4 -0
- package/dist/executor-6RIKIGXK.js.map +1 -0
- package/dist/gemini-adapter-6JIHZ7WI.js +6 -0
- package/dist/gemini-adapter-6JIHZ7WI.js.map +1 -0
- package/dist/gemini-login-ZZLYC3J6.js +346 -0
- package/dist/gemini-login-ZZLYC3J6.js.map +1 -0
- package/dist/index.d.ts +2210 -0
- package/dist/index.js +1419 -0
- package/dist/index.js.map +1 -0
- package/dist/kimi-adapter-JN4HFFHU.js +6 -0
- package/dist/kimi-adapter-JN4HFFHU.js.map +1 -0
- package/dist/kimi-login-CZPS63NK.js +149 -0
- package/dist/kimi-login-CZPS63NK.js.map +1 -0
- package/dist/native-cli-adapters-OLW3XX57.js +6 -0
- package/dist/native-cli-adapters-OLW3XX57.js.map +1 -0
- package/dist/ollama-adapter-OJQ3FKWK.js +6 -0
- package/dist/ollama-adapter-OJQ3FKWK.js.map +1 -0
- package/dist/openai-adapter-XU46EN7B.js +6 -0
- package/dist/openai-adapter-XU46EN7B.js.map +1 -0
- package/dist/registry-4KD24ZC3.js +6 -0
- package/dist/registry-4KD24ZC3.js.map +1 -0
- package/dist/registry-H7B3AHPQ.js +5 -0
- package/dist/registry-H7B3AHPQ.js.map +1 -0
- package/dist/server-manager-PTGBHCLS.js +5 -0
- package/dist/server-manager-PTGBHCLS.js.map +1 -0
- package/dist/session-manager-ECEEACGY.js +12 -0
- package/dist/session-manager-ECEEACGY.js.map +1 -0
- package/dist/team-manager-HC4XGCFY.js +11 -0
- package/dist/team-manager-HC4XGCFY.js.map +1 -0
- package/dist/tmux-manager-GPYZ3WQH.js +6 -0
- package/dist/tmux-manager-GPYZ3WQH.js.map +1 -0
- package/dist/tools-TSMXMHIF.js +6 -0
- package/dist/tools-TSMXMHIF.js.map +1 -0
- package/package.json +89 -0
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { getCredentialsPath, ensureSecureDirectory, getAemeathHome } from './chunk-NBR3GHMT.js';
|
|
2
|
+
import { logger } from './chunk-JAXXTYID.js';
|
|
3
|
+
import { scryptSync, randomBytes, createCipheriv, createDecipheriv } from 'crypto';
|
|
4
|
+
import { existsSync, chmodSync, writeFileSync, readFileSync } from 'fs';
|
|
5
|
+
|
|
6
|
+
var SERVICE_PREFIX = "com.aemeathcli";
|
|
7
|
+
var ALGORITHM = "aes-256-gcm";
|
|
8
|
+
var KEY_LENGTH = 32;
|
|
9
|
+
var IV_LENGTH = 16;
|
|
10
|
+
var TAG_LENGTH = 16;
|
|
11
|
+
var SALT_LENGTH = 32;
|
|
12
|
+
function getServiceName(provider) {
|
|
13
|
+
return `${SERVICE_PREFIX}.${provider}`;
|
|
14
|
+
}
|
|
15
|
+
var CredentialStore = class {
|
|
16
|
+
keytarAvailable;
|
|
17
|
+
/**
|
|
18
|
+
* Store a credential for a provider.
|
|
19
|
+
*/
|
|
20
|
+
async set(provider, credential) {
|
|
21
|
+
const data = JSON.stringify(credential);
|
|
22
|
+
const service = getServiceName(provider);
|
|
23
|
+
if (await this.isKeytarAvailable()) {
|
|
24
|
+
try {
|
|
25
|
+
const keytar = await this.getKeytar();
|
|
26
|
+
await keytar.setPassword(service, provider, data);
|
|
27
|
+
logger.info({ provider }, "Credential stored in OS keychain");
|
|
28
|
+
return;
|
|
29
|
+
} catch (error) {
|
|
30
|
+
logger.warn({ provider }, "OS keychain store failed, using encrypted fallback");
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
this.storeEncrypted(provider, data);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Get a credential for a provider.
|
|
37
|
+
*/
|
|
38
|
+
async get(provider) {
|
|
39
|
+
const service = getServiceName(provider);
|
|
40
|
+
if (await this.isKeytarAvailable()) {
|
|
41
|
+
try {
|
|
42
|
+
const keytar = await this.getKeytar();
|
|
43
|
+
const data = await keytar.getPassword(service, provider);
|
|
44
|
+
if (data) {
|
|
45
|
+
return JSON.parse(data);
|
|
46
|
+
}
|
|
47
|
+
} catch {
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return this.loadEncrypted(provider);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Delete a credential for a provider.
|
|
54
|
+
*/
|
|
55
|
+
async delete(provider) {
|
|
56
|
+
const service = getServiceName(provider);
|
|
57
|
+
if (await this.isKeytarAvailable()) {
|
|
58
|
+
try {
|
|
59
|
+
const keytar = await this.getKeytar();
|
|
60
|
+
await keytar.deletePassword(service, provider);
|
|
61
|
+
} catch {
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
this.deleteEncrypted(provider);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Check if a credential exists for a provider.
|
|
68
|
+
*/
|
|
69
|
+
async has(provider) {
|
|
70
|
+
const credential = await this.get(provider);
|
|
71
|
+
return credential !== void 0;
|
|
72
|
+
}
|
|
73
|
+
// ── Encrypted File Fallback ────────────────────────────────────────────
|
|
74
|
+
getEncryptionKey(salt) {
|
|
75
|
+
const machineId = process.env["USER"] ?? process.env["USERNAME"] ?? "aemeathcli";
|
|
76
|
+
const homedir = process.env["HOME"] ?? process.env["USERPROFILE"] ?? "/";
|
|
77
|
+
const password = `aemeathcli-${machineId}-${homedir}`;
|
|
78
|
+
return scryptSync(password, salt, KEY_LENGTH, {
|
|
79
|
+
N: 32768,
|
|
80
|
+
r: 8,
|
|
81
|
+
p: 1,
|
|
82
|
+
maxmem: 64 * 1024 * 1024
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
storeEncrypted(provider, data) {
|
|
86
|
+
const credPath = getCredentialsPath();
|
|
87
|
+
ensureSecureDirectory(getAemeathHome());
|
|
88
|
+
let store = {};
|
|
89
|
+
if (existsSync(credPath)) {
|
|
90
|
+
try {
|
|
91
|
+
const existing = this.decryptFile(credPath);
|
|
92
|
+
store = JSON.parse(existing);
|
|
93
|
+
} catch {
|
|
94
|
+
store = {};
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
store[provider] = data;
|
|
98
|
+
this.encryptFile(credPath, JSON.stringify(store));
|
|
99
|
+
chmodSync(credPath, 384);
|
|
100
|
+
logger.info({ provider }, "Credential stored in encrypted fallback");
|
|
101
|
+
}
|
|
102
|
+
loadEncrypted(provider) {
|
|
103
|
+
const credPath = getCredentialsPath();
|
|
104
|
+
if (!existsSync(credPath)) {
|
|
105
|
+
return void 0;
|
|
106
|
+
}
|
|
107
|
+
try {
|
|
108
|
+
const content = this.decryptFile(credPath);
|
|
109
|
+
const store = JSON.parse(content);
|
|
110
|
+
const data = store[provider];
|
|
111
|
+
if (data) {
|
|
112
|
+
return JSON.parse(data);
|
|
113
|
+
}
|
|
114
|
+
} catch {
|
|
115
|
+
return void 0;
|
|
116
|
+
}
|
|
117
|
+
return void 0;
|
|
118
|
+
}
|
|
119
|
+
deleteEncrypted(provider) {
|
|
120
|
+
const credPath = getCredentialsPath();
|
|
121
|
+
if (!existsSync(credPath)) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
try {
|
|
125
|
+
const content = this.decryptFile(credPath);
|
|
126
|
+
const store = JSON.parse(content);
|
|
127
|
+
delete store[provider];
|
|
128
|
+
this.encryptFile(credPath, JSON.stringify(store));
|
|
129
|
+
} catch {
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
encryptFile(filePath, plaintext) {
|
|
133
|
+
const salt = randomBytes(SALT_LENGTH);
|
|
134
|
+
const key = this.getEncryptionKey(salt);
|
|
135
|
+
const iv = randomBytes(IV_LENGTH);
|
|
136
|
+
const cipher = createCipheriv(ALGORITHM, key, iv);
|
|
137
|
+
const encrypted = Buffer.concat([cipher.update(plaintext, "utf-8"), cipher.final()]);
|
|
138
|
+
const tag = cipher.getAuthTag();
|
|
139
|
+
const output = Buffer.concat([salt, iv, tag, encrypted]);
|
|
140
|
+
writeFileSync(filePath, output);
|
|
141
|
+
}
|
|
142
|
+
decryptFile(filePath) {
|
|
143
|
+
const fileContent = readFileSync(filePath);
|
|
144
|
+
const hasStoredSalt = fileContent.length > SALT_LENGTH + IV_LENGTH + TAG_LENGTH;
|
|
145
|
+
let salt;
|
|
146
|
+
let dataOffset;
|
|
147
|
+
if (hasStoredSalt) {
|
|
148
|
+
salt = fileContent.subarray(0, SALT_LENGTH);
|
|
149
|
+
dataOffset = SALT_LENGTH;
|
|
150
|
+
} else {
|
|
151
|
+
const machineId = process.env["USER"] ?? process.env["USERNAME"] ?? "aemeathcli";
|
|
152
|
+
salt = Buffer.from(`aemeathcli-${machineId}`.padEnd(SALT_LENGTH, "\0").slice(0, SALT_LENGTH));
|
|
153
|
+
dataOffset = 0;
|
|
154
|
+
}
|
|
155
|
+
const key = this.getEncryptionKey(salt);
|
|
156
|
+
const iv = fileContent.subarray(dataOffset, dataOffset + IV_LENGTH);
|
|
157
|
+
const tag = fileContent.subarray(dataOffset + IV_LENGTH, dataOffset + IV_LENGTH + TAG_LENGTH);
|
|
158
|
+
const encrypted = fileContent.subarray(dataOffset + IV_LENGTH + TAG_LENGTH);
|
|
159
|
+
const decipher = createDecipheriv(ALGORITHM, key, iv);
|
|
160
|
+
decipher.setAuthTag(tag);
|
|
161
|
+
const decrypted = Buffer.concat([decipher.update(encrypted), decipher.final()]);
|
|
162
|
+
return decrypted.toString("utf-8");
|
|
163
|
+
}
|
|
164
|
+
// ── Keytar Detection ───────────────────────────────────────────────────
|
|
165
|
+
async isKeytarAvailable() {
|
|
166
|
+
if (this.keytarAvailable !== void 0) {
|
|
167
|
+
return this.keytarAvailable;
|
|
168
|
+
}
|
|
169
|
+
try {
|
|
170
|
+
await import('keytar');
|
|
171
|
+
this.keytarAvailable = true;
|
|
172
|
+
} catch {
|
|
173
|
+
this.keytarAvailable = false;
|
|
174
|
+
}
|
|
175
|
+
return this.keytarAvailable;
|
|
176
|
+
}
|
|
177
|
+
async getKeytar() {
|
|
178
|
+
return import('keytar');
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
export { CredentialStore };
|
|
183
|
+
//# sourceMappingURL=chunk-4IJD72YB.js.map
|
|
184
|
+
//# sourceMappingURL=chunk-4IJD72YB.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/auth/credential-store.ts"],"names":[],"mappings":"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","file":"chunk-4IJD72YB.js","sourcesContent":["/**\n * Credential storage per PRD section 13.6\n * Primary: OS keychain via node-keytar\n * Fallback: AES-256-GCM encrypted file\n */\n\nimport { createCipheriv, createDecipheriv, randomBytes, scryptSync } from \"node:crypto\";\nimport { readFileSync, writeFileSync, existsSync, chmodSync } from \"node:fs\";\nimport type { ProviderName, ICredential } from \"../types/index.js\";\nimport { getCredentialsPath, ensureSecureDirectory, getAemeathHome } from \"../utils/index.js\";\nimport { logger } from \"../utils/index.js\";\n\nconst SERVICE_PREFIX = \"com.aemeathcli\";\nconst ALGORITHM = \"aes-256-gcm\";\nconst KEY_LENGTH = 32;\nconst IV_LENGTH = 16;\nconst TAG_LENGTH = 16;\nconst SALT_LENGTH = 32;\n\nfunction getServiceName(provider: ProviderName): string {\n return `${SERVICE_PREFIX}.${provider}`;\n}\n\nexport class CredentialStore {\n private keytarAvailable: boolean | undefined;\n\n /**\n * Store a credential for a provider.\n */\n async set(provider: ProviderName, credential: ICredential): Promise<void> {\n const data = JSON.stringify(credential);\n const service = getServiceName(provider);\n\n if (await this.isKeytarAvailable()) {\n try {\n const keytar = await this.getKeytar();\n await keytar.setPassword(service, provider, data);\n logger.info({ provider }, \"Credential stored in OS keychain\");\n return;\n } catch (error: unknown) {\n logger.warn({ provider }, \"OS keychain store failed, using encrypted fallback\");\n }\n }\n\n // Fallback: encrypted file\n this.storeEncrypted(provider, data);\n }\n\n /**\n * Get a credential for a provider.\n */\n async get(provider: ProviderName): Promise<ICredential | undefined> {\n const service = getServiceName(provider);\n\n if (await this.isKeytarAvailable()) {\n try {\n const keytar = await this.getKeytar();\n const data = await keytar.getPassword(service, provider);\n if (data) {\n return JSON.parse(data) as ICredential;\n }\n } catch {\n // Try fallback\n }\n }\n\n // Fallback: encrypted file\n return this.loadEncrypted(provider);\n }\n\n /**\n * Delete a credential for a provider.\n */\n async delete(provider: ProviderName): Promise<void> {\n const service = getServiceName(provider);\n\n if (await this.isKeytarAvailable()) {\n try {\n const keytar = await this.getKeytar();\n await keytar.deletePassword(service, provider);\n } catch {\n // Ignore\n }\n }\n\n // Also clean fallback\n this.deleteEncrypted(provider);\n }\n\n /**\n * Check if a credential exists for a provider.\n */\n async has(provider: ProviderName): Promise<boolean> {\n const credential = await this.get(provider);\n return credential !== undefined;\n }\n\n // ── Encrypted File Fallback ────────────────────────────────────────────\n\n private getEncryptionKey(salt: Buffer): Buffer {\n // Derive key from machine-specific data + random salt using scrypt with high cost\n const machineId = process.env[\"USER\"] ?? process.env[\"USERNAME\"] ?? \"aemeathcli\";\n const homedir = process.env[\"HOME\"] ?? process.env[\"USERPROFILE\"] ?? \"/\";\n const password = `aemeathcli-${machineId}-${homedir}`;\n return scryptSync(password, salt, KEY_LENGTH, {\n N: 32768,\n r: 8,\n p: 1,\n maxmem: 64 * 1024 * 1024,\n });\n }\n\n private storeEncrypted(provider: ProviderName, data: string): void {\n const credPath = getCredentialsPath();\n ensureSecureDirectory(getAemeathHome());\n\n let store: Record<string, string> = {};\n if (existsSync(credPath)) {\n try {\n const existing = this.decryptFile(credPath);\n store = JSON.parse(existing) as Record<string, string>;\n } catch {\n store = {};\n }\n }\n\n store[provider] = data;\n this.encryptFile(credPath, JSON.stringify(store));\n chmodSync(credPath, 0o600);\n logger.info({ provider }, \"Credential stored in encrypted fallback\");\n }\n\n private loadEncrypted(provider: ProviderName): ICredential | undefined {\n const credPath = getCredentialsPath();\n if (!existsSync(credPath)) {\n return undefined;\n }\n\n try {\n const content = this.decryptFile(credPath);\n const store = JSON.parse(content) as Record<string, string>;\n const data = store[provider];\n if (data) {\n return JSON.parse(data) as ICredential;\n }\n } catch {\n return undefined;\n }\n\n return undefined;\n }\n\n private deleteEncrypted(provider: ProviderName): void {\n const credPath = getCredentialsPath();\n if (!existsSync(credPath)) {\n return;\n }\n\n try {\n const content = this.decryptFile(credPath);\n const store = JSON.parse(content) as Record<string, string>;\n delete store[provider];\n this.encryptFile(credPath, JSON.stringify(store));\n } catch {\n // Ignore\n }\n }\n\n private encryptFile(filePath: string, plaintext: string): void {\n const salt = randomBytes(SALT_LENGTH);\n const key = this.getEncryptionKey(salt);\n const iv = randomBytes(IV_LENGTH);\n const cipher = createCipheriv(ALGORITHM, key, iv);\n const encrypted = Buffer.concat([cipher.update(plaintext, \"utf-8\"), cipher.final()]);\n const tag = cipher.getAuthTag();\n\n // Format: salt(32) + iv(16) + tag(16) + encrypted\n const output = Buffer.concat([salt, iv, tag, encrypted]);\n writeFileSync(filePath, output);\n }\n\n private decryptFile(filePath: string): string {\n const fileContent = readFileSync(filePath);\n\n // Handle legacy format without salt (iv(16) + tag(16) + encrypted)\n const hasStoredSalt = fileContent.length > SALT_LENGTH + IV_LENGTH + TAG_LENGTH;\n let salt: Buffer;\n let dataOffset: number;\n\n if (hasStoredSalt) {\n salt = fileContent.subarray(0, SALT_LENGTH);\n dataOffset = SALT_LENGTH;\n } else {\n // Legacy fallback: derive salt from username (for backward compatibility)\n const machineId = process.env[\"USER\"] ?? process.env[\"USERNAME\"] ?? \"aemeathcli\";\n salt = Buffer.from(`aemeathcli-${machineId}`.padEnd(SALT_LENGTH, \"\\0\").slice(0, SALT_LENGTH));\n dataOffset = 0;\n }\n\n const key = this.getEncryptionKey(salt);\n const iv = fileContent.subarray(dataOffset, dataOffset + IV_LENGTH);\n const tag = fileContent.subarray(dataOffset + IV_LENGTH, dataOffset + IV_LENGTH + TAG_LENGTH);\n const encrypted = fileContent.subarray(dataOffset + IV_LENGTH + TAG_LENGTH);\n\n const decipher = createDecipheriv(ALGORITHM, key, iv);\n decipher.setAuthTag(tag);\n const decrypted = Buffer.concat([decipher.update(encrypted), decipher.final()]);\n\n return decrypted.toString(\"utf-8\");\n }\n\n // ── Keytar Detection ───────────────────────────────────────────────────\n\n private async isKeytarAvailable(): Promise<boolean> {\n if (this.keytarAvailable !== undefined) {\n return this.keytarAvailable;\n }\n\n try {\n await import(\"keytar\");\n this.keytarAvailable = true;\n } catch {\n this.keytarAvailable = false;\n }\n\n return this.keytarAvailable;\n }\n\n private async getKeytar(): Promise<typeof import(\"keytar\")> {\n return import(\"keytar\");\n }\n}\n"]}
|
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
import { SUPPORTED_MODELS } from './chunk-HCIHOHLX.js';
|
|
2
|
+
import { ModelNotFoundError, AuthenticationError } from './chunk-ZGOHARPV.js';
|
|
3
|
+
import { logger } from './chunk-JAXXTYID.js';
|
|
4
|
+
import { randomUUID } from 'crypto';
|
|
5
|
+
import { execa } from 'execa';
|
|
6
|
+
|
|
7
|
+
var CHARS_PER_TOKEN_ESTIMATE = 4;
|
|
8
|
+
function resolveCliTimeoutMs() {
|
|
9
|
+
const raw = process.env["AEMEATHCLI_NATIVE_CLI_TIMEOUT_MS"];
|
|
10
|
+
if (raw === void 0) {
|
|
11
|
+
return 0;
|
|
12
|
+
}
|
|
13
|
+
const parsed = Number.parseInt(raw, 10);
|
|
14
|
+
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
15
|
+
return 0;
|
|
16
|
+
}
|
|
17
|
+
return parsed;
|
|
18
|
+
}
|
|
19
|
+
var CLI_TIMEOUT_MS = resolveCliTimeoutMs();
|
|
20
|
+
function isRecord(value) {
|
|
21
|
+
return typeof value === "object" && value !== null;
|
|
22
|
+
}
|
|
23
|
+
function asString(value) {
|
|
24
|
+
return typeof value === "string" ? value : void 0;
|
|
25
|
+
}
|
|
26
|
+
function asNumber(value) {
|
|
27
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
28
|
+
}
|
|
29
|
+
function toJsonLines(output) {
|
|
30
|
+
const lines = output.split(/\r?\n/u).map((line) => line.trim()).filter((line) => line.length > 0 && line.startsWith("{"));
|
|
31
|
+
const parsed = [];
|
|
32
|
+
for (const line of lines) {
|
|
33
|
+
try {
|
|
34
|
+
parsed.push(JSON.parse(line));
|
|
35
|
+
} catch {
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return parsed;
|
|
39
|
+
}
|
|
40
|
+
function buildPrompt(request) {
|
|
41
|
+
const latestUser = [...request.messages].reverse().find((message) => message.role === "user");
|
|
42
|
+
const fallbackLast = request.messages.length > 0 ? request.messages[request.messages.length - 1] : void 0;
|
|
43
|
+
const latestPrompt = latestUser?.content ?? fallbackLast?.content ?? "";
|
|
44
|
+
if (request.system !== void 0 && request.system.length > 0) {
|
|
45
|
+
return `${request.system}
|
|
46
|
+
|
|
47
|
+
${latestPrompt}`.trim();
|
|
48
|
+
}
|
|
49
|
+
return latestPrompt;
|
|
50
|
+
}
|
|
51
|
+
function computeCost(modelInfo, inputTokens, outputTokens) {
|
|
52
|
+
return inputTokens / 1e6 * modelInfo.inputPricePerMToken + outputTokens / 1e6 * modelInfo.outputPricePerMToken;
|
|
53
|
+
}
|
|
54
|
+
function classifyCliError(provider, error) {
|
|
55
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
56
|
+
const lower = message.toLowerCase();
|
|
57
|
+
if (lower.includes("login") || lower.includes("credential") || lower.includes("authentication") || lower.includes("unauthorized") || lower.includes("forbidden") || lower.includes("api key") || lower.includes("token")) {
|
|
58
|
+
return new AuthenticationError(provider, message);
|
|
59
|
+
}
|
|
60
|
+
return error instanceof Error ? error : new Error(message);
|
|
61
|
+
}
|
|
62
|
+
var BaseNativeCLIAdapter = class {
|
|
63
|
+
async chat(request) {
|
|
64
|
+
const modelInfo = this.getModelInfo(request.model);
|
|
65
|
+
const prompt = buildPrompt(request);
|
|
66
|
+
try {
|
|
67
|
+
const result = await this.runCLI(request.model, prompt);
|
|
68
|
+
const inputTokens = result.inputTokens ?? Math.ceil(prompt.length / CHARS_PER_TOKEN_ESTIMATE);
|
|
69
|
+
const outputTokens = result.outputTokens ?? Math.ceil(result.text.length / CHARS_PER_TOKEN_ESTIMATE);
|
|
70
|
+
const usage = {
|
|
71
|
+
inputTokens,
|
|
72
|
+
outputTokens,
|
|
73
|
+
totalTokens: inputTokens + outputTokens,
|
|
74
|
+
costUsd: computeCost(modelInfo, inputTokens, outputTokens)
|
|
75
|
+
};
|
|
76
|
+
const responseMessage = {
|
|
77
|
+
id: randomUUID(),
|
|
78
|
+
role: "assistant",
|
|
79
|
+
content: result.text,
|
|
80
|
+
model: request.model,
|
|
81
|
+
provider: this.name,
|
|
82
|
+
tokenUsage: usage,
|
|
83
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
84
|
+
};
|
|
85
|
+
return {
|
|
86
|
+
id: randomUUID(),
|
|
87
|
+
model: request.model,
|
|
88
|
+
provider: this.name,
|
|
89
|
+
message: responseMessage,
|
|
90
|
+
usage,
|
|
91
|
+
finishReason: result.finishReason ?? "stop"
|
|
92
|
+
};
|
|
93
|
+
} catch (error) {
|
|
94
|
+
throw classifyCliError(this.name, error);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
async *stream(request) {
|
|
98
|
+
try {
|
|
99
|
+
const response = await this.chat(request);
|
|
100
|
+
if (response.message.content.length > 0) {
|
|
101
|
+
yield { type: "text", content: response.message.content };
|
|
102
|
+
}
|
|
103
|
+
yield { type: "usage", usage: response.usage };
|
|
104
|
+
yield { type: "done" };
|
|
105
|
+
} catch (error) {
|
|
106
|
+
const rawMsg = error instanceof Error ? error.message : String(error);
|
|
107
|
+
const truncated = rawMsg.length > 500 ? rawMsg.slice(0, 500) + "..." : rawMsg;
|
|
108
|
+
yield { type: "error", error: truncated };
|
|
109
|
+
yield { type: "done" };
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
async countTokens(text, _model) {
|
|
113
|
+
return Math.ceil(text.length / CHARS_PER_TOKEN_ESTIMATE);
|
|
114
|
+
}
|
|
115
|
+
getModelInfo(model) {
|
|
116
|
+
const info = SUPPORTED_MODELS[model];
|
|
117
|
+
if (info === void 0 || info.provider !== this.name) {
|
|
118
|
+
throw new ModelNotFoundError(model);
|
|
119
|
+
}
|
|
120
|
+
return info;
|
|
121
|
+
}
|
|
122
|
+
async listAvailableModels() {
|
|
123
|
+
return [...this.supportedModels];
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
var ClaudeNativeCLIAdapter = class extends BaseNativeCLIAdapter {
|
|
127
|
+
name = "anthropic";
|
|
128
|
+
supportedModels = [
|
|
129
|
+
"claude-opus-4-6",
|
|
130
|
+
"claude-opus-4-6-1m",
|
|
131
|
+
"claude-sonnet-4-6",
|
|
132
|
+
"claude-sonnet-4-6-1m",
|
|
133
|
+
"claude-haiku-4-5"
|
|
134
|
+
];
|
|
135
|
+
async runCLI(model, prompt) {
|
|
136
|
+
const { stdout } = await execa(
|
|
137
|
+
"claude",
|
|
138
|
+
["-p", "--output-format", "json", "--model", model, prompt],
|
|
139
|
+
{
|
|
140
|
+
timeout: CLI_TIMEOUT_MS,
|
|
141
|
+
stdin: "ignore",
|
|
142
|
+
env: { ...process.env, NO_COLOR: "1" }
|
|
143
|
+
}
|
|
144
|
+
);
|
|
145
|
+
const lines = toJsonLines(stdout);
|
|
146
|
+
const lastJson = lines.length > 0 ? lines[lines.length - 1] : void 0;
|
|
147
|
+
if (!isRecord(lastJson)) {
|
|
148
|
+
throw new Error("Claude CLI returned no JSON result");
|
|
149
|
+
}
|
|
150
|
+
const text = asString(lastJson["result"]) ?? "";
|
|
151
|
+
const usage = isRecord(lastJson["usage"]) ? lastJson["usage"] : void 0;
|
|
152
|
+
const inputTokens = usage ? asNumber(usage["input_tokens"]) : void 0;
|
|
153
|
+
const outputTokens = usage ? asNumber(usage["output_tokens"]) : void 0;
|
|
154
|
+
return {
|
|
155
|
+
text,
|
|
156
|
+
inputTokens,
|
|
157
|
+
outputTokens,
|
|
158
|
+
finishReason: "stop"
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
var CodexNativeCLIAdapter = class extends BaseNativeCLIAdapter {
|
|
163
|
+
name = "openai";
|
|
164
|
+
supportedModels = [
|
|
165
|
+
"gpt-5.3-codex",
|
|
166
|
+
"gpt-5.3-codex-spark",
|
|
167
|
+
"gpt-5.2-codex",
|
|
168
|
+
"gpt-5.1-codex-max",
|
|
169
|
+
"gpt-5.2",
|
|
170
|
+
"gpt-5.1-codex-mini"
|
|
171
|
+
];
|
|
172
|
+
async runCLI(model, prompt) {
|
|
173
|
+
const sandbox = process.env["AEMEATHCLI_CODEX_SANDBOX"] ?? "read-only";
|
|
174
|
+
const { stdout } = await execa(
|
|
175
|
+
"codex",
|
|
176
|
+
[
|
|
177
|
+
"exec",
|
|
178
|
+
"--skip-git-repo-check",
|
|
179
|
+
...sandbox !== "none" ? ["--sandbox", sandbox] : [],
|
|
180
|
+
"--json",
|
|
181
|
+
"--model",
|
|
182
|
+
model,
|
|
183
|
+
prompt
|
|
184
|
+
],
|
|
185
|
+
{
|
|
186
|
+
timeout: CLI_TIMEOUT_MS,
|
|
187
|
+
stdin: "ignore",
|
|
188
|
+
env: { ...process.env, NO_COLOR: "1" }
|
|
189
|
+
}
|
|
190
|
+
);
|
|
191
|
+
const lines = toJsonLines(stdout);
|
|
192
|
+
const textParts = [];
|
|
193
|
+
let inputTokens;
|
|
194
|
+
let outputTokens;
|
|
195
|
+
for (const line of lines) {
|
|
196
|
+
if (!isRecord(line)) continue;
|
|
197
|
+
const type = asString(line["type"]);
|
|
198
|
+
if (type === "item.completed") {
|
|
199
|
+
const item = isRecord(line["item"]) ? line["item"] : void 0;
|
|
200
|
+
if (item && asString(item["type"]) === "agent_message") {
|
|
201
|
+
const text = asString(item["text"]);
|
|
202
|
+
if (text && text.length > 0) {
|
|
203
|
+
textParts.push(text);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
if (type === "turn.completed") {
|
|
208
|
+
const usage = isRecord(line["usage"]) ? line["usage"] : void 0;
|
|
209
|
+
if (usage) {
|
|
210
|
+
inputTokens = asNumber(usage["input_tokens"]) ?? inputTokens;
|
|
211
|
+
outputTokens = asNumber(usage["output_tokens"]) ?? outputTokens;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
return {
|
|
216
|
+
text: textParts.join("\n").trim(),
|
|
217
|
+
inputTokens,
|
|
218
|
+
outputTokens,
|
|
219
|
+
finishReason: "stop"
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
var GeminiNativeCLIAdapter = class extends BaseNativeCLIAdapter {
|
|
224
|
+
name = "google";
|
|
225
|
+
supportedModels = [
|
|
226
|
+
"gemini-3-pro-preview",
|
|
227
|
+
"gemini-3-flash-preview",
|
|
228
|
+
"gemini-2.5-pro",
|
|
229
|
+
"gemini-2.5-flash",
|
|
230
|
+
"gemini-2.5-flash-lite"
|
|
231
|
+
];
|
|
232
|
+
async runCLI(model, prompt) {
|
|
233
|
+
const { stdout } = await execa(
|
|
234
|
+
"gemini",
|
|
235
|
+
[
|
|
236
|
+
"-p",
|
|
237
|
+
prompt,
|
|
238
|
+
"--model",
|
|
239
|
+
model,
|
|
240
|
+
"--output-format",
|
|
241
|
+
"stream-json",
|
|
242
|
+
"--approval-mode",
|
|
243
|
+
"yolo"
|
|
244
|
+
],
|
|
245
|
+
{
|
|
246
|
+
timeout: CLI_TIMEOUT_MS,
|
|
247
|
+
stdin: "ignore",
|
|
248
|
+
env: { ...process.env, NO_COLOR: "1" }
|
|
249
|
+
}
|
|
250
|
+
);
|
|
251
|
+
const lines = toJsonLines(stdout);
|
|
252
|
+
let text = "";
|
|
253
|
+
let inputTokens;
|
|
254
|
+
let outputTokens;
|
|
255
|
+
for (const line of lines) {
|
|
256
|
+
if (!isRecord(line)) continue;
|
|
257
|
+
const type = asString(line["type"]);
|
|
258
|
+
if (type === "message" && asString(line["role"]) === "assistant") {
|
|
259
|
+
const content = asString(line["content"]);
|
|
260
|
+
if (content !== void 0) {
|
|
261
|
+
const delta = line["delta"] === true;
|
|
262
|
+
text = delta ? `${text}${content}` : content;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
if (type === "result") {
|
|
266
|
+
const stats = isRecord(line["stats"]) ? line["stats"] : void 0;
|
|
267
|
+
if (stats) {
|
|
268
|
+
inputTokens = asNumber(stats["input_tokens"]) ?? inputTokens;
|
|
269
|
+
outputTokens = asNumber(stats["output_tokens"]) ?? outputTokens;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
return {
|
|
274
|
+
text: text.trim(),
|
|
275
|
+
inputTokens,
|
|
276
|
+
outputTokens,
|
|
277
|
+
finishReason: "stop"
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
};
|
|
281
|
+
var KimiNativeCLIAdapter = class extends BaseNativeCLIAdapter {
|
|
282
|
+
name = "kimi";
|
|
283
|
+
supportedModels = ["kimi-for-coding"];
|
|
284
|
+
async runCLI(_model, prompt) {
|
|
285
|
+
const { stdout } = await execa(
|
|
286
|
+
"kimi",
|
|
287
|
+
["--print", "--output-format", "stream-json", "-p", prompt],
|
|
288
|
+
{
|
|
289
|
+
timeout: CLI_TIMEOUT_MS,
|
|
290
|
+
stdin: "ignore",
|
|
291
|
+
env: { ...process.env, NO_COLOR: "1" }
|
|
292
|
+
}
|
|
293
|
+
);
|
|
294
|
+
const lines = toJsonLines(stdout);
|
|
295
|
+
let text = "";
|
|
296
|
+
for (const line of lines) {
|
|
297
|
+
if (!isRecord(line)) continue;
|
|
298
|
+
if (asString(line["role"]) !== "assistant") continue;
|
|
299
|
+
const content = line["content"];
|
|
300
|
+
if (!Array.isArray(content)) continue;
|
|
301
|
+
const textParts = [];
|
|
302
|
+
for (const part of content) {
|
|
303
|
+
if (!isRecord(part)) continue;
|
|
304
|
+
if (asString(part["type"]) === "text") {
|
|
305
|
+
const piece = asString(part["text"]);
|
|
306
|
+
if (piece) textParts.push(piece);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
if (textParts.length > 0) {
|
|
310
|
+
text = textParts.join("");
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
return {
|
|
314
|
+
text: text.trim(),
|
|
315
|
+
finishReason: "stop"
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
};
|
|
319
|
+
function logNativeAdapterSelection(provider) {
|
|
320
|
+
logger.info({ provider }, "Using native CLI adapter");
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
export { ClaudeNativeCLIAdapter, CodexNativeCLIAdapter, GeminiNativeCLIAdapter, KimiNativeCLIAdapter, logNativeAdapterSelection };
|
|
324
|
+
//# sourceMappingURL=chunk-6PDJ45T4.js.map
|
|
325
|
+
//# sourceMappingURL=chunk-6PDJ45T4.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/providers/native-cli-adapters.ts"],"names":[],"mappings":"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","file":"chunk-6PDJ45T4.js","sourcesContent":["/**\n * Native CLI-backed provider adapters.\n * Uses official provider CLIs in non-interactive mode when credentials come from native login.\n */\n\nimport { randomUUID } from \"node:crypto\";\nimport { execa } from \"execa\";\nimport {\n AuthenticationError,\n ModelNotFoundError,\n} from \"../types/errors.js\";\nimport { SUPPORTED_MODELS } from \"../types/model.js\";\nimport { logger } from \"../utils/logger.js\";\nimport type { IModelInfo, ProviderName } from \"../types/model.js\";\nimport type {\n IChatMessage,\n IChatRequest,\n IChatResponse,\n IStreamChunk,\n ITokenUsage,\n} from \"../types/message.js\";\nimport type { IModelProvider } from \"./types.js\";\n\ninterface ICLIResult {\n readonly text: string;\n readonly inputTokens?: number | undefined;\n readonly outputTokens?: number | undefined;\n readonly finishReason?: IChatResponse[\"finishReason\"] | undefined;\n}\n\nconst CHARS_PER_TOKEN_ESTIMATE = 4;\n\n/**\n * Resolve CLI timeout from environment. Default is 0 (no timeout) so that\n * long-running agent tasks are never prematurely killed.\n * Set AEMEATHCLI_NATIVE_CLI_TIMEOUT_MS to a positive integer to enforce a limit.\n */\nfunction resolveCliTimeoutMs(): number {\n const raw = process.env[\"AEMEATHCLI_NATIVE_CLI_TIMEOUT_MS\"];\n if (raw === undefined) {\n return 0;\n }\n\n const parsed = Number.parseInt(raw, 10);\n if (!Number.isFinite(parsed) || parsed <= 0) {\n return 0;\n }\n\n return parsed;\n}\n\nconst CLI_TIMEOUT_MS = resolveCliTimeoutMs();\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction asString(value: unknown): string | undefined {\n return typeof value === \"string\" ? value : undefined;\n}\n\nfunction asNumber(value: unknown): number | undefined {\n return typeof value === \"number\" && Number.isFinite(value) ? value : undefined;\n}\n\nfunction toJsonLines(output: string): unknown[] {\n const lines = output\n .split(/\\r?\\n/u)\n .map((line) => line.trim())\n .filter((line) => line.length > 0 && line.startsWith(\"{\"));\n\n const parsed: unknown[] = [];\n for (const line of lines) {\n try {\n parsed.push(JSON.parse(line) as unknown);\n } catch {\n // Ignore non-JSON lines\n }\n }\n return parsed;\n}\n\nfunction buildPrompt(request: IChatRequest): string {\n const latestUser = [...request.messages]\n .reverse()\n .find((message) => message.role === \"user\");\n const fallbackLast = request.messages.length > 0\n ? request.messages[request.messages.length - 1]\n : undefined;\n\n const latestPrompt = latestUser?.content ?? fallbackLast?.content ?? \"\";\n if (request.system !== undefined && request.system.length > 0) {\n return `${request.system}\\n\\n${latestPrompt}`.trim();\n }\n return latestPrompt;\n}\n\nfunction computeCost(modelInfo: IModelInfo, inputTokens: number, outputTokens: number): number {\n return (\n (inputTokens / 1_000_000) * modelInfo.inputPricePerMToken +\n (outputTokens / 1_000_000) * modelInfo.outputPricePerMToken\n );\n}\n\nfunction classifyCliError(provider: ProviderName, error: unknown): Error {\n const message = error instanceof Error ? error.message : String(error);\n const lower = message.toLowerCase();\n\n if (\n lower.includes(\"login\")\n || lower.includes(\"credential\")\n || lower.includes(\"authentication\")\n || lower.includes(\"unauthorized\")\n || lower.includes(\"forbidden\")\n || lower.includes(\"api key\")\n || lower.includes(\"token\")\n ) {\n return new AuthenticationError(provider, message);\n }\n\n return error instanceof Error ? error : new Error(message);\n}\n\nabstract class BaseNativeCLIAdapter implements IModelProvider {\n abstract readonly name: ProviderName;\n abstract readonly supportedModels: readonly string[];\n\n protected abstract runCLI(model: string, prompt: string): Promise<ICLIResult>;\n\n async chat(request: IChatRequest): Promise<IChatResponse> {\n const modelInfo = this.getModelInfo(request.model);\n const prompt = buildPrompt(request);\n\n try {\n const result = await this.runCLI(request.model, prompt);\n\n const inputTokens = result.inputTokens ?? Math.ceil(prompt.length / CHARS_PER_TOKEN_ESTIMATE);\n const outputTokens = result.outputTokens ?? Math.ceil(result.text.length / CHARS_PER_TOKEN_ESTIMATE);\n\n const usage: ITokenUsage = {\n inputTokens,\n outputTokens,\n totalTokens: inputTokens + outputTokens,\n costUsd: computeCost(modelInfo, inputTokens, outputTokens),\n };\n\n const responseMessage: IChatMessage = {\n id: randomUUID(),\n role: \"assistant\",\n content: result.text,\n model: request.model,\n provider: this.name,\n tokenUsage: usage,\n createdAt: new Date(),\n };\n\n return {\n id: randomUUID(),\n model: request.model,\n provider: this.name,\n message: responseMessage,\n usage,\n finishReason: result.finishReason ?? \"stop\",\n };\n } catch (error: unknown) {\n throw classifyCliError(this.name, error);\n }\n }\n\n async *stream(request: IChatRequest): AsyncIterable<IStreamChunk> {\n try {\n const response = await this.chat(request);\n if (response.message.content.length > 0) {\n yield { type: \"text\", content: response.message.content };\n }\n yield { type: \"usage\", usage: response.usage };\n yield { type: \"done\" };\n } catch (error: unknown) {\n // Execa errors can include raw stdout/stderr in the message.\n // Truncate to prevent raw CLI protocol output from leaking through.\n const rawMsg = error instanceof Error ? error.message : String(error);\n const truncated = rawMsg.length > 500 ? rawMsg.slice(0, 500) + \"...\" : rawMsg;\n yield { type: \"error\", error: truncated };\n yield { type: \"done\" };\n }\n }\n\n async countTokens(text: string, _model: string): Promise<number> {\n return Math.ceil(text.length / CHARS_PER_TOKEN_ESTIMATE);\n }\n\n getModelInfo(model: string): IModelInfo {\n const info = SUPPORTED_MODELS[model];\n if (info === undefined || info.provider !== this.name) {\n throw new ModelNotFoundError(model);\n }\n return info;\n }\n\n async listAvailableModels(): Promise<readonly string[]> {\n return [...this.supportedModels];\n }\n}\n\nexport class ClaudeNativeCLIAdapter extends BaseNativeCLIAdapter {\n readonly name: ProviderName = \"anthropic\";\n readonly supportedModels = [\n \"claude-opus-4-6\",\n \"claude-opus-4-6-1m\",\n \"claude-sonnet-4-6\",\n \"claude-sonnet-4-6-1m\",\n \"claude-haiku-4-5\",\n ] as const;\n\n protected async runCLI(model: string, prompt: string): Promise<ICLIResult> {\n const { stdout } = await execa(\n \"claude\",\n [\"-p\", \"--output-format\", \"json\", \"--model\", model, prompt],\n {\n timeout: CLI_TIMEOUT_MS,\n stdin: \"ignore\",\n env: { ...process.env, NO_COLOR: \"1\" },\n },\n );\n\n const lines = toJsonLines(stdout);\n const lastJson = lines.length > 0 ? lines[lines.length - 1] : undefined;\n\n if (!isRecord(lastJson)) {\n throw new Error(\"Claude CLI returned no JSON result\");\n }\n\n const text = asString(lastJson[\"result\"]) ?? \"\";\n const usage = isRecord(lastJson[\"usage\"]) ? lastJson[\"usage\"] : undefined;\n const inputTokens = usage ? asNumber(usage[\"input_tokens\"]) : undefined;\n const outputTokens = usage ? asNumber(usage[\"output_tokens\"]) : undefined;\n\n return {\n text,\n inputTokens,\n outputTokens,\n finishReason: \"stop\",\n };\n }\n}\n\nexport class CodexNativeCLIAdapter extends BaseNativeCLIAdapter {\n readonly name: ProviderName = \"openai\";\n readonly supportedModels = [\n \"gpt-5.3-codex\",\n \"gpt-5.3-codex-spark\",\n \"gpt-5.2-codex\",\n \"gpt-5.1-codex-max\",\n \"gpt-5.2\",\n \"gpt-5.1-codex-mini\",\n ] as const;\n\n protected async runCLI(model: string, prompt: string): Promise<ICLIResult> {\n // Allow agent panes to set a writable sandbox so codex can write to the\n // shared board directory. Default to \"read-only\" for normal usage.\n const sandbox = process.env[\"AEMEATHCLI_CODEX_SANDBOX\"] ?? \"read-only\";\n const { stdout } = await execa(\n \"codex\",\n [\n \"exec\",\n \"--skip-git-repo-check\",\n ...(sandbox !== \"none\" ? [\"--sandbox\", sandbox] : []),\n \"--json\",\n \"--model\",\n model,\n prompt,\n ],\n {\n timeout: CLI_TIMEOUT_MS,\n stdin: \"ignore\",\n env: { ...process.env, NO_COLOR: \"1\" },\n },\n );\n\n const lines = toJsonLines(stdout);\n const textParts: string[] = [];\n let inputTokens: number | undefined;\n let outputTokens: number | undefined;\n\n for (const line of lines) {\n if (!isRecord(line)) continue;\n const type = asString(line[\"type\"]);\n\n if (type === \"item.completed\") {\n const item = isRecord(line[\"item\"]) ? line[\"item\"] : undefined;\n if (item && asString(item[\"type\"]) === \"agent_message\") {\n const text = asString(item[\"text\"]);\n if (text && text.length > 0) {\n textParts.push(text);\n }\n }\n }\n\n if (type === \"turn.completed\") {\n const usage = isRecord(line[\"usage\"]) ? line[\"usage\"] : undefined;\n if (usage) {\n inputTokens = asNumber(usage[\"input_tokens\"]) ?? inputTokens;\n outputTokens = asNumber(usage[\"output_tokens\"]) ?? outputTokens;\n }\n }\n }\n\n return {\n text: textParts.join(\"\\n\").trim(),\n inputTokens,\n outputTokens,\n finishReason: \"stop\",\n };\n }\n}\n\nexport class GeminiNativeCLIAdapter extends BaseNativeCLIAdapter {\n readonly name: ProviderName = \"google\";\n readonly supportedModels = [\n \"gemini-3-pro-preview\",\n \"gemini-3-flash-preview\",\n \"gemini-2.5-pro\",\n \"gemini-2.5-flash\",\n \"gemini-2.5-flash-lite\",\n ] as const;\n\n protected async runCLI(model: string, prompt: string): Promise<ICLIResult> {\n const { stdout } = await execa(\n \"gemini\",\n [\n \"-p\",\n prompt,\n \"--model\",\n model,\n \"--output-format\",\n \"stream-json\",\n \"--approval-mode\",\n \"yolo\",\n ],\n {\n timeout: CLI_TIMEOUT_MS,\n stdin: \"ignore\",\n env: { ...process.env, NO_COLOR: \"1\" },\n },\n );\n\n const lines = toJsonLines(stdout);\n let text = \"\";\n let inputTokens: number | undefined;\n let outputTokens: number | undefined;\n\n for (const line of lines) {\n if (!isRecord(line)) continue;\n const type = asString(line[\"type\"]);\n\n if (type === \"message\" && asString(line[\"role\"]) === \"assistant\") {\n const content = asString(line[\"content\"]);\n if (content !== undefined) {\n const delta = line[\"delta\"] === true;\n text = delta ? `${text}${content}` : content;\n }\n }\n\n if (type === \"result\") {\n const stats = isRecord(line[\"stats\"]) ? line[\"stats\"] : undefined;\n if (stats) {\n inputTokens = asNumber(stats[\"input_tokens\"]) ?? inputTokens;\n outputTokens = asNumber(stats[\"output_tokens\"]) ?? outputTokens;\n }\n }\n }\n\n return {\n text: text.trim(),\n inputTokens,\n outputTokens,\n finishReason: \"stop\",\n };\n }\n}\n\nexport class KimiNativeCLIAdapter extends BaseNativeCLIAdapter {\n readonly name: ProviderName = \"kimi\";\n readonly supportedModels = [\"kimi-for-coding\"] as const;\n\n protected async runCLI(_model: string, prompt: string): Promise<ICLIResult> {\n const { stdout } = await execa(\n \"kimi\",\n [\"--print\", \"--output-format\", \"stream-json\", \"-p\", prompt],\n {\n timeout: CLI_TIMEOUT_MS,\n stdin: \"ignore\",\n env: { ...process.env, NO_COLOR: \"1\" },\n },\n );\n\n const lines = toJsonLines(stdout);\n let text = \"\";\n\n for (const line of lines) {\n if (!isRecord(line)) continue;\n if (asString(line[\"role\"]) !== \"assistant\") continue;\n\n const content = line[\"content\"];\n if (!Array.isArray(content)) continue;\n\n const textParts: string[] = [];\n for (const part of content) {\n if (!isRecord(part)) continue;\n if (asString(part[\"type\"]) === \"text\") {\n const piece = asString(part[\"text\"]);\n if (piece) textParts.push(piece);\n }\n }\n\n if (textParts.length > 0) {\n text = textParts.join(\"\");\n }\n }\n\n return {\n text: text.trim(),\n finishReason: \"stop\",\n };\n }\n}\n\nexport function logNativeAdapterSelection(provider: ProviderName): void {\n logger.info({ provider }, \"Using native CLI adapter\");\n}\n"]}
|