sleev 0.0.11 → 0.0.12

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 (2) hide show
  1. package/dist/apps/codex.js +70 -46
  2. package/package.json +1 -1
@@ -1,8 +1,11 @@
1
1
  // Codex setup owns global TOML patching for the OpenAI-compatible proxy provider.
2
- import { mkdir, readFile, writeFile } from 'node:fs/promises';
2
+ import { chmod, mkdir, readFile, writeFile } from 'node:fs/promises';
3
3
  import { homedir } from 'node:os';
4
4
  import { dirname, join } from 'node:path';
5
5
  import { field, success } from '../terminal.js';
6
+ const PROVIDER = 'sleev';
7
+ const HARNESS = 'codex cli';
8
+ const OLD_HARNESS = 'codex';
6
9
  export async function setupCodex(auth, path = codexPath()) {
7
10
  const result = await patchCodex(auth, path);
8
11
  success(process.stdout, 'Configured Codex');
@@ -12,8 +15,7 @@ export async function setupCodex(auth, path = codexPath()) {
12
15
  export async function patchCodex(auth, path = codexPath()) {
13
16
  const existing = await readText(path);
14
17
  const config = patchCodexConfig(existing, auth);
15
- await mkdir(dirname(path), { recursive: true, mode: 0o700 });
16
- await writeFile(path, config, { mode: 0o600 });
18
+ await writeText(path, config);
17
19
  return { path };
18
20
  }
19
21
  export async function unpatchCodex(path = codexPath()) {
@@ -21,25 +23,25 @@ export async function unpatchCodex(path = codexPath()) {
21
23
  if (!existing)
22
24
  return;
23
25
  const config = unpatchCodexConfig(existing);
24
- await mkdir(dirname(path), { recursive: true, mode: 0o700 });
25
- await writeFile(path, config, { mode: 0o600 });
26
+ await writeText(path, config);
26
27
  }
27
28
  export function codexPath(env = process.env) {
28
29
  return join(env.CODEX_HOME || join(homedir(), '.codex'), 'config.toml');
29
30
  }
30
31
  export function patchCodexConfig(input, auth) {
31
- const provider = rootString(input, 'model_provider') ?? 'openai';
32
- const target = reserved(provider) ? 'sleev' : provider;
33
- const stale = removeTable(input.trimEnd(), 'model_providers.sleev');
34
- const clean = target === provider ? stale : removeRootKey(stale, 'model_provider');
35
- const root = target === provider ? clean : insertRootKey(clean.trimEnd(), 'model_provider', target);
36
- const base = trim(auth.proxyUrl);
37
- return `${patchProvider(root, target, auth, base).trimEnd()}\n`;
32
+ const previous = previousProvider(input);
33
+ const stale = removeTable(removeTable(input.trimEnd(), table(PROVIDER)), 'sleev.codex');
34
+ const clean = removeRootKey(stale, 'model_provider');
35
+ const root = insertRootKey(clean.trimEnd(), 'model_provider', PROVIDER);
36
+ const meta = previous ? `\n\n[sleev.codex]\nprevious_model_provider = "${toml(previous)}"` : '';
37
+ return `${patchProvider(root, auth).trimEnd()}${meta}\n`;
38
38
  }
39
39
  export function unpatchCodexConfig(input) {
40
+ const previous = backup(input);
40
41
  const provider = rootString(input, 'model_provider') ?? 'openai';
41
- const clean = removeTable(removeRootKey(input.trimEnd(), 'model_provider'), 'model_providers.sleev');
42
- const config = provider === 'sleev' ? clean : removeSleevKeys(input, provider);
42
+ const clean = removeTable(removeTable(removeRootKey(input.trimEnd(), 'model_provider'), table(PROVIDER)), 'sleev.codex');
43
+ const restored = previous ? insertRootKey(clean.trimEnd(), 'model_provider', previous) : clean;
44
+ const config = provider === PROVIDER ? restored : removeSleevKeys(input, provider);
43
45
  return `${config.trimEnd()}\n`;
44
46
  }
45
47
  function insertRootKey(input, key, value) {
@@ -73,11 +75,11 @@ function removeRootKey(input, key) {
73
75
  }
74
76
  return next.join('\n');
75
77
  }
76
- function removeTable(input, table) {
78
+ function removeTable(input, name) {
77
79
  const lines = input.split('\n');
78
80
  const next = [];
79
81
  let skip = false;
80
- const header = new RegExp(`^\\s*\\[\\s*${escape(table)}(?:\\.|\\s*\\])`);
82
+ const header = new RegExp(`^\\s*\\[\\s*${escape(name)}(?:\\.|\\s*\\])`);
81
83
  for (const line of lines) {
82
84
  if (header.test(line)) {
83
85
  skip = true;
@@ -90,38 +92,23 @@ function removeTable(input, table) {
90
92
  }
91
93
  return next.join('\n');
92
94
  }
93
- function patchProvider(input, provider, auth, url) {
94
- const table = `model_providers.${provider}`;
95
- const clean = removeTable(input, `${table}.http_headers`);
96
- const lines = clean.split('\n');
97
- const header = new RegExp(`^\\s*\\[\\s*${escape(table)}\\s*\\]\\s*(#.*)?$`);
98
- const index = lines.findIndex((line) => header.test(line));
99
- const keys = providerKeys(auth, url);
100
- if (index === -1)
101
- return `${clean.trimEnd()}\n\n[${table}]\nname = "Sleev"\n${keys.join('\n')}`;
102
- const next = [];
103
- for (let i = 0; i < lines.length; i += 1) {
104
- const line = lines[i] ?? '';
105
- const inside = i > index && !/^\s*\[/.test(line);
106
- if (inside && /^\s*(base_url|wire_api|http_headers)\s*=/.test(line))
107
- continue;
108
- next.push(line);
109
- if (i === index)
110
- next.push(...keys);
111
- }
112
- return next.join('\n');
95
+ function patchProvider(input, auth) {
96
+ return `${input.trimEnd()}\n\n[${table(PROVIDER)}]\nname = "Sleev"\n${providerKeys(auth).join('\n')}`;
113
97
  }
114
- function providerKeys(auth, url) {
98
+ function providerKeys(auth) {
115
99
  return [
116
- `base_url = "${toml(url)}"`,
100
+ `base_url = "${toml(baseUrl(auth.proxyUrl))}"`,
117
101
  'wire_api = "responses"',
118
- `http_headers = { "sleeve-token" = "${toml(auth.token)}", "sleeve-provider" = "openai", "sleeve-harness" = "codex" }`,
102
+ '',
103
+ `[${table(PROVIDER)}.http_headers]`,
104
+ `"sleeve-token" = "${toml(auth.token)}"`,
105
+ '"sleeve-provider" = "openai"',
106
+ `"sleeve-harness" = "${HARNESS}"`,
119
107
  ];
120
108
  }
121
109
  function removeSleevKeys(input, provider) {
122
- const table = `model_providers.${provider}`;
123
110
  const lines = input.split('\n');
124
- const header = new RegExp(`^\\s*\\[\\s*${escape(table)}\\s*\\]\\s*(#.*)?$`);
111
+ const header = new RegExp(`^\\s*\\[\\s*${escape(table(provider))}\\s*\\]\\s*(#.*)?$`);
125
112
  const index = lines.findIndex((line) => header.test(line));
126
113
  if (index === -1)
127
114
  return input;
@@ -132,7 +119,7 @@ function removeSleevKeys(input, provider) {
132
119
  break;
133
120
  current.push(line);
134
121
  }
135
- if (!current.some((line) => line.includes('"sleeve-harness" = "codex"')))
122
+ if (!current.some((line) => owned(line)))
136
123
  return input;
137
124
  return lines
138
125
  .filter((line, i) => {
@@ -143,20 +130,40 @@ function removeSleevKeys(input, provider) {
143
130
  })
144
131
  .join('\n');
145
132
  }
133
+ function previousProvider(input) {
134
+ const current = rootString(input, 'model_provider');
135
+ return backup(input) ?? (current && current !== PROVIDER ? current : null);
136
+ }
137
+ function backup(input) {
138
+ return tableString(input, 'sleev.codex', 'previous_model_provider');
139
+ }
140
+ function tableString(input, name, key) {
141
+ const lines = input.split('\n');
142
+ const header = new RegExp(`^\\s*\\[\\s*${escape(name)}\\s*\\]\\s*(#.*)?$`);
143
+ const index = lines.findIndex((line) => header.test(line));
144
+ if (index === -1)
145
+ return null;
146
+ for (let i = index + 1; i < lines.length; i += 1) {
147
+ const line = lines[i] ?? '';
148
+ if (/^\s*\[/.test(line))
149
+ return null;
150
+ const match = new RegExp(`^\\s*${escape(key)}\\s*=\\s*(["'])([^"']+)\\1`).exec(line);
151
+ if (match?.[2])
152
+ return match[2];
153
+ }
154
+ return null;
155
+ }
146
156
  function rootString(input, key) {
147
157
  const lines = input.split('\n');
148
158
  for (const line of lines) {
149
159
  if (/^\s*\[/.test(line))
150
160
  return null;
151
- const match = new RegExp(`^\\s*${escape(key)}\\s*=\\s*([\"'])([^\"']+)\\1`).exec(line);
161
+ const match = new RegExp(`^\\s*${escape(key)}\\s*=\\s*(["'])([^"']+)\\1`).exec(line);
152
162
  if (match?.[2])
153
163
  return match[2];
154
164
  }
155
165
  return null;
156
166
  }
157
- function reserved(provider) {
158
- return provider === 'openai' || provider === 'ollama' || provider === 'lmstudio';
159
- }
160
167
  async function readText(path) {
161
168
  try {
162
169
  return await readFile(path, 'utf8');
@@ -176,6 +183,23 @@ function escape(value) {
176
183
  function trim(url) {
177
184
  return url.replace(/\/+$/, '');
178
185
  }
186
+ function baseUrl(url) {
187
+ const clean = trim(url);
188
+ if (clean.endsWith('/v1'))
189
+ return clean;
190
+ return `${clean}/v1`;
191
+ }
192
+ function table(provider) {
193
+ return `model_providers.${provider}`;
194
+ }
195
+ function owned(line) {
196
+ return line.includes(`"sleeve-harness" = "${HARNESS}"`) || line.includes(`"sleeve-harness" = "${OLD_HARNESS}"`);
197
+ }
198
+ async function writeText(path, config) {
199
+ await mkdir(dirname(path), { recursive: true, mode: 0o700 });
200
+ await writeFile(path, config, { mode: 0o600 });
201
+ await chmod(path, 0o600);
202
+ }
179
203
  function code(err) {
180
204
  if (typeof err !== 'object' || err === null || !('code' in err))
181
205
  return undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sleev",
3
- "version": "0.0.11",
3
+ "version": "0.0.12",
4
4
  "description": "Sleev command-line tools.",
5
5
  "type": "module",
6
6
  "bin": {