@xynogen/pix-toolbox 0.2.0 → 0.2.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 CHANGED
@@ -15,7 +15,7 @@ Registers a `/toolbox` slash command — a TUI fuzzy-search picker listing every
15
15
  Keys: `tab` switch tab · `↑↓` navigate · `ctrl+e` enable · `ctrl+f` defer · `ctrl+d` disable · `space` cycle · any other key types into the search.
16
16
 
17
17
  - Four tools (`bash`, `edit`, `read`, `write`) are protected and stay enabled.
18
- - State persists to `~/.pi/agent/toolbox.json`. Only changes from the default are saved: `disabledTools` (tools you disabled) and `loadedTools` (deferred tools you enabled). A newly installed tool keeps its default. A legacy `enabledTools` file is migrated on the next session start.
18
+ - State persists to `~/.pi/agent/pix.json` under `toolbox`. Only changes from the default are saved: `disabledTools` (tools you disabled) and `loadedTools` (deferred tools you enabled). A newly installed tool keeps its default. A legacy `enabledTools` file is migrated on the next session start.
19
19
  - Headless subcommands: `/toolbox enable|defer|disable <names>`, `/toolbox list [query]`.
20
20
 
21
21
  ## Install
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@xynogen/pix-toolbox",
3
- "version": "0.2.0",
4
- "description": "Pi tool — gated tool toggle UI (/toolbox)",
3
+ "version": "0.2.1",
4
+ "description": "Pi tool \u2014 gated tool toggle UI (/toolbox)",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
7
7
  "scripts": {
@@ -35,7 +35,8 @@
35
35
  "access": "public"
36
36
  },
37
37
  "dependencies": {
38
- "@xynogen/pix-pretty": "^1.29.0"
38
+ "@xynogen/pix-pretty": "^1.30.0",
39
+ "@xynogen/pix-runtime": "^0.13.0"
39
40
  },
40
41
  "peerDependencies": {
41
42
  "@earendil-works/pi-coding-agent": "*",
package/src/toolbox.ts CHANGED
@@ -13,15 +13,12 @@
13
13
  */
14
14
 
15
15
  import { createHash } from "node:crypto";
16
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
17
- import { dirname, join } from "node:path";
18
16
  import type {
19
17
  ExtensionAPI,
20
18
  ExtensionContext,
21
19
  Theme,
22
20
  ToolInfo,
23
21
  } from "@earendil-works/pi-coding-agent";
24
- import { getAgentDir } from "@earendil-works/pi-coding-agent";
25
22
  import {
26
23
  fuzzyFilter,
27
24
  Input,
@@ -41,6 +38,8 @@ import {
41
38
  modalWidth,
42
39
  terminalModalHeight,
43
40
  } from "@xynogen/pix-pretty/modal-frame";
41
+ import { config, pixRuntime, updateConfig } from "@xynogen/pix-runtime/config";
42
+ import { toolboxSection } from "@xynogen/pix-runtime/sections";
44
43
 
45
44
  // ─── Constants ──────────────────────────────────────────────────────────────
46
45
 
@@ -196,10 +195,6 @@ interface ToolboxState {
196
195
  enabledTools?: string[];
197
196
  }
198
197
 
199
- function getStatePath(): string {
200
- return join(getAgentDir(), "toolbox.json");
201
- }
202
-
203
198
  const isStringArray = (v: unknown): v is string[] =>
204
199
  Array.isArray(v) && v.every((x) => typeof x === "string");
205
200
 
@@ -286,26 +281,32 @@ function createState(pi: ExtensionAPI) {
286
281
  console.warn("toolbox: persist failed:", err);
287
282
  }
288
283
  // Write to disk so state survives across completely new sessions
289
- try {
290
- const sp = getStatePath();
291
- mkdirSync(dirname(sp), { recursive: true });
292
- writeFileSync(sp, `${JSON.stringify(data, null, 2)}\n`, "utf-8");
293
- } catch (err) {
294
- console.warn("toolbox: file persist failed:", err);
295
- }
284
+ void updateConfig(toolboxSection, { ...data, loadedTools: data.loadedTools ?? [] })
285
+ .then((change) => {
286
+ if (
287
+ !change &&
288
+ JSON.stringify(config(toolboxSection).disabledTools) !==
289
+ JSON.stringify(data.disabledTools)
290
+ )
291
+ pi.sendMessage({
292
+ customType: "toolbox-error",
293
+ content: "Failed to save toolbox settings to pix.json",
294
+ display: true,
295
+ });
296
+ })
297
+ .catch((err) =>
298
+ pi.sendMessage({
299
+ customType: "toolbox-error",
300
+ content: `Failed to save toolbox settings: ${String(err)}`,
301
+ display: true,
302
+ }),
303
+ );
296
304
  }
297
305
 
298
306
  /** Raw persisted state from disk, or undefined when absent/corrupt. */
299
307
  function loadFromFile(): { raw: unknown; legacy: boolean } | undefined {
300
- try {
301
- const sp = getStatePath();
302
- if (!existsSync(sp)) return undefined;
303
- const raw = JSON.parse(readFileSync(sp, "utf-8")) as ToolboxState;
304
- return { raw, legacy: !isStringArray(raw?.disabledTools) };
305
- } catch {
306
- // corrupt, or a test env without getAgentDir
307
- return undefined;
308
- }
308
+ const raw = config(toolboxSection);
309
+ return Object.keys(raw).length ? { raw, legacy: !isStringArray(raw.disabledTools) } : undefined;
309
310
  }
310
311
 
311
312
  /** Latest toolbox-config entry in the session, or undefined. */
@@ -397,6 +398,7 @@ export default function registerToolbox(pi: ExtensionAPI): void {
397
398
  // Defer init until tools are registered — session_start fires after all extensions load.
398
399
  // Try to restore persisted state; fall back to full init if no config found.
399
400
  pi.on("session_start", async (_event, ctx) => {
401
+ await pixRuntime().init();
400
402
  state.restoreFromBranch(ctx);
401
403
  });
402
404