pi-warden 0.5.0 → 0.5.1
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 +9 -4
- package/dist/config.js +2 -0
- package/dist/extension.js +18 -10
- package/dist/panel.d.ts +26 -6
- package/dist/panel.js +45 -19
- package/dist/widget.d.ts +3 -1
- package/dist/widget.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -112,11 +112,15 @@ The action guard receives the latest user message plus up to eight previous user
|
|
|
112
112
|
| `/warden mode steer\|confirm\|advise` | Choose how holds are handled; without an argument, show the current mode |
|
|
113
113
|
| `/warden config` | Edit the user config JSON in Pi's editor and save it |
|
|
114
114
|
| `/warden test` | Evaluate one synthetic destructive action and show the verdict and what the agent would be told |
|
|
115
|
-
| `/warden trace` |
|
|
115
|
+
| `/warden trace` | Toggle the trace sidebar (or print the last 20 events without a UI) |
|
|
116
116
|
|
|
117
|
-
## Status line and trace
|
|
117
|
+
## Status line and trace sidebar
|
|
118
118
|
|
|
119
|
-
The line above the editor shows the latest verdict per guard, for example `warden · bash · irreversible 0.84 · off-task 0.86 · unrelated · confirm`. Every verdict is also kept in a session trace with what was inspected (redacted command or path), the pattern hits, Jev's scores with model and latency, the reasons, and the exact text the agent was told.
|
|
119
|
+
The line above the editor shows the latest verdict per guard, for example `warden · bash · irreversible 0.84 · off-task 0.86 · unrelated · confirm`. Every verdict is also kept in a session trace with what was inspected (redacted command or path), the pattern hits, Jev's scores with model and latency, the reasons, and the exact text the agent was told.
|
|
120
|
+
|
|
121
|
+
`/warden trace`, `ctrl+shift+w`, and a click on the status line each **toggle a right-hand sidebar** with that trace, newest first, live-updating while the agent works. The sidebar does not take the keyboard: you keep typing in the editor while it is open. Click inside it to give it the keys (↑↓/PgUp/PgDn scroll, `c` clears, Esc hands input back to the editor, `q` closes); the wheel scrolls it without focus. `widget.panelWidth` sets its width (`"40%"` or a column count).
|
|
122
|
+
|
|
123
|
+
Clicks and the wheel need Pi's fullscreen mode (`tuiMode: "fullscreen"` in `/settings`); regular mode leaves the mouse to the terminal for scrollback. If the mouse does nothing in fullscreen, the terminal is not reporting it: in macOS Terminal.app enable View → Allow Mouse Reporting (⌘R). Pi's extension API offers floating overlays but no side dock that narrows the transcript, so the sidebar covers the right part of the screen instead of pushing the transcript aside.
|
|
120
124
|
|
|
121
125
|
Templates in `config.widget` control the text. Segments are separated by ` · `; a segment whose token has no value for that verdict is dropped, so optional information disappears together with its label:
|
|
122
126
|
|
|
@@ -125,6 +129,7 @@ Templates in `config.widget` control the text. Segments are separated by ` · `;
|
|
|
125
129
|
"enabled": true,
|
|
126
130
|
"placement": "aboveEditor",
|
|
127
131
|
"shortcut": "ctrl+shift+w",
|
|
132
|
+
"panelWidth": "40%",
|
|
128
133
|
"action": "warden · {tool} · irreversible {irreversible} · off-task {offTask} · {scope} · slop: {slop} · patterns: {patterns} · {flags} · {level}",
|
|
129
134
|
"stuck": "warden · stuck · {failures} failures · same strategy {sameStrategy} · change {approachChange} · progress {progress} · {flags} · {status}",
|
|
130
135
|
"done": "warden · done-check · {changes} changes · {checksPassed}/{checks} checks passed · claims done {claimsDone} · claims verified {claimsVerified} · checks apply {checksApply} · {outcome} · {status}",
|
|
@@ -163,7 +168,7 @@ User file `~/.pi/agent/pi-warden/config.json` (owner-only). Missing keys use the
|
|
|
163
168
|
"threshold": 0.7,
|
|
164
169
|
"prose": { "enabled": true, "audience": "technical", "threshold": 0.7, "trend": 2, "minChars": 200 }
|
|
165
170
|
},
|
|
166
|
-
"widget": { "enabled": true, "placement": "aboveEditor", "shortcut": "ctrl+shift+w" },
|
|
171
|
+
"widget": { "enabled": true, "placement": "aboveEditor", "shortcut": "ctrl+shift+w", "panelWidth": "40%" },
|
|
167
172
|
"steerVisible": false
|
|
168
173
|
}
|
|
169
174
|
```
|
package/dist/config.js
CHANGED
|
@@ -128,6 +128,8 @@ function applyWidget(base, raw) {
|
|
|
128
128
|
enabled: boolean(raw.enabled, base.enabled),
|
|
129
129
|
placement: raw.placement === "belowEditor" || raw.placement === "aboveEditor" ? raw.placement : base.placement,
|
|
130
130
|
shortcut: typeof raw.shortcut === "string" ? raw.shortcut.trim() : base.shortcut,
|
|
131
|
+
panelWidth: typeof raw.panelWidth === "number" && Number.isSafeInteger(raw.panelWidth) && raw.panelWidth >= 20 ? raw.panelWidth
|
|
132
|
+
: typeof raw.panelWidth === "string" && /^[1-9]\d?%$/.test(raw.panelWidth.trim()) ? raw.panelWidth.trim() : base.panelWidth,
|
|
131
133
|
action: template(raw.action, base.action),
|
|
132
134
|
stuck: template(raw.stuck, base.stuck),
|
|
133
135
|
done: template(raw.done, base.done),
|
package/dist/extension.js
CHANGED
|
@@ -94,7 +94,7 @@ export default function wardenExtension(pi) {
|
|
|
94
94
|
let stats = freshStats();
|
|
95
95
|
const widget = new Map();
|
|
96
96
|
const trace = new Trace();
|
|
97
|
-
let
|
|
97
|
+
let panel;
|
|
98
98
|
let lastUi;
|
|
99
99
|
/** Calls held in steer mode, with the user prompt current at that time; a retry after the user replies asks Jev about approval. */
|
|
100
100
|
const held = new Map();
|
|
@@ -118,11 +118,18 @@ export default function wardenExtension(pi) {
|
|
|
118
118
|
if (ctx.hasUI)
|
|
119
119
|
ctx.ui.notify(`warden: ${message}${budgetExhausted ? " Pattern checks continue without TypeSafe for the rest of this session." : ""}`, "warning");
|
|
120
120
|
};
|
|
121
|
-
|
|
122
|
-
|
|
121
|
+
/** Click, shortcut, and /warden trace all toggle the same sidebar. */
|
|
122
|
+
const togglePanel = (ui, config) => {
|
|
123
|
+
if (!ui)
|
|
123
124
|
return;
|
|
124
|
-
|
|
125
|
-
|
|
125
|
+
if (panel) {
|
|
126
|
+
panel.close();
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
const opened = openTracePanel(ui, trace, { width: config.widget.panelWidth });
|
|
130
|
+
panel = opened;
|
|
131
|
+
opened.closed.catch(() => undefined).finally(() => { if (panel === opened)
|
|
132
|
+
panel = undefined; });
|
|
126
133
|
};
|
|
127
134
|
const paint = (ctx, config) => {
|
|
128
135
|
if (!ctx.hasUI)
|
|
@@ -137,7 +144,7 @@ export default function wardenExtension(pi) {
|
|
|
137
144
|
ctx.ui.setWidget(WIDGET, (_tui, theme) => new MouseRegion(new Text(lines.map(line => theme.fg("muted", line)).join("\n"), 0, 0), event => {
|
|
138
145
|
if (event.type !== "click" || event.button !== "left")
|
|
139
146
|
return undefined;
|
|
140
|
-
|
|
147
|
+
togglePanel(lastUi, config);
|
|
141
148
|
return { handled: true };
|
|
142
149
|
}), { placement: config.widget.placement });
|
|
143
150
|
};
|
|
@@ -153,6 +160,7 @@ export default function wardenExtension(pi) {
|
|
|
153
160
|
stats = freshStats();
|
|
154
161
|
widget.clear();
|
|
155
162
|
trace.clear();
|
|
163
|
+
panel?.close();
|
|
156
164
|
held.clear();
|
|
157
165
|
attempts.reset();
|
|
158
166
|
evidence = emptyEvidence();
|
|
@@ -372,9 +380,9 @@ export default function wardenExtension(pi) {
|
|
|
372
380
|
const shortcut = loadConfig().widget.shortcut;
|
|
373
381
|
if (/^(?:(?:ctrl|shift|alt|super)\+)+[a-z0-9]+$|^f\d{1,2}$/i.test(shortcut)) {
|
|
374
382
|
pi.registerShortcut(shortcut, {
|
|
375
|
-
description: "
|
|
383
|
+
description: "Toggle the pi-warden trace sidebar",
|
|
376
384
|
handler: async (ctx) => { if (ctx.hasUI)
|
|
377
|
-
|
|
385
|
+
togglePanel(ctx.ui, configFor(ctx)); },
|
|
378
386
|
});
|
|
379
387
|
}
|
|
380
388
|
const actions = ["status", "enable", "disable", "mode", "config", "test", "trace"];
|
|
@@ -405,7 +413,7 @@ export default function wardenExtension(pi) {
|
|
|
405
413
|
`Thresholds: irreversible warn ${config.action.irreversible.warn} / hold ${config.action.irreversible.confirm}; off-task warn ${config.action.offTask.warn} / hold ${config.action.offTask.confirm}; stuck same-strategy ${config.stuck.sameStrategy} after ${config.stuck.minFailures} failures; done claims ${config.done.claimsDone}; slop ${config.slop.threshold}, prose ${config.slop.prose.threshold} in ${config.slop.prose.trend}/3 replies; failOpen ${config.action.failOpen}.`,
|
|
406
414
|
`Config: ${userConfigPath()}${ctx.isProjectTrusted() ? ` and ${projectConfigPath(ctx.cwd)}` : ""}.`,
|
|
407
415
|
widget.size ? `Last: ${[...widget.values()].join(" | ")}` : "No guarded activity yet this session.",
|
|
408
|
-
`Trace: ${trace.entries().length} events (/warden trace${shortcut ? `, ${shortcut}` : ""}, or click the status line in fullscreen mode). Widget templates in config.widget: action tokens ${TOKEN_NAMES.action.map(name => `{${name}}`).join(" ")}.`,
|
|
416
|
+
`Trace: ${trace.entries().length} events (/warden trace${shortcut ? `, ${shortcut}` : ""}, or click the status line in fullscreen mode; each toggles the sidebar). Widget templates in config.widget: action tokens ${TOKEN_NAMES.action.map(name => `{${name}}`).join(" ")}.`,
|
|
409
417
|
].join(" "));
|
|
410
418
|
return;
|
|
411
419
|
}
|
|
@@ -415,7 +423,7 @@ export default function wardenExtension(pi) {
|
|
|
415
423
|
report(entries.length ? entries.slice(-20).map(entry => `${new Date(entry.at).toTimeString().slice(0, 8)} ${entry.guard}: ${entry.line}${entry.details.length ? `\n ${entry.details.join("\n ")}` : ""}`).join("\n") : "No guarded activity yet this session.");
|
|
416
424
|
return;
|
|
417
425
|
}
|
|
418
|
-
|
|
426
|
+
togglePanel(ctx.ui, config);
|
|
419
427
|
return;
|
|
420
428
|
}
|
|
421
429
|
if (action === "enable") {
|
package/dist/panel.d.ts
CHANGED
|
@@ -4,25 +4,35 @@ interface ThemeLike {
|
|
|
4
4
|
fg(color: string, text: string): string;
|
|
5
5
|
bold(text: string): string;
|
|
6
6
|
}
|
|
7
|
+
export interface PanelActions {
|
|
8
|
+
/** Remove the sidebar. */
|
|
9
|
+
close(): void;
|
|
10
|
+
/** Keep the sidebar visible but give keyboard input back to the editor. */
|
|
11
|
+
unfocus(): void;
|
|
12
|
+
}
|
|
7
13
|
/**
|
|
8
|
-
*
|
|
9
|
-
*
|
|
14
|
+
* Sidebar listing the trace newest-first, live-updating while open. It opens without taking keyboard input: the editor
|
|
15
|
+
* keeps working while it is visible. A click inside it (fullscreen mode) focuses it; then ↑/↓/j/k scroll a line,
|
|
16
|
+
* PgUp/PgDn a page, Home/End jump, c clears the trace, Esc returns input to the editor, and q closes. Wheel scrolling
|
|
17
|
+
* works without focus.
|
|
10
18
|
*/
|
|
11
19
|
export declare class TracePanel implements Component {
|
|
12
20
|
private readonly trace;
|
|
13
21
|
private readonly theme;
|
|
14
|
-
private readonly
|
|
22
|
+
private readonly actions;
|
|
15
23
|
private readonly requestRender;
|
|
16
24
|
private readonly title;
|
|
25
|
+
/** Set by the TUI when keyboard focus changes. */
|
|
17
26
|
focused: boolean;
|
|
18
27
|
private scroll;
|
|
19
28
|
private viewport;
|
|
20
29
|
private readonly unsubscribe;
|
|
21
|
-
constructor(trace: Trace, theme: ThemeLike,
|
|
30
|
+
constructor(trace: Trace, theme: ThemeLike, actions: PanelActions, requestRender: () => void, title?: string);
|
|
22
31
|
dispose(): void;
|
|
23
32
|
/** Rendering is cheap and derived from the trace each time; nothing is cached. */
|
|
24
33
|
invalidate(): void;
|
|
25
34
|
private lines;
|
|
35
|
+
/** A left border makes the overlay read as a pane; the content column is two cells narrower. */
|
|
26
36
|
render(width: number): string[];
|
|
27
37
|
/** The overlay tells us how tall we may be through the layout; fall back to a fixed viewport otherwise. */
|
|
28
38
|
setViewport(rows: number): void;
|
|
@@ -39,6 +49,16 @@ export interface PanelUi {
|
|
|
39
49
|
dispose?(): void;
|
|
40
50
|
}, options?: Record<string, unknown>): Promise<T>;
|
|
41
51
|
}
|
|
42
|
-
|
|
43
|
-
|
|
52
|
+
export interface PanelController {
|
|
53
|
+
/** Resolves when the sidebar has been removed, by the user or by close(). */
|
|
54
|
+
closed: Promise<void>;
|
|
55
|
+
close(): void;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Open the trace as a right-hand sidebar. Pi's public UI API offers floating overlays but no side dock that narrows the
|
|
59
|
+
* transcript, so the sidebar covers the right part of the screen; `nonCapturing` keeps the editor focused.
|
|
60
|
+
*/
|
|
61
|
+
export declare function openTracePanel(ui: PanelUi, trace: Trace, options?: {
|
|
62
|
+
width?: string | number;
|
|
63
|
+
}): PanelController;
|
|
44
64
|
export {};
|
package/dist/panel.js
CHANGED
|
@@ -1,23 +1,26 @@
|
|
|
1
1
|
import { Key, matchesKey, truncateToWidth, wrapTextWithAnsi } from "@earendil-works/pi-tui";
|
|
2
2
|
const LEVEL_COLOR = { allow: "success", ok: "success", warn: "warning", unverified: "warning", nudged: "warning", confirm: "error", stuck: "error", "false claim": "error" };
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Sidebar listing the trace newest-first, live-updating while open. It opens without taking keyboard input: the editor
|
|
5
|
+
* keeps working while it is visible. A click inside it (fullscreen mode) focuses it; then ↑/↓/j/k scroll a line,
|
|
6
|
+
* PgUp/PgDn a page, Home/End jump, c clears the trace, Esc returns input to the editor, and q closes. Wheel scrolling
|
|
7
|
+
* works without focus.
|
|
6
8
|
*/
|
|
7
9
|
export class TracePanel {
|
|
8
10
|
trace;
|
|
9
11
|
theme;
|
|
10
|
-
|
|
12
|
+
actions;
|
|
11
13
|
requestRender;
|
|
12
14
|
title;
|
|
13
|
-
|
|
15
|
+
/** Set by the TUI when keyboard focus changes. */
|
|
16
|
+
focused = false;
|
|
14
17
|
scroll = 0;
|
|
15
18
|
viewport = 20;
|
|
16
19
|
unsubscribe;
|
|
17
|
-
constructor(trace, theme,
|
|
20
|
+
constructor(trace, theme, actions, requestRender, title = "pi-warden trace") {
|
|
18
21
|
this.trace = trace;
|
|
19
22
|
this.theme = theme;
|
|
20
|
-
this.
|
|
23
|
+
this.actions = actions;
|
|
21
24
|
this.requestRender = requestRender;
|
|
22
25
|
this.title = title;
|
|
23
26
|
this.unsubscribe = trace.subscribe(() => this.requestRender());
|
|
@@ -31,10 +34,13 @@ export class TracePanel {
|
|
|
31
34
|
const { theme } = this;
|
|
32
35
|
const entries = this.trace.entries();
|
|
33
36
|
const out = [];
|
|
34
|
-
|
|
37
|
+
const keys = this.focused ? "↑↓ PgUp PgDn scroll · c clear · esc back to editor · q close" : "click for keys · wheel scrolls · /warden trace closes";
|
|
38
|
+
out.push(theme.bold(theme.fg("accent", `${this.title}`)) + theme.fg("muted", ` · ${entries.length} event${entries.length === 1 ? "" : "s"}`));
|
|
39
|
+
out.push(theme.fg("muted", keys));
|
|
35
40
|
out.push(theme.fg("muted", "─".repeat(Math.max(0, width))));
|
|
36
41
|
if (!entries.length) {
|
|
37
|
-
|
|
42
|
+
for (const line of wrapTextWithAnsi(theme.fg("muted", "No guarded activity yet this session. Verdicts, Jev scores, and what the agent was told will appear here."), Math.max(10, width)))
|
|
43
|
+
out.push(line);
|
|
38
44
|
return out.map(line => truncateToWidth(line, width, ""));
|
|
39
45
|
}
|
|
40
46
|
for (let index = entries.length - 1; index >= 0; index--) {
|
|
@@ -56,25 +62,35 @@ export class TracePanel {
|
|
|
56
62
|
}
|
|
57
63
|
return out.map(line => truncateToWidth(line, width, ""));
|
|
58
64
|
}
|
|
65
|
+
/** A left border makes the overlay read as a pane; the content column is two cells narrower. */
|
|
59
66
|
render(width) {
|
|
60
|
-
const
|
|
67
|
+
const border = theme_fg(this.theme, "muted", "│ ");
|
|
68
|
+
const inner = Math.max(10, width - 2);
|
|
69
|
+
const all = this.lines(inner);
|
|
61
70
|
const maxScroll = Math.max(0, all.length - this.viewport);
|
|
62
71
|
if (this.scroll > maxScroll)
|
|
63
72
|
this.scroll = maxScroll;
|
|
64
73
|
const visible = all.slice(this.scroll, this.scroll + this.viewport);
|
|
65
74
|
if (all.length > this.viewport) {
|
|
66
75
|
const last = visible.length - 1;
|
|
67
|
-
visible[last] = truncateToWidth(theme_fg(this.theme, "muted",
|
|
76
|
+
visible[last] = truncateToWidth(theme_fg(this.theme, "muted", `… ${all.length - this.scroll - this.viewport > 0 ? `${all.length - this.scroll - this.viewport} more lines below` : "end"} · ${this.scroll} above`), inner, "");
|
|
68
77
|
}
|
|
69
|
-
|
|
78
|
+
while (visible.length < this.viewport)
|
|
79
|
+
visible.push("");
|
|
80
|
+
return visible.map(line => border + line);
|
|
70
81
|
}
|
|
71
82
|
/** The overlay tells us how tall we may be through the layout; fall back to a fixed viewport otherwise. */
|
|
72
83
|
setViewport(rows) {
|
|
73
84
|
this.viewport = Math.max(5, rows);
|
|
74
85
|
}
|
|
75
86
|
handleInput(data) {
|
|
76
|
-
if (
|
|
77
|
-
this.close();
|
|
87
|
+
if (data === "q" || matchesKey(data, Key.ctrl("c"))) {
|
|
88
|
+
this.actions.close();
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
if (matchesKey(data, Key.escape)) {
|
|
92
|
+
this.actions.unfocus();
|
|
93
|
+
this.requestRender();
|
|
78
94
|
return;
|
|
79
95
|
}
|
|
80
96
|
if (matchesKey(data, Key.up) || data === "k")
|
|
@@ -100,22 +116,32 @@ export class TracePanel {
|
|
|
100
116
|
this.scroll = Math.max(0, this.scroll + (event.wheelDelta ?? 0) * 3);
|
|
101
117
|
return { handled: true, render: true };
|
|
102
118
|
}
|
|
119
|
+
if (event.type === "press" && event.button === "left")
|
|
120
|
+
return { handled: true, focus: true, render: true };
|
|
103
121
|
return undefined;
|
|
104
122
|
}
|
|
105
123
|
}
|
|
106
124
|
function theme_fg(theme, color, text) {
|
|
107
125
|
return theme.fg(color, text);
|
|
108
126
|
}
|
|
109
|
-
/**
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
127
|
+
/**
|
|
128
|
+
* Open the trace as a right-hand sidebar. Pi's public UI API offers floating overlays but no side dock that narrows the
|
|
129
|
+
* transcript, so the sidebar covers the right part of the screen; `nonCapturing` keeps the editor focused.
|
|
130
|
+
*/
|
|
131
|
+
export function openTracePanel(ui, trace, options = {}) {
|
|
132
|
+
let close = () => { };
|
|
133
|
+
let unfocus = () => { };
|
|
134
|
+
const closed = ui.custom((tui, theme, _keybindings, done) => {
|
|
135
|
+
close = () => done();
|
|
136
|
+
const panel = new TracePanel(trace, theme, { close, unfocus: () => unfocus() }, () => tui.requestRender());
|
|
113
137
|
const rows = tui.terminal?.rows;
|
|
114
138
|
if (typeof rows === "number")
|
|
115
|
-
panel.setViewport(
|
|
139
|
+
panel.setViewport(rows - 2);
|
|
116
140
|
return panel;
|
|
117
141
|
}, {
|
|
118
142
|
overlay: true,
|
|
119
|
-
overlayOptions: { anchor: "right-center", width: "
|
|
143
|
+
overlayOptions: { anchor: "right-center", width: options.width ?? "40%", minWidth: 44, maxHeight: "100%", nonCapturing: true },
|
|
144
|
+
onHandle: (handle) => { unfocus = () => handle.unfocus(); },
|
|
120
145
|
});
|
|
146
|
+
return { closed, close: () => close() };
|
|
121
147
|
}
|
package/dist/widget.d.ts
CHANGED
|
@@ -6,8 +6,10 @@ export type WidgetPlacement = "aboveEditor" | "belowEditor";
|
|
|
6
6
|
export interface WidgetConfig {
|
|
7
7
|
enabled: boolean;
|
|
8
8
|
placement: WidgetPlacement;
|
|
9
|
-
/** Keyboard shortcut that
|
|
9
|
+
/** Keyboard shortcut that toggles the trace sidebar; empty string disables it. */
|
|
10
10
|
shortcut: string;
|
|
11
|
+
/** Sidebar width: a percentage string such as "40%" or a column count. */
|
|
12
|
+
panelWidth: string | number;
|
|
11
13
|
/** Templates per guard. Segments are separated by " · "; a segment whose token has no value is dropped. */
|
|
12
14
|
action: string;
|
|
13
15
|
stuck: string;
|
package/dist/widget.js
CHANGED
|
@@ -7,7 +7,7 @@ export const DEFAULT_TEMPLATES = {
|
|
|
7
7
|
context: "warden · context · {tool} · {retention} · saved {bytesSaved} bytes",
|
|
8
8
|
};
|
|
9
9
|
export function defaultWidgetConfig() {
|
|
10
|
-
return { enabled: true, placement: "aboveEditor", shortcut: "ctrl+shift+w", ...DEFAULT_TEMPLATES };
|
|
10
|
+
return { enabled: true, placement: "aboveEditor", shortcut: "ctrl+shift+w", panelWidth: "40%", ...DEFAULT_TEMPLATES };
|
|
11
11
|
}
|
|
12
12
|
const SEPARATOR = " · ";
|
|
13
13
|
const TOKEN = /\{([a-zA-Z]+)\}/g;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-warden",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"description": "Guardrails for Pi built on pi-typesafe that steer the agent instead of interrupting you: Jev judges irreversible and off-task tool calls before they run, detects stuck loops, checks unverified done claims, and flags slop.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|