gsd-pi 2.29.0-dev.77f06e2 → 2.29.0-dev.f08b4fe
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/dist/extension-registry.d.ts +63 -0
- package/dist/extension-registry.js +166 -0
- package/dist/headless.js +4 -0
- package/dist/loader.js +10 -1
- package/dist/resource-loader.js +11 -1
- package/dist/resources/extensions/async-jobs/extension-manifest.json +13 -0
- package/dist/resources/extensions/bg-shell/extension-manifest.json +14 -0
- package/dist/resources/extensions/browser-tools/extension-manifest.json +37 -0
- package/dist/resources/extensions/context7/extension-manifest.json +12 -0
- package/dist/resources/extensions/google-search/extension-manifest.json +12 -0
- package/dist/resources/extensions/gsd/auto-dashboard.ts +31 -0
- package/dist/resources/extensions/gsd/auto-dispatch.ts +32 -3
- package/dist/resources/extensions/gsd/auto-post-unit.ts +39 -10
- package/dist/resources/extensions/gsd/auto-prompts.ts +40 -17
- package/dist/resources/extensions/gsd/auto-recovery.ts +2 -1
- package/dist/resources/extensions/gsd/auto-start.ts +18 -32
- package/dist/resources/extensions/gsd/auto-worktree.ts +21 -182
- package/dist/resources/extensions/gsd/auto.ts +2 -9
- package/dist/resources/extensions/gsd/captures.ts +4 -10
- package/dist/resources/extensions/gsd/commands-extensions.ts +328 -0
- package/dist/resources/extensions/gsd/commands-handlers.ts +2 -1
- package/dist/resources/extensions/gsd/commands.ts +53 -2
- package/dist/resources/extensions/gsd/detection.ts +2 -1
- package/dist/resources/extensions/gsd/doctor-checks.ts +49 -1
- package/dist/resources/extensions/gsd/doctor-types.ts +3 -1
- package/dist/resources/extensions/gsd/extension-manifest.json +18 -0
- package/dist/resources/extensions/gsd/forensics.ts +2 -2
- package/dist/resources/extensions/gsd/git-service.ts +3 -2
- package/dist/resources/extensions/gsd/gitignore.ts +9 -63
- package/dist/resources/extensions/gsd/gsd-db.ts +1 -165
- package/dist/resources/extensions/gsd/guided-flow.ts +8 -5
- package/dist/resources/extensions/gsd/index.ts +3 -3
- package/dist/resources/extensions/gsd/md-importer.ts +3 -2
- package/dist/resources/extensions/gsd/mechanical-completion.ts +430 -0
- package/dist/resources/extensions/gsd/migrate/command.ts +3 -2
- package/dist/resources/extensions/gsd/migrate/writer.ts +2 -1
- package/dist/resources/extensions/gsd/migrate-external.ts +123 -0
- package/dist/resources/extensions/gsd/paths.ts +24 -2
- package/dist/resources/extensions/gsd/post-unit-hooks.ts +6 -5
- package/dist/resources/extensions/gsd/preferences-models.ts +7 -1
- package/dist/resources/extensions/gsd/preferences-validation.ts +2 -1
- package/dist/resources/extensions/gsd/preferences.ts +10 -5
- package/dist/resources/extensions/gsd/prompts/discuss-headless.md +4 -2
- package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-milestone.md +26 -2
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +15 -1
- package/dist/resources/extensions/gsd/repo-identity.ts +148 -0
- package/dist/resources/extensions/gsd/resource-version.ts +99 -0
- package/dist/resources/extensions/gsd/session-forensics.ts +4 -3
- package/dist/resources/extensions/gsd/tests/activity-log.test.ts +2 -2
- package/dist/resources/extensions/gsd/tests/auto-recovery.test.ts +3 -3
- package/dist/resources/extensions/gsd/tests/auto-worktree.test.ts +0 -58
- package/dist/resources/extensions/gsd/tests/doctor-runtime.test.ts +3 -4
- package/dist/resources/extensions/gsd/tests/feature-branch-lifecycle-integration.test.ts +5 -18
- package/dist/resources/extensions/gsd/tests/git-service.test.ts +10 -37
- package/dist/resources/extensions/gsd/tests/knowledge.test.ts +4 -4
- package/dist/resources/extensions/gsd/tests/mechanical-completion.test.ts +356 -0
- package/dist/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +1 -0
- package/dist/resources/extensions/gsd/tests/token-profile.test.ts +14 -16
- package/dist/resources/extensions/gsd/triage-resolution.ts +2 -1
- package/dist/resources/extensions/gsd/types.ts +2 -0
- package/dist/resources/extensions/gsd/worktree-command.ts +1 -11
- package/dist/resources/extensions/gsd/worktree-manager.ts +3 -2
- package/dist/resources/extensions/gsd/worktree.ts +42 -5
- package/dist/resources/extensions/mac-tools/extension-manifest.json +16 -0
- package/dist/resources/extensions/mcporter/extension-manifest.json +12 -0
- package/dist/resources/extensions/remote-questions/extension-manifest.json +11 -0
- package/dist/resources/extensions/search-the-web/extension-manifest.json +13 -0
- package/dist/resources/extensions/slash-commands/extension-manifest.json +11 -0
- package/dist/resources/extensions/subagent/extension-manifest.json +13 -0
- package/dist/resources/extensions/ttsr/extension-manifest.json +11 -0
- package/dist/resources/extensions/universal-config/extension-manifest.json +13 -0
- package/dist/resources/extensions/voice/extension-manifest.json +12 -0
- package/dist/resources/skills/create-gsd-extension/SKILL.md +87 -0
- package/dist/resources/skills/create-gsd-extension/references/compaction-session-control.md +77 -0
- package/dist/resources/skills/create-gsd-extension/references/custom-commands.md +139 -0
- package/dist/resources/skills/create-gsd-extension/references/custom-rendering.md +108 -0
- package/dist/resources/skills/create-gsd-extension/references/custom-tools.md +183 -0
- package/dist/resources/skills/create-gsd-extension/references/custom-ui.md +490 -0
- package/dist/resources/skills/create-gsd-extension/references/events-reference.md +126 -0
- package/dist/resources/skills/create-gsd-extension/references/extension-lifecycle.md +64 -0
- package/dist/resources/skills/create-gsd-extension/references/extensionapi-reference.md +75 -0
- package/dist/resources/skills/create-gsd-extension/references/extensioncontext-reference.md +53 -0
- package/dist/resources/skills/create-gsd-extension/references/key-rules-gotchas.md +36 -0
- package/dist/resources/skills/create-gsd-extension/references/mode-behavior.md +32 -0
- package/dist/resources/skills/create-gsd-extension/references/model-provider-management.md +89 -0
- package/dist/resources/skills/create-gsd-extension/references/packaging-distribution.md +55 -0
- package/dist/resources/skills/create-gsd-extension/references/remote-execution-overrides.md +90 -0
- package/dist/resources/skills/create-gsd-extension/references/state-management.md +70 -0
- package/dist/resources/skills/create-gsd-extension/references/system-prompt-modification.md +52 -0
- package/dist/resources/skills/create-gsd-extension/templates/extension-skeleton.ts +51 -0
- package/dist/resources/skills/create-gsd-extension/templates/stateful-tool-skeleton.ts +143 -0
- package/dist/resources/skills/create-gsd-extension/workflows/add-capability.md +57 -0
- package/dist/resources/skills/create-gsd-extension/workflows/create-extension.md +156 -0
- package/dist/resources/skills/create-gsd-extension/workflows/debug-extension.md +74 -0
- package/dist/resources/skills/create-skill/SKILL.md +184 -0
- package/dist/resources/skills/create-skill/references/api-security.md +226 -0
- package/dist/resources/skills/create-skill/references/be-clear-and-direct.md +531 -0
- package/dist/resources/skills/create-skill/references/common-patterns.md +595 -0
- package/dist/resources/skills/create-skill/references/core-principles.md +437 -0
- package/dist/resources/skills/create-skill/references/executable-code.md +175 -0
- package/dist/resources/skills/create-skill/references/gsd-skill-ecosystem.md +68 -0
- package/dist/resources/skills/create-skill/references/iteration-and-testing.md +474 -0
- package/dist/resources/skills/create-skill/references/recommended-structure.md +168 -0
- package/dist/resources/skills/create-skill/references/skill-structure.md +372 -0
- package/dist/resources/skills/create-skill/references/use-xml-tags.md +466 -0
- package/dist/resources/skills/create-skill/references/using-scripts.md +113 -0
- package/dist/resources/skills/create-skill/references/using-templates.md +112 -0
- package/dist/resources/skills/create-skill/references/workflows-and-validation.md +510 -0
- package/dist/resources/skills/create-skill/templates/router-skill.md +73 -0
- package/dist/resources/skills/create-skill/templates/simple-skill.md +33 -0
- package/dist/resources/skills/create-skill/workflows/add-reference.md +96 -0
- package/dist/resources/skills/create-skill/workflows/add-script.md +93 -0
- package/dist/resources/skills/create-skill/workflows/add-template.md +74 -0
- package/dist/resources/skills/create-skill/workflows/add-workflow.md +120 -0
- package/dist/resources/skills/create-skill/workflows/audit-skill.md +148 -0
- package/dist/resources/skills/create-skill/workflows/create-new-skill.md +196 -0
- package/dist/resources/skills/create-skill/workflows/get-guidance.md +121 -0
- package/dist/resources/skills/create-skill/workflows/upgrade-to-router.md +161 -0
- package/dist/resources/skills/create-skill/workflows/verify-skill.md +204 -0
- package/dist/resources/skills/react-best-practices/SKILL.md +1 -1
- package/package.json +1 -1
- package/packages/native/dist/native.d.ts +2 -0
- package/packages/native/dist/native.js +19 -5
- package/packages/native/src/native.ts +23 -9
- package/packages/pi-coding-agent/dist/core/lsp/client.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/client.js +3 -0
- package/packages/pi-coding-agent/dist/core/lsp/client.js.map +1 -1
- package/packages/pi-coding-agent/src/core/lsp/client.ts +3 -0
- package/src/resources/extensions/async-jobs/extension-manifest.json +13 -0
- package/src/resources/extensions/bg-shell/extension-manifest.json +14 -0
- package/src/resources/extensions/browser-tools/extension-manifest.json +37 -0
- package/src/resources/extensions/context7/extension-manifest.json +12 -0
- package/src/resources/extensions/google-search/extension-manifest.json +12 -0
- package/src/resources/extensions/gsd/auto-dashboard.ts +31 -0
- package/src/resources/extensions/gsd/auto-dispatch.ts +32 -3
- package/src/resources/extensions/gsd/auto-post-unit.ts +39 -10
- package/src/resources/extensions/gsd/auto-prompts.ts +40 -17
- package/src/resources/extensions/gsd/auto-recovery.ts +2 -1
- package/src/resources/extensions/gsd/auto-start.ts +18 -32
- package/src/resources/extensions/gsd/auto-worktree.ts +21 -182
- package/src/resources/extensions/gsd/auto.ts +2 -9
- package/src/resources/extensions/gsd/captures.ts +4 -10
- package/src/resources/extensions/gsd/commands-extensions.ts +328 -0
- package/src/resources/extensions/gsd/commands-handlers.ts +2 -1
- package/src/resources/extensions/gsd/commands.ts +53 -2
- package/src/resources/extensions/gsd/detection.ts +2 -1
- package/src/resources/extensions/gsd/doctor-checks.ts +49 -1
- package/src/resources/extensions/gsd/doctor-types.ts +3 -1
- package/src/resources/extensions/gsd/extension-manifest.json +18 -0
- package/src/resources/extensions/gsd/forensics.ts +2 -2
- package/src/resources/extensions/gsd/git-service.ts +3 -2
- package/src/resources/extensions/gsd/gitignore.ts +9 -63
- package/src/resources/extensions/gsd/gsd-db.ts +1 -165
- package/src/resources/extensions/gsd/guided-flow.ts +8 -5
- package/src/resources/extensions/gsd/index.ts +3 -3
- package/src/resources/extensions/gsd/md-importer.ts +3 -2
- package/src/resources/extensions/gsd/mechanical-completion.ts +430 -0
- package/src/resources/extensions/gsd/migrate/command.ts +3 -2
- package/src/resources/extensions/gsd/migrate/writer.ts +2 -1
- package/src/resources/extensions/gsd/migrate-external.ts +123 -0
- package/src/resources/extensions/gsd/paths.ts +24 -2
- package/src/resources/extensions/gsd/post-unit-hooks.ts +6 -5
- package/src/resources/extensions/gsd/preferences-models.ts +7 -1
- package/src/resources/extensions/gsd/preferences-validation.ts +2 -1
- package/src/resources/extensions/gsd/preferences.ts +10 -5
- package/src/resources/extensions/gsd/prompts/discuss-headless.md +4 -2
- package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-milestone.md +26 -2
- package/src/resources/extensions/gsd/prompts/plan-slice.md +15 -1
- package/src/resources/extensions/gsd/repo-identity.ts +148 -0
- package/src/resources/extensions/gsd/resource-version.ts +99 -0
- package/src/resources/extensions/gsd/session-forensics.ts +4 -3
- package/src/resources/extensions/gsd/tests/activity-log.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/auto-worktree.test.ts +0 -58
- package/src/resources/extensions/gsd/tests/doctor-runtime.test.ts +3 -4
- package/src/resources/extensions/gsd/tests/feature-branch-lifecycle-integration.test.ts +5 -18
- package/src/resources/extensions/gsd/tests/git-service.test.ts +10 -37
- package/src/resources/extensions/gsd/tests/knowledge.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/mechanical-completion.test.ts +356 -0
- package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/token-profile.test.ts +14 -16
- package/src/resources/extensions/gsd/triage-resolution.ts +2 -1
- package/src/resources/extensions/gsd/types.ts +2 -0
- package/src/resources/extensions/gsd/worktree-command.ts +1 -11
- package/src/resources/extensions/gsd/worktree-manager.ts +3 -2
- package/src/resources/extensions/gsd/worktree.ts +42 -5
- package/src/resources/extensions/mac-tools/extension-manifest.json +16 -0
- package/src/resources/extensions/mcporter/extension-manifest.json +12 -0
- package/src/resources/extensions/remote-questions/extension-manifest.json +11 -0
- package/src/resources/extensions/search-the-web/extension-manifest.json +13 -0
- package/src/resources/extensions/slash-commands/extension-manifest.json +11 -0
- package/src/resources/extensions/subagent/extension-manifest.json +13 -0
- package/src/resources/extensions/ttsr/extension-manifest.json +11 -0
- package/src/resources/extensions/universal-config/extension-manifest.json +13 -0
- package/src/resources/extensions/voice/extension-manifest.json +12 -0
- package/src/resources/skills/create-gsd-extension/SKILL.md +87 -0
- package/src/resources/skills/create-gsd-extension/references/compaction-session-control.md +77 -0
- package/src/resources/skills/create-gsd-extension/references/custom-commands.md +139 -0
- package/src/resources/skills/create-gsd-extension/references/custom-rendering.md +108 -0
- package/src/resources/skills/create-gsd-extension/references/custom-tools.md +183 -0
- package/src/resources/skills/create-gsd-extension/references/custom-ui.md +490 -0
- package/src/resources/skills/create-gsd-extension/references/events-reference.md +126 -0
- package/src/resources/skills/create-gsd-extension/references/extension-lifecycle.md +64 -0
- package/src/resources/skills/create-gsd-extension/references/extensionapi-reference.md +75 -0
- package/src/resources/skills/create-gsd-extension/references/extensioncontext-reference.md +53 -0
- package/src/resources/skills/create-gsd-extension/references/key-rules-gotchas.md +36 -0
- package/src/resources/skills/create-gsd-extension/references/mode-behavior.md +32 -0
- package/src/resources/skills/create-gsd-extension/references/model-provider-management.md +89 -0
- package/src/resources/skills/create-gsd-extension/references/packaging-distribution.md +55 -0
- package/src/resources/skills/create-gsd-extension/references/remote-execution-overrides.md +90 -0
- package/src/resources/skills/create-gsd-extension/references/state-management.md +70 -0
- package/src/resources/skills/create-gsd-extension/references/system-prompt-modification.md +52 -0
- package/src/resources/skills/create-gsd-extension/templates/extension-skeleton.ts +51 -0
- package/src/resources/skills/create-gsd-extension/templates/stateful-tool-skeleton.ts +143 -0
- package/src/resources/skills/create-gsd-extension/workflows/add-capability.md +57 -0
- package/src/resources/skills/create-gsd-extension/workflows/create-extension.md +156 -0
- package/src/resources/skills/create-gsd-extension/workflows/debug-extension.md +74 -0
- package/src/resources/skills/create-skill/SKILL.md +184 -0
- package/src/resources/skills/create-skill/references/api-security.md +226 -0
- package/src/resources/skills/create-skill/references/be-clear-and-direct.md +531 -0
- package/src/resources/skills/create-skill/references/common-patterns.md +595 -0
- package/src/resources/skills/create-skill/references/core-principles.md +437 -0
- package/src/resources/skills/create-skill/references/executable-code.md +175 -0
- package/src/resources/skills/create-skill/references/gsd-skill-ecosystem.md +68 -0
- package/src/resources/skills/create-skill/references/iteration-and-testing.md +474 -0
- package/src/resources/skills/create-skill/references/recommended-structure.md +168 -0
- package/src/resources/skills/create-skill/references/skill-structure.md +372 -0
- package/src/resources/skills/create-skill/references/use-xml-tags.md +466 -0
- package/src/resources/skills/create-skill/references/using-scripts.md +113 -0
- package/src/resources/skills/create-skill/references/using-templates.md +112 -0
- package/src/resources/skills/create-skill/references/workflows-and-validation.md +510 -0
- package/src/resources/skills/create-skill/templates/router-skill.md +73 -0
- package/src/resources/skills/create-skill/templates/simple-skill.md +33 -0
- package/src/resources/skills/create-skill/workflows/add-reference.md +96 -0
- package/src/resources/skills/create-skill/workflows/add-script.md +93 -0
- package/src/resources/skills/create-skill/workflows/add-template.md +74 -0
- package/src/resources/skills/create-skill/workflows/add-workflow.md +120 -0
- package/src/resources/skills/create-skill/workflows/audit-skill.md +148 -0
- package/src/resources/skills/create-skill/workflows/create-new-skill.md +196 -0
- package/src/resources/skills/create-skill/workflows/get-guidance.md +121 -0
- package/src/resources/skills/create-skill/workflows/upgrade-to-router.md +161 -0
- package/src/resources/skills/create-skill/workflows/verify-skill.md +204 -0
- package/src/resources/skills/react-best-practices/SKILL.md +1 -1
- package/dist/resources/extensions/gsd/auto-worktree-sync.ts +0 -199
- package/dist/resources/extensions/gsd/tests/worktree-db-integration.test.ts +0 -205
- package/dist/resources/extensions/gsd/tests/worktree-db.test.ts +0 -442
- package/src/resources/extensions/gsd/auto-worktree-sync.ts +0 -199
- package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +0 -205
- package/src/resources/extensions/gsd/tests/worktree-db.test.ts +0 -442
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* SLICE_BRANCH_RE) remain for backwards compatibility with legacy branches.
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
-
import { existsSync, readFileSync, utimesSync } from "node:fs";
|
|
15
|
+
import { existsSync, lstatSync, readFileSync, utimesSync } from "node:fs";
|
|
16
16
|
import { join, resolve, sep } from "node:path";
|
|
17
17
|
|
|
18
18
|
import { GitServiceImpl, writeIntegrationBranch, type TaskCommitContext } from "./git-service.js";
|
|
@@ -72,6 +72,25 @@ export function captureIntegrationBranch(basePath: string, milestoneId: string,
|
|
|
72
72
|
* Returns null if not inside a GSD worktree (.gsd/worktrees/<name>/).
|
|
73
73
|
*/
|
|
74
74
|
export function detectWorktreeName(basePath: string): string | null {
|
|
75
|
+
// Primary: use git metadata — .git file with gitdir: pointer
|
|
76
|
+
const gitPath = join(basePath, ".git");
|
|
77
|
+
try {
|
|
78
|
+
const stat = lstatSync(gitPath);
|
|
79
|
+
if (stat.isFile()) {
|
|
80
|
+
const content = readFileSync(gitPath, "utf-8").trim();
|
|
81
|
+
if (content.startsWith("gitdir:")) {
|
|
82
|
+
const gitdir = content.slice(7).trim();
|
|
83
|
+
// Git worktree gitdir format: <repo>/.git/worktrees/<name>
|
|
84
|
+
const parts = gitdir.replace(/\\/g, "/").split("/");
|
|
85
|
+
const wtIdx = parts.lastIndexOf("worktrees");
|
|
86
|
+
if (wtIdx !== -1 && wtIdx < parts.length - 1) {
|
|
87
|
+
return parts[wtIdx + 1] || null;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
} catch { /* fall through */ }
|
|
92
|
+
|
|
93
|
+
// Fallback: path-based detection for legacy setups
|
|
75
94
|
const normalizedPath = basePath.replaceAll("\\", "/");
|
|
76
95
|
const marker = "/.gsd/worktrees/";
|
|
77
96
|
const idx = normalizedPath.indexOf(marker);
|
|
@@ -90,14 +109,32 @@ export function detectWorktreeName(basePath: string): string | null {
|
|
|
90
109
|
* operate against the real project root, not a worktree subdirectory.
|
|
91
110
|
*/
|
|
92
111
|
export function resolveProjectRoot(basePath: string): string {
|
|
112
|
+
// Primary: use git metadata to resolve the main worktree root
|
|
113
|
+
const gitPath = join(basePath, ".git");
|
|
114
|
+
try {
|
|
115
|
+
const stat = lstatSync(gitPath);
|
|
116
|
+
if (stat.isFile()) {
|
|
117
|
+
const content = readFileSync(gitPath, "utf-8").trim();
|
|
118
|
+
if (content.startsWith("gitdir:")) {
|
|
119
|
+
const gitdir = resolve(basePath, content.slice(7).trim());
|
|
120
|
+
// Git worktree gitdir: <repo>/.git/worktrees/<name>
|
|
121
|
+
// Walk up to <repo>
|
|
122
|
+
const parts = gitdir.replace(/\\/g, "/").split("/");
|
|
123
|
+
const wtIdx = parts.lastIndexOf("worktrees");
|
|
124
|
+
if (wtIdx >= 2 && parts[wtIdx - 1] === ".git") {
|
|
125
|
+
return parts.slice(0, wtIdx - 1).join("/");
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
} catch { /* fall through */ }
|
|
130
|
+
|
|
131
|
+
// Fallback: legacy path-based detection
|
|
93
132
|
const normalizedPath = basePath.replaceAll("\\", "/");
|
|
94
133
|
const marker = "/.gsd/worktrees/";
|
|
95
134
|
const idx = normalizedPath.indexOf(marker);
|
|
96
135
|
if (idx === -1) return basePath;
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
const sep = basePath.includes("\\") ? "\\" : "/";
|
|
100
|
-
const markerOs = `${sep}.gsd${sep}worktrees${sep}`;
|
|
136
|
+
const osSep = basePath.includes("\\") ? "\\" : "/";
|
|
137
|
+
const markerOs = `${osSep}.gsd${osSep}worktrees${osSep}`;
|
|
101
138
|
const idxOs = basePath.indexOf(markerOs);
|
|
102
139
|
if (idxOs !== -1) return basePath.slice(0, idxOs);
|
|
103
140
|
return basePath.slice(0, idx);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "mac-tools",
|
|
3
|
+
"name": "Mac Tools",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"description": "macOS automation via Accessibility API — screenshots, UI inspection, clicks, and typing",
|
|
6
|
+
"tier": "bundled",
|
|
7
|
+
"requires": { "platform": ">=2.29.0" },
|
|
8
|
+
"provides": {
|
|
9
|
+
"tools": [
|
|
10
|
+
"mac_check_permissions", "mac_list_apps", "mac_launch_app", "mac_activate_app",
|
|
11
|
+
"mac_quit_app", "mac_list_windows", "mac_screenshot", "mac_find",
|
|
12
|
+
"mac_get_tree", "mac_click", "mac_type", "mac_read"
|
|
13
|
+
],
|
|
14
|
+
"hooks": ["before_agent_start"]
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "mcporter",
|
|
3
|
+
"name": "MCPorter",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"description": "Discover and call tools from MCP servers configured in Claude Desktop, Cursor, and VS Code",
|
|
6
|
+
"tier": "bundled",
|
|
7
|
+
"requires": { "platform": ">=2.29.0" },
|
|
8
|
+
"provides": {
|
|
9
|
+
"tools": ["mcp_servers", "mcp_discover", "mcp_call"],
|
|
10
|
+
"hooks": ["session_start"]
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "remote-questions",
|
|
3
|
+
"name": "Remote Questions",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"description": "Remote user question routing via Slack, Discord, and Telegram adapters",
|
|
6
|
+
"tier": "bundled",
|
|
7
|
+
"requires": { "platform": ">=2.29.0" },
|
|
8
|
+
"provides": {
|
|
9
|
+
"commands": ["remote"]
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "search-the-web",
|
|
3
|
+
"name": "Web Search",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"description": "Web search via Brave and page extraction via Jina Reader",
|
|
6
|
+
"tier": "bundled",
|
|
7
|
+
"requires": { "platform": ">=2.29.0" },
|
|
8
|
+
"provides": {
|
|
9
|
+
"tools": ["search-the-web", "fetch_page", "search_and_read", "web_search"],
|
|
10
|
+
"commands": ["search-provider"],
|
|
11
|
+
"hooks": ["model_select", "before_provider_request"]
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "slash-commands",
|
|
3
|
+
"name": "Slash Commands",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"description": "Boilerplate generators for slash commands, extensions, and audit tools",
|
|
6
|
+
"tier": "bundled",
|
|
7
|
+
"requires": { "platform": ">=2.29.0" },
|
|
8
|
+
"provides": {
|
|
9
|
+
"commands": ["create-slash-command", "create-extension", "audit", "clear"]
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "subagent",
|
|
3
|
+
"name": "Subagent",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"description": "Delegate tasks to specialized subagents in single, parallel, or chain modes",
|
|
6
|
+
"tier": "bundled",
|
|
7
|
+
"requires": { "platform": ">=2.29.0" },
|
|
8
|
+
"provides": {
|
|
9
|
+
"tools": ["subagent"],
|
|
10
|
+
"commands": ["subagent"],
|
|
11
|
+
"hooks": ["session_shutdown"]
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "ttsr",
|
|
3
|
+
"name": "Time Traveling Stream Rules",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"description": "Zero-context-cost guardrails that monitor streaming output against regex patterns",
|
|
6
|
+
"tier": "bundled",
|
|
7
|
+
"requires": { "platform": ">=2.29.0" },
|
|
8
|
+
"provides": {
|
|
9
|
+
"hooks": ["session_start", "turn_start", "message_update", "turn_end", "agent_end"]
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "universal-config",
|
|
3
|
+
"name": "Universal Config",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"description": "Discover AI coding tool configurations across Claude Code, Cursor, Windsurf, Gemini CLI, and more",
|
|
6
|
+
"tier": "bundled",
|
|
7
|
+
"requires": { "platform": ">=2.29.0" },
|
|
8
|
+
"provides": {
|
|
9
|
+
"tools": ["discover_configs"],
|
|
10
|
+
"commands": ["configs"],
|
|
11
|
+
"hooks": ["session_switch"]
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "voice",
|
|
3
|
+
"name": "Voice",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"description": "Voice input mode for hands-free interaction",
|
|
6
|
+
"tier": "bundled",
|
|
7
|
+
"requires": { "platform": ">=2.29.0" },
|
|
8
|
+
"provides": {
|
|
9
|
+
"commands": ["voice"],
|
|
10
|
+
"shortcuts": ["Ctrl+Alt+V"]
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: create-gsd-extension
|
|
3
|
+
description: Create, debug, and iterate on GSD extensions (TypeScript modules that add tools, commands, event hooks, custom UI, and providers to GSD). Use when asked to build an extension, add a tool the LLM can call, register a slash command, hook into GSD events, create custom TUI components, or modify GSD behavior. Triggers on "create extension", "build extension", "add a tool", "register command", "hook into gsd", "custom tool", "gsd plugin", "gsd extension".
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
<essential_principles>
|
|
7
|
+
|
|
8
|
+
**Extensions are TypeScript modules** that hook into GSD's runtime (built on pi). They export a default function receiving `ExtensionAPI` and use it to subscribe to events, register tools/commands/shortcuts, and interact with the session.
|
|
9
|
+
|
|
10
|
+
**GSD extension paths:**
|
|
11
|
+
- Global extensions: `~/.gsd/agent/extensions/*.ts` or `~/.gsd/agent/extensions/*/index.ts`
|
|
12
|
+
- Project-local extensions: `.gsd/extensions/*.ts` or `.gsd/extensions/*/index.ts`
|
|
13
|
+
|
|
14
|
+
**The three primitives:**
|
|
15
|
+
1. **Events** — Listen and react (`pi.on("event", handler)`). Can block tool calls, modify messages, inject context.
|
|
16
|
+
2. **Tools** — Give the LLM new abilities (`pi.registerTool()`). LLM calls them autonomously.
|
|
17
|
+
3. **Commands** — Give users slash commands (`pi.registerCommand()`). Users type `/mycommand`.
|
|
18
|
+
|
|
19
|
+
**Non-negotiable rules:**
|
|
20
|
+
- Use `StringEnum` from `@mariozechner/pi-ai` for string enum params (NOT `Type.Union`/`Type.Literal` — breaks Google's API)
|
|
21
|
+
- Truncate tool output to 50KB / 2000 lines max (use `truncateHead`/`truncateTail` from `@mariozechner/pi-coding-agent`)
|
|
22
|
+
- Store stateful tool state in `details` for branching support
|
|
23
|
+
- Check `signal?.aborted` in long-running tool executions
|
|
24
|
+
- Use `pi.exec()` not `child_process` for shell commands
|
|
25
|
+
- Check `ctx.hasUI` before dialog methods (non-interactive modes exist)
|
|
26
|
+
- Session control methods (`waitForIdle`, `newSession`, `fork`, `navigateTree`, `reload`) are ONLY available in command handlers — they deadlock in event handlers
|
|
27
|
+
- Lines from `render()` must not exceed `width` — use `truncateToWidth()`
|
|
28
|
+
- Use theme from callback params, never import directly
|
|
29
|
+
- Strip leading `@` from path params in custom tools (some models add it)
|
|
30
|
+
|
|
31
|
+
**Available imports:**
|
|
32
|
+
|
|
33
|
+
| Package | Purpose |
|
|
34
|
+
|---------|---------|
|
|
35
|
+
| `@mariozechner/pi-coding-agent` | `ExtensionAPI`, `ExtensionContext`, `Theme`, event types, tool utilities, `DynamicBorder`, `BorderedLoader`, `CustomEditor`, `highlightCode` |
|
|
36
|
+
| `@sinclair/typebox` | `Type.Object`, `Type.String`, `Type.Number`, `Type.Optional`, `Type.Boolean`, `Type.Array` |
|
|
37
|
+
| `@mariozechner/pi-ai` | `StringEnum` (required for string enums), `Type` re-export |
|
|
38
|
+
| `@mariozechner/pi-tui` | `Text`, `Box`, `Container`, `Spacer`, `Markdown`, `SelectList`, `Input`, `matchesKey`, `Key`, `truncateToWidth`, `visibleWidth` |
|
|
39
|
+
| Node.js built-ins | `node:fs`, `node:path`, `node:child_process`, etc. |
|
|
40
|
+
|
|
41
|
+
</essential_principles>
|
|
42
|
+
|
|
43
|
+
<routing>
|
|
44
|
+
Based on user intent, route to the appropriate workflow:
|
|
45
|
+
|
|
46
|
+
**Building a new extension:**
|
|
47
|
+
- "Create an extension", "build a tool", "I want to add a command" → `workflows/create-extension.md`
|
|
48
|
+
|
|
49
|
+
**Adding capabilities to an existing extension:**
|
|
50
|
+
- "Add a tool to my extension", "add event hook", "add custom rendering" → `workflows/add-capability.md`
|
|
51
|
+
|
|
52
|
+
**Debugging an extension:**
|
|
53
|
+
- "My extension doesn't work", "tool not showing up", "event not firing" → `workflows/debug-extension.md`
|
|
54
|
+
|
|
55
|
+
**If user intent is clear from context, skip the question and go directly to the workflow.**
|
|
56
|
+
</routing>
|
|
57
|
+
|
|
58
|
+
<reference_index>
|
|
59
|
+
All domain knowledge in `references/`:
|
|
60
|
+
|
|
61
|
+
**Core architecture:** extension-lifecycle.md, events-reference.md
|
|
62
|
+
**API surface:** extensionapi-reference.md, extensioncontext-reference.md
|
|
63
|
+
**Capabilities:** custom-tools.md, custom-commands.md, custom-ui.md, custom-rendering.md
|
|
64
|
+
**Patterns:** state-management.md, system-prompt-modification.md, compaction-session-control.md
|
|
65
|
+
**Infrastructure:** model-provider-management.md, remote-execution-overrides.md, packaging-distribution.md, mode-behavior.md
|
|
66
|
+
**Gotchas:** key-rules-gotchas.md
|
|
67
|
+
</reference_index>
|
|
68
|
+
|
|
69
|
+
<workflows_index>
|
|
70
|
+
| Workflow | Purpose |
|
|
71
|
+
|----------|---------|
|
|
72
|
+
| create-extension.md | Build a new extension from scratch |
|
|
73
|
+
| add-capability.md | Add tools, commands, hooks, UI to an existing extension |
|
|
74
|
+
| debug-extension.md | Diagnose and fix extension issues |
|
|
75
|
+
</workflows_index>
|
|
76
|
+
|
|
77
|
+
<success_criteria>
|
|
78
|
+
Extension is complete when:
|
|
79
|
+
- TypeScript compiles without errors (jiti handles this at runtime)
|
|
80
|
+
- Extension loads on GSD startup or `/reload` without errors
|
|
81
|
+
- Tools appear in the LLM's system prompt and are callable
|
|
82
|
+
- Commands respond to `/command` input
|
|
83
|
+
- Event hooks fire at the expected lifecycle points
|
|
84
|
+
- Custom UI renders correctly within terminal width
|
|
85
|
+
- State persists correctly across session restarts (if stateful)
|
|
86
|
+
- Output is truncated to safe limits (if tools produce variable output)
|
|
87
|
+
</success_criteria>
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
<overview>
|
|
2
|
+
Custom compaction hooks, triggering compaction, and session control methods available only in command handlers.
|
|
3
|
+
</overview>
|
|
4
|
+
|
|
5
|
+
<custom_compaction>
|
|
6
|
+
Override default compaction behavior:
|
|
7
|
+
|
|
8
|
+
```typescript
|
|
9
|
+
pi.on("session_before_compact", async (event, ctx) => {
|
|
10
|
+
const { preparation, branchEntries, customInstructions, signal } = event;
|
|
11
|
+
|
|
12
|
+
// Option 1: Cancel
|
|
13
|
+
return { cancel: true };
|
|
14
|
+
|
|
15
|
+
// Option 2: Custom summary
|
|
16
|
+
return {
|
|
17
|
+
compaction: {
|
|
18
|
+
summary: "Custom summary of conversation so far...",
|
|
19
|
+
firstKeptEntryId: preparation.firstKeptEntryId,
|
|
20
|
+
tokensBefore: preparation.tokensBefore,
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
});
|
|
24
|
+
```
|
|
25
|
+
</custom_compaction>
|
|
26
|
+
|
|
27
|
+
<trigger_compaction>
|
|
28
|
+
Trigger compaction programmatically from any handler:
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
ctx.compact({
|
|
32
|
+
customInstructions: "Focus on the authentication changes",
|
|
33
|
+
onComplete: (result) => ctx.ui.notify("Compacted!", "info"),
|
|
34
|
+
onError: (error) => ctx.ui.notify(`Failed: ${error.message}`, "error"),
|
|
35
|
+
});
|
|
36
|
+
```
|
|
37
|
+
</trigger_compaction>
|
|
38
|
+
|
|
39
|
+
<session_control>
|
|
40
|
+
**Only available in command handlers** (deadlocks in event handlers):
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
pi.registerCommand("handoff", {
|
|
44
|
+
handler: async (args, ctx) => {
|
|
45
|
+
await ctx.waitForIdle();
|
|
46
|
+
|
|
47
|
+
// Create new session with initial context
|
|
48
|
+
const result = await ctx.newSession({
|
|
49
|
+
parentSession: ctx.sessionManager.getSessionFile(),
|
|
50
|
+
setup: async (sm) => {
|
|
51
|
+
sm.appendMessage({
|
|
52
|
+
role: "user",
|
|
53
|
+
content: [{ type: "text", text: `Context: ${args}` }],
|
|
54
|
+
timestamp: Date.now(),
|
|
55
|
+
});
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
if (result.cancelled) { /* extension cancelled via session_before_switch */ }
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
| Method | Purpose |
|
|
65
|
+
|--------|---------|
|
|
66
|
+
| `ctx.waitForIdle()` | Wait for agent to finish streaming |
|
|
67
|
+
| `ctx.newSession(options?)` | Create a new session |
|
|
68
|
+
| `ctx.fork(entryId)` | Fork from a specific entry |
|
|
69
|
+
| `ctx.navigateTree(targetId, options?)` | Navigate session tree (with optional summary) |
|
|
70
|
+
| `ctx.reload()` | Hot-reload everything (treat as terminal — code after runs pre-reload version) |
|
|
71
|
+
|
|
72
|
+
`navigateTree` options:
|
|
73
|
+
- `summarize: boolean` — generate summary of abandoned branch
|
|
74
|
+
- `customInstructions: string` — instructions for summarizer
|
|
75
|
+
- `replaceInstructions: boolean` — replace default prompt entirely
|
|
76
|
+
- `label: string` — label to attach to branch summary
|
|
77
|
+
</session_control>
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
<overview>
|
|
2
|
+
Custom slash commands — registration, argument completions, subcommand patterns, and the extended command context.
|
|
3
|
+
</overview>
|
|
4
|
+
|
|
5
|
+
<basic_registration>
|
|
6
|
+
```typescript
|
|
7
|
+
pi.registerCommand("deploy", {
|
|
8
|
+
description: "Deploy to an environment",
|
|
9
|
+
handler: async (args, ctx) => {
|
|
10
|
+
// args = everything after "/deploy "
|
|
11
|
+
// ctx = ExtensionCommandContext (has session control methods)
|
|
12
|
+
ctx.ui.notify(`Deploying to ${args || "production"}`, "info");
|
|
13
|
+
},
|
|
14
|
+
});
|
|
15
|
+
```
|
|
16
|
+
</basic_registration>
|
|
17
|
+
|
|
18
|
+
<argument_completions>
|
|
19
|
+
Add tab-completion for command arguments:
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
import type { AutocompleteItem } from "@mariozechner/pi-tui";
|
|
23
|
+
|
|
24
|
+
pi.registerCommand("deploy", {
|
|
25
|
+
description: "Deploy to an environment",
|
|
26
|
+
getArgumentCompletions: (prefix: string): AutocompleteItem[] | null => {
|
|
27
|
+
const envs = ["dev", "staging", "prod"];
|
|
28
|
+
const items = envs.map(e => ({ value: e, label: e }));
|
|
29
|
+
const filtered = items.filter(i => i.value.startsWith(prefix));
|
|
30
|
+
return filtered.length > 0 ? filtered : null;
|
|
31
|
+
},
|
|
32
|
+
handler: async (args, ctx) => {
|
|
33
|
+
ctx.ui.notify(`Deploying to ${args}`, "info");
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
```
|
|
37
|
+
</argument_completions>
|
|
38
|
+
|
|
39
|
+
<subcommand_pattern>
|
|
40
|
+
Fake nested commands via first-argument parsing. Used by `/wt new|ls|switch|merge|rm`.
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
pi.registerCommand("foo", {
|
|
44
|
+
description: "Manage foo items: /foo new|list|delete [name]",
|
|
45
|
+
|
|
46
|
+
getArgumentCompletions: (prefix: string) => {
|
|
47
|
+
const parts = prefix.trim().split(/\s+/);
|
|
48
|
+
|
|
49
|
+
// First arg: subcommand
|
|
50
|
+
if (parts.length <= 1) {
|
|
51
|
+
return ["new", "list", "delete"]
|
|
52
|
+
.filter(cmd => cmd.startsWith(parts[0] ?? ""))
|
|
53
|
+
.map(cmd => ({ value: cmd, label: cmd }));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Second arg: depends on subcommand
|
|
57
|
+
if (parts[0] === "delete") {
|
|
58
|
+
const items = getItemsSomehow();
|
|
59
|
+
return items
|
|
60
|
+
.filter(name => name.startsWith(parts[1] ?? ""))
|
|
61
|
+
.map(name => ({ value: `delete ${name}`, label: name }));
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return [];
|
|
65
|
+
},
|
|
66
|
+
|
|
67
|
+
handler: async (args, ctx) => {
|
|
68
|
+
const parts = args.trim().split(/\s+/);
|
|
69
|
+
const sub = parts[0];
|
|
70
|
+
|
|
71
|
+
switch (sub) {
|
|
72
|
+
case "new": /* ... */ return;
|
|
73
|
+
case "list": /* ... */ return;
|
|
74
|
+
case "delete": /* handle parts[1] */ return;
|
|
75
|
+
default:
|
|
76
|
+
ctx.ui.notify("Usage: /foo <new|list|delete> [name]", "info");
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
**Gotcha:** `"".trim().split(/\s+/)` produces `['']`, not `[]`. That's why `parts.length <= 1` handles both empty and partial first arg.
|
|
83
|
+
</subcommand_pattern>
|
|
84
|
+
|
|
85
|
+
<command_context>
|
|
86
|
+
Command handlers get `ExtensionCommandContext` which extends `ExtensionContext` with session control methods:
|
|
87
|
+
|
|
88
|
+
| Method | Purpose |
|
|
89
|
+
|--------|---------|
|
|
90
|
+
| `ctx.waitForIdle()` | Wait for agent to finish streaming |
|
|
91
|
+
| `ctx.newSession(options?)` | Create a new session |
|
|
92
|
+
| `ctx.fork(entryId)` | Fork from an entry |
|
|
93
|
+
| `ctx.navigateTree(targetId, options?)` | Navigate session tree |
|
|
94
|
+
| `ctx.reload()` | Hot-reload everything |
|
|
95
|
+
|
|
96
|
+
**⚠️ These methods are ONLY available in command handlers.** Calling them from event handlers causes deadlocks.
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
pi.registerCommand("handoff", {
|
|
100
|
+
handler: async (args, ctx) => {
|
|
101
|
+
await ctx.waitForIdle();
|
|
102
|
+
await ctx.newSession({
|
|
103
|
+
setup: async (sm) => {
|
|
104
|
+
sm.appendMessage({
|
|
105
|
+
role: "user",
|
|
106
|
+
content: [{ type: "text", text: `Context: ${args}` }],
|
|
107
|
+
timestamp: Date.now(),
|
|
108
|
+
});
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
},
|
|
112
|
+
});
|
|
113
|
+
```
|
|
114
|
+
</command_context>
|
|
115
|
+
|
|
116
|
+
<reload_pattern>
|
|
117
|
+
Expose reload as both a command and a tool the LLM can call:
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
pi.registerCommand("reload-runtime", {
|
|
121
|
+
description: "Reload extensions, skills, prompts, and themes",
|
|
122
|
+
handler: async (_args, ctx) => {
|
|
123
|
+
await ctx.reload();
|
|
124
|
+
return; // Treat reload as terminal
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
pi.registerTool({
|
|
129
|
+
name: "reload_runtime",
|
|
130
|
+
label: "Reload Runtime",
|
|
131
|
+
description: "Reload extensions, skills, prompts, and themes",
|
|
132
|
+
parameters: Type.Object({}),
|
|
133
|
+
async execute() {
|
|
134
|
+
pi.sendUserMessage("/reload-runtime", { deliverAs: "followUp" });
|
|
135
|
+
return { content: [{ type: "text", text: "Queued /reload-runtime as follow-up." }] };
|
|
136
|
+
},
|
|
137
|
+
});
|
|
138
|
+
```
|
|
139
|
+
</reload_pattern>
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
<overview>
|
|
2
|
+
Custom rendering for tools and messages — control how they appear in the TUI.
|
|
3
|
+
</overview>
|
|
4
|
+
|
|
5
|
+
<tool_rendering>
|
|
6
|
+
Tools can provide `renderCall` (how the call looks) and `renderResult` (how the result looks):
|
|
7
|
+
|
|
8
|
+
```typescript
|
|
9
|
+
import { Text } from "@mariozechner/pi-tui";
|
|
10
|
+
import { keyHint } from "@mariozechner/pi-coding-agent";
|
|
11
|
+
|
|
12
|
+
pi.registerTool({
|
|
13
|
+
name: "my_tool",
|
|
14
|
+
// ...
|
|
15
|
+
|
|
16
|
+
renderCall(args, theme) {
|
|
17
|
+
let text = theme.fg("toolTitle", theme.bold("my_tool "));
|
|
18
|
+
text += theme.fg("muted", args.action);
|
|
19
|
+
if (args.text) text += " " + theme.fg("dim", `"${args.text}"`);
|
|
20
|
+
return new Text(text, 0, 0); // 0,0 padding — Box handles it
|
|
21
|
+
},
|
|
22
|
+
|
|
23
|
+
renderResult(result, { expanded, isPartial }, theme) {
|
|
24
|
+
// isPartial = true during streaming (onUpdate was called)
|
|
25
|
+
if (isPartial) {
|
|
26
|
+
return new Text(theme.fg("warning", "Processing..."), 0, 0);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// expanded = user toggled expand (Ctrl+O)
|
|
30
|
+
if (result.details?.error) {
|
|
31
|
+
return new Text(theme.fg("error", `Error: ${result.details.error}`), 0, 0);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
let text = theme.fg("success", "✓ Done");
|
|
35
|
+
if (!expanded) {
|
|
36
|
+
text += ` (${keyHint("expandTools", "to expand")})`;
|
|
37
|
+
}
|
|
38
|
+
if (expanded && result.details?.items) {
|
|
39
|
+
for (const item of result.details.items) {
|
|
40
|
+
text += "\n " + theme.fg("dim", item);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return new Text(text, 0, 0);
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
If you omit `renderCall`/`renderResult`, the built-in renderer is used. Useful for tool overrides where you just wrap logic without reimplementing UI.
|
|
49
|
+
|
|
50
|
+
**Fallback:** If render methods throw, `renderCall` shows tool name, `renderResult` shows raw `content` text.
|
|
51
|
+
</tool_rendering>
|
|
52
|
+
|
|
53
|
+
<key_hints>
|
|
54
|
+
Key hint helpers for showing keybinding info in render output:
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
import { keyHint, appKeyHint, editorKey, rawKeyHint } from "@mariozechner/pi-coding-agent";
|
|
58
|
+
|
|
59
|
+
// Editor action hint (respects user keybinding config)
|
|
60
|
+
keyHint("expandTools", "to expand") // e.g., "Ctrl+O to expand"
|
|
61
|
+
keyHint("selectConfirm", "to select")
|
|
62
|
+
|
|
63
|
+
// Raw key hint (always shows literal key)
|
|
64
|
+
rawKeyHint("Ctrl+O", "to expand")
|
|
65
|
+
```
|
|
66
|
+
</key_hints>
|
|
67
|
+
|
|
68
|
+
<message_rendering>
|
|
69
|
+
Register a renderer for custom message types:
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
import { Text } from "@mariozechner/pi-tui";
|
|
73
|
+
|
|
74
|
+
pi.registerMessageRenderer("my-extension", (message, options, theme) => {
|
|
75
|
+
const { expanded } = options;
|
|
76
|
+
let text = theme.fg("accent", `[${message.customType}] `) + message.content;
|
|
77
|
+
if (expanded && message.details) {
|
|
78
|
+
text += "\n" + theme.fg("dim", JSON.stringify(message.details, null, 2));
|
|
79
|
+
}
|
|
80
|
+
return new Text(text, 0, 0);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// Send messages that use this renderer:
|
|
84
|
+
pi.sendMessage({
|
|
85
|
+
customType: "my-extension", // Matches renderer name
|
|
86
|
+
content: "Status update",
|
|
87
|
+
display: true,
|
|
88
|
+
details: { foo: "bar" },
|
|
89
|
+
});
|
|
90
|
+
```
|
|
91
|
+
</message_rendering>
|
|
92
|
+
|
|
93
|
+
<syntax_highlighting>
|
|
94
|
+
```typescript
|
|
95
|
+
import { highlightCode, getLanguageFromPath } from "@mariozechner/pi-coding-agent";
|
|
96
|
+
|
|
97
|
+
const lang = getLanguageFromPath("/path/to/file.rs"); // "rust"
|
|
98
|
+
const highlighted = highlightCode(code, lang, theme);
|
|
99
|
+
```
|
|
100
|
+
</syntax_highlighting>
|
|
101
|
+
|
|
102
|
+
<best_practices>
|
|
103
|
+
- Return `Text` with padding `(0, 0)` — the wrapping `Box` handles padding
|
|
104
|
+
- Support `expanded` for detail on demand
|
|
105
|
+
- Handle `isPartial` for streaming progress
|
|
106
|
+
- Keep collapsed view compact
|
|
107
|
+
- Use `\n` for multi-line content within a single `Text`
|
|
108
|
+
</best_practices>
|