gsd-pi 2.29.0-dev.2ccf3fb → 2.29.0-dev.6a38b5d

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 (50) hide show
  1. package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
  2. package/package.json +1 -1
  3. package/packages/native/dist/native.d.ts +0 -2
  4. package/packages/native/dist/native.js +5 -19
  5. package/packages/native/src/native.ts +9 -23
  6. package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
  7. package/dist/resources/skills/create-gsd-extension/SKILL.md +0 -87
  8. package/dist/resources/skills/create-gsd-extension/references/compaction-session-control.md +0 -77
  9. package/dist/resources/skills/create-gsd-extension/references/custom-commands.md +0 -139
  10. package/dist/resources/skills/create-gsd-extension/references/custom-rendering.md +0 -108
  11. package/dist/resources/skills/create-gsd-extension/references/custom-tools.md +0 -183
  12. package/dist/resources/skills/create-gsd-extension/references/custom-ui.md +0 -490
  13. package/dist/resources/skills/create-gsd-extension/references/events-reference.md +0 -126
  14. package/dist/resources/skills/create-gsd-extension/references/extension-lifecycle.md +0 -64
  15. package/dist/resources/skills/create-gsd-extension/references/extensionapi-reference.md +0 -75
  16. package/dist/resources/skills/create-gsd-extension/references/extensioncontext-reference.md +0 -53
  17. package/dist/resources/skills/create-gsd-extension/references/key-rules-gotchas.md +0 -36
  18. package/dist/resources/skills/create-gsd-extension/references/mode-behavior.md +0 -32
  19. package/dist/resources/skills/create-gsd-extension/references/model-provider-management.md +0 -89
  20. package/dist/resources/skills/create-gsd-extension/references/packaging-distribution.md +0 -55
  21. package/dist/resources/skills/create-gsd-extension/references/remote-execution-overrides.md +0 -90
  22. package/dist/resources/skills/create-gsd-extension/references/state-management.md +0 -70
  23. package/dist/resources/skills/create-gsd-extension/references/system-prompt-modification.md +0 -52
  24. package/dist/resources/skills/create-gsd-extension/templates/extension-skeleton.ts +0 -51
  25. package/dist/resources/skills/create-gsd-extension/templates/stateful-tool-skeleton.ts +0 -143
  26. package/dist/resources/skills/create-gsd-extension/workflows/add-capability.md +0 -57
  27. package/dist/resources/skills/create-gsd-extension/workflows/create-extension.md +0 -156
  28. package/dist/resources/skills/create-gsd-extension/workflows/debug-extension.md +0 -74
  29. package/src/resources/skills/create-gsd-extension/SKILL.md +0 -87
  30. package/src/resources/skills/create-gsd-extension/references/compaction-session-control.md +0 -77
  31. package/src/resources/skills/create-gsd-extension/references/custom-commands.md +0 -139
  32. package/src/resources/skills/create-gsd-extension/references/custom-rendering.md +0 -108
  33. package/src/resources/skills/create-gsd-extension/references/custom-tools.md +0 -183
  34. package/src/resources/skills/create-gsd-extension/references/custom-ui.md +0 -490
  35. package/src/resources/skills/create-gsd-extension/references/events-reference.md +0 -126
  36. package/src/resources/skills/create-gsd-extension/references/extension-lifecycle.md +0 -64
  37. package/src/resources/skills/create-gsd-extension/references/extensionapi-reference.md +0 -75
  38. package/src/resources/skills/create-gsd-extension/references/extensioncontext-reference.md +0 -53
  39. package/src/resources/skills/create-gsd-extension/references/key-rules-gotchas.md +0 -36
  40. package/src/resources/skills/create-gsd-extension/references/mode-behavior.md +0 -32
  41. package/src/resources/skills/create-gsd-extension/references/model-provider-management.md +0 -89
  42. package/src/resources/skills/create-gsd-extension/references/packaging-distribution.md +0 -55
  43. package/src/resources/skills/create-gsd-extension/references/remote-execution-overrides.md +0 -90
  44. package/src/resources/skills/create-gsd-extension/references/state-management.md +0 -70
  45. package/src/resources/skills/create-gsd-extension/references/system-prompt-modification.md +0 -52
  46. package/src/resources/skills/create-gsd-extension/templates/extension-skeleton.ts +0 -51
  47. package/src/resources/skills/create-gsd-extension/templates/stateful-tool-skeleton.ts +0 -143
  48. package/src/resources/skills/create-gsd-extension/workflows/add-capability.md +0 -57
  49. package/src/resources/skills/create-gsd-extension/workflows/create-extension.md +0 -156
  50. package/src/resources/skills/create-gsd-extension/workflows/debug-extension.md +0 -74
