pi-fold 3.0.0 → 3.1.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.
@@ -50,17 +50,6 @@ const THRESHOLD_FIELDS = [
50
50
 
51
51
  export type FoldSettingId = typeof THRESHOLD_FIELDS[number];
52
52
 
53
- function readProportion(raw: string, field: string): number {
54
- const value = Number(raw);
55
- if (!Number.isFinite(value) || value <= 0 || value >= 1) {
56
- throw new ThresholdPolicyError(
57
- field,
58
- `thresholds.${field} must be a proportion above 0 and below 1`,
59
- );
60
- }
61
- return value;
62
- }
63
-
64
53
  // One edit, applied against the WHOLE draft: the merged thresholds object is
65
54
  // re-validated through resolveThresholds so cross-field invariants
66
55
  // (minTarget < maxTarget) hold at every saved state, never
@@ -71,18 +60,10 @@ export function applyFoldSettingsEdit(
71
60
  rawValue: string,
72
61
  ): { ok: true; draft: FoldSettingsFile } | { ok: false; error: string } {
73
62
  try {
74
- if (id === "consolidateAfter" || id === "minFoldChars") {
75
- const value = Number(rawValue.trim());
76
- if (!Number.isSafeInteger(value)) {
77
- return { ok: false, error: `thresholds.${id} must be a whole number` };
78
- }
79
- const thresholds = resolveThresholds({
80
- ...(draft.thresholds ?? DEFAULT_THRESHOLDS),
81
- [id]: value,
82
- });
83
- return { ok: true, draft: { ...draft, thresholds } };
63
+ const value = Number(rawValue.trim());
64
+ if ((id === "consolidateAfter" || id === "minFoldChars") && !Number.isSafeInteger(value)) {
65
+ return { ok: false, error: `thresholds.${id} must be a whole number` };
84
66
  }
85
- const value = readProportion(rawValue.trim(), id);
86
67
  const thresholds = resolveThresholds({
87
68
  ...(draft.thresholds ?? DEFAULT_THRESHOLDS),
88
69
  [id]: value,
@@ -245,16 +226,15 @@ function shareCandidates(id: "maxTarget" | "minTarget"): number[] {
245
226
  return values;
246
227
  }
247
228
 
248
- function allowedValues(id: FoldSettingId, thresholds: ActiveContextThresholds, budgetTokens: number): string[] {
249
- if (id === "consolidateAfter") return CONSOLIDATE_CHOICES.map(String);
250
- if (id === "minFoldChars") return MIN_FOLD_CHOICES.map((value) => `${value.toLocaleString("en-US")} chars`);
229
+ // The lattice a row steps along, as numbers. Display belongs to rowDisplayValue and
230
+ // only to it: this list is stepped, never shown.
231
+ function allowedValues(id: FoldSettingId, thresholds: ActiveContextThresholds): number[] {
232
+ if (id === "consolidateAfter") return CONSOLIDATE_CHOICES;
233
+ if (id === "minFoldChars") return MIN_FOLD_CHOICES;
251
234
  const { minTarget, maxTarget } = thresholds;
252
- const candidates = id === "maxTarget"
235
+ return id === "maxTarget"
253
236
  ? shareCandidates("maxTarget").filter((v) => v > minTarget)
254
237
  : shareCandidates("minTarget").filter((v) => v < maxTarget);
255
- // Entries carry the SAME display format as currentValue: SettingsList cycles by
256
- // indexOf(currentValue), so a format mismatch wraps every first press to the head.
257
- return candidates.map((v) => `${v.toFixed(2)} · ${Math.round(v * budgetTokens).toLocaleString("en-US")} tok`);
258
238
  }
259
239
 
260
240
  function rowRawValue(settings: FoldSettingsFile, id: FoldSettingId): string {
@@ -385,7 +365,7 @@ export class FoldSettingsEditor extends Container {
385
365
  row.label,
386
366
  row.description,
387
367
  rowRawValue(draft, row.id),
388
- (raw) => this.applyEdit(row.id, raw),
368
+ (raw) => this.applyAndSave(row.id, raw),
389
369
  submenuDone,
390
370
  ),
391
371
  })),
@@ -405,8 +385,7 @@ export class FoldSettingsEditor extends Container {
405
385
  // surface; an exact off-lattice value arrives only through Enter's editor.
406
386
  private step(id: FoldSettingId, direction: number): void {
407
387
  const thresholds = this.draft.thresholds ?? DEFAULT_THRESHOLDS;
408
- const candidates = allowedValues(id, thresholds).map((entry) =>
409
- Number.parseFloat(entry.replace(/,/g, "")));
388
+ const candidates = allowedValues(id, thresholds);
410
389
  const current = Number(rowRawValue(this.draft, id));
411
390
  const target = direction > 0
412
391
  ? candidates.find((candidate) => candidate > current + 1e-9)
@@ -427,10 +406,6 @@ export class FoldSettingsEditor extends Container {
427
406
  return { ok: true, display: rowDisplayValue(this.draft, id, this.budgetTokens) };
428
407
  }
429
408
 
430
- private applyEdit(id: FoldSettingId, raw: string): { ok: true; display: string } | { ok: false; error: string } {
431
- return this.applyAndSave(id, raw);
432
- }
433
-
434
409
  handleInput(data: string): void {
435
410
  // An open submenu owns everything until it closes.
436
411
  if (this.settingsList.submenuComponent) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-fold",
3
- "version": "3.0.0",
3
+ "version": "3.1.0",
4
4
  "description": "Lossless, agent-governed context folding for the Pi coding agent: only the oldest context changes; the fresh window stays untouched.",
5
5
  "keywords": [
6
6
  "pi-package",