pi-shit 0.1.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.
Files changed (42) hide show
  1. package/README.md +44 -0
  2. package/extensions/README.md +23 -0
  3. package/extensions/deep-review/README.md +56 -0
  4. package/extensions/deep-review/index.test.ts +97 -0
  5. package/extensions/deep-review/index.ts +1541 -0
  6. package/extensions/pi-notify/LICENSE +21 -0
  7. package/extensions/pi-notify/README.md +84 -0
  8. package/extensions/pi-notify/index.ts +75 -0
  9. package/extensions/pi-notify/package.json +28 -0
  10. package/extensions/plan-mode/README.md +69 -0
  11. package/extensions/plan-mode/index.ts +345 -0
  12. package/extensions/plan-mode/utils.test.ts +261 -0
  13. package/extensions/plan-mode/utils.ts +168 -0
  14. package/package.json +35 -0
  15. package/skills/README.md +70 -0
  16. package/skills/brave-search/SKILL.md +83 -0
  17. package/skills/brave-search/content.js +86 -0
  18. package/skills/brave-search/package-lock.json +623 -0
  19. package/skills/brave-search/package.json +14 -0
  20. package/skills/brave-search/search.js +199 -0
  21. package/skills/code-review/SKILL.md +97 -0
  22. package/skills/code-simplifier/SKILL.md +55 -0
  23. package/skills/context-packer/SKILL.md +77 -0
  24. package/skills/context-packer/prepare-context.sh +490 -0
  25. package/skills/image-compress/SKILL.md +53 -0
  26. package/skills/image-compress/compress.sh +172 -0
  27. package/skills/markdown-converter/SKILL.md +71 -0
  28. package/skills/multi-review/SKILL.md +143 -0
  29. package/skills/package.json +26 -0
  30. package/skills/pr-context-packer/SKILL.md +76 -0
  31. package/skills/pr-context-packer/prepare-pr-context.sh +941 -0
  32. package/skills/session-analyzer/IDEAS.md +42 -0
  33. package/skills/session-analyzer/SKILL.md +81 -0
  34. package/skills/session-analyzer/analyze.js +460 -0
  35. package/skills/session-analyzer/package-lock.json +3943 -0
  36. package/skills/session-analyzer/package.json +7 -0
  37. package/skills/video-compress/SKILL.md +43 -0
  38. package/skills/video-compress/compress.sh +107 -0
  39. package/skills/youtube-transcript/SKILL.md +59 -0
  40. package/skills/youtube-transcript/transcript.sh +46 -0
  41. package/themes/rose-pine-dawn.json +102 -0
  42. package/themes/rose-pine.json +102 -0