@@ -1,143 +0,0 @@
1
- /**
2
- * {{EXTENSION_NAME}} — Stateful tool with persistence
3
- *
4
- * State is stored in tool result details for proper branching support.
5
- */
6
-
7
- import type { ExtensionAPI, ExtensionContext } from "@mariozechner/pi-coding-agent";
8
- import { Type } from "@sinclair/typebox";
9
- import { StringEnum } from "@mariozechner/pi-ai";
10
- import { Text, truncateToWidth, matchesKey, Key } from "@mariozechner/pi-tui";
11
-
12
- interface {{ItemType}} {
13
- id: number;
14
- // Add fields
15
- }
16
-
17
- interface {{ToolDetails}} {
18
- action: string;
19
- items: {{ItemType}}[];
20
- nextId: number;
21
- error?: string;
22
- }
23
-
24
- export default function (pi: ExtensionAPI) {
25
- let items: {{ItemType}}[] = [];
26
- let nextId = 1;
27
-
28
- // Reconstruct state from session
29
- const reconstructState = (ctx: ExtensionContext) => {
30
- items = [];
31
- nextId = 1;
32
- for (const entry of ctx.sessionManager.getBranch()) {
33
- if (entry.type === "message" && entry.message.role === "toolResult") {
34
- if (entry.message.toolName === "{{tool_name}}") {
35
- const details = entry.message.details as {{ToolDetails}} | undefined;
36
- if (details) {
37
- items = details.items;
38
- nextId = details.nextId;
39
- }
40
- }
41
- }
42
- }
43
- };
44
-
45
- // Reconstruct on ALL session change events
46
- pi.on("session_start", async (_event, ctx) => reconstructState(ctx));
47
- pi.on("session_switch", async (_event, ctx) => reconstructState(ctx));
48
- pi.on("session_fork", async (_event, ctx) => reconstructState(ctx));
49
- pi.on("session_tree", async (_event, ctx) => reconstructState(ctx));
50
-
51
- // Register the tool
52
- pi.registerTool({
53
- name: "{{tool_name}}",
54
- label: "{{Tool Label}}",
55
- description: "{{Description for LLM}}",
56
- parameters: Type.Object({
57
- action: StringEnum(["list", "add", "remove"] as const),
58
- text: Type.Optional(Type.String({ description: "Item text" })),
59
- id: Type.Optional(Type.Number({ description: "Item ID" })),
60
- }),
61
-
62
- async execute(toolCallId, params, signal, onUpdate, ctx) {
63
- if (signal?.aborted) {
64
- return { content: [{ type: "text", text: "Cancelled" }] };
65
- }
66
-
67
- switch (params.action) {
68
- case "list":
69
- return {
70
- content: [{ type: "text", text: items.length ? JSON.stringify(items) : "No items" }],
71
- details: { action: "list", items: [...items], nextId } as {{ToolDetails}},
72
- };
73
-
74
- case "add": {
75
- if (!params.text) throw new Error("text required for add");
76
- const item: {{ItemType}} = { id: nextId++ /* , ... */ };
77
- items.push(item);
78
- return {
79
- content: [{ type: "text", text: `Added #${item.id}` }],
80
- details: { action: "add", items: [...items], nextId } as {{ToolDetails}},
81
- };
82
- }
83
-
84
- case "remove": {
85
- if (params.id === undefined) throw new Error("id required for remove");
86
- const idx = items.findIndex(i => i.id === params.id);
87
- if (idx === -1) throw new Error(`Item #${params.id} not found`);
88
- items.splice(idx, 1);
89
- return {
90
- content: [{ type: "text", text: `Removed #${params.id}` }],
91
- details: { action: "remove", items: [...items], nextId } as {{ToolDetails}},
92
- };
93
- }
94
-
95
- default:
96
- throw new Error(`Unknown action: ${params.action}`);
97
- }
98
- },
99
-
100
- // Custom rendering
101
- renderCall(args, theme) {
102
- let text = theme.fg("toolTitle", theme.bold("{{tool_name}} "));
103
- text += theme.fg("muted", args.action);
104
- return new Text(text, 0, 0);
105
- },
106
-
107
- renderResult(result, { expanded }, theme) {
108
- const details = result.details as {{ToolDetails}} | undefined;
109
- if (!details) return new Text("", 0, 0);
110
- if (details.error) return new Text(theme.fg("error", details.error), 0, 0);
111
- return new Text(theme.fg("success", `✓ ${details.action} (${details.items.length} items)`), 0, 0);
112
- },
113
- });
114
-
115
- // User command to view state
116
- pi.registerCommand("{{command_name}}", {
117
- description: "View {{items}}",
118
- handler: async (_args, ctx) => {
119
- if (!ctx.hasUI) {
120
- ctx.ui.notify("Requires interactive mode", "error");
121
- return;
122
- }
123
- await ctx.ui.custom<void>((_tui, theme, _kb, done) => ({
124
- render(width: number): string[] {
125
- const lines = [
126
- "",
127
- truncateToWidth(theme.fg("accent", ` {{Items}} (${items.length}) `), width),
128
- "",
129
- ];
130
- for (const item of items) {
131
- lines.push(truncateToWidth(` #${item.id}`, width));
132
- }
133
- lines.push("", truncateToWidth(theme.fg("dim", " Press Escape to close"), width), "");
134
- return lines;
135
- },
136
- handleInput(data: string) {
137
- if (matchesKey(data, Key.escape)) done();
138
- },
139
- invalidate() {},
140
- }));
141
- },
142
- });
143
- }
@@ -1,57 +0,0 @@
1
- <required_reading>
2
- Read the reference file for the specific capability being added:
3
- - Tools → references/custom-tools.md
4
- - Commands → references/custom-commands.md
5
- - Events → references/events-reference.md
6
- - UI → references/custom-ui.md
7
- - Rendering → references/custom-rendering.md
8
- - State → references/state-management.md
9
- - System prompt → references/system-prompt-modification.md
10
- </required_reading>
11
-
12
- <process>
13
-
14
- ## Step 1: Identify the Extension
15
-
16
- Locate the existing extension file. Check:
17
- - `~/.gsd/agent/extensions/` (global)
18
- - `.gsd/extensions/` (project-local)
19
-
20
- Read the current extension code to understand its structure.
21
-
22
- ## Step 2: Add the Capability
23
-
24
- Add the new registration/hook inside the existing `export default function (pi: ExtensionAPI)` body. Follow the patterns in the relevant reference file.
25
-
26
- If the extension needs new imports, add them at the top of the file.
27
-
28
- ## Step 3: Handle Structural Changes
29
-
30
- **Single file → Directory**: If the extension is outgrowing a single file:
31
- 1. Create `~/.gsd/agent/extensions/my-extension/`
32
- 2. Move the file to `index.ts`
33
- 3. Extract helpers to separate files
34
-
35
- **Adding npm dependencies**: If new packages are needed:
36
- 1. Create `package.json` in the extension directory
37
- 2. Add dependencies
38
- 3. Run `npm install`
39
- 4. Add `"pi": { "extensions": ["./index.ts"] }` to package.json
40
-
41
- ## Step 4: Test
42
-
43
- ```bash
44
- /reload
45
- ```
46
-
47
- Verify the new capability works alongside existing ones.
48
-
49
- </process>
50
-
51
- <success_criteria>
52
- Capability addition is complete when:
53
- - [ ] New capability added without breaking existing functionality
54
- - [ ] All new imports resolve
55
- - [ ] `/reload` succeeds
56
- - [ ] New tool/command/hook tested with real invocation
57
- </success_criteria>
@@ -1,156 +0,0 @@
1
- <required_reading>
2
- **Read these reference files before proceeding:**
3
- 1. references/extension-lifecycle.md
4
- 2. references/custom-tools.md (if building tools)
5
- 3. references/custom-commands.md (if building commands)
6
- 4. references/events-reference.md (if building event hooks)
7
- 5. references/key-rules-gotchas.md (always)
8
- </required_reading>
9
-
10
- <process>
11
-
12
- ## Step 1: Determine Scope and Placement
13
-
14
- Ask the user:
15
- - **Global** (`~/.gsd/agent/extensions/`) — Available in all GSD sessions
16
- - **Project-local** (`.gsd/extensions/`) — Available only in this project
17
-
18
- ## Step 2: Determine Extension Capabilities
19
-
20
- Identify what the extension needs from the user's description:
21
-
22
- | Capability | API | When |
23
- |------------|-----|------|
24
- | Custom tool (LLM-callable) | `pi.registerTool()` | LLM needs to perform new actions |
25
- | Slash command | `pi.registerCommand()` | User needs direct actions |
26
- | Event interception | `pi.on("event", ...)` | Block/modify tool calls, inject context, react to lifecycle |
27
- | Custom UI | `ctx.ui.custom()` | Complex interactive displays |
28
- | System prompt modification | `before_agent_start` event | Add per-turn instructions |
29
- | Context filtering | `context` event | Modify messages sent to LLM |
30
- | State persistence | `details` in tool results or `pi.appendEntry()` | Stateful behavior |
31
- | Custom rendering | `renderCall` / `renderResult` | Control how tools appear in TUI |
32
- | Provider management | `pi.registerProvider()` | Custom model endpoints |
33
- | Keyboard shortcut | `pi.registerShortcut()` | Hotkey triggers |
34
-
35
- ## Step 3: Choose Extension Structure
36
-
37
- **Single file** — for small extensions (1-2 tools/commands, simple hooks):
38
- ```
39
- ~/.gsd/agent/extensions/my-extension.ts
40
- ```
41
-
42
- **Directory with index.ts** — for multi-file extensions:
43
- ```
44
- ~/.gsd/agent/extensions/my-extension/
45
- ├── index.ts
46
- ├── tools.ts
47
- └── utils.ts
48
- ```
49
-
50
- **Package with dependencies** — when npm packages are needed:
51
- ```
52
- ~/.gsd/agent/extensions/my-extension/
53
- ├── package.json
54
- ├── src/index.ts
55
- └── node_modules/
56
- ```
57
-
58
- For packages, `package.json` needs:
59
- ```json
60
- {
61
- "name": "my-extension",
62
- "dependencies": { ... },
63
- "pi": { "extensions": ["./src/index.ts"] }
64
- }
65
- ```
66
-
67
- ## Step 4: Write the Extension
68
-
69
- Start with the skeleton:
70
-
71
- ```typescript
72
- import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
73
-
74
- export default function (pi: ExtensionAPI) {
75
- // Register events, tools, commands here
76
- }
77
- ```
78
-
79
- Then add capabilities based on Step 2. Reference the appropriate reference files for each capability.
80
-
81
- **Tool registration pattern:**
82
- ```typescript
83
- import { Type } from "@sinclair/typebox";
84
- import { StringEnum } from "@mariozechner/pi-ai";
85
-
86
- pi.registerTool({
87
- name: "my_tool",
88
- label: "My Tool",
89
- description: "What this tool does (shown to LLM)",
90
- parameters: Type.Object({
91
- action: StringEnum(["list", "add"] as const),
92
- text: Type.Optional(Type.String({ description: "Item text" })),
93
- }),
94
- async execute(toolCallId, params, signal, onUpdate, ctx) {
95
- if (signal?.aborted) return { content: [{ type: "text", text: "Cancelled" }] };
96
- return {
97
- content: [{ type: "text", text: "Result for LLM" }],
98
- details: { data: "for rendering and state" },
99
- };
100
- },
101
- });
102
- ```
103
-
104
- **Command registration pattern:**
105
- ```typescript
106
- pi.registerCommand("mycommand", {
107
- description: "What this command does",
108
- handler: async (args, ctx) => {
109
- ctx.ui.notify(`Running with args: ${args}`, "info");
110
- },
111
- });
112
- ```
113
-
114
- **Event hook pattern:**
115
- ```typescript
116
- pi.on("tool_call", async (event, ctx) => {
117
- if (event.toolName === "bash" && event.input.command?.includes("rm -rf")) {
118
- return { block: true, reason: "Blocked dangerous command" };
119
- }
120
- });
121
- ```
122
-
123
- ## Step 5: Test the Extension
124
-
125
- ```bash
126
- # Quick test without installing
127
- gsd -e ./path/to/my-extension.ts
128
-
129
- # Or place in extensions dir and reload
130
- /reload
131
- ```
132
-
133
- Verify:
134
- - Extension loads without errors (check GSD startup output)
135
- - Tools appear when LLM is asked to use them
136
- - Commands respond to `/mycommand`
137
- - Event hooks trigger at expected points
138
-
139
- ## Step 6: Iterate
140
-
141
- Fix issues, add features, refine. Use `/reload` for hot-reload during development.
142
-
143
- </process>
144
-
145
- <success_criteria>
146
- Extension creation is complete when:
147
- - [ ] Extension file(s) written to correct location
148
- - [ ] All imports resolve (TypeBox, pi-ai, pi-coding-agent, pi-tui as needed)
149
- - [ ] Tools use `StringEnum` for string enums (not `Type.Union`/`Type.Literal`)
150
- - [ ] Tool output is truncated if variable-length
151
- - [ ] State stored in `details` if extension is stateful
152
- - [ ] `ctx.hasUI` checked before dialog methods
153
- - [ ] Extension loads on `/reload` without errors
154
- - [ ] Tools callable by LLM, commands by user
155
- - [ ] Tested with at least one real invocation
156
- </success_criteria>
@@ -1,74 +0,0 @@
1
- <required_reading>
2
- 1. references/key-rules-gotchas.md
3
- 2. references/extension-lifecycle.md
4
- </required_reading>
5
-
6
- <process>
7
-
8
- ## Step 1: Identify the Symptom
9
-
10
- | Symptom | Likely Cause |
11
- |---------|--------------|
12
- | Extension not loading | File not in discovery path, syntax error, missing export default |
13
- | Tool not appearing for LLM | Tool not registered, `pi.setActiveTools()` excluding it, tool name conflict |
14
- | Command not responding | Command not registered, name collision with built-in |
15
- | Event not firing | Wrong event name, handler returning too early, handler error (logged but swallowed) |
16
- | UI not rendering | `ctx.hasUI` is false (print mode), render lines exceed width, component not returning lines |
17
- | State lost on restart | State not stored in `details` or `appendEntry`, not reconstructing on `session_start` |
18
- | Google API errors | Using `Type.Union`/`Type.Literal` instead of `StringEnum` |
19
- | Context overflow | Tool output not truncated |
20
- | Deadlock/hang | Session control methods called from event handler (must be in command handler only) |
21
- | Render garbage | Theme imported directly instead of from callback, missing `truncateToWidth()` |
22
-
23
- ## Step 2: Check Extension Loading
24
-
25
- ```bash
26
- # Test in isolation
27
- gsd -e ./path/to/extension.ts
28
-
29
- # Check GSD startup output for errors
30
- # Extension errors are logged but don't crash GSD
31
- ```
32
-
33
- ## Step 3: Verify File Location
34
-
35
- Extensions must be in auto-discovery paths:
36
- - `~/.gsd/agent/extensions/*.ts`
37
- - `~/.gsd/agent/extensions/*/index.ts`
38
- - `.gsd/extensions/*.ts`
39
- - `.gsd/extensions/*/index.ts`
40
-
41
- The file must `export default function(pi: ExtensionAPI) { ... }`.
42
-
43
- ## Step 4: Check for Common Mistakes
44
-
45
- Read `references/key-rules-gotchas.md` and verify each rule against the extension code.
46
-
47
- ## Step 5: Add Debugging
48
-
49
- ```typescript
50
- // Temporary: log to stderr (visible in GSD output)
51
- console.error("[my-ext] Loading...");
52
-
53
- pi.on("session_start", async (_event, ctx) => {
54
- console.error("[my-ext] Session started");
55
- ctx.ui.notify("Extension loaded", "info");
56
- });
57
- ```
58
-
59
- ## Step 6: Fix and Reload
60
-
61
- Apply the fix and test:
62
- ```
63
- /reload
64
- ```
65
-
66
- </process>
67
-
68
- <success_criteria>
69
- Debugging is complete when:
70
- - [ ] Root cause identified
71
- - [ ] Fix applied
72
- - [ ] Extension loads and functions correctly after `/reload`
73
- - [ ] No regression in existing functionality
74
- </success_criteria>