@xynogen/pix-runtime 0.7.0 → 0.8.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/package.json +1 -1
- package/src/extension.ts +3 -1
- package/src/herdr-state.ts +31 -1
- package/src/index.ts +6 -0
- package/src/pix-command.ts +10 -6
package/package.json
CHANGED
package/src/extension.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import { bindHerdrNotify } from "./herdr-notify.ts";
|
|
3
|
-
import { bindAgentStateEvents, resetAgentState } from "./herdr-state.ts";
|
|
3
|
+
import { bindAgentStateEvents, resetAgentState, resetUnattendedState } from "./herdr-state.ts";
|
|
4
4
|
import { once } from "./once.ts";
|
|
5
5
|
import { registerPixCommand } from "./pix-command.ts";
|
|
6
6
|
import { pixRuntime } from "./runtime.ts";
|
|
@@ -23,6 +23,7 @@ export default function registerRuntime(pi: ExtensionAPI): void {
|
|
|
23
23
|
|
|
24
24
|
let initialized = false;
|
|
25
25
|
pi.on("session_start", async () => {
|
|
26
|
+
resetUnattendedState(pi.events);
|
|
26
27
|
if (initialized) {
|
|
27
28
|
await runtime.reload({ origin: "reload", source: "session_start" });
|
|
28
29
|
} else {
|
|
@@ -34,6 +35,7 @@ export default function registerRuntime(pi: ExtensionAPI): void {
|
|
|
34
35
|
|
|
35
36
|
pi.on("session_shutdown", async () => {
|
|
36
37
|
resetAgentState(pi.events);
|
|
38
|
+
resetUnattendedState(pi.events);
|
|
37
39
|
unbindHerdrNotify();
|
|
38
40
|
unbindAgentState();
|
|
39
41
|
await runtime.flush();
|
package/src/herdr-state.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { EventBus } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
|
|
3
3
|
export type PixAgentState = "working" | "blocked" | "idle";
|
|
4
|
+
export type UnattendedMode = "off" | "afk" | "yolo";
|
|
4
5
|
export type PixAgentStateEvent = {
|
|
5
6
|
state: PixAgentState;
|
|
6
7
|
message?: string;
|
|
@@ -12,6 +13,8 @@ type Entry = { source: string; message?: string };
|
|
|
12
13
|
type Coordinator = {
|
|
13
14
|
activities: Map<symbol, Entry>;
|
|
14
15
|
blocks: Map<symbol, Entry>;
|
|
16
|
+
unattendedMode: UnattendedMode;
|
|
17
|
+
yoloConsent: boolean;
|
|
15
18
|
};
|
|
16
19
|
|
|
17
20
|
function coordinators(): WeakMap<EventBus, Coordinator> {
|
|
@@ -24,7 +27,12 @@ function coordinator(events: EventBus): Coordinator {
|
|
|
24
27
|
const registry = coordinators();
|
|
25
28
|
let state = registry.get(events);
|
|
26
29
|
if (!state) {
|
|
27
|
-
state = {
|
|
30
|
+
state = {
|
|
31
|
+
activities: new Map(),
|
|
32
|
+
blocks: new Map(),
|
|
33
|
+
unattendedMode: "off",
|
|
34
|
+
yoloConsent: false,
|
|
35
|
+
};
|
|
28
36
|
registry.set(events, state);
|
|
29
37
|
}
|
|
30
38
|
return state;
|
|
@@ -100,6 +108,28 @@ export async function withAgentBlock<T>(
|
|
|
100
108
|
}
|
|
101
109
|
}
|
|
102
110
|
|
|
111
|
+
export function getUnattendedMode(events: EventBus): UnattendedMode {
|
|
112
|
+
return coordinator(events).unattendedMode;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export function setUnattendedMode(events: EventBus, mode: UnattendedMode): void {
|
|
116
|
+
coordinator(events).unattendedMode = mode;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export function hasYoloConsent(events: EventBus): boolean {
|
|
120
|
+
return coordinator(events).yoloConsent;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export function setYoloConsent(events: EventBus, consent: boolean): void {
|
|
124
|
+
coordinator(events).yoloConsent = consent;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export function resetUnattendedState(events: EventBus): void {
|
|
128
|
+
const state = coordinator(events);
|
|
129
|
+
state.unattendedMode = "off";
|
|
130
|
+
state.yoloConsent = false;
|
|
131
|
+
}
|
|
132
|
+
|
|
103
133
|
/** Bind state replay/reset to one Pi session lifecycle. */
|
|
104
134
|
export function bindAgentStateEvents(events: EventBus): () => void {
|
|
105
135
|
const off = events.on("pix:agent-state:request", () => publish(events));
|
package/src/index.ts
CHANGED
|
@@ -11,9 +11,15 @@ export { bindHerdrNotify } from "./herdr-notify.ts";
|
|
|
11
11
|
export {
|
|
12
12
|
beginAgentActivity,
|
|
13
13
|
bindAgentStateEvents,
|
|
14
|
+
getUnattendedMode,
|
|
15
|
+
hasYoloConsent,
|
|
14
16
|
type PixAgentState,
|
|
15
17
|
type PixAgentStateEvent,
|
|
16
18
|
resetAgentState,
|
|
19
|
+
resetUnattendedState,
|
|
20
|
+
setUnattendedMode,
|
|
21
|
+
setYoloConsent,
|
|
22
|
+
type UnattendedMode,
|
|
17
23
|
withAgentBlock,
|
|
18
24
|
} from "./herdr-state.ts";
|
|
19
25
|
export { ioTimeoutMs, ioTimeoutSignal } from "./io.ts";
|
package/src/pix-command.ts
CHANGED
|
@@ -205,6 +205,7 @@ export function registerPixCommand(pi: ExtensionAPI, runtime: PixRuntime): void
|
|
|
205
205
|
handler: async (_args: string, ctx: ExtensionCommandContext) => {
|
|
206
206
|
// Re-parse pix.json so section parsers remain the single validation source.
|
|
207
207
|
await runtime.reload({ origin: "command", source: "pix" });
|
|
208
|
+
// SAFETY: Runtime UI supports custom overlays beyond the published command context type.
|
|
208
209
|
const ui = ctx.ui as unknown as {
|
|
209
210
|
custom?: (f: unknown, opts?: unknown) => Promise<unknown>;
|
|
210
211
|
notify(m: string, t?: "info" | "warning" | "error"): void;
|
|
@@ -227,8 +228,8 @@ export function registerPixCommand(pi: ExtensionAPI, runtime: PixRuntime): void
|
|
|
227
228
|
done: (v: null) => void,
|
|
228
229
|
) => {
|
|
229
230
|
const guide = (key: string, action: string) =>
|
|
230
|
-
theme.fg("text", key) + theme.fg("
|
|
231
|
-
const guideSep = theme.fg("
|
|
231
|
+
theme.fg("text", key) + theme.fg("muted", ` ${action}`);
|
|
232
|
+
const guideSep = theme.fg("muted", " · ");
|
|
232
233
|
let selected = 0;
|
|
233
234
|
let bodyOffset = 0;
|
|
234
235
|
let visibleBodyLines = 1;
|
|
@@ -241,8 +242,11 @@ export function registerPixCommand(pi: ExtensionAPI, runtime: PixRuntime): void
|
|
|
241
242
|
// Functional updater: the runtime queue serializes writes, and the
|
|
242
243
|
// callback sees the latest committed value — so rapid presses each
|
|
243
244
|
// advance exactly one step instead of collapsing on a stale snapshot.
|
|
244
|
-
|
|
245
|
-
|
|
245
|
+
type SettingsState = Record<string, unknown>;
|
|
246
|
+
const step = (current: unknown): SettingsState => {
|
|
247
|
+
const state: SettingsState =
|
|
248
|
+
current !== null && typeof current === "object" ? { ...(current as object) } : {};
|
|
249
|
+
const curVal = row.read(state);
|
|
246
250
|
let cur = row.values.indexOf(curVal);
|
|
247
251
|
// ponytail: unsupported custom values snap to section default on first change.
|
|
248
252
|
if (cur === -1) {
|
|
@@ -252,8 +256,8 @@ export function registerPixCommand(pi: ExtensionAPI, runtime: PixRuntime): void
|
|
|
252
256
|
}
|
|
253
257
|
const next = (cur + direction + row.values.length) % row.values.length;
|
|
254
258
|
const val = row.values[next];
|
|
255
|
-
if (val === undefined) return
|
|
256
|
-
return { ...
|
|
259
|
+
if (val === undefined) return state;
|
|
260
|
+
return { ...state, ...(row.patch(val) as object) };
|
|
257
261
|
};
|
|
258
262
|
// Re-render AFTER the commit lands; the synchronous render in
|
|
259
263
|
// handleInput fires before the queued write and shows a stale value.
|