@xynogen/pix-commands 0.1.2 → 0.1.4

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
@@ -1,10 +1,12 @@
1
1
  # pix-commands
2
2
 
3
- Pi extension — `/diff` and `/clear` slash commands.
3
+ Pi extension — `/clear` slash command.
4
4
 
5
5
  ## What it does
6
6
 
7
- Registers two slash commands. `/diff` asks the agent to inspect `git status` and `git diff`, then respond with a one-sentence TL;DR, a per-file breakdown of what changed and why (with +/− line counts), and a brief impact note on behaviour or tests. If an agent turn is already in progress, the prompt is queued as a follow-up. `/clear` deletes `~/.cache/pi` — useful for flushing stale model-data or BenchLM cache — and prompts you to run `/reload` to apply the change. No extra dependencies beyond Pi.
7
+ Registers the `/clear` slash command. `/clear` deletes `~/.cache/pi` — useful for flushing stale model-data or BenchLM cache — and prompts you to run `/reload` to apply the change. No extra dependencies beyond Pi.
8
+
9
+ > Diff review moved to the `diff` skill in [`@xynogen/pix-skills`](https://github.com/xynogen/pix-mono/tree/main/packages/pix-skills), which pre-populates `git status` + staged/unstaged diffs via the `` !`cmd` `` directive.
8
10
 
9
11
  ## Install
10
12
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@xynogen/pix-commands",
3
- "version": "0.1.2",
4
- "description": "Pi extension — /diff and /clear commands",
3
+ "version": "0.1.4",
4
+ "description": "Pi extension — /clear command",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
7
7
  "scripts": {
package/src/extension.ts CHANGED
@@ -1,11 +1,9 @@
1
1
  import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
2
2
  import registerClear from "./clear.ts";
3
- import registerDiff from "./diff.ts";
4
3
  import { once } from "./once.ts";
5
4
 
6
5
  export default function (pi: ExtensionAPI): void {
7
- once("pix-commands", () => {
8
- registerDiff(pi);
6
+ once(pi, "pix-commands", () => {
9
7
  registerClear(pi);
10
8
  });
11
9
  }
package/src/index.ts CHANGED
@@ -1,2 +1 @@
1
1
  export { default as registerClear } from "./clear.ts";
2
- export { default as registerDiff } from "./diff.ts";
package/src/once.ts CHANGED
@@ -1,15 +1,25 @@
1
1
  /**
2
- * Idempotency guard for extension activation.
2
+ * Per-instance idempotency guard for extension activation.
3
3
  *
4
- * pix-core (the meta-package) invokes this package's factory in addition to a
5
- * possible direct install. Pi's loader uses jiti with `moduleCache: false`, so
6
- * each load pass re-evaluates modules a plain module-level flag would not be
7
- * shared. The dedupe key therefore lives on `globalThis`, which persists for
8
- * the lifetime of the process across all load passes.
4
+ * pix-core (the meta-package) invokes this package's factory, and a standalone
5
+ * install makes Pi invoke it again sometimes against the SAME `pi`. We must
6
+ * dedupe that. But Pi rebuilds the extension runtime on /new, /resume, /fork,
7
+ * and /reload, handing the factory a BRAND-NEW `pi`; that must re-register.
8
+ *
9
+ * Keying the registry on the `pi` instance satisfies both: same instance =>
10
+ * skip, new instance => run. The registry lives on globalThis because jiti
11
+ * (`moduleCache: false`) re-evaluates this module on every load pass, so a
12
+ * module-scoped WeakMap would not be shared between the aggregator pass and the
13
+ * standalone pass within a single session.
9
14
  */
10
- export function once(key: string, fn: () => void): void {
11
- const g = globalThis as { __pixLoaded?: Set<string> };
12
- const loaded = (g.__pixLoaded ??= new Set<string>());
15
+ export function once(pi: object, key: string, fn: () => void): void {
16
+ const g = globalThis as { __pixOnce?: WeakMap<object, Set<string>> };
17
+ const registry = (g.__pixOnce ??= new WeakMap<object, Set<string>>());
18
+ let loaded = registry.get(pi);
19
+ if (!loaded) {
20
+ loaded = new Set<string>();
21
+ registry.set(pi, loaded);
22
+ }
13
23
  if (loaded.has(key)) return;
14
24
  loaded.add(key);
15
25
  fn();
package/src/diff.ts DELETED
@@ -1,38 +0,0 @@
1
- /**
2
- * /diff — summarise unstaged git diff: what changed, why, and impact.
3
- *
4
- * The agent runs `git status` + `git diff`, then replies with:
5
- * 1. One-line TL;DR of the overall change
6
- * 2. Per-file summary: what changed and why (not just counts)
7
- * 3. Brief impact note (behaviour change, bug fix, refactor, etc.)
8
- */
9
-
10
- import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
11
-
12
- const DIFF_PROMPT = `Run \`git status\` and \`git diff\` to inspect all unstaged changes, then respond with:
13
-
14
- **TL;DR** — one sentence: what is the overall change.
15
-
16
- **Per-file breakdown** — for each changed file:
17
- - Filename (+lines/-lines)
18
- - What changed (describe the actual code change)
19
- - Why it changed (intent / reason behind the edit)
20
-
21
- **Impact** — one sentence: what effect does this have on behaviour, tests, or users.
22
-
23
- Rules: base everything on the actual diff content. Use \`git diff --stat\` for line counts. Skip staged-only changes. Be concise — each file entry should fit in 1-2 lines.`;
24
-
25
- export default function (pi: ExtensionAPI) {
26
- pi.registerCommand("diff", {
27
- description:
28
- "Summarise unstaged diff: TL;DR, per-file what/why/counts, impact",
29
- handler: async (_args, ctx) => {
30
- if (!ctx.isIdle()) {
31
- pi.sendUserMessage(DIFF_PROMPT, { deliverAs: "followUp" });
32
- ctx.ui.notify("Queued /diff after the current turn finishes.", "info");
33
- return;
34
- }
35
- pi.sendUserMessage(DIFF_PROMPT);
36
- },
37
- });
38
- }