@narumitw/pi-codex-compact 0.51.3 → 0.53.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 +90 -90
- package/dist/chunks/chunk-7H7JJ7ZV.js +37 -0
- package/dist/chunks/chunk-7H7JJ7ZV.js.map +7 -0
- package/dist/chunks/{settings-menu-PEDLURUH.js → settings-menu-TVWWDPBF.js} +52 -35
- package/dist/chunks/settings-menu-TVWWDPBF.js.map +7 -0
- package/dist/index.ts +541 -101
- package/dist/index.ts.map +4 -4
- package/package.json +53 -57
- package/src/checkpoint.ts +265 -218
- package/src/codex-compact.ts +252 -229
- package/src/model-api.ts +56 -5
- package/src/protocol.ts +318 -179
- package/src/remote-compact.ts +276 -0
- package/src/remote-shared.ts +16 -0
- package/src/remote-types.ts +46 -0
- package/src/remote-v2.ts +66 -0
- package/src/remote.ts +14 -116
- package/src/settings-menu.ts +213 -201
- package/src/settings.ts +228 -176
- package/src/terminal.ts +6 -0
- package/dist/chunks/chunk-6TZ2L2BM.js +0 -13
- package/dist/chunks/chunk-6TZ2L2BM.js.map +0 -7
- package/dist/chunks/settings-menu-PEDLURUH.js.map +0 -7
package/src/settings.ts
CHANGED
|
@@ -3,225 +3,277 @@ import { constants } from "node:fs";
|
|
|
3
3
|
import { mkdir, open, rename, rm, writeFile } from "node:fs/promises";
|
|
4
4
|
import { basename, dirname, join } from "node:path";
|
|
5
5
|
import { getAgentDir } from "@earendil-works/pi-coding-agent";
|
|
6
|
+
import type { RemoteCompactionProtocolSetting } from "./model-api.js";
|
|
6
7
|
|
|
7
8
|
export const CODEX_COMPACT_SETTINGS_FILE = "pi-codex-compact.json";
|
|
8
9
|
export const MAX_SETTINGS_BYTES = 64 * 1024;
|
|
9
10
|
|
|
10
11
|
export interface CodexCompactSettings {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
enabled: boolean;
|
|
13
|
+
protocol: RemoteCompactionProtocolSetting;
|
|
14
|
+
apiProfiles: Record<string, "codex-responses-v1">;
|
|
15
|
+
requestTimeoutMs: number;
|
|
16
|
+
maxRetries: number;
|
|
17
|
+
replacementTokenBudget: number;
|
|
18
|
+
notifyOnFallback: boolean;
|
|
16
19
|
}
|
|
17
20
|
|
|
18
21
|
export const DEFAULT_CODEX_COMPACT_SETTINGS: Readonly<CodexCompactSettings> = Object.freeze({
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
enabled: true,
|
|
23
|
+
protocol: "auto",
|
|
24
|
+
apiProfiles: {},
|
|
25
|
+
requestTimeoutMs: 300_000,
|
|
26
|
+
maxRetries: 2,
|
|
27
|
+
replacementTokenBudget: 64_000,
|
|
28
|
+
notifyOnFallback: true,
|
|
24
29
|
});
|
|
25
30
|
|
|
26
31
|
const LIMITS = Object.freeze({
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
32
|
+
requestTimeoutMs: { minimum: 30_000, maximum: 600_000 },
|
|
33
|
+
maxRetries: { minimum: 0, maximum: 2 },
|
|
34
|
+
replacementTokenBudget: { minimum: 8_000, maximum: 128_000 },
|
|
30
35
|
});
|
|
31
36
|
|
|
37
|
+
const BUILT_IN_APIS = new Set([
|
|
38
|
+
"openai-completions",
|
|
39
|
+
"mistral-conversations",
|
|
40
|
+
"openai-codex-responses",
|
|
41
|
+
"openai-responses",
|
|
42
|
+
"azure-openai-responses",
|
|
43
|
+
"anthropic-messages",
|
|
44
|
+
"bedrock-converse-stream",
|
|
45
|
+
"google-generative-ai",
|
|
46
|
+
"google-vertex",
|
|
47
|
+
"pi-messages",
|
|
48
|
+
]);
|
|
49
|
+
const MAX_API_PROFILE_ID_LENGTH = 256;
|
|
50
|
+
|
|
32
51
|
export interface CodexCompactSettingsState {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
52
|
+
kind: "missing" | "loaded" | "invalid";
|
|
53
|
+
path: string;
|
|
54
|
+
settings: CodexCompactSettings;
|
|
55
|
+
document?: Record<string, unknown>;
|
|
56
|
+
issue?: string;
|
|
38
57
|
}
|
|
39
58
|
|
|
40
59
|
export interface CodexCompactSettingsRuntime {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
signal?: AbortSignal,
|
|
46
|
-
): Promise<Readonly<CodexCompactSettingsState>>;
|
|
47
|
-
flush(): Promise<void>;
|
|
60
|
+
get(): Readonly<CodexCompactSettingsState>;
|
|
61
|
+
reload(signal?: AbortSignal): Promise<Readonly<CodexCompactSettingsState>>;
|
|
62
|
+
update(patch: Partial<CodexCompactSettings>, signal?: AbortSignal): Promise<Readonly<CodexCompactSettingsState>>;
|
|
63
|
+
flush(): Promise<void>;
|
|
48
64
|
}
|
|
49
65
|
|
|
50
66
|
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
51
|
-
|
|
67
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
52
68
|
}
|
|
53
69
|
|
|
54
70
|
function validInteger(value: unknown, minimum: number, maximum: number): value is number {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
71
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= minimum && value <= maximum;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function hasWhitespaceOrControl(value: string): boolean {
|
|
75
|
+
return [...value].some((character) => {
|
|
76
|
+
const code = character.codePointAt(0) ?? 0;
|
|
77
|
+
return code <= 0x20 || code === 0x7f;
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function normalizeApiProfiles(value: unknown): Record<string, "codex-responses-v1"> | undefined {
|
|
82
|
+
if (
|
|
83
|
+
!isRecord(value) ||
|
|
84
|
+
(Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null)
|
|
85
|
+
) {
|
|
86
|
+
return undefined;
|
|
87
|
+
}
|
|
88
|
+
const profiles: Record<string, "codex-responses-v1"> = {};
|
|
89
|
+
for (const [api, profile] of Object.entries(value)) {
|
|
90
|
+
if (
|
|
91
|
+
api.length === 0 ||
|
|
92
|
+
api.length > MAX_API_PROFILE_ID_LENGTH ||
|
|
93
|
+
api.trim() !== api ||
|
|
94
|
+
hasWhitespaceOrControl(api) ||
|
|
95
|
+
BUILT_IN_APIS.has(api) ||
|
|
96
|
+
api === "__proto__" ||
|
|
97
|
+
api === "constructor" ||
|
|
98
|
+
api === "prototype" ||
|
|
99
|
+
profile !== "codex-responses-v1"
|
|
100
|
+
) {
|
|
101
|
+
return undefined;
|
|
102
|
+
}
|
|
103
|
+
profiles[api] = profile;
|
|
104
|
+
}
|
|
105
|
+
return profiles;
|
|
58
106
|
}
|
|
59
107
|
|
|
60
108
|
export function normalizeCodexCompactSettings(value: unknown): CodexCompactSettings | undefined {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
109
|
+
if (!isRecord(value)) return undefined;
|
|
110
|
+
if (Object.hasOwn(value, "enabled") && typeof value.enabled !== "boolean") return undefined;
|
|
111
|
+
if (
|
|
112
|
+
Object.hasOwn(value, "protocol") &&
|
|
113
|
+
value.protocol !== "auto" &&
|
|
114
|
+
value.protocol !== "remote-v2" &&
|
|
115
|
+
value.protocol !== "responses-compact"
|
|
116
|
+
) {
|
|
117
|
+
return undefined;
|
|
118
|
+
}
|
|
119
|
+
if (Object.hasOwn(value, "notifyOnFallback") && typeof value.notifyOnFallback !== "boolean") {
|
|
120
|
+
return undefined;
|
|
121
|
+
}
|
|
122
|
+
if (Object.hasOwn(value, "apiProfiles") && normalizeApiProfiles(value.apiProfiles) === undefined) return undefined;
|
|
123
|
+
for (const [field, limits] of Object.entries(LIMITS) as [
|
|
124
|
+
keyof typeof LIMITS,
|
|
125
|
+
{ minimum: number; maximum: number },
|
|
126
|
+
][]) {
|
|
127
|
+
if (Object.hasOwn(value, field) && !validInteger(value[field], limits.minimum, limits.maximum)) {
|
|
128
|
+
return undefined;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return {
|
|
132
|
+
enabled: typeof value.enabled === "boolean" ? value.enabled : DEFAULT_CODEX_COMPACT_SETTINGS.enabled,
|
|
133
|
+
protocol:
|
|
134
|
+
value.protocol === "remote-v2" || value.protocol === "responses-compact"
|
|
135
|
+
? value.protocol
|
|
136
|
+
: DEFAULT_CODEX_COMPACT_SETTINGS.protocol,
|
|
137
|
+
apiProfiles: normalizeApiProfiles(value.apiProfiles) ?? structuredClone(DEFAULT_CODEX_COMPACT_SETTINGS.apiProfiles),
|
|
138
|
+
requestTimeoutMs:
|
|
139
|
+
typeof value.requestTimeoutMs === "number"
|
|
140
|
+
? value.requestTimeoutMs
|
|
141
|
+
: DEFAULT_CODEX_COMPACT_SETTINGS.requestTimeoutMs,
|
|
142
|
+
maxRetries: typeof value.maxRetries === "number" ? value.maxRetries : DEFAULT_CODEX_COMPACT_SETTINGS.maxRetries,
|
|
143
|
+
replacementTokenBudget:
|
|
144
|
+
typeof value.replacementTokenBudget === "number"
|
|
145
|
+
? value.replacementTokenBudget
|
|
146
|
+
: DEFAULT_CODEX_COMPACT_SETTINGS.replacementTokenBudget,
|
|
147
|
+
notifyOnFallback:
|
|
148
|
+
typeof value.notifyOnFallback === "boolean"
|
|
149
|
+
? value.notifyOnFallback
|
|
150
|
+
: DEFAULT_CODEX_COMPACT_SETTINGS.notifyOnFallback,
|
|
151
|
+
};
|
|
96
152
|
}
|
|
97
153
|
|
|
98
154
|
export function codexCompactSettingsPath(): string {
|
|
99
|
-
|
|
155
|
+
return join(getAgentDir(), CODEX_COMPACT_SETTINGS_FILE);
|
|
100
156
|
}
|
|
101
157
|
|
|
102
158
|
function aborted(signal?: AbortSignal): void {
|
|
103
|
-
|
|
159
|
+
if (signal?.aborted) throw new DOMException("Settings operation aborted", "AbortError");
|
|
104
160
|
}
|
|
105
161
|
|
|
106
162
|
export async function loadCodexCompactSettings(
|
|
107
|
-
|
|
108
|
-
|
|
163
|
+
path = codexCompactSettingsPath(),
|
|
164
|
+
signal?: AbortSignal,
|
|
109
165
|
): Promise<CodexCompactSettingsState> {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
166
|
+
aborted(signal);
|
|
167
|
+
try {
|
|
168
|
+
const handle = await open(path, constants.O_RDONLY | constants.O_NOFOLLOW);
|
|
169
|
+
let text: string;
|
|
170
|
+
try {
|
|
171
|
+
const stats = await handle.stat();
|
|
172
|
+
aborted(signal);
|
|
173
|
+
if (!stats.isFile()) throw new Error("settings path is not a regular file");
|
|
174
|
+
if (stats.size > MAX_SETTINGS_BYTES) throw new Error("settings file exceeds 64 KiB");
|
|
175
|
+
text = await handle.readFile("utf8");
|
|
176
|
+
} finally {
|
|
177
|
+
await handle.close();
|
|
178
|
+
}
|
|
179
|
+
aborted(signal);
|
|
180
|
+
const document = JSON.parse(text) as unknown;
|
|
181
|
+
const settings = normalizeCodexCompactSettings(document);
|
|
182
|
+
if (!settings || !isRecord(document)) throw new Error("invalid settings shape or bounds");
|
|
183
|
+
return { kind: "loaded", path, settings, document };
|
|
184
|
+
} catch (error) {
|
|
185
|
+
if (signal?.aborted) throw error;
|
|
186
|
+
if (isNodeError(error) && error.code === "ENOENT") {
|
|
187
|
+
return {
|
|
188
|
+
kind: "missing",
|
|
189
|
+
path,
|
|
190
|
+
settings: { ...DEFAULT_CODEX_COMPACT_SETTINGS },
|
|
191
|
+
document: {},
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
return {
|
|
195
|
+
kind: "invalid",
|
|
196
|
+
path,
|
|
197
|
+
settings: { ...DEFAULT_CODEX_COMPACT_SETTINGS },
|
|
198
|
+
issue:
|
|
199
|
+
isNodeError(error) && error.code === "ELOOP"
|
|
200
|
+
? "symbolic links are not accepted"
|
|
201
|
+
: error instanceof Error
|
|
202
|
+
? error.message
|
|
203
|
+
: String(error),
|
|
204
|
+
};
|
|
205
|
+
}
|
|
150
206
|
}
|
|
151
207
|
|
|
152
208
|
async function savePatch(
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
209
|
+
path: string,
|
|
210
|
+
patch: Partial<CodexCompactSettings>,
|
|
211
|
+
signal?: AbortSignal,
|
|
156
212
|
): Promise<CodexCompactSettingsState> {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
}
|
|
188
|
-
return { kind: "loaded", path, settings, document };
|
|
213
|
+
const latest = await loadCodexCompactSettings(path, signal);
|
|
214
|
+
if (latest.kind === "invalid") {
|
|
215
|
+
throw new Error("Cannot overwrite an invalid pi-codex-compact.json; repair it and reload first");
|
|
216
|
+
}
|
|
217
|
+
const document = { ...latest.document, ...patch };
|
|
218
|
+
const settings = normalizeCodexCompactSettings(document);
|
|
219
|
+
if (!settings) throw new Error("Refusing to save invalid Codex compaction settings");
|
|
220
|
+
const temporaryPath = join(dirname(path), `.${basename(path)}.${randomUUID()}.tmp`);
|
|
221
|
+
await mkdir(dirname(path), { recursive: true });
|
|
222
|
+
aborted(signal);
|
|
223
|
+
try {
|
|
224
|
+
await writeFile(temporaryPath, `${JSON.stringify(document, null, 2)}\n`, {
|
|
225
|
+
encoding: "utf8",
|
|
226
|
+
flag: "wx",
|
|
227
|
+
mode: 0o600,
|
|
228
|
+
});
|
|
229
|
+
aborted(signal);
|
|
230
|
+
const current = await loadCodexCompactSettings(path, signal);
|
|
231
|
+
if (
|
|
232
|
+
current.kind === "invalid" ||
|
|
233
|
+
current.kind !== latest.kind ||
|
|
234
|
+
JSON.stringify(current.document) !== JSON.stringify(latest.document)
|
|
235
|
+
) {
|
|
236
|
+
throw new Error("pi-codex-compact.json changed while saving; reopen settings and retry");
|
|
237
|
+
}
|
|
238
|
+
await rename(temporaryPath, path);
|
|
239
|
+
} finally {
|
|
240
|
+
await rm(temporaryPath, { force: true }).catch(() => undefined);
|
|
241
|
+
}
|
|
242
|
+
return { kind: "loaded", path, settings, document };
|
|
189
243
|
}
|
|
190
244
|
|
|
191
|
-
export function createCodexCompactSettingsRuntime(
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
flush: () => queue,
|
|
222
|
-
};
|
|
245
|
+
export function createCodexCompactSettingsRuntime(path = codexCompactSettingsPath()): CodexCompactSettingsRuntime {
|
|
246
|
+
let state: CodexCompactSettingsState = {
|
|
247
|
+
kind: "missing",
|
|
248
|
+
path,
|
|
249
|
+
settings: { ...DEFAULT_CODEX_COMPACT_SETTINGS },
|
|
250
|
+
document: {},
|
|
251
|
+
};
|
|
252
|
+
let queue = Promise.resolve();
|
|
253
|
+
const enqueue = <T>(operation: () => Promise<T>): Promise<T> => {
|
|
254
|
+
const result = queue.then(operation, operation);
|
|
255
|
+
queue = result.then(
|
|
256
|
+
() => undefined,
|
|
257
|
+
() => undefined,
|
|
258
|
+
);
|
|
259
|
+
return result;
|
|
260
|
+
};
|
|
261
|
+
return {
|
|
262
|
+
get: () => structuredClone(state),
|
|
263
|
+
reload: (signal) =>
|
|
264
|
+
enqueue(async () => {
|
|
265
|
+
state = await loadCodexCompactSettings(path, signal);
|
|
266
|
+
return structuredClone(state);
|
|
267
|
+
}),
|
|
268
|
+
update: (patch, signal) =>
|
|
269
|
+
enqueue(async () => {
|
|
270
|
+
state = await savePatch(path, patch, signal);
|
|
271
|
+
return structuredClone(state);
|
|
272
|
+
}),
|
|
273
|
+
flush: () => queue,
|
|
274
|
+
};
|
|
223
275
|
}
|
|
224
276
|
|
|
225
277
|
function isNodeError(error: unknown): error is NodeJS.ErrnoException {
|
|
226
|
-
|
|
278
|
+
return error instanceof Error && "code" in error;
|
|
227
279
|
}
|
package/src/terminal.ts
ADDED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
// @generated by scripts/build-runtime.mjs; do not edit.
|
|
2
|
-
// @ts-nocheck -- the generated entry uses a .ts extension for Pi's Jiti loader.
|
|
3
|
-
|
|
4
|
-
// src/model-api.ts
|
|
5
|
-
import { hasApi } from "@earendil-works/pi-ai";
|
|
6
|
-
function usesCodexResponsesApi(model) {
|
|
7
|
-
return model !== void 0 && hasApi(model, "openai-codex-responses");
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export {
|
|
11
|
-
usesCodexResponsesApi
|
|
12
|
-
};
|
|
13
|
-
//# sourceMappingURL=chunk-6TZ2L2BM.js.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../src/model-api.ts"],
|
|
4
|
-
"sourcesContent": ["import type { Api, Model } from \"@earendil-works/pi-ai\";\nimport { hasApi } from \"@earendil-works/pi-ai\";\n\nexport function usesCodexResponsesApi(\n\tmodel: Model<Api> | undefined,\n): model is Model<\"openai-codex-responses\"> {\n\treturn model !== undefined && hasApi(model, \"openai-codex-responses\");\n}\n"],
|
|
5
|
-
"mappings": ";;;;AACA,SAAS,cAAc;AAEhB,SAAS,sBACf,OAC2C;AAC3C,SAAO,UAAU,UAAa,OAAO,OAAO,wBAAwB;AACrE;",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../src/settings-menu.ts"],
|
|
4
|
-
"sourcesContent": ["import type { ExtensionCommandContext } from \"@earendil-works/pi-coding-agent\";\nimport type { MenuDefinition } from \"@narumitw/pi-tui-kit\";\nimport { usesCodexResponsesApi } from \"./model-api.js\";\nimport type {\n\tCodexCompactSettings,\n\tCodexCompactSettingsRuntime,\n\tCodexCompactSettingsState,\n} from \"./settings.js\";\n\ntype Screen = \"main\" | \"settings\" | \"invalid\";\ntype Action =\n\t| \"compact-now\"\n\t| \"set-enabled\"\n\t| \"set-timeout\"\n\t| \"set-retries\"\n\t| \"set-retention\"\n\t| \"set-notify\";\n\nexport interface SettingsMenuOwner {\n\tsignal: AbortSignal;\n\tisCurrent(): boolean;\n}\n\ninterface CompactMenuStatus {\n\tmodel: string;\n\tremoteEligible: boolean;\n}\n\nfunction safeText(value: string): string {\n\treturn Array.from(value, (character) => {\n\t\tconst codePoint = character.codePointAt(0) ?? 0;\n\t\treturn codePoint < 32 || (codePoint >= 127 && codePoint <= 159) ? \" \" : character;\n\t}).join(\"\");\n}\n\nfunction timeoutLabel(milliseconds: number): string {\n\treturn `${milliseconds / 60_000} min`;\n}\n\nfunction retentionLabel(tokens: number): string {\n\treturn `${tokens / 1000}K tokens`;\n}\n\nasync function update(\n\truntime: CodexCompactSettingsRuntime,\n\tctx: ExtensionCommandContext,\n\tpatch: Partial<CodexCompactSettings>,\n\tsignal: AbortSignal,\n) {\n\ttry {\n\t\tawait runtime.update(patch, signal);\n\t\tctx.ui.notify(\"Codex compaction settings saved.\", \"info\");\n\t\treturn { kind: \"stay\" as const };\n\t} catch (error) {\n\t\tif (signal.aborted) return { kind: \"rejected\" as const };\n\t\tctx.ui.notify(\n\t\t\t`Could not save pi-codex-compact.json: ${safeText(error instanceof Error ? error.message : String(error))}`,\n\t\t\t\"error\",\n\t\t);\n\t\treturn { kind: \"rejected\" as const };\n\t}\n}\n\nexport function createCodexCompactMenu(\n\truntime: CodexCompactSettingsRuntime,\n\toptions: { onCompactRequested?: () => void; status?: CompactMenuStatus } = {},\n): MenuDefinition<CodexCompactSettingsState, Screen, Action, ExtensionCommandContext> {\n\treturn {\n\t\tstart: \"main\",\n\t\tscreens: {\n\t\t\tmain: ({ state }) => ({\n\t\t\t\tkind: \"actions\",\n\t\t\t\ttitle: \"Codex Remote Compaction\",\n\t\t\t\tlines: [\n\t\t\t\t\t`Remote V2: ${state.settings.enabled ? \"On\" : \"Off\"}`,\n\t\t\t\t\t`Active model: ${safeText(options.status?.model ?? \"none\")}`,\n\t\t\t\t\t`Compact route: ${safeText(compactRoute(state, options.status))}`,\n\t\t\t\t],\n\t\t\t\titems: [\n\t\t\t\t\t{\n\t\t\t\t\t\tid: \"compact-now\",\n\t\t\t\t\t\tlabel: \"Compact now\",\n\t\t\t\t\t\tdescription: \"Close this menu and compact the active session immediately.\",\n\t\t\t\t\t\taction: \"compact-now\",\n\t\t\t\t\t},\n\t\t\t\t\tstate.kind === \"invalid\"\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\tid: \"settings\",\n\t\t\t\t\t\t\t\tlabel: \"Settings\",\n\t\t\t\t\t\t\t\tdescription: \"Read-only until the invalid settings file is repaired.\",\n\t\t\t\t\t\t\t\tto: \"invalid\" as const,\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t: { id: \"settings\", label: \"Settings\", to: \"settings\" as const },\n\t\t\t\t\t{ id: \"close\", label: \"Close\", close: true },\n\t\t\t\t],\n\t\t\t\thint: \"close\",\n\t\t\t}),\n\t\t\tsettings: ({ state }) => ({\n\t\t\t\tkind: \"settings\",\n\t\t\t\ttitle: \"Codex Remote Compaction Settings\",\n\t\t\t\tlines: [`User settings \u00B7 ${safeText(state.path)}`],\n\t\t\t\titems: [\n\t\t\t\t\t{\n\t\t\t\t\t\tid: \"enabled\",\n\t\t\t\t\t\tlabel: \"Remote compaction\",\n\t\t\t\t\t\tdescription: \"Use Codex Remote V2 when the model uses openai-codex-responses.\",\n\t\t\t\t\t\tcurrentValue: state.settings.enabled ? \"On\" : \"Off\",\n\t\t\t\t\t\tvalues: [\"On\", \"Off\"],\n\t\t\t\t\t\taction: \"set-enabled\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tid: \"requestTimeoutMs\",\n\t\t\t\t\t\tlabel: \"Request timeout\",\n\t\t\t\t\t\tdescription: \"Maximum time for the extension-owned remote compaction request.\",\n\t\t\t\t\t\tcurrentValue: timeoutLabel(state.settings.requestTimeoutMs),\n\t\t\t\t\t\tvalues: [\"2 min\", \"5 min\", \"10 min\"],\n\t\t\t\t\t\taction: \"set-timeout\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tid: \"maxRetries\",\n\t\t\t\t\t\tlabel: \"Transport retries\",\n\t\t\t\t\t\tdescription: \"Retry transient provider failures before falling back to Pi.\",\n\t\t\t\t\t\tcurrentValue: String(state.settings.maxRetries),\n\t\t\t\t\t\tvalues: [\"0\", \"1\", \"2\"],\n\t\t\t\t\t\taction: \"set-retries\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tid: \"replacementTokenBudget\",\n\t\t\t\t\t\tlabel: \"Retained user history\",\n\t\t\t\t\t\tdescription: \"Approximate user-message budget kept beside the opaque checkpoint.\",\n\t\t\t\t\t\tcurrentValue: retentionLabel(state.settings.replacementTokenBudget),\n\t\t\t\t\t\tvalues: [\"32K tokens\", \"64K tokens\", \"96K tokens\", \"128K tokens\"],\n\t\t\t\t\t\taction: \"set-retention\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tid: \"notifyOnFallback\",\n\t\t\t\t\t\tlabel: \"Fallback notifications\",\n\t\t\t\t\t\tdescription: \"Warn when Remote V2 fails and native Pi compaction takes over.\",\n\t\t\t\t\t\tcurrentValue: state.settings.notifyOnFallback ? \"On\" : \"Off\",\n\t\t\t\t\t\tvalues: [\"On\", \"Off\"],\n\t\t\t\t\t\taction: \"set-notify\",\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t}),\n\t\t\tinvalid: ({ state }) => ({\n\t\t\t\tkind: \"detail\",\n\t\t\t\ttitle: \"Codex Compact Settings \u00B7 Read only\",\n\t\t\t\tlines: [\n\t\t\t\t\t`Invalid settings file: ${safeText(state.path)}`,\n\t\t\t\t\t`Issue: ${safeText(state.issue ?? \"unknown validation error\")}`,\n\t\t\t\t\t\"Built-in defaults are active. Repair the file and run /reload; it will not be overwritten.\",\n\t\t\t\t],\n\t\t\t\thint: \"back\",\n\t\t\t}),\n\t\t},\n\t\tactions: {\n\t\t\t\"compact-now\": async () => {\n\t\t\t\toptions.onCompactRequested?.();\n\t\t\t\treturn { kind: \"close\" };\n\t\t\t},\n\t\t\t\"set-enabled\": ({ ctx, value, signal }) =>\n\t\t\t\tupdate(runtime, ctx, { enabled: value === \"On\" }, signal),\n\t\t\t\"set-timeout\": ({ ctx, value, signal }) =>\n\t\t\t\tupdate(\n\t\t\t\t\truntime,\n\t\t\t\t\tctx,\n\t\t\t\t\t{ requestTimeoutMs: Number.parseInt(value ?? \"5\", 10) * 60_000 },\n\t\t\t\t\tsignal,\n\t\t\t\t),\n\t\t\t\"set-retries\": ({ ctx, value, signal }) =>\n\t\t\t\tupdate(runtime, ctx, { maxRetries: Number.parseInt(value ?? \"2\", 10) }, signal),\n\t\t\t\"set-retention\": ({ ctx, value, signal }) =>\n\t\t\t\tupdate(\n\t\t\t\t\truntime,\n\t\t\t\t\tctx,\n\t\t\t\t\t{ replacementTokenBudget: Number.parseInt(value ?? \"64\", 10) * 1000 },\n\t\t\t\t\tsignal,\n\t\t\t\t),\n\t\t\t\"set-notify\": ({ ctx, value, signal }) =>\n\t\t\t\tupdate(runtime, ctx, { notifyOnFallback: value === \"On\" }, signal),\n\t\t},\n\t};\n}\n\nexport async function showCodexCompactMenu(\n\truntime: CodexCompactSettingsRuntime,\n\tctx: ExtensionCommandContext,\n\towner: SettingsMenuOwner,\n): Promise<void> {\n\tif (ctx.mode !== \"tui\") {\n\t\tctx.ui.notify(`Edit Codex compaction settings at ${safeText(runtime.get().path)}.`, \"info\");\n\t\treturn;\n\t}\n\tconst { runMenu } = await import(\"@narumitw/pi-tui-kit\");\n\tif (owner.signal.aborted || !owner.isCurrent()) return;\n\tlet compactRequested = false;\n\tawait runMenu(\n\t\tctx,\n\t\tcreateCodexCompactMenu(runtime, {\n\t\t\tonCompactRequested: () => {\n\t\t\t\tcompactRequested = true;\n\t\t\t},\n\t\t\tstatus: compactMenuStatus(ctx),\n\t\t}),\n\t\t{\n\t\t\tgetState: () => runtime.get(),\n\t\t\tsignal: owner.signal,\n\t\t\tisCurrent: owner.isCurrent,\n\t\t},\n\t);\n\tif (!compactRequested || owner.signal.aborted || !owner.isCurrent()) return;\n\tctx.compact({\n\t\tonError: (error) => {\n\t\t\tif (!owner.signal.aborted && owner.isCurrent()) {\n\t\t\t\tctx.ui.notify(`Compaction failed: ${safeText(error.message)}`, \"error\");\n\t\t\t}\n\t\t},\n\t});\n}\n\nexport function compactMenuStatus(ctx: ExtensionCommandContext): CompactMenuStatus {\n\tconst model = ctx.model;\n\treturn {\n\t\tmodel: model ? `${model.provider}/${model.id}` : \"none\",\n\t\tremoteEligible: usesCodexResponsesApi(model),\n\t};\n}\n\nfunction compactRoute(\n\tstate: Readonly<CodexCompactSettingsState>,\n\tstatus: CompactMenuStatus | undefined,\n): string {\n\tif (!state.settings.enabled) return \"Pi native (Remote V2 off)\";\n\treturn status?.remoteEligible ? \"Codex Remote V2\" : \"Pi native (requires openai-codex-responses)\";\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|