@xynogen/pix-runtime 0.2.0 → 0.3.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xynogen/pix-runtime",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
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",
@@ -12,7 +12,6 @@ import type { PixRuntime } from "./runtime.ts";
12
12
  import type { DeepPartial, SectionHandle } from "./schema.ts";
13
13
  import { collapseSection } from "./sections/collapse.ts";
14
14
  import { gateSection } from "./sections/gate.ts";
15
- import { optimizerSection } from "./sections/optimizer.ts";
16
15
  import { prettySection } from "./sections/pretty.ts";
17
16
 
18
17
  interface SettingRow<T> {
@@ -62,29 +61,13 @@ const SETTINGS: SettingRow<unknown>[] = [
62
61
  read: (v) => String(v.delaySec),
63
62
  patch: (value) => ({ delaySec: Number(value) }),
64
63
  }),
65
- row({
66
- section: "Optimizer",
67
- label: "caveman",
68
- handle: optimizerSection,
69
- values: ["off", "lite", "full", "ultra", "micro"],
70
- read: (v) => v.caveman,
71
- patch: (value) => ({ caveman: value as "off" | "lite" | "full" | "ultra" | "micro" }),
72
- }),
73
- row({
74
- section: "Optimizer",
75
- label: "rtk",
76
- handle: optimizerSection,
77
- values: ["on", "off"],
78
- read: (v) => v.rtk,
79
- patch: (value) => ({ rtk: value as "on" | "off" }),
80
- }),
81
64
  row({
82
65
  section: "Gate",
83
- label: "disable defaults",
66
+ label: "Guardrails",
84
67
  handle: gateSection,
85
- values: ["false", "true"],
86
- read: (v) => String(v.disableDefaults),
87
- patch: (value) => ({ disableDefaults: value === "true" }),
68
+ values: ["on", "off"],
69
+ read: (v) => v.guardrails,
70
+ patch: (guardrails) => ({ guardrails: guardrails as "on" | "off" }),
88
71
  }),
89
72
  ];
90
73
 
@@ -124,6 +107,7 @@ export function registerPixCommand(pi: ExtensionAPI, runtime: PixRuntime): void
124
107
  tui: { requestRender(): void },
125
108
  theme: {
126
109
  fg(c: string, t: string): string;
110
+ bg(c: string, t: string): string;
127
111
  bold(t: string): string;
128
112
  },
129
113
  _kb: unknown,
@@ -165,7 +149,12 @@ export function registerPixCommand(pi: ExtensionAPI, runtime: PixRuntime): void
165
149
  }
166
150
  lines.push("");
167
151
  lines.push(theme.fg("dim", "←→ change · ↑↓ move · esc close"));
168
- return lines;
152
+ return frameLines({
153
+ width: boxW,
154
+ lines,
155
+ color: (s: string) => theme.fg("accent", s),
156
+ bg: (s: string) => theme.bg("customMessageBg", s),
157
+ });
169
158
  },
170
159
  invalidate: () => {},
171
160
  handleInput: (data: string) => {
@@ -195,3 +184,47 @@ export function registerPixCommand(pi: ExtensionAPI, runtime: PixRuntime): void
195
184
  },
196
185
  });
197
186
  }
187
+
188
+ // ── Inline frameLines (runtime must not depend on pix-pretty — pretty depends on us) ─
189
+
190
+ interface FrameOptions {
191
+ width: number;
192
+ lines: string[];
193
+ color: (s: string) => string;
194
+ bg?: (s: string) => string;
195
+ }
196
+
197
+ function visibleWidth(s: string): number {
198
+ // Strip ANSI escape sequences for width calculation.
199
+ return s.replace(/\x1b\[[0-9;]*m/g, "").length;
200
+ }
201
+
202
+ /** Render a rounded bordered modal box (╭─╮╰─╯) with solid background fill. */
203
+ function frameLines(opts: FrameOptions): string[] {
204
+ const { width, lines, color } = opts;
205
+ const bg = opts.bg ?? ((s: string) => s);
206
+ const inner = Math.max(1, width - 4); // 2 border + 2 padding
207
+ const dashes = "─".repeat(width - 2);
208
+
209
+ // Re-assert the bg OPEN sequence after any full reset (\x1b[0m) or bg reset
210
+ // (\x1b[49m) embedded in themed content, so the fill has no transparent holes.
211
+ const SENTINEL = "\x00";
212
+ const bgOpen = bg(SENTINEL).split(SENTINEL)[0] ?? "";
213
+ const reassert = (s: string): string =>
214
+ bgOpen
215
+ ? s.replace(/\x1b\[([0-9;]*)m/g, (seq, p: string) =>
216
+ p === "0" || p.split(";").includes("49") ? `${seq}${bgOpen}` : seq,
217
+ )
218
+ : s;
219
+
220
+ const row = (content: string): string => {
221
+ const pad = inner - visibleWidth(content);
222
+ const padded = pad > 0 ? content + " ".repeat(pad) : content.slice(0, inner);
223
+ return bg(`${color("│")} ${reassert(padded)} ${color("│")}`);
224
+ };
225
+
226
+ const out: string[] = [bg(color(`╭${dashes}╮`))];
227
+ for (const line of lines) out.push(row(line));
228
+ out.push(bg(color(`╰${dashes}╯`)));
229
+ return out;
230
+ }
@@ -1,4 +1,4 @@
1
- import { boolOr, defineSection, isObj, strArr } from "../schema.ts";
1
+ import { defineSection, enumOr, isObj, strArr } from "../schema.ts";
2
2
 
3
3
  export type GateSeverity = "risky" | "dangerous" | "critical";
4
4
 
@@ -10,7 +10,8 @@ export interface GateRuleConfig {
10
10
  }
11
11
 
12
12
  export interface GateConfig {
13
- disableDefaults: boolean;
13
+ /** Whether Pix's built-in command protections are active. */
14
+ guardrails: "on" | "off";
14
15
  autoApprove: string[];
15
16
  extraRules: GateRuleConfig[];
16
17
  }
@@ -18,7 +19,7 @@ export interface GateConfig {
18
19
  const SEVERITIES: readonly GateSeverity[] = ["risky", "dangerous", "critical"];
19
20
 
20
21
  const DEFAULTS: Readonly<GateConfig> = {
21
- disableDefaults: false,
22
+ guardrails: "on",
22
23
  autoApprove: [],
23
24
  extraRules: [],
24
25
  };
@@ -37,7 +38,7 @@ export const gateSection = defineSection<"gate", GateConfig>({
37
38
  key: "gate",
38
39
  defaults: DEFAULTS,
39
40
  parse(raw, ctx) {
40
- if (!isObj(raw)) return { disableDefaults: false, autoApprove: [], extraRules: [] };
41
+ if (!isObj(raw)) return { guardrails: "on", autoApprove: [], extraRules: [] };
41
42
  const extraRules: GateRuleConfig[] = [];
42
43
  if (Array.isArray(raw.extraRules)) {
43
44
  raw.extraRules.forEach((r, i) => {
@@ -63,7 +64,7 @@ export const gateSection = defineSection<"gate", GateConfig>({
63
64
  });
64
65
  }
65
66
  return {
66
- disableDefaults: boolOr(raw.disableDefaults, DEFAULTS.disableDefaults),
67
+ guardrails: enumOr(raw.guardrails, ["on", "off"], DEFAULTS.guardrails),
67
68
  autoApprove: strArr(raw.autoApprove),
68
69
  extraRules,
69
70
  };