@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 +1 -1
- package/src/pix-command.ts +55 -22
- package/src/sections/gate.ts +6 -5
package/package.json
CHANGED
package/src/pix-command.ts
CHANGED
|
@@ -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: "
|
|
66
|
+
label: "Guardrails",
|
|
84
67
|
handle: gateSection,
|
|
85
|
-
values: ["
|
|
86
|
-
read: (v) =>
|
|
87
|
-
patch: (
|
|
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
|
|
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
|
+
}
|
package/src/sections/gate.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
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
|
-
|
|
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
|
-
|
|
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 {
|
|
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
|
-
|
|
67
|
+
guardrails: enumOr(raw.guardrails, ["on", "off"], DEFAULTS.guardrails),
|
|
67
68
|
autoApprove: strArr(raw.autoApprove),
|
|
68
69
|
extraRules,
|
|
69
70
|
};
|