@xynogen/pix-runtime 0.3.1 → 0.4.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/DESIGN.md CHANGED
@@ -132,7 +132,6 @@ interface PixConfigV1 {
132
132
  optimizer: {
133
133
  caveman: "off" | "lite" | "full" | "ultra" | "micro"; // default off
134
134
  rtk: "off" | "on"; // default on
135
- toon: "off" | "on"; // default on
136
135
  ponytail: "off" | "lite" | "full" | "ultra"; // default off
137
136
  };
138
137
  gate: {
package/README.md CHANGED
@@ -10,7 +10,7 @@ See `DESIGN.md` for the full contract.
10
10
  ## What it does
11
11
 
12
12
  - Versioned, sparse `pix.json` (`$version: 1`) — defaults resolve in code.
13
- - Typed sections: `collapse`, `pretty`, `optimizer`, `gate`.
13
+ - Typed sections: `collapse`, `pretty`, `io`, `optimizer`, `gate`.
14
14
  - Atomic writes behind a serialized in-process queue and a short-lived
15
15
  cross-process lock. A failed write leaves the old file intact.
16
16
  - Immutable, deeply frozen config snapshots with a monotonic revision.
@@ -38,8 +38,17 @@ import { prettySection } from "@xynogen/pix-runtime/sections";
38
38
  const icons = config(prettySection).icons; // synchronous read
39
39
  await updateConfig(prettySection, { icons: "ascii" });
40
40
  const off = onConfigChange((c) => render(), { paths: ["pretty.icons"] });
41
+
42
+ import { ioTimeoutMs, ioTimeoutSignal } from "@xynogen/pix-runtime/io";
43
+ const timeoutMs = ioTimeoutMs(); // shared network timeout
44
+ const signal = ioTimeoutSignal(toolSignal); // timeout + cancellation
41
45
  ```
42
46
 
47
+ Set `io.timeoutSec` in `~/.pi/agent/pix.json`, or change **Network → timeout (sec)**
48
+ with `/pix`. The default is 30 seconds. It applies to Pix network operations,
49
+ including remote skills, web fetch/search/transcription, MCP requests and
50
+ connection bootstrap, background model-data refreshes, and update downloads.
51
+
43
52
  Collapse policy helpers:
44
53
 
45
54
  ```ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xynogen/pix-runtime",
3
- "version": "0.3.1",
3
+ "version": "0.4.2",
4
4
  "description": "Pix shared runtime — versioned pix.json config, atomic persistence, typed change events",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -24,6 +24,7 @@
24
24
  "./config": "./src/runtime.ts",
25
25
  "./sections": "./src/sections/index.ts",
26
26
  "./collapse": "./src/collapse.ts",
27
+ "./io": "./src/io.ts",
27
28
  "./once": "./src/once.ts",
28
29
  "./testing": "./src/testing.ts"
29
30
  },
package/src/index.ts CHANGED
@@ -7,6 +7,7 @@ export type {
7
7
  SubscribeOptions,
8
8
  } from "./events.ts";
9
9
  export { default } from "./extension.ts";
10
+ export { ioTimeoutMs, ioTimeoutSignal } from "./io.ts";
10
11
  export {
11
12
  config,
12
13
  createRuntime,
@@ -34,6 +35,8 @@ export {
34
35
  type GateConfig,
35
36
  type GateRuleConfig,
36
37
  gateSection,
38
+ type IoConfig,
39
+ ioSection,
37
40
  type OptimizerConfig,
38
41
  optimizerSection,
39
42
  type PrettyConfig,
package/src/io.ts ADDED
@@ -0,0 +1,11 @@
1
+ import { config } from "./runtime.ts";
2
+ import { ioSection } from "./sections/io.ts";
3
+
4
+ export function ioTimeoutMs(): number {
5
+ return config(ioSection).timeoutSec * 1000;
6
+ }
7
+
8
+ export function ioTimeoutSignal(signal?: AbortSignal): AbortSignal {
9
+ const timeout = AbortSignal.timeout(ioTimeoutMs());
10
+ return signal ? AbortSignal.any([signal, timeout]) : timeout;
11
+ }
package/src/migrations.ts CHANGED
@@ -25,7 +25,7 @@ const LEGACY_DIFF_COLOR_KEYS = [
25
25
  "fgDel",
26
26
  ] as const;
27
27
 
28
- const OPTIMIZER_KEYS = ["caveman", "rtk", "toon", "ponytail"] as const;
28
+ const OPTIMIZER_KEYS = ["caveman", "rtk", "ponytail"] as const;
29
29
 
30
30
  export interface MigrationResult {
31
31
  document: RawDocument;
@@ -80,6 +80,14 @@ export function migrate(input: RawDocument, ctx: ParseContext): MigrationResult
80
80
  doc.pretty = pretty;
81
81
  }
82
82
 
83
+ // TOON is now an on-demand pix-skills capability, not optimizer state.
84
+ if (isObj(doc.optimizer) && "toon" in doc.optimizer) {
85
+ doc.optimizer = Object.fromEntries(
86
+ Object.entries(doc.optimizer).filter(([key]) => key !== "toon"),
87
+ );
88
+ changed = true;
89
+ }
90
+
83
91
  if (doc.$version !== CONFIG_FORMAT_VERSION) {
84
92
  doc.$version = CONFIG_FORMAT_VERSION;
85
93
  changed = true;
@@ -128,6 +136,7 @@ export function importOptimizerSidecar(
128
136
  }
129
137
  if (changed) doc.optimizer = existing;
130
138
 
139
+ const hasLegacyToon = typeof raw.toon === "string";
131
140
  const archive = () => {
132
141
  let target = `${sidecarPath}.migrated-v1`;
133
142
  if (existsSync(target)) target = `${target}.${Date.now()}`;
@@ -138,5 +147,5 @@ export function importOptimizerSidecar(
138
147
  }
139
148
  };
140
149
 
141
- return { changed, archive };
150
+ return { changed: changed || hasLegacyToon, archive };
142
151
  }
@@ -19,6 +19,7 @@ import type { PixRuntime } from "./runtime.ts";
19
19
  import type { DeepPartial, SectionHandle } from "./schema.ts";
20
20
  import { collapseSection } from "./sections/collapse.ts";
21
21
  import { gateSection } from "./sections/gate.ts";
22
+ import { ioSection } from "./sections/io.ts";
22
23
  import { prettySection } from "./sections/pretty.ts";
23
24
 
24
25
  interface SettingRow<T> {
@@ -68,6 +69,14 @@ const SETTINGS: SettingRow<unknown>[] = [
68
69
  read: (v) => String(v.delaySec),
69
70
  patch: (value) => ({ delaySec: Number(value) }),
70
71
  }),
72
+ row({
73
+ section: "Network",
74
+ label: "timeout (sec)",
75
+ handle: ioSection,
76
+ values: ["30", "10", "60", "120", "300"],
77
+ read: (v) => String(v.timeoutSec),
78
+ patch: (value) => ({ timeoutSec: Number(value) }),
79
+ }),
71
80
  row({
72
81
  section: "Gate",
73
82
  label: "Guardrails",
@@ -120,6 +129,9 @@ export function registerPixCommand(pi: ExtensionAPI, runtime: PixRuntime): void
120
129
  kb: KeybindingsManager,
121
130
  done: (v: null) => void,
122
131
  ) => {
132
+ const guide = (key: string, action: string) =>
133
+ theme.fg("text", key) + theme.fg("dim", ` ${action}`);
134
+ const guideSep = theme.fg("dim", " · ");
123
135
  let selected = 0;
124
136
  let bodyOffset = 0;
125
137
  let visibleBodyLines = 1;
@@ -168,7 +180,13 @@ export function registerPixCommand(pi: ExtensionAPI, runtime: PixRuntime): void
168
180
  body,
169
181
  footer: [
170
182
  "",
171
- theme.fg("dim", "←→ change · ↑↓ move · PgUp/PgDn inspect · esc close"),
183
+ guide("←→", "change") +
184
+ guideSep +
185
+ guide("↑↓", "move") +
186
+ guideSep +
187
+ guide("PgUp/PgDn", "inspect") +
188
+ guideSep +
189
+ guide("esc", "close"),
172
190
  ],
173
191
  bodyOffset,
174
192
  selectedBodyLine: inspectingPage ? undefined : settingBodyLines[selected],
@@ -5,6 +5,7 @@ export {
5
5
  type GateSeverity,
6
6
  gateSection,
7
7
  } from "./gate.ts";
8
+ export { type IoConfig, ioSection } from "./io.ts";
8
9
  export {
9
10
  type CavemanLevel,
10
11
  type OptimizerConfig,
@@ -22,6 +23,7 @@ export {
22
23
 
23
24
  import { collapseSection } from "./collapse.ts";
24
25
  import { gateSection } from "./gate.ts";
26
+ import { ioSection } from "./io.ts";
25
27
  import { optimizerSection } from "./optimizer.ts";
26
28
  import { prettySection } from "./pretty.ts";
27
29
 
@@ -29,6 +31,7 @@ import { prettySection } from "./pretty.ts";
29
31
  export const builtinSections = [
30
32
  collapseSection,
31
33
  prettySection,
34
+ ioSection,
32
35
  optimizerSection,
33
36
  gateSection,
34
37
  ] as const;
@@ -0,0 +1,21 @@
1
+ import { defineSection, isObj, posNumOr } from "../schema.ts";
2
+
3
+ export interface IoConfig {
4
+ /** Default timeout in seconds for Pix network requests. */
5
+ timeoutSec: number;
6
+ }
7
+
8
+ const DEFAULTS: Readonly<IoConfig> = {
9
+ timeoutSec: 30,
10
+ };
11
+
12
+ export const ioSection = defineSection<"io", IoConfig>({
13
+ key: "io",
14
+ defaults: DEFAULTS,
15
+ parse(raw) {
16
+ if (!isObj(raw)) return { ...DEFAULTS };
17
+ return {
18
+ timeoutSec: posNumOr(raw.timeoutSec, DEFAULTS.timeoutSec),
19
+ };
20
+ },
21
+ });
@@ -7,7 +7,6 @@ export type Toggle = "off" | "on";
7
7
  export interface OptimizerConfig {
8
8
  caveman: CavemanLevel;
9
9
  rtk: Toggle;
10
- toon: Toggle;
11
10
  ponytail: PonytailLevel;
12
11
  }
13
12
 
@@ -18,7 +17,6 @@ const TOGGLE: readonly Toggle[] = ["off", "on"];
18
17
  const DEFAULTS: Readonly<OptimizerConfig> = {
19
18
  caveman: "off",
20
19
  rtk: "on",
21
- toon: "on",
22
20
  ponytail: "off",
23
21
  };
24
22
 
@@ -30,7 +28,6 @@ export const optimizerSection = defineSection<"optimizer", OptimizerConfig>({
30
28
  return {
31
29
  caveman: enumOr(raw.caveman, CAVEMAN, DEFAULTS.caveman),
32
30
  rtk: enumOr(raw.rtk, TOGGLE, DEFAULTS.rtk),
33
- toon: enumOr(raw.toon, TOGGLE, DEFAULTS.toon),
34
31
  ponytail: enumOr(raw.ponytail, PONYTAIL, DEFAULTS.ponytail),
35
32
  };
36
33
  },