pi-blackhole 0.4.2 → 0.4.3
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 +15 -0
- package/dist/index.js +11660 -0
- package/dist/index.js.map +1 -0
- package/example-config.json +1 -1
- package/index.ts +37 -63
- package/package.json +21 -9
- package/src/commands/cleanup.ts +279 -240
- package/src/commands/memory.ts +236 -184
- package/src/commands/pi-vcc.ts +202 -152
- package/src/commands/vcc-recall.ts +126 -95
- package/src/core/brief.ts +167 -33
- package/src/core/build-sections.ts +8 -2
- package/src/core/config-env.ts +117 -0
- package/src/core/content.ts +31 -7
- package/src/core/drill-down.ts +41 -11
- package/src/core/filter-noise.ts +9 -3
- package/src/core/format-recall.ts +15 -6
- package/src/core/format.ts +14 -4
- package/src/core/lineage.ts +9 -3
- package/src/core/load-messages.ts +24 -5
- package/src/core/normalize.ts +38 -14
- package/src/core/recall-scope.ts +11 -3
- package/src/core/render-entries.ts +22 -6
- package/src/core/sanitize.ts +5 -1
- package/src/core/search-entries.ts +111 -19
- package/src/core/settings.ts +1 -3
- package/src/core/summarize.ts +42 -21
- package/src/core/unified-config.ts +549 -411
- package/src/extract/commits.ts +4 -2
- package/src/extract/files.ts +10 -5
- package/src/extract/goals.ts +7 -2
- package/src/hooks/before-compact.ts +210 -88
- package/src/om/agents/dropper/agent.ts +380 -265
- package/src/om/agents/dropper/coverage.ts +102 -82
- package/src/om/agents/observer/agent.ts +242 -206
- package/src/om/agents/reflector/agent.ts +212 -153
- package/src/om/cleanup.ts +239 -218
- package/src/om/clipboard.ts +59 -51
- package/src/om/compaction-trigger.ts +448 -333
- package/src/om/config.ts +13 -6
- package/src/om/configure-overlay.ts +518 -355
- package/src/om/consolidation.ts +1460 -953
- package/src/om/cooldown.ts +75 -65
- package/src/om/debug-log.ts +86 -68
- package/src/om/ids.ts +1 -1
- package/src/om/ledger/fold.ts +89 -78
- package/src/om/ledger/progress.ts +181 -153
- package/src/om/ledger/projection.ts +248 -185
- package/src/om/ledger/recall.ts +247 -196
- package/src/om/ledger/render-summary.ts +79 -50
- package/src/om/ledger/types.ts +146 -117
- package/src/om/model-budget.ts +23 -13
- package/src/om/pending.ts +243 -179
- package/src/om/provider-stream.ts +52 -7
- package/src/om/retryable-error.ts +12 -16
- package/src/om/reverse-recall.ts +97 -91
- package/src/om/runtime.ts +474 -375
- package/src/om/serialize.ts +190 -166
- package/src/om/status-overlay.ts +246 -195
- package/src/om/tokens.ts +28 -21
- package/src/pi-base/blackhole-settings.ts +437 -0
- package/src/pi-base/config-manager.ts +440 -0
- package/src/pi-base/config.ts +469 -0
- package/src/pi-base/env.ts +43 -0
- package/src/pi-base/paths.ts +47 -0
- package/src/pi-base/settings/body.ts +1648 -0
- package/src/pi-base/settings/fields/action.ts +43 -0
- package/src/pi-base/settings/fields/boolean.ts +47 -0
- package/src/pi-base/settings/fields/custom.ts +72 -0
- package/src/pi-base/settings/fields/enum.ts +310 -0
- package/src/pi-base/settings/fields/index.ts +46 -0
- package/src/pi-base/settings/fields/model.ts +452 -0
- package/src/pi-base/settings/fields/string.ts +527 -0
- package/src/pi-base/settings/fields/text.ts +115 -0
- package/src/pi-base/settings/frame.ts +197 -0
- package/src/pi-base/settings/index.ts +77 -0
- package/src/pi-base/settings/inline-edit.ts +313 -0
- package/src/pi-base/settings/modal.ts +152 -0
- package/src/pi-base/settings/types.ts +500 -0
- package/src/pi-base/settings/validate-field.ts +113 -0
- package/src/pi-base/shell.ts +117 -0
- package/src/pi-base/types.ts +6 -0
- package/src/pi-base/ui.ts +32 -0
- package/src/tools/recall.ts +347 -225
- package/src/types.ts +20 -3
- package/tsup.config.ts +23 -0
- package/vitest.config.ts +15 -15
|
@@ -0,0 +1,437 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Blackhole settings — modal-based configuration via ConfigManager.
|
|
3
|
+
*
|
|
4
|
+
* Replaces the hand-rolled configure overlay (src/om/configure-overlay.ts)
|
|
5
|
+
* with pi-base's ConfigManager + openSettingsModal.
|
|
6
|
+
*
|
|
7
|
+
* Env-var overrides are applied by ConfigManager after load + validate,
|
|
8
|
+
* so they take effect for both the runtime path (loadUnifiedConfig) and
|
|
9
|
+
* the modal path (config.load / config.openSettings).
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { join } from "node:path";
|
|
13
|
+
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
14
|
+
import { ConfigManager } from "../pi-base/config-manager.js";
|
|
15
|
+
import { getPiAgentDir } from "../pi-base/paths.js";
|
|
16
|
+
import { DECLARATIVE_ENV_OVERRIDES } from "../core/config-env.js";
|
|
17
|
+
import { DEFAULTS, type UnifiedConfig } from "../core/unified-config.js";
|
|
18
|
+
|
|
19
|
+
const CONFIG_FILENAME = "pi-blackhole-config.json";
|
|
20
|
+
|
|
21
|
+
export const GLOBAL_CONFIG_DIR = join(getPiAgentDir(), "pi-blackhole");
|
|
22
|
+
|
|
23
|
+
// ── Env-var parsers ──────────────────────────────────────────────────────────
|
|
24
|
+
|
|
25
|
+
function parseCompactionEnv(
|
|
26
|
+
raw: string,
|
|
27
|
+
): "auto" | "manual" | "off" | undefined {
|
|
28
|
+
const trimmed = raw.trim().toLowerCase();
|
|
29
|
+
return ["auto", "manual", "off"].includes(trimmed)
|
|
30
|
+
? (trimmed as "auto" | "manual" | "off")
|
|
31
|
+
: undefined;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function parseCompactionEngineEnv(
|
|
35
|
+
raw: string,
|
|
36
|
+
): "blackhole" | "pi-default" | undefined {
|
|
37
|
+
const trimmed = raw.trim().toLowerCase();
|
|
38
|
+
return ["blackhole", "pi-default"].includes(trimmed)
|
|
39
|
+
? (trimmed as "blackhole" | "pi-default")
|
|
40
|
+
: undefined;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// ── ConfigManager instance ───────────────────────────────────────────────────
|
|
44
|
+
|
|
45
|
+
export const config = new ConfigManager<UnifiedConfig>({
|
|
46
|
+
id: "pi-blackhole",
|
|
47
|
+
label: "pi-blackhole",
|
|
48
|
+
filename: CONFIG_FILENAME,
|
|
49
|
+
defaults: DEFAULTS,
|
|
50
|
+
|
|
51
|
+
fields: (cfg) => [
|
|
52
|
+
// ── Compaction ──
|
|
53
|
+
{
|
|
54
|
+
key: "compaction",
|
|
55
|
+
type: "enum",
|
|
56
|
+
label: "Compaction mode",
|
|
57
|
+
description:
|
|
58
|
+
"auto=trigger on threshold, manual=only /blackhole, off=auto:Pi handles, /blackhole:blackhole pipeline",
|
|
59
|
+
value: cfg.compaction,
|
|
60
|
+
options: ["auto", "manual", "off"],
|
|
61
|
+
optionLabels: {
|
|
62
|
+
auto: "auto — trigger on threshold",
|
|
63
|
+
manual: "manual — only /blackhole",
|
|
64
|
+
off: "off — auto:Pi handles, /blackhole:blackhole pipeline",
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
key: "compactionEngine",
|
|
69
|
+
type: "enum",
|
|
70
|
+
label: "Compaction engine",
|
|
71
|
+
description:
|
|
72
|
+
"blackhole=structured summary+OM, pi-default=built-in Pi summarization",
|
|
73
|
+
value: cfg.compactionEngine,
|
|
74
|
+
options: ["blackhole", "pi-default"],
|
|
75
|
+
optionLabels: {
|
|
76
|
+
blackhole: "blackhole — structured summary + OM",
|
|
77
|
+
"pi-default": "pi-default — built-in Pi summarization",
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
key: "tailBehavior",
|
|
82
|
+
type: "enum",
|
|
83
|
+
label: "Visible tail",
|
|
84
|
+
description:
|
|
85
|
+
"minimal=keep last user message only (default), pi-default=keep Pi's preserved visible context",
|
|
86
|
+
value: cfg.tailBehavior,
|
|
87
|
+
options: ["minimal", "pi-default"],
|
|
88
|
+
optionLabels: {
|
|
89
|
+
minimal: "minimal — keep last user message only (default)",
|
|
90
|
+
"pi-default": "pi-default — keep Pi's preserved visible context",
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
key: "midRunCompaction",
|
|
95
|
+
type: "enum",
|
|
96
|
+
label: "Mid-run compaction",
|
|
97
|
+
description:
|
|
98
|
+
"resume=compact at threshold during tool loops and continue (default), pause=compact and stop, off=only check when run ends",
|
|
99
|
+
value: cfg.midRunCompaction,
|
|
100
|
+
options: ["resume", "pause", "off"],
|
|
101
|
+
optionLabels: {
|
|
102
|
+
resume: "resume — compact and continue (default)",
|
|
103
|
+
pause: "pause — compact and stop",
|
|
104
|
+
off: "off — only check when run ends",
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
key: "compactAfterTokens",
|
|
109
|
+
type: "number",
|
|
110
|
+
label: "Auto-compact threshold",
|
|
111
|
+
description: "Token count that triggers auto-compaction when reached",
|
|
112
|
+
value: cfg.compactAfterTokens,
|
|
113
|
+
min: 1_000,
|
|
114
|
+
max: 500_000,
|
|
115
|
+
step: 1_000,
|
|
116
|
+
},
|
|
117
|
+
|
|
118
|
+
// ── Observational Memory ──
|
|
119
|
+
{
|
|
120
|
+
key: "memory",
|
|
121
|
+
type: "boolean",
|
|
122
|
+
label: "Observational memory",
|
|
123
|
+
description:
|
|
124
|
+
"Enable OM workers (observer, reflector, dropper) and content injection",
|
|
125
|
+
value: cfg.memory,
|
|
126
|
+
valueDescriptions: {
|
|
127
|
+
on: "Active — OM workers + content injection enabled",
|
|
128
|
+
off: "Suspended — OM disabled",
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
key: "sessionFallback",
|
|
133
|
+
type: "boolean",
|
|
134
|
+
label: "Session model fallback",
|
|
135
|
+
description:
|
|
136
|
+
"off=skip stage when all OM models fail, instead of falling back to the main coding model",
|
|
137
|
+
value: cfg.sessionFallback ?? true,
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
key: "observeAfterTokens",
|
|
141
|
+
type: "number",
|
|
142
|
+
label: "Observer threshold",
|
|
143
|
+
description:
|
|
144
|
+
"Tokens accumulated since last observer run before triggering next observe",
|
|
145
|
+
value: cfg.observeAfterTokens,
|
|
146
|
+
min: 1_000,
|
|
147
|
+
max: 200_000,
|
|
148
|
+
step: 1_000,
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
key: "reflectAfterTokens",
|
|
152
|
+
type: "number",
|
|
153
|
+
label: "Reflect + dropper threshold",
|
|
154
|
+
description:
|
|
155
|
+
"Tokens accumulated since last reflect before triggering reflector and dropper",
|
|
156
|
+
value: cfg.reflectAfterTokens,
|
|
157
|
+
min: 1_000,
|
|
158
|
+
max: 200_000,
|
|
159
|
+
step: 1_000,
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
key: "observationsPoolMaxTokens",
|
|
163
|
+
type: "number",
|
|
164
|
+
label: "Observation pool max",
|
|
165
|
+
description:
|
|
166
|
+
"Max tokens in observation pool before dropper prunes (fold pressure)",
|
|
167
|
+
value: cfg.observationsPoolMaxTokens,
|
|
168
|
+
min: 1_000,
|
|
169
|
+
max: 200_000,
|
|
170
|
+
step: 1_000,
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
key: "observationsPoolTargetTokens",
|
|
174
|
+
type: "number",
|
|
175
|
+
label: "Observation pool target",
|
|
176
|
+
description:
|
|
177
|
+
"Target tokens after dropper prunes (defaults to half of pool max)",
|
|
178
|
+
value: cfg.observationsPoolTargetTokens,
|
|
179
|
+
min: 500,
|
|
180
|
+
max: 200_000,
|
|
181
|
+
step: 500,
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
key: "reflectorInputMaxTokens",
|
|
185
|
+
type: "number",
|
|
186
|
+
label: "Reflector input max",
|
|
187
|
+
description:
|
|
188
|
+
"Max prompt tokens for reflector model input (rolling window cap)",
|
|
189
|
+
value: cfg.reflectorInputMaxTokens,
|
|
190
|
+
min: 1_000,
|
|
191
|
+
max: 500_000,
|
|
192
|
+
step: 1_000,
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
key: "dropperInputMaxTokens",
|
|
196
|
+
type: "number",
|
|
197
|
+
label: "Dropper input max",
|
|
198
|
+
description:
|
|
199
|
+
"Max prompt tokens for dropper model input (rolling window cap)",
|
|
200
|
+
value: cfg.dropperInputMaxTokens,
|
|
201
|
+
min: 1_000,
|
|
202
|
+
max: 500_000,
|
|
203
|
+
step: 1_000,
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
key: "observerChunkMaxTokens",
|
|
207
|
+
type: "number",
|
|
208
|
+
label: "Observer chunk max",
|
|
209
|
+
description: "Max source entry tokens sent to observer per chunk",
|
|
210
|
+
value: cfg.observerChunkMaxTokens,
|
|
211
|
+
min: 1_000,
|
|
212
|
+
max: 200_000,
|
|
213
|
+
step: 1_000,
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
key: "observerPreambleMaxTokens",
|
|
217
|
+
type: "number",
|
|
218
|
+
label: "Observer preamble max",
|
|
219
|
+
description:
|
|
220
|
+
"Preamble budget in manual compaction mode (0=auto-compute 30% of chunk)",
|
|
221
|
+
value: cfg.observerPreambleMaxTokens,
|
|
222
|
+
min: 0,
|
|
223
|
+
max: 100_000,
|
|
224
|
+
step: 500,
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
key: "dropperPressureThreshold",
|
|
228
|
+
type: "number",
|
|
229
|
+
label: "Dropper pressure threshold",
|
|
230
|
+
description:
|
|
231
|
+
"Fraction of reflectorInputMaxTokens that triggers pressure-driven dropper (0-1, default 0.70)",
|
|
232
|
+
value: cfg.dropperPressureThreshold,
|
|
233
|
+
min: 0.01,
|
|
234
|
+
max: 1,
|
|
235
|
+
step: 0.01,
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
key: "dropperPoolFullnessThreshold",
|
|
239
|
+
type: "number",
|
|
240
|
+
label: "Dropper pool fullness threshold",
|
|
241
|
+
description:
|
|
242
|
+
"Min observation-pool fullness (fraction of pool max) before the dropper runs (0-1, default 0.10)",
|
|
243
|
+
value: cfg.dropperPoolFullnessThreshold,
|
|
244
|
+
min: 0.01,
|
|
245
|
+
max: 1,
|
|
246
|
+
step: 0.01,
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
key: "agentMaxTurns",
|
|
250
|
+
type: "number",
|
|
251
|
+
label: "Max turns per agent",
|
|
252
|
+
description: "Shared turn cap for background memory agents",
|
|
253
|
+
value: cfg.agentMaxTurns,
|
|
254
|
+
min: 1,
|
|
255
|
+
max: 100,
|
|
256
|
+
step: 1,
|
|
257
|
+
},
|
|
258
|
+
{
|
|
259
|
+
key: "fullFoldAlways",
|
|
260
|
+
type: "boolean",
|
|
261
|
+
label: "Preserve OM on first compaction",
|
|
262
|
+
description:
|
|
263
|
+
"When true, early reflections/drops survive the first compaction in a fresh session",
|
|
264
|
+
value: cfg.fullFoldAlways,
|
|
265
|
+
},
|
|
266
|
+
|
|
267
|
+
// ── Debug ──
|
|
268
|
+
{
|
|
269
|
+
key: "debug",
|
|
270
|
+
type: "boolean",
|
|
271
|
+
label: "Debug snapshots",
|
|
272
|
+
description:
|
|
273
|
+
"Write detailed debug snapshots to /tmp/pi-blackhole-debug.json",
|
|
274
|
+
value: cfg.debug,
|
|
275
|
+
},
|
|
276
|
+
{
|
|
277
|
+
key: "debugLog",
|
|
278
|
+
type: "boolean",
|
|
279
|
+
label: "Debug JSONL logging",
|
|
280
|
+
description: "Write structured JSONL debug logs to agent directory",
|
|
281
|
+
value: cfg.debugLog,
|
|
282
|
+
},
|
|
283
|
+
],
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Validate raw loaded data, apply legacy migration, clamp numeric fields,
|
|
287
|
+
* and apply all env-var overrides (both declarative env-map and legacy
|
|
288
|
+
* passive/compaction env vars).
|
|
289
|
+
*/
|
|
290
|
+
validate: (raw) => {
|
|
291
|
+
const parsed = { ...raw } as Partial<UnifiedConfig>;
|
|
292
|
+
|
|
293
|
+
// ── Migration: legacy keys → new surface ──
|
|
294
|
+
if (
|
|
295
|
+
parsed.compaction === undefined &&
|
|
296
|
+
parsed.compactionEngine === undefined
|
|
297
|
+
) {
|
|
298
|
+
if (parsed.passive === true) {
|
|
299
|
+
parsed.compaction = "off";
|
|
300
|
+
parsed.memory = false;
|
|
301
|
+
} else if (parsed.noAutoCompact === true) {
|
|
302
|
+
parsed.compaction = "manual";
|
|
303
|
+
}
|
|
304
|
+
if (parsed.overrideDefaultCompaction === true) {
|
|
305
|
+
parsed.compactionEngine = "blackhole";
|
|
306
|
+
if (parsed.tailBehavior === undefined) {
|
|
307
|
+
parsed.tailBehavior = "minimal";
|
|
308
|
+
}
|
|
309
|
+
} else if (parsed.overrideDefaultCompaction === false) {
|
|
310
|
+
parsed.compactionEngine = "pi-default";
|
|
311
|
+
}
|
|
312
|
+
delete (parsed as Record<string, unknown>).passive;
|
|
313
|
+
delete (parsed as Record<string, unknown>).noAutoCompact;
|
|
314
|
+
delete (parsed as Record<string, unknown>).overrideDefaultCompaction;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// ── Legacy passive env vars (Layer 4, highest priority) ──
|
|
318
|
+
const envPassive =
|
|
319
|
+
process.env.PI_BLACKHOLE_PASSIVE ??
|
|
320
|
+
process.env.PI_VCC_OM_PASSIVE ??
|
|
321
|
+
process.env.PI_OBSERVATIONAL_MEMORY_PASSIVE;
|
|
322
|
+
if (envPassive !== undefined) {
|
|
323
|
+
const v = envPassive.trim().toLowerCase();
|
|
324
|
+
if (["1", "true", "yes", "on"].includes(v)) {
|
|
325
|
+
parsed.compaction = "off";
|
|
326
|
+
parsed.memory = false;
|
|
327
|
+
} else if (["0", "false", "no", "off"].includes(v)) {
|
|
328
|
+
if (raw.passive === true) {
|
|
329
|
+
delete parsed.compaction;
|
|
330
|
+
delete (parsed as Record<string, unknown>).memory;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// ── New compaction env vars ──
|
|
336
|
+
const envCompaction = process.env.PI_BLACKHOLE_COMPACTION;
|
|
337
|
+
if (envCompaction !== undefined) {
|
|
338
|
+
const parsedEnv = parseCompactionEnv(envCompaction);
|
|
339
|
+
if (parsedEnv) {
|
|
340
|
+
parsed.compaction = parsedEnv;
|
|
341
|
+
} else {
|
|
342
|
+
console.warn(
|
|
343
|
+
`blackhole: invalid PI_BLACKHOLE_COMPACTION value "${envCompaction}"; ignoring`,
|
|
344
|
+
);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
const envCompactionEngine = process.env.PI_BLACKHOLE_COMPACTION_ENGINE;
|
|
349
|
+
if (envCompactionEngine !== undefined) {
|
|
350
|
+
const parsedEnv = parseCompactionEngineEnv(envCompactionEngine);
|
|
351
|
+
if (parsedEnv) {
|
|
352
|
+
parsed.compactionEngine = parsedEnv;
|
|
353
|
+
} else {
|
|
354
|
+
console.warn(
|
|
355
|
+
`blackhole: invalid PI_BLACKHOLE_COMPACTION_ENGINE value "${envCompactionEngine}"; ignoring`,
|
|
356
|
+
);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// ── Merge with defaults ──
|
|
361
|
+
const merged = { ...DEFAULTS, ...parsed } as UnifiedConfig;
|
|
362
|
+
|
|
363
|
+
// ── Numeric field validation ──
|
|
364
|
+
const REQUIRED_NUMERIC_KEYS: readonly (keyof UnifiedConfig)[] = [
|
|
365
|
+
"observeAfterTokens",
|
|
366
|
+
"reflectAfterTokens",
|
|
367
|
+
"compactAfterTokens",
|
|
368
|
+
"observationsPoolMaxTokens",
|
|
369
|
+
"observationsPoolTargetTokens",
|
|
370
|
+
"reflectorInputMaxTokens",
|
|
371
|
+
"dropperInputMaxTokens",
|
|
372
|
+
"observerChunkMaxTokens",
|
|
373
|
+
"observerPreambleMaxTokens",
|
|
374
|
+
"agentMaxTurns",
|
|
375
|
+
];
|
|
376
|
+
for (const k of REQUIRED_NUMERIC_KEYS) {
|
|
377
|
+
const v = (merged as unknown as Record<string, unknown>)[k];
|
|
378
|
+
const minVal = k === "observerPreambleMaxTokens" ? 0 : 1;
|
|
379
|
+
if (typeof v !== "number" || !Number.isFinite(v) || v < minVal) {
|
|
380
|
+
(merged as unknown as Record<string, unknown>)[k] = DEFAULTS[k];
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// dropperPressureThreshold — must be in (0, 1]
|
|
385
|
+
const dpt = merged.dropperPressureThreshold;
|
|
386
|
+
if (
|
|
387
|
+
typeof dpt !== "number" ||
|
|
388
|
+
!Number.isFinite(dpt) ||
|
|
389
|
+
dpt <= 0 ||
|
|
390
|
+
dpt > 1
|
|
391
|
+
) {
|
|
392
|
+
merged.dropperPressureThreshold = DEFAULTS.dropperPressureThreshold;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
// dropperPoolFullnessThreshold — must be in (0, 1]
|
|
396
|
+
const dpf = merged.dropperPoolFullnessThreshold;
|
|
397
|
+
if (
|
|
398
|
+
typeof dpf !== "number" ||
|
|
399
|
+
!Number.isFinite(dpf) ||
|
|
400
|
+
dpf <= 0 ||
|
|
401
|
+
dpf > 1
|
|
402
|
+
) {
|
|
403
|
+
merged.dropperPoolFullnessThreshold =
|
|
404
|
+
DEFAULTS.dropperPoolFullnessThreshold;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// observationsPoolTargetTokens — must be < max
|
|
408
|
+
if (
|
|
409
|
+
merged.observationsPoolTargetTokens === undefined ||
|
|
410
|
+
merged.observationsPoolTargetTokens >= merged.observationsPoolMaxTokens
|
|
411
|
+
) {
|
|
412
|
+
merged.observationsPoolTargetTokens = Math.floor(
|
|
413
|
+
merged.observationsPoolMaxTokens / 2,
|
|
414
|
+
);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
return merged;
|
|
418
|
+
},
|
|
419
|
+
|
|
420
|
+
env: DECLARATIVE_ENV_OVERRIDES,
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
// ── Public entry point ───────────────────────────────────────────────────────
|
|
424
|
+
|
|
425
|
+
export async function openBlackholeSettings(
|
|
426
|
+
ctx: ExtensionContext,
|
|
427
|
+
): Promise<void> {
|
|
428
|
+
await config.openSettings(
|
|
429
|
+
ctx,
|
|
430
|
+
ctx.cwd,
|
|
431
|
+
(_updated) => {
|
|
432
|
+
// onSave is called after the config is persisted; caller (pi-vcc.ts)
|
|
433
|
+
// is responsible for reloading runtime.config from this instance.
|
|
434
|
+
},
|
|
435
|
+
GLOBAL_CONFIG_DIR,
|
|
436
|
+
);
|
|
437
|
+
}
|