@vandeepunk/pi-coding-agent 0.0.2 → 0.0.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/CHANGELOG.md +105 -0
- package/README.md +6 -6
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +1 -0
- package/dist/cli/args.js.map +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +2 -2
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +7 -0
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-storage.d.ts.map +1 -1
- package/dist/core/auth-storage.js +16 -0
- package/dist/core/auth-storage.js.map +1 -1
- package/dist/core/export-html/template.css +3 -0
- package/dist/core/export-html/template.js +32 -15
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +17 -2
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +53 -9
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/wrapper.d.ts.map +1 -1
- package/dist/core/extensions/wrapper.js +3 -3
- package/dist/core/extensions/wrapper.js.map +1 -1
- package/dist/core/model-registry.d.ts +3 -1
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +133 -37
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +5 -5
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/package-manager.d.ts +21 -1
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +134 -33
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/prompt-templates.d.ts +3 -3
- package/dist/core/prompt-templates.d.ts.map +1 -1
- package/dist/core/prompt-templates.js +15 -15
- package/dist/core/prompt-templates.js.map +1 -1
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +6 -6
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/settings-manager.d.ts +2 -2
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +4 -4
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/skills.d.ts.map +1 -1
- package/dist/core/skills.js +57 -3
- package/dist/core/skills.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +1 -0
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +172 -177
- package/dist/main.js.map +1 -1
- package/dist/migrations.d.ts.map +1 -1
- package/dist/migrations.js +11 -11
- package/dist/migrations.js.map +1 -1
- package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/assistant-message.js +9 -4
- package/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/dist/modes/interactive/components/config-selector.d.ts +1 -1
- package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/config-selector.js +6 -6
- package/dist/modes/interactive/components/config-selector.js.map +1 -1
- package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/model-selector.js +5 -0
- package/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.js +5 -0
- package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +49 -34
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +0 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +117 -104
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/utils/git.d.ts +21 -1
- package/dist/utils/git.d.ts.map +1 -1
- package/dist/utils/git.js +150 -4
- package/dist/utils/git.js.map +1 -1
- package/docs/extensions.md +5 -0
- package/docs/models.md +40 -1
- package/docs/packages.md +23 -3
- package/docs/prompt-templates.md +6 -6
- package/docs/providers.md +13 -0
- package/docs/rpc.md +1 -1
- package/docs/sdk.md +5 -3
- package/docs/settings.md +2 -2
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/custom-provider-qwen-cli/package.json +1 -1
- package/examples/extensions/hello.ts +1 -1
- package/examples/extensions/subagent/README.md +4 -4
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/examples/sdk/08-prompt-templates.ts +2 -2
- package/package.json +7 -8
- /package/examples/extensions/subagent/{prompts → commands}/implement-and-review.md +0 -0
- /package/examples/extensions/subagent/{prompts → commands}/implement.md +0 -0
- /package/examples/extensions/subagent/{prompts → commands}/scout-and-plan.md +0 -0
package/dist/utils/git.d.ts
CHANGED
|
@@ -1,2 +1,22 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Parsed git URL information.
|
|
3
|
+
*/
|
|
4
|
+
export type GitSource = {
|
|
5
|
+
/** Always "git" for git sources */
|
|
6
|
+
type: "git";
|
|
7
|
+
/** Clone URL (always valid for git clone, without ref suffix) */
|
|
8
|
+
repo: string;
|
|
9
|
+
/** Git host domain (e.g., "github.com") */
|
|
10
|
+
host: string;
|
|
11
|
+
/** Repository path (e.g., "user/repo") */
|
|
12
|
+
path: string;
|
|
13
|
+
/** Git ref (branch, tag, commit) if specified */
|
|
14
|
+
ref?: string;
|
|
15
|
+
/** True if ref was specified (package won't be auto-updated) */
|
|
16
|
+
pinned: boolean;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Parse any git URL (SSH or HTTPS) into a GitSource.
|
|
20
|
+
*/
|
|
21
|
+
export declare function parseGitUrl(source: string): GitSource | null;
|
|
2
22
|
//# sourceMappingURL=git.d.ts.map
|
package/dist/utils/git.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../src/utils/git.ts"],"names":[],"mappings":"AAEA,
|
|
1
|
+
{"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../src/utils/git.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,MAAM,SAAS,GAAG;IACvB,mCAAmC;IACnC,IAAI,EAAE,KAAK,CAAC;IACZ,iEAAiE;IACjE,IAAI,EAAE,MAAM,CAAC;IACb,2CAA2C;IAC3C,IAAI,EAAE,MAAM,CAAC;IACb,0CAA0C;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,iDAAiD;IACjD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,gEAAgE;IAChE,MAAM,EAAE,OAAO,CAAC;CAChB,CAAC;AA2GF;;GAEG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAkD5D","sourcesContent":["import hostedGitInfo from \"hosted-git-info\";\n\n/**\n * Parsed git URL information.\n */\nexport type GitSource = {\n\t/** Always \"git\" for git sources */\n\ttype: \"git\";\n\t/** Clone URL (always valid for git clone, without ref suffix) */\n\trepo: string;\n\t/** Git host domain (e.g., \"github.com\") */\n\thost: string;\n\t/** Repository path (e.g., \"user/repo\") */\n\tpath: string;\n\t/** Git ref (branch, tag, commit) if specified */\n\tref?: string;\n\t/** True if ref was specified (package won't be auto-updated) */\n\tpinned: boolean;\n};\n\nfunction splitRef(url: string): { repo: string; ref?: string } {\n\tconst scpLikeMatch = url.match(/^git@([^:]+):(.+)$/);\n\tif (scpLikeMatch) {\n\t\tconst pathWithMaybeRef = scpLikeMatch[2] ?? \"\";\n\t\tconst refSeparator = pathWithMaybeRef.indexOf(\"@\");\n\t\tif (refSeparator < 0) return { repo: url };\n\t\tconst repoPath = pathWithMaybeRef.slice(0, refSeparator);\n\t\tconst ref = pathWithMaybeRef.slice(refSeparator + 1);\n\t\tif (!repoPath || !ref) return { repo: url };\n\t\treturn {\n\t\t\trepo: `git@${scpLikeMatch[1] ?? \"\"}:${repoPath}`,\n\t\t\tref,\n\t\t};\n\t}\n\n\tif (url.includes(\"://\")) {\n\t\ttry {\n\t\t\tconst parsed = new URL(url);\n\t\t\tconst pathWithMaybeRef = parsed.pathname.replace(/^\\/+/, \"\");\n\t\t\tconst refSeparator = pathWithMaybeRef.indexOf(\"@\");\n\t\t\tif (refSeparator < 0) return { repo: url };\n\t\t\tconst repoPath = pathWithMaybeRef.slice(0, refSeparator);\n\t\t\tconst ref = pathWithMaybeRef.slice(refSeparator + 1);\n\t\t\tif (!repoPath || !ref) return { repo: url };\n\t\t\tparsed.pathname = `/${repoPath}`;\n\t\t\treturn {\n\t\t\t\trepo: parsed.toString().replace(/\\/$/, \"\"),\n\t\t\t\tref,\n\t\t\t};\n\t\t} catch {\n\t\t\treturn { repo: url };\n\t\t}\n\t}\n\n\tconst slashIndex = url.indexOf(\"/\");\n\tif (slashIndex < 0) {\n\t\treturn { repo: url };\n\t}\n\tconst host = url.slice(0, slashIndex);\n\tconst pathWithMaybeRef = url.slice(slashIndex + 1);\n\tconst refSeparator = pathWithMaybeRef.indexOf(\"@\");\n\tif (refSeparator < 0) {\n\t\treturn { repo: url };\n\t}\n\tconst repoPath = pathWithMaybeRef.slice(0, refSeparator);\n\tconst ref = pathWithMaybeRef.slice(refSeparator + 1);\n\tif (!repoPath || !ref) {\n\t\treturn { repo: url };\n\t}\n\treturn {\n\t\trepo: `${host}/${repoPath}`,\n\t\tref,\n\t};\n}\n\nfunction parseGenericGitUrl(url: string): GitSource | null {\n\tconst { repo: repoWithoutRef, ref } = splitRef(url);\n\tlet repo = repoWithoutRef;\n\tlet host = \"\";\n\tlet path = \"\";\n\n\tconst scpLikeMatch = repoWithoutRef.match(/^git@([^:]+):(.+)$/);\n\tif (scpLikeMatch) {\n\t\thost = scpLikeMatch[1] ?? \"\";\n\t\tpath = scpLikeMatch[2] ?? \"\";\n\t} else if (\n\t\trepoWithoutRef.startsWith(\"https://\") ||\n\t\trepoWithoutRef.startsWith(\"http://\") ||\n\t\trepoWithoutRef.startsWith(\"ssh://\")\n\t) {\n\t\ttry {\n\t\t\tconst parsed = new URL(repoWithoutRef);\n\t\t\thost = parsed.hostname;\n\t\t\tpath = parsed.pathname.replace(/^\\/+/, \"\");\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t} else {\n\t\tconst slashIndex = repoWithoutRef.indexOf(\"/\");\n\t\tif (slashIndex < 0) {\n\t\t\treturn null;\n\t\t}\n\t\thost = repoWithoutRef.slice(0, slashIndex);\n\t\tpath = repoWithoutRef.slice(slashIndex + 1);\n\t\tif (!host.includes(\".\") && host !== \"localhost\") {\n\t\t\treturn null;\n\t\t}\n\t\trepo = `https://${repoWithoutRef}`;\n\t}\n\n\tconst normalizedPath = path.replace(/\\.git$/, \"\").replace(/^\\/+/, \"\");\n\tif (!host || !normalizedPath || normalizedPath.split(\"/\").length < 2) {\n\t\treturn null;\n\t}\n\n\treturn {\n\t\ttype: \"git\",\n\t\trepo,\n\t\thost,\n\t\tpath: normalizedPath,\n\t\tref,\n\t\tpinned: Boolean(ref),\n\t};\n}\n\n/**\n * Parse any git URL (SSH or HTTPS) into a GitSource.\n */\nexport function parseGitUrl(source: string): GitSource | null {\n\tconst url = source.startsWith(\"git:\") ? source.slice(4).trim() : source;\n\tconst split = splitRef(url);\n\n\tconst hostedCandidates = [split.ref ? `${split.repo}#${split.ref}` : undefined, url].filter(\n\t\t(value): value is string => Boolean(value),\n\t);\n\tfor (const candidate of hostedCandidates) {\n\t\tconst info = hostedGitInfo.fromUrl(candidate);\n\t\tif (info) {\n\t\t\tif (split.ref && info.project?.includes(\"@\")) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst useHttpsPrefix =\n\t\t\t\t!split.repo.startsWith(\"http://\") &&\n\t\t\t\t!split.repo.startsWith(\"https://\") &&\n\t\t\t\t!split.repo.startsWith(\"ssh://\") &&\n\t\t\t\t!split.repo.startsWith(\"git@\");\n\t\t\treturn {\n\t\t\t\ttype: \"git\",\n\t\t\t\trepo: useHttpsPrefix ? `https://${split.repo}` : split.repo,\n\t\t\t\thost: info.domain || \"\",\n\t\t\t\tpath: `${info.user}/${info.project}`.replace(/\\.git$/, \"\"),\n\t\t\t\tref: info.committish || split.ref || undefined,\n\t\t\t\tpinned: Boolean(info.committish || split.ref),\n\t\t\t};\n\t\t}\n\t}\n\n\tconst httpsCandidates = [split.ref ? `https://${split.repo}#${split.ref}` : undefined, `https://${url}`].filter(\n\t\t(value): value is string => Boolean(value),\n\t);\n\tfor (const candidate of httpsCandidates) {\n\t\tconst info = hostedGitInfo.fromUrl(candidate);\n\t\tif (info) {\n\t\t\tif (split.ref && info.project?.includes(\"@\")) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\treturn {\n\t\t\t\ttype: \"git\",\n\t\t\t\trepo: `https://${split.repo}`,\n\t\t\t\thost: info.domain || \"\",\n\t\t\t\tpath: `${info.user}/${info.project}`.replace(/\\.git$/, \"\"),\n\t\t\t\tref: info.committish || split.ref || undefined,\n\t\t\t\tpinned: Boolean(info.committish || split.ref),\n\t\t\t};\n\t\t}\n\t}\n\n\treturn parseGenericGitUrl(url);\n}\n"]}
|
package/dist/utils/git.js
CHANGED
|
@@ -1,6 +1,152 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const
|
|
4
|
-
|
|
1
|
+
import hostedGitInfo from "hosted-git-info";
|
|
2
|
+
function splitRef(url) {
|
|
3
|
+
const scpLikeMatch = url.match(/^git@([^:]+):(.+)$/);
|
|
4
|
+
if (scpLikeMatch) {
|
|
5
|
+
const pathWithMaybeRef = scpLikeMatch[2] ?? "";
|
|
6
|
+
const refSeparator = pathWithMaybeRef.indexOf("@");
|
|
7
|
+
if (refSeparator < 0)
|
|
8
|
+
return { repo: url };
|
|
9
|
+
const repoPath = pathWithMaybeRef.slice(0, refSeparator);
|
|
10
|
+
const ref = pathWithMaybeRef.slice(refSeparator + 1);
|
|
11
|
+
if (!repoPath || !ref)
|
|
12
|
+
return { repo: url };
|
|
13
|
+
return {
|
|
14
|
+
repo: `git@${scpLikeMatch[1] ?? ""}:${repoPath}`,
|
|
15
|
+
ref,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
if (url.includes("://")) {
|
|
19
|
+
try {
|
|
20
|
+
const parsed = new URL(url);
|
|
21
|
+
const pathWithMaybeRef = parsed.pathname.replace(/^\/+/, "");
|
|
22
|
+
const refSeparator = pathWithMaybeRef.indexOf("@");
|
|
23
|
+
if (refSeparator < 0)
|
|
24
|
+
return { repo: url };
|
|
25
|
+
const repoPath = pathWithMaybeRef.slice(0, refSeparator);
|
|
26
|
+
const ref = pathWithMaybeRef.slice(refSeparator + 1);
|
|
27
|
+
if (!repoPath || !ref)
|
|
28
|
+
return { repo: url };
|
|
29
|
+
parsed.pathname = `/${repoPath}`;
|
|
30
|
+
return {
|
|
31
|
+
repo: parsed.toString().replace(/\/$/, ""),
|
|
32
|
+
ref,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return { repo: url };
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
const slashIndex = url.indexOf("/");
|
|
40
|
+
if (slashIndex < 0) {
|
|
41
|
+
return { repo: url };
|
|
42
|
+
}
|
|
43
|
+
const host = url.slice(0, slashIndex);
|
|
44
|
+
const pathWithMaybeRef = url.slice(slashIndex + 1);
|
|
45
|
+
const refSeparator = pathWithMaybeRef.indexOf("@");
|
|
46
|
+
if (refSeparator < 0) {
|
|
47
|
+
return { repo: url };
|
|
48
|
+
}
|
|
49
|
+
const repoPath = pathWithMaybeRef.slice(0, refSeparator);
|
|
50
|
+
const ref = pathWithMaybeRef.slice(refSeparator + 1);
|
|
51
|
+
if (!repoPath || !ref) {
|
|
52
|
+
return { repo: url };
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
repo: `${host}/${repoPath}`,
|
|
56
|
+
ref,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
function parseGenericGitUrl(url) {
|
|
60
|
+
const { repo: repoWithoutRef, ref } = splitRef(url);
|
|
61
|
+
let repo = repoWithoutRef;
|
|
62
|
+
let host = "";
|
|
63
|
+
let path = "";
|
|
64
|
+
const scpLikeMatch = repoWithoutRef.match(/^git@([^:]+):(.+)$/);
|
|
65
|
+
if (scpLikeMatch) {
|
|
66
|
+
host = scpLikeMatch[1] ?? "";
|
|
67
|
+
path = scpLikeMatch[2] ?? "";
|
|
68
|
+
}
|
|
69
|
+
else if (repoWithoutRef.startsWith("https://") ||
|
|
70
|
+
repoWithoutRef.startsWith("http://") ||
|
|
71
|
+
repoWithoutRef.startsWith("ssh://")) {
|
|
72
|
+
try {
|
|
73
|
+
const parsed = new URL(repoWithoutRef);
|
|
74
|
+
host = parsed.hostname;
|
|
75
|
+
path = parsed.pathname.replace(/^\/+/, "");
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
const slashIndex = repoWithoutRef.indexOf("/");
|
|
83
|
+
if (slashIndex < 0) {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
host = repoWithoutRef.slice(0, slashIndex);
|
|
87
|
+
path = repoWithoutRef.slice(slashIndex + 1);
|
|
88
|
+
if (!host.includes(".") && host !== "localhost") {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
repo = `https://${repoWithoutRef}`;
|
|
92
|
+
}
|
|
93
|
+
const normalizedPath = path.replace(/\.git$/, "").replace(/^\/+/, "");
|
|
94
|
+
if (!host || !normalizedPath || normalizedPath.split("/").length < 2) {
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
type: "git",
|
|
99
|
+
repo,
|
|
100
|
+
host,
|
|
101
|
+
path: normalizedPath,
|
|
102
|
+
ref,
|
|
103
|
+
pinned: Boolean(ref),
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Parse any git URL (SSH or HTTPS) into a GitSource.
|
|
108
|
+
*/
|
|
109
|
+
export function parseGitUrl(source) {
|
|
110
|
+
const url = source.startsWith("git:") ? source.slice(4).trim() : source;
|
|
111
|
+
const split = splitRef(url);
|
|
112
|
+
const hostedCandidates = [split.ref ? `${split.repo}#${split.ref}` : undefined, url].filter((value) => Boolean(value));
|
|
113
|
+
for (const candidate of hostedCandidates) {
|
|
114
|
+
const info = hostedGitInfo.fromUrl(candidate);
|
|
115
|
+
if (info) {
|
|
116
|
+
if (split.ref && info.project?.includes("@")) {
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
const useHttpsPrefix = !split.repo.startsWith("http://") &&
|
|
120
|
+
!split.repo.startsWith("https://") &&
|
|
121
|
+
!split.repo.startsWith("ssh://") &&
|
|
122
|
+
!split.repo.startsWith("git@");
|
|
123
|
+
return {
|
|
124
|
+
type: "git",
|
|
125
|
+
repo: useHttpsPrefix ? `https://${split.repo}` : split.repo,
|
|
126
|
+
host: info.domain || "",
|
|
127
|
+
path: `${info.user}/${info.project}`.replace(/\.git$/, ""),
|
|
128
|
+
ref: info.committish || split.ref || undefined,
|
|
129
|
+
pinned: Boolean(info.committish || split.ref),
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
const httpsCandidates = [split.ref ? `https://${split.repo}#${split.ref}` : undefined, `https://${url}`].filter((value) => Boolean(value));
|
|
134
|
+
for (const candidate of httpsCandidates) {
|
|
135
|
+
const info = hostedGitInfo.fromUrl(candidate);
|
|
136
|
+
if (info) {
|
|
137
|
+
if (split.ref && info.project?.includes("@")) {
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
return {
|
|
141
|
+
type: "git",
|
|
142
|
+
repo: `https://${split.repo}`,
|
|
143
|
+
host: info.domain || "",
|
|
144
|
+
path: `${info.user}/${info.project}`.replace(/\.git$/, ""),
|
|
145
|
+
ref: info.committish || split.ref || undefined,
|
|
146
|
+
pinned: Boolean(info.committish || split.ref),
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return parseGenericGitUrl(url);
|
|
5
151
|
}
|
|
6
152
|
//# sourceMappingURL=git.js.map
|
package/dist/utils/git.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"git.js","sourceRoot":"","sources":["../../src/utils/git.ts"],"names":[],"mappings":"AAAA,MAAM,SAAS,GAAG,CAAC,YAAY,EAAE,YAAY,EAAE,eAAe,EAAE,cAAc,CAAC,CAAC;AAEhF,MAAM,UAAU,eAAe,CAAC,MAAc,EAAW;IACxD,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;IACtD,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC;AAAA,CACnE","sourcesContent":["const GIT_HOSTS = [\"github.com\", \"gitlab.com\", \"bitbucket.org\", \"codeberg.org\"];\n\nexport function looksLikeGitUrl(source: string): boolean {\n\tconst normalized = source.replace(/^https?:\\/\\//, \"\");\n\treturn GIT_HOSTS.some((host) => normalized.startsWith(`${host}/`));\n}\n"]}
|
|
1
|
+
{"version":3,"file":"git.js","sourceRoot":"","sources":["../../src/utils/git.ts"],"names":[],"mappings":"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","sourcesContent":["import hostedGitInfo from \"hosted-git-info\";\n\n/**\n * Parsed git URL information.\n */\nexport type GitSource = {\n\t/** Always \"git\" for git sources */\n\ttype: \"git\";\n\t/** Clone URL (always valid for git clone, without ref suffix) */\n\trepo: string;\n\t/** Git host domain (e.g., \"github.com\") */\n\thost: string;\n\t/** Repository path (e.g., \"user/repo\") */\n\tpath: string;\n\t/** Git ref (branch, tag, commit) if specified */\n\tref?: string;\n\t/** True if ref was specified (package won't be auto-updated) */\n\tpinned: boolean;\n};\n\nfunction splitRef(url: string): { repo: string; ref?: string } {\n\tconst scpLikeMatch = url.match(/^git@([^:]+):(.+)$/);\n\tif (scpLikeMatch) {\n\t\tconst pathWithMaybeRef = scpLikeMatch[2] ?? \"\";\n\t\tconst refSeparator = pathWithMaybeRef.indexOf(\"@\");\n\t\tif (refSeparator < 0) return { repo: url };\n\t\tconst repoPath = pathWithMaybeRef.slice(0, refSeparator);\n\t\tconst ref = pathWithMaybeRef.slice(refSeparator + 1);\n\t\tif (!repoPath || !ref) return { repo: url };\n\t\treturn {\n\t\t\trepo: `git@${scpLikeMatch[1] ?? \"\"}:${repoPath}`,\n\t\t\tref,\n\t\t};\n\t}\n\n\tif (url.includes(\"://\")) {\n\t\ttry {\n\t\t\tconst parsed = new URL(url);\n\t\t\tconst pathWithMaybeRef = parsed.pathname.replace(/^\\/+/, \"\");\n\t\t\tconst refSeparator = pathWithMaybeRef.indexOf(\"@\");\n\t\t\tif (refSeparator < 0) return { repo: url };\n\t\t\tconst repoPath = pathWithMaybeRef.slice(0, refSeparator);\n\t\t\tconst ref = pathWithMaybeRef.slice(refSeparator + 1);\n\t\t\tif (!repoPath || !ref) return { repo: url };\n\t\t\tparsed.pathname = `/${repoPath}`;\n\t\t\treturn {\n\t\t\t\trepo: parsed.toString().replace(/\\/$/, \"\"),\n\t\t\t\tref,\n\t\t\t};\n\t\t} catch {\n\t\t\treturn { repo: url };\n\t\t}\n\t}\n\n\tconst slashIndex = url.indexOf(\"/\");\n\tif (slashIndex < 0) {\n\t\treturn { repo: url };\n\t}\n\tconst host = url.slice(0, slashIndex);\n\tconst pathWithMaybeRef = url.slice(slashIndex + 1);\n\tconst refSeparator = pathWithMaybeRef.indexOf(\"@\");\n\tif (refSeparator < 0) {\n\t\treturn { repo: url };\n\t}\n\tconst repoPath = pathWithMaybeRef.slice(0, refSeparator);\n\tconst ref = pathWithMaybeRef.slice(refSeparator + 1);\n\tif (!repoPath || !ref) {\n\t\treturn { repo: url };\n\t}\n\treturn {\n\t\trepo: `${host}/${repoPath}`,\n\t\tref,\n\t};\n}\n\nfunction parseGenericGitUrl(url: string): GitSource | null {\n\tconst { repo: repoWithoutRef, ref } = splitRef(url);\n\tlet repo = repoWithoutRef;\n\tlet host = \"\";\n\tlet path = \"\";\n\n\tconst scpLikeMatch = repoWithoutRef.match(/^git@([^:]+):(.+)$/);\n\tif (scpLikeMatch) {\n\t\thost = scpLikeMatch[1] ?? \"\";\n\t\tpath = scpLikeMatch[2] ?? \"\";\n\t} else if (\n\t\trepoWithoutRef.startsWith(\"https://\") ||\n\t\trepoWithoutRef.startsWith(\"http://\") ||\n\t\trepoWithoutRef.startsWith(\"ssh://\")\n\t) {\n\t\ttry {\n\t\t\tconst parsed = new URL(repoWithoutRef);\n\t\t\thost = parsed.hostname;\n\t\t\tpath = parsed.pathname.replace(/^\\/+/, \"\");\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t} else {\n\t\tconst slashIndex = repoWithoutRef.indexOf(\"/\");\n\t\tif (slashIndex < 0) {\n\t\t\treturn null;\n\t\t}\n\t\thost = repoWithoutRef.slice(0, slashIndex);\n\t\tpath = repoWithoutRef.slice(slashIndex + 1);\n\t\tif (!host.includes(\".\") && host !== \"localhost\") {\n\t\t\treturn null;\n\t\t}\n\t\trepo = `https://${repoWithoutRef}`;\n\t}\n\n\tconst normalizedPath = path.replace(/\\.git$/, \"\").replace(/^\\/+/, \"\");\n\tif (!host || !normalizedPath || normalizedPath.split(\"/\").length < 2) {\n\t\treturn null;\n\t}\n\n\treturn {\n\t\ttype: \"git\",\n\t\trepo,\n\t\thost,\n\t\tpath: normalizedPath,\n\t\tref,\n\t\tpinned: Boolean(ref),\n\t};\n}\n\n/**\n * Parse any git URL (SSH or HTTPS) into a GitSource.\n */\nexport function parseGitUrl(source: string): GitSource | null {\n\tconst url = source.startsWith(\"git:\") ? source.slice(4).trim() : source;\n\tconst split = splitRef(url);\n\n\tconst hostedCandidates = [split.ref ? `${split.repo}#${split.ref}` : undefined, url].filter(\n\t\t(value): value is string => Boolean(value),\n\t);\n\tfor (const candidate of hostedCandidates) {\n\t\tconst info = hostedGitInfo.fromUrl(candidate);\n\t\tif (info) {\n\t\t\tif (split.ref && info.project?.includes(\"@\")) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst useHttpsPrefix =\n\t\t\t\t!split.repo.startsWith(\"http://\") &&\n\t\t\t\t!split.repo.startsWith(\"https://\") &&\n\t\t\t\t!split.repo.startsWith(\"ssh://\") &&\n\t\t\t\t!split.repo.startsWith(\"git@\");\n\t\t\treturn {\n\t\t\t\ttype: \"git\",\n\t\t\t\trepo: useHttpsPrefix ? `https://${split.repo}` : split.repo,\n\t\t\t\thost: info.domain || \"\",\n\t\t\t\tpath: `${info.user}/${info.project}`.replace(/\\.git$/, \"\"),\n\t\t\t\tref: info.committish || split.ref || undefined,\n\t\t\t\tpinned: Boolean(info.committish || split.ref),\n\t\t\t};\n\t\t}\n\t}\n\n\tconst httpsCandidates = [split.ref ? `https://${split.repo}#${split.ref}` : undefined, `https://${url}`].filter(\n\t\t(value): value is string => Boolean(value),\n\t);\n\tfor (const candidate of httpsCandidates) {\n\t\tconst info = hostedGitInfo.fromUrl(candidate);\n\t\tif (info) {\n\t\t\tif (split.ref && info.project?.includes(\"@\")) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\treturn {\n\t\t\t\ttype: \"git\",\n\t\t\t\trepo: `https://${split.repo}`,\n\t\t\t\thost: info.domain || \"\",\n\t\t\t\tpath: `${info.user}/${info.project}`.replace(/\\.git$/, \"\"),\n\t\t\t\tref: info.committish || split.ref || undefined,\n\t\t\t\tpinned: Boolean(info.committish || split.ref),\n\t\t\t};\n\t\t}\n\t}\n\n\treturn parseGenericGitUrl(url);\n}\n"]}
|
package/docs/extensions.md
CHANGED
|
@@ -524,6 +524,11 @@ pi.on("tool_call", (event) => {
|
|
|
524
524
|
|
|
525
525
|
Fired after tool executes. **Can modify result.**
|
|
526
526
|
|
|
527
|
+
`tool_result` handlers chain like middleware:
|
|
528
|
+
- Handlers run in extension load order
|
|
529
|
+
- Each handler sees the latest result after previous handler changes
|
|
530
|
+
- Handlers can return partial patches (`content`, `details`, or `isError`); omitted fields keep their current values
|
|
531
|
+
|
|
527
532
|
```typescript
|
|
528
533
|
import { isBashToolResult } from "@mariozechner/pi-coding-agent";
|
|
529
534
|
|
package/docs/models.md
CHANGED
|
@@ -10,6 +10,7 @@ Add custom providers and models (Ollama, vLLM, LM Studio, proxies) via `~/.pi/ag
|
|
|
10
10
|
- [Provider Configuration](#provider-configuration)
|
|
11
11
|
- [Model Configuration](#model-configuration)
|
|
12
12
|
- [Overriding Built-in Providers](#overriding-built-in-providers)
|
|
13
|
+
- [Per-model Overrides](#per-model-overrides)
|
|
13
14
|
- [OpenAI Compatibility](#openai-compatibility)
|
|
14
15
|
|
|
15
16
|
## Minimal Example
|
|
@@ -84,6 +85,7 @@ Set `api` at provider level (default for all models) or model level (override pe
|
|
|
84
85
|
| `headers` | Custom headers (see value resolution below) |
|
|
85
86
|
| `authHeader` | Set `true` to add `Authorization: Bearer <apiKey>` automatically |
|
|
86
87
|
| `models` | Array of model configurations |
|
|
88
|
+
| `modelOverrides` | Per-model overrides for built-in models on this provider |
|
|
87
89
|
|
|
88
90
|
### Value Resolution
|
|
89
91
|
|
|
@@ -151,7 +153,7 @@ Route a built-in provider through a proxy without redefining models:
|
|
|
151
153
|
|
|
152
154
|
All built-in Anthropic models remain available. Existing OAuth or API key auth continues to work.
|
|
153
155
|
|
|
154
|
-
To
|
|
156
|
+
To merge custom models into a built-in provider, include the `models` array:
|
|
155
157
|
|
|
156
158
|
```json
|
|
157
159
|
{
|
|
@@ -166,6 +168,43 @@ To fully replace a built-in provider with custom models, include the `models` ar
|
|
|
166
168
|
}
|
|
167
169
|
```
|
|
168
170
|
|
|
171
|
+
Merge semantics:
|
|
172
|
+
- Built-in models are kept.
|
|
173
|
+
- Custom models are upserted by `id` within the provider.
|
|
174
|
+
- If a custom model `id` matches a built-in model `id`, the custom model replaces that built-in model.
|
|
175
|
+
- If a custom model `id` is new, it is added alongside built-in models.
|
|
176
|
+
|
|
177
|
+
## Per-model Overrides
|
|
178
|
+
|
|
179
|
+
Use `modelOverrides` to customize specific built-in models without replacing the provider's full model list.
|
|
180
|
+
|
|
181
|
+
```json
|
|
182
|
+
{
|
|
183
|
+
"providers": {
|
|
184
|
+
"openrouter": {
|
|
185
|
+
"modelOverrides": {
|
|
186
|
+
"anthropic/claude-sonnet-4": {
|
|
187
|
+
"name": "Claude Sonnet 4 (Bedrock Route)",
|
|
188
|
+
"compat": {
|
|
189
|
+
"openRouterRouting": {
|
|
190
|
+
"only": ["amazon-bedrock"]
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
`modelOverrides` supports these fields per model: `name`, `reasoning`, `input`, `cost` (partial), `contextWindow`, `maxTokens`, `headers`, `compat`.
|
|
201
|
+
|
|
202
|
+
Behavior notes:
|
|
203
|
+
- `modelOverrides` are applied to built-in provider models.
|
|
204
|
+
- Unknown model IDs are ignored.
|
|
205
|
+
- You can combine provider-level `baseUrl`/`headers` with `modelOverrides`.
|
|
206
|
+
- If `models` is also defined for a provider, custom models are merged after built-in overrides. A custom model with the same `id` replaces the overridden built-in model entry.
|
|
207
|
+
|
|
169
208
|
## OpenAI Compatibility
|
|
170
209
|
|
|
171
210
|
For providers with partial OpenAI compatibility, use the `compat` field:
|
package/docs/packages.md
CHANGED
|
@@ -60,13 +60,33 @@ npm:pkg
|
|
|
60
60
|
```
|
|
61
61
|
git:github.com/user/repo@v1
|
|
62
62
|
https://github.com/user/repo@v1
|
|
63
|
+
git@github.com:user/repo@v1
|
|
64
|
+
ssh://git@github.com/user/repo@v1
|
|
63
65
|
```
|
|
64
66
|
|
|
67
|
+
- HTTPS and SSH URLs are both supported.
|
|
68
|
+
- SSH URLs use your configured SSH keys automatically (respects `~/.ssh/config`).
|
|
69
|
+
- For non-interactive runs (for example CI), you can set `GIT_TERMINAL_PROMPT=0` to disable credential prompts and set `GIT_SSH_COMMAND` (for example `ssh -o BatchMode=yes -o ConnectTimeout=5`) to fail fast.
|
|
65
70
|
- Raw `https://` URLs work without the `git:` prefix.
|
|
66
71
|
- Refs pin the package and skip `pi update`.
|
|
67
72
|
- Cloned to `~/.pi/agent/git/<host>/<path>` (global) or `.pi/git/<host>/<path>` (project).
|
|
68
73
|
- Runs `npm install` after clone or pull if `package.json` exists.
|
|
69
74
|
|
|
75
|
+
**SSH examples:**
|
|
76
|
+
```bash
|
|
77
|
+
# Standard git@host:path format
|
|
78
|
+
pi install git@github.com:user/repo
|
|
79
|
+
|
|
80
|
+
# With git: prefix
|
|
81
|
+
pi install git:git@github.com:user/repo
|
|
82
|
+
|
|
83
|
+
# ssh:// protocol format
|
|
84
|
+
pi install ssh://git@github.com/user/repo
|
|
85
|
+
|
|
86
|
+
# With version ref
|
|
87
|
+
pi install git@github.com:user/repo@v1.0.0
|
|
88
|
+
```
|
|
89
|
+
|
|
70
90
|
### Local Paths
|
|
71
91
|
|
|
72
92
|
```
|
|
@@ -87,7 +107,7 @@ Add a `pi` manifest to `package.json` or use conventional directories. Include t
|
|
|
87
107
|
"pi": {
|
|
88
108
|
"extensions": ["./extensions"],
|
|
89
109
|
"skills": ["./skills"],
|
|
90
|
-
"
|
|
110
|
+
"commands": ["./commands"],
|
|
91
111
|
"themes": ["./themes"]
|
|
92
112
|
}
|
|
93
113
|
}
|
|
@@ -124,7 +144,7 @@ If no `pi` manifest is present, pi auto-discovers resources from these directori
|
|
|
124
144
|
|
|
125
145
|
- `extensions/` loads `.ts` and `.js` files
|
|
126
146
|
- `skills/` recursively finds `SKILL.md` folders and loads top-level `.md` files as skills
|
|
127
|
-
- `
|
|
147
|
+
- `commands/` loads `.md` files
|
|
128
148
|
- `themes/` loads `.json` files
|
|
129
149
|
|
|
130
150
|
## Dependencies
|
|
@@ -162,7 +182,7 @@ Filter what a package loads using the object form in settings:
|
|
|
162
182
|
"source": "npm:my-package",
|
|
163
183
|
"extensions": ["extensions/*.ts", "!extensions/legacy.ts"],
|
|
164
184
|
"skills": [],
|
|
165
|
-
"
|
|
185
|
+
"commands": ["commands/review.md"],
|
|
166
186
|
"themes": ["+themes/legacy.json"]
|
|
167
187
|
}
|
|
168
188
|
]
|
package/docs/prompt-templates.md
CHANGED
|
@@ -8,10 +8,10 @@ Prompt templates are Markdown snippets that expand into full prompts. Type `/nam
|
|
|
8
8
|
|
|
9
9
|
Pi loads prompt templates from:
|
|
10
10
|
|
|
11
|
-
- Global: `~/.pi/agent/
|
|
12
|
-
- Project: `.pi/
|
|
13
|
-
- Packages: `
|
|
14
|
-
- Settings: `
|
|
11
|
+
- Global: `~/.pi/agent/commands/*.md`
|
|
12
|
+
- Project: `.pi/commands/*.md`
|
|
13
|
+
- Packages: `commands/` directories or `pi.commands` entries in `package.json`
|
|
14
|
+
- Settings: `commands` array with files or directories
|
|
15
15
|
- CLI: `--prompt-template <path>` (repeatable)
|
|
16
16
|
|
|
17
17
|
Disable discovery with `--no-prompt-templates`.
|
|
@@ -63,5 +63,5 @@ Usage: `/component Button "onClick handler" "disabled support"`
|
|
|
63
63
|
|
|
64
64
|
## Loading Rules
|
|
65
65
|
|
|
66
|
-
- Template discovery in `
|
|
67
|
-
- If you want templates in subdirectories, add them explicitly via `
|
|
66
|
+
- Template discovery in `commands/` is non-recursive.
|
|
67
|
+
- If you want templates in subdirectories, add them explicitly via `commands` settings or a package manifest.
|
package/docs/providers.md
CHANGED
|
@@ -140,6 +140,19 @@ Also supports ECS task roles (`AWS_CONTAINER_CREDENTIALS_*`) and IRSA (`AWS_WEB_
|
|
|
140
140
|
pi --provider amazon-bedrock --model us.anthropic.claude-sonnet-4-20250514-v1:0
|
|
141
141
|
```
|
|
142
142
|
|
|
143
|
+
If you are connecting to a Bedrock API proxy, the following environment variables can be used:
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
# Set the URL for the Bedrock proxy (standard AWS SDK env var)
|
|
147
|
+
export AWS_ENDPOINT_URL_BEDROCK_RUNTIME=https://my.corp.proxy/bedrock
|
|
148
|
+
|
|
149
|
+
# Set if your proxy does not require authentication
|
|
150
|
+
export AWS_BEDROCK_SKIP_AUTH=1
|
|
151
|
+
|
|
152
|
+
# Set if your proxy only supports HTTP/1.1
|
|
153
|
+
export AWS_BEDROCK_FORCE_HTTP1=1
|
|
154
|
+
```
|
|
155
|
+
|
|
143
156
|
### Google Vertex AI
|
|
144
157
|
|
|
145
158
|
Uses Application Default Credentials:
|
package/docs/rpc.md
CHANGED
|
@@ -665,7 +665,7 @@ Response:
|
|
|
665
665
|
"data": {
|
|
666
666
|
"commands": [
|
|
667
667
|
{"name": "session-name", "description": "Set or clear session name", "source": "extension", "path": "/home/user/.pi/agent/extensions/session.ts"},
|
|
668
|
-
{"name": "fix-tests", "description": "Fix failing tests", "source": "prompt", "location": "project", "path": "/home/user/myproject/.pi/agent/
|
|
668
|
+
{"name": "fix-tests", "description": "Fix failing tests", "source": "prompt", "location": "project", "path": "/home/user/myproject/.pi/agent/commands/fix-tests.md"},
|
|
669
669
|
{"name": "skill:brave-search", "description": "Web search via Brave API", "source": "skill", "location": "user", "path": "/home/user/.pi/agent/skills/brave-search/SKILL.md"}
|
|
670
670
|
]
|
|
671
671
|
}
|
package/docs/sdk.md
CHANGED
|
@@ -259,14 +259,14 @@ const { session } = await createAgentSession({
|
|
|
259
259
|
`cwd` is used by `DefaultResourceLoader` for:
|
|
260
260
|
- Project extensions (`.pi/extensions/`)
|
|
261
261
|
- Project skills (`.pi/skills/`)
|
|
262
|
-
- Project prompts (`.pi/
|
|
262
|
+
- Project prompts (`.pi/commands/`)
|
|
263
263
|
- Context files (`AGENTS.md` walking up from cwd)
|
|
264
264
|
- Session directory naming
|
|
265
265
|
|
|
266
266
|
`agentDir` is used by `DefaultResourceLoader` for:
|
|
267
267
|
- Global extensions (`extensions/`)
|
|
268
268
|
- Global skills (`skills/`)
|
|
269
|
-
- Global prompts (`
|
|
269
|
+
- Global prompts (`commands/`)
|
|
270
270
|
- Global context file (`AGENTS.md`)
|
|
271
271
|
- Settings (`settings.json`)
|
|
272
272
|
- Custom models (`models.json`)
|
|
@@ -580,6 +580,8 @@ const loader = new DefaultResourceLoader({
|
|
|
580
580
|
});
|
|
581
581
|
await loader.reload();
|
|
582
582
|
|
|
583
|
+
const { session } = await createAgentSession({ resourceLoader: loader });
|
|
584
|
+
|
|
583
585
|
const { session } = await createAgentSession({ resourceLoader: loader });
|
|
584
586
|
```
|
|
585
587
|
|
|
@@ -704,7 +706,7 @@ Project overrides global. Nested objects merge keys. Setters modify global setti
|
|
|
704
706
|
|
|
705
707
|
## ResourceLoader
|
|
706
708
|
|
|
707
|
-
Use `DefaultResourceLoader` to discover extensions, skills,
|
|
709
|
+
Use `DefaultResourceLoader` to discover extensions, skills, commands, themes, and context files.
|
|
708
710
|
|
|
709
711
|
```typescript
|
|
710
712
|
import {
|
package/docs/settings.md
CHANGED
|
@@ -134,7 +134,7 @@ When a provider requests a retry delay longer than `maxDelayMs` (e.g., Google's
|
|
|
134
134
|
|
|
135
135
|
### Resources
|
|
136
136
|
|
|
137
|
-
These settings define where to load extensions, skills,
|
|
137
|
+
These settings define where to load extensions, skills, commands, and themes from.
|
|
138
138
|
|
|
139
139
|
Paths in `~/.pi/agent/settings.json` resolve relative to `~/.pi/agent`. Paths in `.pi/settings.json` resolve relative to `.pi`. Absolute paths and `~` are supported.
|
|
140
140
|
|
|
@@ -143,7 +143,7 @@ Paths in `~/.pi/agent/settings.json` resolve relative to `~/.pi/agent`. Paths in
|
|
|
143
143
|
| `packages` | array | `[]` | npm/git packages to load resources from |
|
|
144
144
|
| `extensions` | string[] | `[]` | Local extension file paths or directories |
|
|
145
145
|
| `skills` | string[] | `[]` | Local skill file paths or directories |
|
|
146
|
-
| `
|
|
146
|
+
| `commands` | string[] | `[]` | Local command template paths or directories |
|
|
147
147
|
| `themes` | string[] | `[]` | Local theme file paths or directories |
|
|
148
148
|
| `enableSkillCommands` | boolean | `true` | Register skills as `/skill:name` commands |
|
|
149
149
|
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-extension-custom-provider",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.7",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "pi-extension-custom-provider",
|
|
9
|
-
"version": "1.
|
|
9
|
+
"version": "1.3.7",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"@anthropic-ai/sdk": "^0.52.0"
|
|
12
12
|
}
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* Hello Tool - Minimal custom tool example
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
+
import { Type } from "@mariozechner/pi-ai";
|
|
5
6
|
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
6
|
-
import { Type } from "@sinclair/typebox";
|
|
7
7
|
|
|
8
8
|
export default function (pi: ExtensionAPI) {
|
|
9
9
|
pi.registerTool({
|
|
@@ -23,7 +23,7 @@ subagent/
|
|
|
23
23
|
│ ├── planner.md # Creates implementation plans
|
|
24
24
|
│ ├── reviewer.md # Code review
|
|
25
25
|
│ └── worker.md # General-purpose (full capabilities)
|
|
26
|
-
└──
|
|
26
|
+
└── commands/ # Workflow presets (prompt templates)
|
|
27
27
|
├── implement.md # scout -> planner -> worker
|
|
28
28
|
├── scout-and-plan.md # scout -> planner (no implementation)
|
|
29
29
|
└── implement-and-review.md # worker -> reviewer -> worker
|
|
@@ -46,9 +46,9 @@ for f in packages/coding-agent/examples/extensions/subagent/agents/*.md; do
|
|
|
46
46
|
done
|
|
47
47
|
|
|
48
48
|
# Symlink workflow prompts
|
|
49
|
-
mkdir -p ~/.pi/agent/
|
|
50
|
-
for f in packages/coding-agent/examples/extensions/subagent/
|
|
51
|
-
ln -sf "$(pwd)/$f" ~/.pi/agent/
|
|
49
|
+
mkdir -p ~/.pi/agent/commands
|
|
50
|
+
for f in packages/coding-agent/examples/extensions/subagent/commands/*.md; do
|
|
51
|
+
ln -sf "$(pwd)/$f" ~/.pi/agent/commands/$(basename "$f")
|
|
52
52
|
done
|
|
53
53
|
```
|
|
54
54
|
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-extension-with-deps",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.16.7",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "pi-extension-with-deps",
|
|
9
|
-
"version": "1.
|
|
9
|
+
"version": "1.16.7",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"ms": "^2.1.3"
|
|
12
12
|
},
|
|
@@ -16,7 +16,7 @@ const deployTemplate: PromptTemplate = {
|
|
|
16
16
|
name: "deploy",
|
|
17
17
|
description: "Deploy the application",
|
|
18
18
|
source: "path",
|
|
19
|
-
filePath: "/virtual/
|
|
19
|
+
filePath: "/virtual/commands/deploy.md",
|
|
20
20
|
content: `# Deploy Instructions
|
|
21
21
|
|
|
22
22
|
1. Build: npm run build
|
|
@@ -32,7 +32,7 @@ const loader = new DefaultResourceLoader({
|
|
|
32
32
|
});
|
|
33
33
|
await loader.reload();
|
|
34
34
|
|
|
35
|
-
// Discover templates from cwd/.pi/
|
|
35
|
+
// Discover templates from cwd/.pi/commands/ and ~/.pi/agent/commands/
|
|
36
36
|
const discovered = loader.getPrompts().prompts;
|
|
37
37
|
console.log("Discovered prompt templates:");
|
|
38
38
|
for (const template of discovered) {
|