package/README.md ADDED
@@ -0,0 +1,44 @@
1
+ # pi-shit
2
+
3
+ Combined Pi package for personal extensions + skills.
4
+
5
+ ## Structure
6
+
7
+ - `extensions/` → Pi extensions (for example `deep-review`, `plan-mode`)
8
+ - `skills/` → Pi skills (including `pr-context-packer`)
9
+ - `themes/` → Pi themes (`rose-pine`, `rose-pine-dawn`)
10
+
11
+ ## Install in Pi
12
+
13
+ ```bash
14
+ pi install npm:pi-shit
15
+ ```
16
+
17
+ Or from git/local:
18
+
19
+ ```bash
20
+ pi install git:github.com/ferologics/pi-shit
21
+ pi install /path/to/pi-shit
22
+ ```
23
+
24
+ ## Sync
25
+
26
+ This repo is assembled from:
27
+
28
+ - `skills/` ← `pi-skills` (git subtree)
29
+ - `extensions/` ← `pi-extensions` (git subtree)
30
+ - `themes/` ← `zenobi-us/pi-rose-pine` (via `just update-themes`)
31
+
32
+ Update all sources with:
33
+
34
+ ```bash
35
+ just update
36
+ ```
37
+
38
+ Or update individually:
39
+
40
+ ```bash
41
+ just update-skills
42
+ just update-extensions
43
+ just update-themes
44
+ ```
@@ -0,0 +1,23 @@
1
+ # pi-extensions
2
+
3
+ Custom extensions for [pi-coding-agent](https://github.com/badlogic/pi-mono).
4
+
5
+ ## Extensions
6
+
7
+ | Extension | Description |
8
+ | ----------------------------- | ----------------------------------------------------------------------------- |
9
+ | [`deep-review`](deep-review/) | Run context-pack + direct OpenAI Responses deep review with live streaming UI |
10
+ | [`pi-notify`](pi-notify/) | Desktop notifications when the agent finishes |
11
+ | [`plan-mode`](plan-mode/) | Read-only plan mode with progress tracking and questionnaire support |
12
+
13
+ Each extension folder contains full usage details and examples.
14
+
15
+ ## Setup
16
+
17
+ Symlink extensions to `~/.pi/agent/extensions/`:
18
+
19
+ ```bash
20
+ ln -s ~/dev/pi-extensions/deep-review ~/.pi/agent/extensions/
21
+ ln -s ~/dev/pi-extensions/pi-notify ~/.pi/agent/extensions/
22
+ ln -s ~/dev/pi-extensions/plan-mode ~/.pi/agent/extensions/
23
+ ```
@@ -0,0 +1,56 @@
1
+ # Deep Review Extension
2
+
3
+ Run a 2-phase deep PR review flow inside your current Pi session:
4
+
5
+ 1. Context packing via nested `pi -p` + `/skill:pr-context-packer`
6
+ 2. Direct OpenAI Responses API streaming (thinking + final answer)
7
+
8
+ ## Commands
9
+
10
+ - `/deep-review <query> [options]`
11
+ - `/deep-review-stop`
12
+
13
+ ## Defaults
14
+
15
+ - Model: `gpt-5.2`
16
+ - Reasoning effort: `xhigh`
17
+ - Summary: `auto` (shows readable reasoning summary deltas)
18
+ - Verbosity: `medium`
19
+ - Base ref: auto-detected by `pr-context-packer`
20
+
21
+ ## Options
22
+
23
+ - `--query <text>` (alternative to positional query; cannot be combined with positional query text)
24
+ - `--project <path>`
25
+ - `--base <ref>`
26
+ - `--model <id>`
27
+ - `--effort minimal|low|medium|high|xhigh`
28
+ - `--verbosity low|medium|high`
29
+ - `--summary auto|detailed|null`
30
+ - `--no-summary` (shortcut for `--summary null`)
31
+ - `--org <id>`
32
+ - `--project-id <id>`
33
+ - `--debug`
34
+ - `--help`
35
+
36
+ ## Example
37
+
38
+ ```text
39
+ /deep-review "find bugs and regressions"
40
+ ```
41
+
42
+ ## Notes
43
+
44
+ - The context-pack subprocess is launched with explicit skill scope:
45
+ - `--no-skills --skill <bundled skills/pr-context-packer/SKILL.md>`
46
+ - `deep-review` fails fast if that bundled skill file is missing.
47
+ - Intended package layout is `pi-shit` (`extensions/` + `skills/` in one package).
48
+ - Scribe expansion stays enabled in context-packer (no disable flag in this extension).
49
+ - Use `--no-summary` if you want parity mode without readable reasoning summary text.
50
+ - The command updates Pi UI live with a compact status widget (phase + stream progress).
51
+ - Streamed thinking/answer text is not previewed live in the widget; full markdown answer is posted at completion.
52
+ - Context-pack stage output is posted into the current session.
53
+ - Final response includes duration, token usage, and estimated cost.
54
+ - Final answer/thinking/report are written to a temp output folder and linked in the result.
55
+ - The extension attempts to copy the final answer to clipboard automatically.
56
+ - For auth, `OPENAI_API_KEY` is recommended.
@@ -0,0 +1,97 @@
1
+ import { beforeAll, describe, expect, it, vi } from "vitest";
2
+ import * as os from "node:os";
3
+ import * as path from "node:path";
4
+ import { mkdtemp, writeFile } from "node:fs/promises";
5
+
6
+ vi.mock("@mariozechner/pi-ai", () => ({
7
+ calculateCost: vi.fn(),
8
+ getModel: vi.fn(),
9
+ }));
10
+
11
+ vi.mock("@mariozechner/pi-coding-agent", () => ({
12
+ getMarkdownTheme: vi.fn(() => ({})),
13
+ }));
14
+
15
+ vi.mock("@mariozechner/pi-tui", () => ({
16
+ Markdown: class {},
17
+ }));
18
+
19
+ let splitArgs: (input: string, platform?: NodeJS.Platform) => string[];
20
+ let parseOptions: (rawArgs: string, cwd: string) => { ok: boolean; message?: string };
21
+ let extractContextPackPath: (output: string) => Promise<string | undefined>;
22
+ let normalizeSectionLikeBoldMarkdown: (markdown: string) => string;
23
+ let parseSseStream: (
24
+ body: ReadableStream<Uint8Array>,
25
+ ) => AsyncGenerator<{ type?: string; [key: string]: unknown }, void, void>;
26
+
27
+ beforeAll(async () => {
28
+ const mod = await import("./index.js");
29
+ splitArgs = mod.splitArgs;
30
+ parseOptions = mod.parseOptions;
31
+ extractContextPackPath = mod.extractContextPackPath;
32
+ normalizeSectionLikeBoldMarkdown = mod.normalizeSectionLikeBoldMarkdown;
33
+ parseSseStream = mod.parseSseStream;
34
+ });
35
+
36
+ describe("splitArgs", () => {
37
+ it("keeps Windows backslashes on win32", () => {
38
+ const tokens = splitArgs('--project C:\\repo --query "review"', "win32");
39
+ expect(tokens).toEqual(["--project", "C:\\repo", "--query", "review"]);
40
+ });
41
+
42
+ it("supports escaped spaces on posix", () => {
43
+ const tokens = splitArgs("--project /tmp/my\\ repo --query test", "darwin");
44
+ expect(tokens).toEqual(["--project", "/tmp/my repo", "--query", "test"]);
45
+ });
46
+ });
47
+
48
+ describe("parseOptions", () => {
49
+ it("rejects positional + --query together", () => {
50
+ const parsed = parseOptions('positional --query "flag"', "/tmp");
51
+ expect(parsed.ok).toBe(false);
52
+ expect(parsed.message).toContain("both positionally and via --query");
53
+ });
54
+ });
55
+
56
+ describe("extractContextPackPath", () => {
57
+ it("returns an existing candidate path", async () => {
58
+ const dir = await mkdtemp(path.join(os.tmpdir(), "deep-review-test-"));
59
+ const realPath = path.join(dir, "pr-context.txt");
60
+ await writeFile(realPath, "test", "utf8");
61
+
62
+ const output = `Output: /nope/pr-context.txt\nOutput: ${realPath}`;
63
+ const extracted = await extractContextPackPath(output);
64
+
65
+ expect(extracted).toBe(realPath);
66
+ });
67
+ });
68
+
69
+ describe("normalizeSectionLikeBoldMarkdown", () => {
70
+ it("converts standalone bold lines to headings", () => {
71
+ const input = "**Overview**\nBody text";
72
+ const output = normalizeSectionLikeBoldMarkdown(input);
73
+ expect(output).toContain("### Overview");
74
+ expect(output).toContain("Body text");
75
+ });
76
+ });
77
+
78
+ describe("parseSseStream", () => {
79
+ it("parses JSON SSE events and ignores DONE", async () => {
80
+ const encoder = new TextEncoder();
81
+ const stream = new ReadableStream<Uint8Array>({
82
+ start(controller) {
83
+ controller.enqueue(encoder.encode('data: {"type":"response.created"}\n\n'));
84
+ controller.enqueue(encoder.encode("data: [DONE]\n\n"));
85
+ controller.close();
86
+ },
87
+ });
88
+
89
+ const events: Array<{ type?: string }> = [];
90
+ for await (const event of parseSseStream(stream)) {
91
+ events.push(event);
92
+ }
93
+
94
+ expect(events).toHaveLength(1);
95
+ expect(events[0].type).toBe("response.created");
96
+ });
97
+ });