@narumitw/pi-codex-compact 0.50.0 → 0.50.2
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 +87 -85
- package/dist/chunks/settings-menu-BLWCLVPZ.ts +187 -0
- package/dist/chunks/settings-menu-BLWCLVPZ.ts.map +7 -0
- package/dist/index.ts +813 -0
- package/dist/index.ts.map +7 -0
- package/package.json +13 -9
- package/src/checkpoint.ts +31 -10
- package/src/codex-compact.ts +5 -3
package/README.md
CHANGED
|
@@ -1,30 +1,22 @@
|
|
|
1
|
-
# 🗜️ pi-codex-compact — Remote Compaction
|
|
1
|
+
# 🗜️ pi-codex-compact — Use Codex Remote Compaction in Pi
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@narumitw/pi-codex-compact) [](https://pi.dev) [](./LICENSE)
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
[Pi Coding Agent](https://pi.dev) for the built-in `openai-codex` OAuth provider. It replaces Pi's
|
|
7
|
-
plaintext summary-generation call with a server-generated opaque compaction item and safely replays
|
|
8
|
-
that item in later OpenAI Codex Responses requests.
|
|
5
|
+
Use OpenAI Codex Remote Compaction V2 in Pi instead of generating a local plaintext summary for compatible `openai-codex` sessions.
|
|
9
6
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
replay.
|
|
7
|
+
The extension requests and stores an opaque server-generated checkpoint, then safely replays it in later Codex Responses requests.
|
|
8
|
+
|
|
9
|
+
Pi still decides when compaction runs and retains its normal `/compact`, threshold, overflow, and session-publication behavior.
|
|
14
10
|
|
|
15
11
|
## ✨ Features
|
|
16
12
|
|
|
17
13
|
- Uses the active `openai-codex` OAuth credentials without persisting tokens or request headers.
|
|
18
|
-
- Handles
|
|
19
|
-
- Validates one bounded opaque
|
|
20
|
-
-
|
|
21
|
-
|
|
22
|
-
-
|
|
23
|
-
|
|
24
|
-
- Supports repeated compaction by carrying the previous opaque item into the next Remote V2 request.
|
|
25
|
-
- Falls back to Pi's native plaintext compaction after authentication, transport, protocol, or
|
|
26
|
-
validation failure; user cancellation does not launch the fallback.
|
|
27
|
-
- Provides `/codex-compact` for manual compaction, effective-route visibility, and bounded settings.
|
|
14
|
+
- Handles manual, threshold, and overflow compaction through Pi's existing lifecycle.
|
|
15
|
+
- Validates and persists one bounded opaque checkpoint that survives compatible reloads, resumes, and forks.
|
|
16
|
+
- Replays the latest checkpoint while preserving newer conversation and extension context.
|
|
17
|
+
- Supports repeated compaction by carrying the previous checkpoint into the next request.
|
|
18
|
+
- Falls back to Pi's native plaintext compaction on non-cancellation failures.
|
|
19
|
+
- Provides `/codex-compact` for route status, settings, and manual compaction.
|
|
28
20
|
|
|
29
21
|
## 📦 Install
|
|
30
22
|
|
|
@@ -43,32 +35,33 @@ pi -e npm:@narumitw/pi-codex-compact
|
|
|
43
35
|
Try a local checkout from the repository root:
|
|
44
36
|
|
|
45
37
|
```bash
|
|
38
|
+
npm --workspace @narumitw/pi-codex-compact run build
|
|
46
39
|
pi -e ./packages/pi-codex-compact
|
|
47
|
-
# or
|
|
48
|
-
just try codex-compact
|
|
49
40
|
```
|
|
50
41
|
|
|
51
|
-
|
|
52
|
-
|
|
42
|
+
The package declares `dist/index.ts`, so an unbuilt local checkout must be built before Pi loads the package directory.
|
|
43
|
+
Loading the package enables Remote V2 with safe defaults.
|
|
44
|
+
Avoid loading a global npm installation and the local workspace at the same time.
|
|
53
45
|
|
|
54
46
|
## 🚀 Quick start
|
|
55
47
|
|
|
56
48
|
1. Sign in through Pi's built-in OpenAI Codex OAuth provider.
|
|
57
49
|
2. Select a model whose provider is `openai-codex` and API is `openai-codex-responses`.
|
|
58
|
-
3. Work normally.
|
|
50
|
+
3. Work normally.
|
|
51
|
+
Pi's automatic compaction and built-in `/compact` continue to operate.
|
|
59
52
|
4. Run `/codex-compact` to inspect the effective route or choose **Compact now**.
|
|
60
53
|
5. After compaction, continue the session normally; compatible requests replay the opaque checkpoint.
|
|
61
54
|
|
|
62
55
|
When the active model is unsupported, compaction remains entirely Pi-native.
|
|
63
56
|
|
|
64
|
-
## 💬
|
|
57
|
+
## 💬 Commands
|
|
65
58
|
|
|
66
59
|
```text
|
|
67
60
|
/codex-compact
|
|
68
61
|
```
|
|
69
62
|
|
|
70
|
-
In TUI mode, the root menu shows whether Remote V2 is enabled, the active model, and whether a
|
|
71
|
-
|
|
63
|
+
In TUI mode, the root menu shows whether Remote V2 is enabled, the active model, and whether a manual compact will use **Codex Remote V2** or **Pi native**.
|
|
64
|
+
It contains:
|
|
72
65
|
|
|
73
66
|
```text
|
|
74
67
|
Compact now
|
|
@@ -76,13 +69,12 @@ Settings
|
|
|
76
69
|
Close
|
|
77
70
|
```
|
|
78
71
|
|
|
79
|
-
**Compact now** closes the menu before asking Pi to compact the active session.
|
|
80
|
-
closes without compacting, and an obsolete menu cannot trigger work after session replacement or
|
|
81
|
-
|
|
82
|
-
manual settings path instead of opening custom UI or compacting.
|
|
72
|
+
**Compact now** closes the menu before asking Pi to compact the active session.
|
|
73
|
+
Escape or Ctrl+C closes without compacting, and an obsolete menu cannot trigger work after session replacement or shutdown.
|
|
74
|
+
**Settings** opens the bounded settings editor.
|
|
75
|
+
In non-TUI modes, the command reports the manual settings path instead of opening custom UI or compacting.
|
|
83
76
|
|
|
84
|
-
Pi's built-in `/compact` remains available and follows the same extension hook when the active model
|
|
85
|
-
is compatible.
|
|
77
|
+
Pi's built-in `/compact` remains available and follows the same extension hook when the active model is compatible.
|
|
86
78
|
|
|
87
79
|
## ⚙️ Settings
|
|
88
80
|
|
|
@@ -92,8 +84,8 @@ The extension has one optional, global-only JSON settings file:
|
|
|
92
84
|
<getAgentDir()>/pi-codex-compact.json
|
|
93
85
|
```
|
|
94
86
|
|
|
95
|
-
The normal path is `~/.pi/agent/pi-codex-compact.json`.
|
|
96
|
-
project-level override.
|
|
87
|
+
The normal path is `~/.pi/agent/pi-codex-compact.json`.
|
|
88
|
+
There is no environment-variable or project-level override.
|
|
97
89
|
|
|
98
90
|
```json
|
|
99
91
|
{
|
|
@@ -113,15 +105,14 @@ project-level override.
|
|
|
113
105
|
| `replacementTokenBudget` | `64000` | Integer from 8,000 to 128,000 tokens | Bound approximate retained user-message text beside the opaque item. | Keep 64K; lower it to reduce session size or raise it only when recent user context is being lost. |
|
|
114
106
|
| `notifyOnFallback` | `true` | Boolean | Warn when Remote V2 fails and Pi-native compaction takes over. | Keep enabled so silent fallback does not hide protocol or entitlement problems. |
|
|
115
107
|
|
|
116
|
-
Missing fields use defaults.
|
|
117
|
-
|
|
118
|
-
Pi process, and use a final conflict check plus same-directory atomic rename.
|
|
119
|
-
files use mode `0600`.
|
|
108
|
+
Missing fields use defaults.
|
|
109
|
+
Settings reload on every `session_start`, including `/reload`, resume, and fork.
|
|
110
|
+
Menu writes apply immediately, preserve unknown JSON fields, serialize within the current Pi process, and use a final conflict check plus same-directory atomic rename.
|
|
111
|
+
On Unix, temporary files use mode `0600`.
|
|
120
112
|
|
|
121
|
-
Malformed, invalid, oversized, or symlinked settings files are never overwritten.
|
|
122
|
-
active, and the menu provides read-only repair guidance until the file is fixed and Pi is reloaded.
|
|
123
|
-
Separate Pi processes do not share a mutation lock; a detected concurrent edit is rejected so the
|
|
124
|
-
user can reopen Settings and retry.
|
|
113
|
+
Malformed, invalid, oversized, or symlinked settings files are never overwritten.
|
|
114
|
+
Safe defaults stay active, and the menu provides read-only repair guidance until the file is fixed and Pi is reloaded.
|
|
115
|
+
Separate Pi processes do not share a mutation lock; a detected concurrent edit is rejected so the user can reopen Settings and retry.
|
|
125
116
|
|
|
126
117
|
### Relationship to Codex configuration
|
|
127
118
|
|
|
@@ -142,35 +133,27 @@ This extension does **not** read `~/.codex/config.toml`.
|
|
|
142
133
|
- API `openai-codex-responses` on the active model.
|
|
143
134
|
- A working OpenAI Codex OAuth login and Remote V2 entitlement.
|
|
144
135
|
|
|
145
|
-
OpenAI API-key, Azure, GitHub Copilot, proxies, and arbitrary Responses-compatible providers are not
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
opaque replay.
|
|
136
|
+
OpenAI API-key, Azure, GitHub Copilot, proxies, and arbitrary Responses-compatible providers are not supported.
|
|
137
|
+
Switching to another provider or model leaves Pi's visible fallback marker plus retained recent messages in context.
|
|
138
|
+
Switching back to the checkpoint's original compatible model restores opaque replay.
|
|
149
139
|
|
|
150
140
|
## 🔄 How it works
|
|
151
141
|
|
|
152
142
|
1. Pi prepares compaction and selects the recent message suffix it will retain.
|
|
153
|
-
2. The extension projects an earlier compatible checkpoint, if present, into the current Responses
|
|
154
|
-
|
|
155
|
-
3. It appends exactly one final `compaction_trigger` and sends a normal authenticated Codex Responses
|
|
156
|
-
SSE request with cache retention disabled.
|
|
143
|
+
2. The extension projects an earlier compatible checkpoint, if present, into the current Responses input.
|
|
144
|
+
3. It appends exactly one final `compaction_trigger` and sends a normal authenticated Codex Responses SSE request with cache retention disabled.
|
|
157
145
|
4. It requires a completed response containing exactly one non-empty opaque `compaction` item.
|
|
158
|
-
5. It constructs bounded replacement history from recent raw user-role Responses items followed by
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
`CompactionEntry.details`.
|
|
162
|
-
7. On later compatible requests, it replaces an exactly validated marker with the persisted
|
|
163
|
-
replacement history immediately before provider dispatch.
|
|
146
|
+
5. It constructs bounded replacement history from recent raw user-role Responses items followed by the opaque item.
|
|
147
|
+
6. It stores that history and fingerprints of Pi's retained suffix in versioned `CompactionEntry.details`.
|
|
148
|
+
7. On later compatible requests, it replaces an exactly validated marker with the persisted replacement history immediately before provider dispatch.
|
|
164
149
|
|
|
165
|
-
If fingerprints, model identity, payload shape, or marker count do not match exactly, the extension
|
|
166
|
-
leaves Pi's visible fallback context unchanged instead of guessing.
|
|
150
|
+
If fingerprints, model identity, payload shape, or marker count do not match exactly, the extension leaves Pi's visible fallback context unchanged instead of guessing.
|
|
167
151
|
|
|
168
|
-
##
|
|
152
|
+
## 🔒 Security and privacy
|
|
169
153
|
|
|
170
|
-
Remote compaction sends the active conversation context, system prompt, and active tool schemas to
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
authorization headers, or request headers in checkpoint details.
|
|
154
|
+
Remote compaction sends the active conversation context, system prompt, and active tool schemas to the same OpenAI Codex backend used by the selected model.
|
|
155
|
+
The Pi session stores the encrypted compaction item and bounded recent user-role Responses items.
|
|
156
|
+
It does not store OAuth tokens, authorization headers, or request headers in checkpoint details.
|
|
174
157
|
|
|
175
158
|
| Boundary | Limit |
|
|
176
159
|
| --- | ---: |
|
|
@@ -182,22 +165,19 @@ authorization headers, or request headers in checkpoint details.
|
|
|
182
165
|
| Transport retries | At most 2 |
|
|
183
166
|
| Request timeout | At most 10 minutes |
|
|
184
167
|
|
|
185
|
-
An individually oversized media item is dropped rather than making the session entry unbounded.
|
|
186
|
-
oldest fitting text item may be partially truncated to preserve newer context.
|
|
187
|
-
ceilings are intentionally not configurable.
|
|
168
|
+
An individually oversized media item is dropped rather than making the session entry unbounded.
|
|
169
|
+
The oldest fitting text item may be partially truncated to preserve newer context.
|
|
170
|
+
These hard byte ceilings are intentionally not configurable.
|
|
188
171
|
|
|
189
|
-
## 🚧
|
|
172
|
+
## 🚧 Limitations
|
|
190
173
|
|
|
191
|
-
- The wire contract is undocumented and can change independently of Pi or this package.
|
|
192
|
-
backups of important sessions.
|
|
193
|
-
- Full older history depends on this extension and the same compatible model.
|
|
194
|
-
exposes only the portability fallback marker and Pi-retained recent messages.
|
|
195
|
-
- The package does not reproduce Codex core's context-window UUID/number lineage, previous-model
|
|
196
|
-
|
|
197
|
-
-
|
|
198
|
-
and native compaction entries over time.
|
|
199
|
-
- Settings concurrency is coordinated only within one Pi process; separate processes rely on the
|
|
200
|
-
final conflict check.
|
|
174
|
+
- The wire contract is undocumented and can change independently of Pi or this package.
|
|
175
|
+
Keep backups of important sessions.
|
|
176
|
+
- Full older history depends on this extension and the same compatible model.
|
|
177
|
+
Removing the extension exposes only the portability fallback marker and Pi-retained recent messages.
|
|
178
|
+
- The package does not reproduce Codex core's context-window UUID/number lineage, previous-model compatibility fallback, exact pre-turn ordering, or exact mid-turn model-session ownership.
|
|
179
|
+
- Remote failure falls back to Pi's plaintext summary, so a session can contain both remote opaque and native compaction entries over time.
|
|
180
|
+
- Settings concurrency is coordinated only within one Pi process; separate processes rely on the final conflict check.
|
|
201
181
|
|
|
202
182
|
## 🗂️ Package layout
|
|
203
183
|
|
|
@@ -208,11 +188,36 @@ src/remote.ts Provider stream invocation, auth payload, timeout, and ret
|
|
|
208
188
|
src/protocol.ts Bounded SSE parsing and Remote V2 payload/output validation
|
|
209
189
|
src/checkpoint.ts Replacement history, fingerprints, persistence, and replay projection
|
|
210
190
|
src/settings.ts Global settings validation and atomic persistence
|
|
211
|
-
src/settings-menu.ts
|
|
191
|
+
src/settings-menu.ts First-use manual compaction and settings TUI
|
|
212
192
|
|
|
213
|
-
|
|
193
|
+
dist/ Generated source-mapped Jiti runtime and lazy menu chunk
|
|
194
|
+
scripts/ Runtime builder
|
|
195
|
+
benchmark/ Three-arm compaction benchmark, self-test, and methodology
|
|
196
|
+
test/ Protocol, checkpoint, lifecycle, remote, settings, menu, and builder coverage
|
|
214
197
|
```
|
|
215
198
|
|
|
199
|
+
## 📊 Benchmark
|
|
200
|
+
|
|
201
|
+
The repository includes a seeded three-arm benchmark for uncompressed full context, Pi-native plaintext compaction, and this extension's Codex Remote Compaction V2 path.
|
|
202
|
+
|
|
203
|
+
It holds history length nearly fixed while varying information density across five state categories and ten history epochs.
|
|
204
|
+
|
|
205
|
+
Benchmark v3 uses repeated artifacts, isolated evaluator probes, seed-level paired statistics, one Pi SDK estimator for dry and live fixtures, and committed protocol manifests for confirmatory candidates.
|
|
206
|
+
|
|
207
|
+
It never treats nominal Pi 20K and Codex 20K settings as equal information capacity or automatically claims that protocol-conformant evidence was genuinely held out.
|
|
208
|
+
|
|
209
|
+
Preview its exploratory diagnostic without making a provider request:
|
|
210
|
+
|
|
211
|
+
```bash
|
|
212
|
+
just benchmark-codex-compact
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
A live run requires an explicit `--live` flag, reviewed request and cost exposure, OpenAI Codex OAuth, and Remote V2 entitlement.
|
|
216
|
+
|
|
217
|
+
The repository preserves the explicitly labeled v2 matched-tail diagnostic and the v3 calibration evidence, while seeds 301–304 remain consumed and unavailable for future confirmatory protocols.
|
|
218
|
+
|
|
219
|
+
See the [benchmark guide](https://github.com/narumiruna/pi-extensions/tree/main/packages/pi-codex-compact/benchmark) for manifests, repetitions, commands, privacy, cost semantics, and interpretation limits.
|
|
220
|
+
|
|
216
221
|
## 🧪 Development
|
|
217
222
|
|
|
218
223
|
From the repository root:
|
|
@@ -223,14 +228,11 @@ npm test
|
|
|
223
228
|
just pack codex-compact
|
|
224
229
|
```
|
|
225
230
|
|
|
226
|
-
See
|
|
227
|
-
[`docs/implementation-notes/codex-compaction-mechanism.md`](../../docs/implementation-notes/codex-compaction-mechanism.md)
|
|
228
|
-
for the underlying Codex mechanism research and the extension boundary.
|
|
231
|
+
See [`docs/implementation-notes/codex-compaction-mechanism.md`](../../docs/implementation-notes/codex-compaction-mechanism.md) for the underlying Codex mechanism research and the extension boundary.
|
|
229
232
|
|
|
230
233
|
## 🔎 Keywords
|
|
231
234
|
|
|
232
|
-
Pi extension, Pi coding agent, OpenAI Codex, OAuth, Remote Compaction V2, opaque checkpoint,
|
|
233
|
-
Responses API, context compaction.
|
|
235
|
+
Pi extension, Pi coding agent, OpenAI Codex, OAuth, Remote Compaction V2, opaque checkpoint, Responses API, context compaction.
|
|
234
236
|
|
|
235
237
|
## 📄 License
|
|
236
238
|
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
// @generated by scripts/build-runtime.mjs; do not edit.
|
|
2
|
+
// @ts-nocheck -- generated JavaScript uses a .ts extension for Pi's Jiti loader.
|
|
3
|
+
|
|
4
|
+
// src/settings-menu.ts
|
|
5
|
+
function safeText(value) {
|
|
6
|
+
return Array.from(value, (character) => {
|
|
7
|
+
const codePoint = character.codePointAt(0) ?? 0;
|
|
8
|
+
return codePoint < 32 || codePoint >= 127 && codePoint <= 159 ? " " : character;
|
|
9
|
+
}).join("");
|
|
10
|
+
}
|
|
11
|
+
function timeoutLabel(milliseconds) {
|
|
12
|
+
return `${milliseconds / 6e4} min`;
|
|
13
|
+
}
|
|
14
|
+
function retentionLabel(tokens) {
|
|
15
|
+
return `${tokens / 1e3}K tokens`;
|
|
16
|
+
}
|
|
17
|
+
async function update(runtime, ctx, patch, signal) {
|
|
18
|
+
try {
|
|
19
|
+
await runtime.update(patch, signal);
|
|
20
|
+
ctx.ui.notify("Codex compaction settings saved.", "info");
|
|
21
|
+
return { kind: "stay" };
|
|
22
|
+
} catch (error) {
|
|
23
|
+
if (signal.aborted) return { kind: "rejected" };
|
|
24
|
+
ctx.ui.notify(
|
|
25
|
+
`Could not save pi-codex-compact.json: ${safeText(error instanceof Error ? error.message : String(error))}`,
|
|
26
|
+
"error"
|
|
27
|
+
);
|
|
28
|
+
return { kind: "rejected" };
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function createCodexCompactMenu(runtime, options = {}) {
|
|
32
|
+
return {
|
|
33
|
+
start: "main",
|
|
34
|
+
screens: {
|
|
35
|
+
main: ({ state }) => ({
|
|
36
|
+
kind: "actions",
|
|
37
|
+
title: "Codex Remote Compaction",
|
|
38
|
+
lines: [
|
|
39
|
+
`Remote V2: ${state.settings.enabled ? "On" : "Off"}`,
|
|
40
|
+
`Active model: ${safeText(options.status?.model ?? "none")}`,
|
|
41
|
+
`Compact route: ${safeText(compactRoute(state, options.status))}`
|
|
42
|
+
],
|
|
43
|
+
items: [
|
|
44
|
+
{
|
|
45
|
+
id: "compact-now",
|
|
46
|
+
label: "Compact now",
|
|
47
|
+
description: "Close this menu and compact the active session immediately.",
|
|
48
|
+
action: "compact-now"
|
|
49
|
+
},
|
|
50
|
+
state.kind === "invalid" ? {
|
|
51
|
+
id: "settings",
|
|
52
|
+
label: "Settings",
|
|
53
|
+
description: "Read-only until the invalid settings file is repaired.",
|
|
54
|
+
to: "invalid"
|
|
55
|
+
} : { id: "settings", label: "Settings", to: "settings" },
|
|
56
|
+
{ id: "close", label: "Close", close: true }
|
|
57
|
+
],
|
|
58
|
+
hint: "close"
|
|
59
|
+
}),
|
|
60
|
+
settings: ({ state }) => ({
|
|
61
|
+
kind: "settings",
|
|
62
|
+
title: "Codex Remote Compaction Settings",
|
|
63
|
+
lines: [`User settings \xB7 ${safeText(state.path)}`],
|
|
64
|
+
items: [
|
|
65
|
+
{
|
|
66
|
+
id: "enabled",
|
|
67
|
+
label: "Remote compaction",
|
|
68
|
+
description: "Use Codex Remote V2 when the active model is compatible.",
|
|
69
|
+
currentValue: state.settings.enabled ? "On" : "Off",
|
|
70
|
+
values: ["On", "Off"],
|
|
71
|
+
action: "set-enabled"
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
id: "requestTimeoutMs",
|
|
75
|
+
label: "Request timeout",
|
|
76
|
+
description: "Maximum time for the extension-owned remote compaction request.",
|
|
77
|
+
currentValue: timeoutLabel(state.settings.requestTimeoutMs),
|
|
78
|
+
values: ["2 min", "5 min", "10 min"],
|
|
79
|
+
action: "set-timeout"
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
id: "maxRetries",
|
|
83
|
+
label: "Transport retries",
|
|
84
|
+
description: "Retry transient provider failures before falling back to Pi.",
|
|
85
|
+
currentValue: String(state.settings.maxRetries),
|
|
86
|
+
values: ["0", "1", "2"],
|
|
87
|
+
action: "set-retries"
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
id: "replacementTokenBudget",
|
|
91
|
+
label: "Retained user history",
|
|
92
|
+
description: "Approximate user-message budget kept beside the opaque checkpoint.",
|
|
93
|
+
currentValue: retentionLabel(state.settings.replacementTokenBudget),
|
|
94
|
+
values: ["32K tokens", "64K tokens", "96K tokens", "128K tokens"],
|
|
95
|
+
action: "set-retention"
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
id: "notifyOnFallback",
|
|
99
|
+
label: "Fallback notifications",
|
|
100
|
+
description: "Warn when Remote V2 fails and native Pi compaction takes over.",
|
|
101
|
+
currentValue: state.settings.notifyOnFallback ? "On" : "Off",
|
|
102
|
+
values: ["On", "Off"],
|
|
103
|
+
action: "set-notify"
|
|
104
|
+
}
|
|
105
|
+
]
|
|
106
|
+
}),
|
|
107
|
+
invalid: ({ state }) => ({
|
|
108
|
+
kind: "detail",
|
|
109
|
+
title: "Codex Compact Settings \xB7 Read only",
|
|
110
|
+
lines: [
|
|
111
|
+
`Invalid settings file: ${safeText(state.path)}`,
|
|
112
|
+
`Issue: ${safeText(state.issue ?? "unknown validation error")}`,
|
|
113
|
+
"Built-in defaults are active. Repair the file and run /reload; it will not be overwritten."
|
|
114
|
+
],
|
|
115
|
+
hint: "back"
|
|
116
|
+
})
|
|
117
|
+
},
|
|
118
|
+
actions: {
|
|
119
|
+
"compact-now": async () => {
|
|
120
|
+
options.onCompactRequested?.();
|
|
121
|
+
return { kind: "close" };
|
|
122
|
+
},
|
|
123
|
+
"set-enabled": ({ ctx, value, signal }) => update(runtime, ctx, { enabled: value === "On" }, signal),
|
|
124
|
+
"set-timeout": ({ ctx, value, signal }) => update(
|
|
125
|
+
runtime,
|
|
126
|
+
ctx,
|
|
127
|
+
{ requestTimeoutMs: Number.parseInt(value ?? "5", 10) * 6e4 },
|
|
128
|
+
signal
|
|
129
|
+
),
|
|
130
|
+
"set-retries": ({ ctx, value, signal }) => update(runtime, ctx, { maxRetries: Number.parseInt(value ?? "2", 10) }, signal),
|
|
131
|
+
"set-retention": ({ ctx, value, signal }) => update(
|
|
132
|
+
runtime,
|
|
133
|
+
ctx,
|
|
134
|
+
{ replacementTokenBudget: Number.parseInt(value ?? "64", 10) * 1e3 },
|
|
135
|
+
signal
|
|
136
|
+
),
|
|
137
|
+
"set-notify": ({ ctx, value, signal }) => update(runtime, ctx, { notifyOnFallback: value === "On" }, signal)
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
async function showCodexCompactMenu(runtime, ctx, owner) {
|
|
142
|
+
if (ctx.mode !== "tui") {
|
|
143
|
+
ctx.ui.notify(`Edit Codex compaction settings at ${safeText(runtime.get().path)}.`, "info");
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
const { runMenu } = await import("@narumitw/pi-tui-kit");
|
|
147
|
+
if (owner.signal.aborted || !owner.isCurrent()) return;
|
|
148
|
+
let compactRequested = false;
|
|
149
|
+
await runMenu(
|
|
150
|
+
ctx,
|
|
151
|
+
createCodexCompactMenu(runtime, {
|
|
152
|
+
onCompactRequested: () => {
|
|
153
|
+
compactRequested = true;
|
|
154
|
+
},
|
|
155
|
+
status: compactMenuStatus(ctx)
|
|
156
|
+
}),
|
|
157
|
+
{
|
|
158
|
+
getState: () => runtime.get(),
|
|
159
|
+
signal: owner.signal,
|
|
160
|
+
isCurrent: owner.isCurrent
|
|
161
|
+
}
|
|
162
|
+
);
|
|
163
|
+
if (!compactRequested || owner.signal.aborted || !owner.isCurrent()) return;
|
|
164
|
+
ctx.compact({
|
|
165
|
+
onError: (error) => {
|
|
166
|
+
if (!owner.signal.aborted && owner.isCurrent()) {
|
|
167
|
+
ctx.ui.notify(`Compaction failed: ${safeText(error.message)}`, "error");
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
function compactMenuStatus(ctx) {
|
|
173
|
+
const model = ctx.model;
|
|
174
|
+
return {
|
|
175
|
+
model: model ? `${model.provider}/${model.id}` : "none",
|
|
176
|
+
remoteCompatible: model?.provider === "openai-codex" && model.api === "openai-codex-responses"
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
function compactRoute(state, status) {
|
|
180
|
+
if (!state.settings.enabled) return "Pi native (Remote V2 off)";
|
|
181
|
+
return status?.remoteCompatible ? "Codex Remote V2" : "Pi native (model not compatible)";
|
|
182
|
+
}
|
|
183
|
+
export {
|
|
184
|
+
createCodexCompactMenu,
|
|
185
|
+
showCodexCompactMenu
|
|
186
|
+
};
|
|
187
|
+
//# sourceMappingURL=settings-menu-BLWCLVPZ.ts.map
|
|
@@ -0,0 +1,7 @@
|
|
|
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 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\tremoteCompatible: 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 active model is compatible.\",\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\nfunction compactMenuStatus(ctx: ExtensionCommandContext): CompactMenuStatus {\n\tconst model = ctx.model;\n\treturn {\n\t\tmodel: model ? `${model.provider}/${model.id}` : \"none\",\n\t\tremoteCompatible: model?.provider === \"openai-codex\" && model.api === \"openai-codex-responses\",\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?.remoteCompatible ? \"Codex Remote V2\" : \"Pi native (model not compatible)\";\n}\n"],
|
|
5
|
+
"mappings": ";;;;AA2BA,SAAS,SAAS,OAAuB;AACxC,SAAO,MAAM,KAAK,OAAO,CAAC,cAAc;AACvC,UAAM,YAAY,UAAU,YAAY,CAAC,KAAK;AAC9C,WAAO,YAAY,MAAO,aAAa,OAAO,aAAa,MAAO,MAAM;AAAA,EACzE,CAAC,EAAE,KAAK,EAAE;AACX;AAEA,SAAS,aAAa,cAA8B;AACnD,SAAO,GAAG,eAAe,GAAM;AAChC;AAEA,SAAS,eAAe,QAAwB;AAC/C,SAAO,GAAG,SAAS,GAAI;AACxB;AAEA,eAAe,OACd,SACA,KACA,OACA,QACC;AACD,MAAI;AACH,UAAM,QAAQ,OAAO,OAAO,MAAM;AAClC,QAAI,GAAG,OAAO,oCAAoC,MAAM;AACxD,WAAO,EAAE,MAAM,OAAgB;AAAA,EAChC,SAAS,OAAO;AACf,QAAI,OAAO,QAAS,QAAO,EAAE,MAAM,WAAoB;AACvD,QAAI,GAAG;AAAA,MACN,yCAAyC,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC,CAAC;AAAA,MACzG;AAAA,IACD;AACA,WAAO,EAAE,MAAM,WAAoB;AAAA,EACpC;AACD;AAEO,SAAS,uBACf,SACA,UAA2E,CAAC,GACS;AACrF,SAAO;AAAA,IACN,OAAO;AAAA,IACP,SAAS;AAAA,MACR,MAAM,CAAC,EAAE,MAAM,OAAO;AAAA,QACrB,MAAM;AAAA,QACN,OAAO;AAAA,QACP,OAAO;AAAA,UACN,cAAc,MAAM,SAAS,UAAU,OAAO,KAAK;AAAA,UACnD,iBAAiB,SAAS,QAAQ,QAAQ,SAAS,MAAM,CAAC;AAAA,UAC1D,kBAAkB,SAAS,aAAa,OAAO,QAAQ,MAAM,CAAC,CAAC;AAAA,QAChE;AAAA,QACA,OAAO;AAAA,UACN;AAAA,YACC,IAAI;AAAA,YACJ,OAAO;AAAA,YACP,aAAa;AAAA,YACb,QAAQ;AAAA,UACT;AAAA,UACA,MAAM,SAAS,YACZ;AAAA,YACA,IAAI;AAAA,YACJ,OAAO;AAAA,YACP,aAAa;AAAA,YACb,IAAI;AAAA,UACL,IACC,EAAE,IAAI,YAAY,OAAO,YAAY,IAAI,WAAoB;AAAA,UAChE,EAAE,IAAI,SAAS,OAAO,SAAS,OAAO,KAAK;AAAA,QAC5C;AAAA,QACA,MAAM;AAAA,MACP;AAAA,MACA,UAAU,CAAC,EAAE,MAAM,OAAO;AAAA,QACzB,MAAM;AAAA,QACN,OAAO;AAAA,QACP,OAAO,CAAC,sBAAmB,SAAS,MAAM,IAAI,CAAC,EAAE;AAAA,QACjD,OAAO;AAAA,UACN;AAAA,YACC,IAAI;AAAA,YACJ,OAAO;AAAA,YACP,aAAa;AAAA,YACb,cAAc,MAAM,SAAS,UAAU,OAAO;AAAA,YAC9C,QAAQ,CAAC,MAAM,KAAK;AAAA,YACpB,QAAQ;AAAA,UACT;AAAA,UACA;AAAA,YACC,IAAI;AAAA,YACJ,OAAO;AAAA,YACP,aAAa;AAAA,YACb,cAAc,aAAa,MAAM,SAAS,gBAAgB;AAAA,YAC1D,QAAQ,CAAC,SAAS,SAAS,QAAQ;AAAA,YACnC,QAAQ;AAAA,UACT;AAAA,UACA;AAAA,YACC,IAAI;AAAA,YACJ,OAAO;AAAA,YACP,aAAa;AAAA,YACb,cAAc,OAAO,MAAM,SAAS,UAAU;AAAA,YAC9C,QAAQ,CAAC,KAAK,KAAK,GAAG;AAAA,YACtB,QAAQ;AAAA,UACT;AAAA,UACA;AAAA,YACC,IAAI;AAAA,YACJ,OAAO;AAAA,YACP,aAAa;AAAA,YACb,cAAc,eAAe,MAAM,SAAS,sBAAsB;AAAA,YAClE,QAAQ,CAAC,cAAc,cAAc,cAAc,aAAa;AAAA,YAChE,QAAQ;AAAA,UACT;AAAA,UACA;AAAA,YACC,IAAI;AAAA,YACJ,OAAO;AAAA,YACP,aAAa;AAAA,YACb,cAAc,MAAM,SAAS,mBAAmB,OAAO;AAAA,YACvD,QAAQ,CAAC,MAAM,KAAK;AAAA,YACpB,QAAQ;AAAA,UACT;AAAA,QACD;AAAA,MACD;AAAA,MACA,SAAS,CAAC,EAAE,MAAM,OAAO;AAAA,QACxB,MAAM;AAAA,QACN,OAAO;AAAA,QACP,OAAO;AAAA,UACN,0BAA0B,SAAS,MAAM,IAAI,CAAC;AAAA,UAC9C,UAAU,SAAS,MAAM,SAAS,0BAA0B,CAAC;AAAA,UAC7D;AAAA,QACD;AAAA,QACA,MAAM;AAAA,MACP;AAAA,IACD;AAAA,IACA,SAAS;AAAA,MACR,eAAe,YAAY;AAC1B,gBAAQ,qBAAqB;AAC7B,eAAO,EAAE,MAAM,QAAQ;AAAA,MACxB;AAAA,MACA,eAAe,CAAC,EAAE,KAAK,OAAO,OAAO,MACpC,OAAO,SAAS,KAAK,EAAE,SAAS,UAAU,KAAK,GAAG,MAAM;AAAA,MACzD,eAAe,CAAC,EAAE,KAAK,OAAO,OAAO,MACpC;AAAA,QACC;AAAA,QACA;AAAA,QACA,EAAE,kBAAkB,OAAO,SAAS,SAAS,KAAK,EAAE,IAAI,IAAO;AAAA,QAC/D;AAAA,MACD;AAAA,MACD,eAAe,CAAC,EAAE,KAAK,OAAO,OAAO,MACpC,OAAO,SAAS,KAAK,EAAE,YAAY,OAAO,SAAS,SAAS,KAAK,EAAE,EAAE,GAAG,MAAM;AAAA,MAC/E,iBAAiB,CAAC,EAAE,KAAK,OAAO,OAAO,MACtC;AAAA,QACC;AAAA,QACA;AAAA,QACA,EAAE,wBAAwB,OAAO,SAAS,SAAS,MAAM,EAAE,IAAI,IAAK;AAAA,QACpE;AAAA,MACD;AAAA,MACD,cAAc,CAAC,EAAE,KAAK,OAAO,OAAO,MACnC,OAAO,SAAS,KAAK,EAAE,kBAAkB,UAAU,KAAK,GAAG,MAAM;AAAA,IACnE;AAAA,EACD;AACD;AAEA,eAAsB,qBACrB,SACA,KACA,OACgB;AAChB,MAAI,IAAI,SAAS,OAAO;AACvB,QAAI,GAAG,OAAO,qCAAqC,SAAS,QAAQ,IAAI,EAAE,IAAI,CAAC,KAAK,MAAM;AAC1F;AAAA,EACD;AACA,QAAM,EAAE,QAAQ,IAAI,MAAM,OAAO,sBAAsB;AACvD,MAAI,MAAM,OAAO,WAAW,CAAC,MAAM,UAAU,EAAG;AAChD,MAAI,mBAAmB;AACvB,QAAM;AAAA,IACL;AAAA,IACA,uBAAuB,SAAS;AAAA,MAC/B,oBAAoB,MAAM;AACzB,2BAAmB;AAAA,MACpB;AAAA,MACA,QAAQ,kBAAkB,GAAG;AAAA,IAC9B,CAAC;AAAA,IACD;AAAA,MACC,UAAU,MAAM,QAAQ,IAAI;AAAA,MAC5B,QAAQ,MAAM;AAAA,MACd,WAAW,MAAM;AAAA,IAClB;AAAA,EACD;AACA,MAAI,CAAC,oBAAoB,MAAM,OAAO,WAAW,CAAC,MAAM,UAAU,EAAG;AACrE,MAAI,QAAQ;AAAA,IACX,SAAS,CAAC,UAAU;AACnB,UAAI,CAAC,MAAM,OAAO,WAAW,MAAM,UAAU,GAAG;AAC/C,YAAI,GAAG,OAAO,sBAAsB,SAAS,MAAM,OAAO,CAAC,IAAI,OAAO;AAAA,MACvE;AAAA,IACD;AAAA,EACD,CAAC;AACF;AAEA,SAAS,kBAAkB,KAAiD;AAC3E,QAAM,QAAQ,IAAI;AAClB,SAAO;AAAA,IACN,OAAO,QAAQ,GAAG,MAAM,QAAQ,IAAI,MAAM,EAAE,KAAK;AAAA,IACjD,kBAAkB,OAAO,aAAa,kBAAkB,MAAM,QAAQ;AAAA,EACvE;AACD;AAEA,SAAS,aACR,OACA,QACS;AACT,MAAI,CAAC,MAAM,SAAS,QAAS,QAAO;AACpC,SAAO,QAAQ,mBAAmB,oBAAoB;AACvD;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|