pi-forge 0.0.0 → 1.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +48 -4
- package/bin/pi-forge.mjs +37 -0
- package/dist/client/assets/CodeMirrorEditor-BqaaP1EE.js +34 -0
- package/dist/client/assets/CodeMirrorEditor-BqaaP1EE.js.map +1 -0
- package/dist/client/assets/index-B-529kgJ.css +32 -0
- package/dist/client/assets/index-BzKzxXFs.js +392 -0
- package/dist/client/assets/index-BzKzxXFs.js.map +1 -0
- package/dist/client/assets/workbox-window.prod.es5-BBnX5xw4.js +3 -0
- package/dist/client/assets/workbox-window.prod.es5-BBnX5xw4.js.map +1 -0
- package/dist/client/icons/icon-192.png +0 -0
- package/dist/client/icons/icon-512.png +0 -0
- package/dist/client/icons/icon-maskable-512.png +0 -0
- package/dist/client/icons/icon.svg +9 -0
- package/dist/client/index.html +24 -0
- package/dist/client/manifest.webmanifest +1 -0
- package/dist/client/offline.html +142 -0
- package/dist/client/sw.js +3 -0
- package/dist/client/sw.js.map +1 -0
- package/dist/client/workbox-6d7155ed.js +3 -0
- package/dist/client/workbox-6d7155ed.js.map +1 -0
- package/dist/server/agent-resource-loader.js +126 -0
- package/dist/server/agent-resource-loader.js.map +1 -0
- package/dist/server/attachment-converters.js +96 -0
- package/dist/server/attachment-converters.js.map +1 -0
- package/dist/server/auth.js +209 -0
- package/dist/server/auth.js.map +1 -0
- package/dist/server/compaction-history.js +106 -0
- package/dist/server/compaction-history.js.map +1 -0
- package/dist/server/concurrency.js +49 -0
- package/dist/server/concurrency.js.map +1 -0
- package/dist/server/config-export.js +220 -0
- package/dist/server/config-export.js.map +1 -0
- package/dist/server/config-manager.js +528 -0
- package/dist/server/config-manager.js.map +1 -0
- package/dist/server/config.js +326 -0
- package/dist/server/config.js.map +1 -0
- package/dist/server/conversion-worker.mjs +90 -0
- package/dist/server/diagnostics.js +137 -0
- package/dist/server/diagnostics.js.map +1 -0
- package/dist/server/extensions-discovery.js +147 -0
- package/dist/server/extensions-discovery.js.map +1 -0
- package/dist/server/file-manager.js +734 -0
- package/dist/server/file-manager.js.map +1 -0
- package/dist/server/file-references.js +215 -0
- package/dist/server/file-references.js.map +1 -0
- package/dist/server/file-searcher.js +385 -0
- package/dist/server/file-searcher.js.map +1 -0
- package/dist/server/git-runner.js +684 -0
- package/dist/server/git-runner.js.map +1 -0
- package/dist/server/index.js +468 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/mcp/config.js +133 -0
- package/dist/server/mcp/config.js.map +1 -0
- package/dist/server/mcp/manager.js +351 -0
- package/dist/server/mcp/manager.js.map +1 -0
- package/dist/server/mcp/tool-bridge.js +173 -0
- package/dist/server/mcp/tool-bridge.js.map +1 -0
- package/dist/server/project-manager.js +301 -0
- package/dist/server/project-manager.js.map +1 -0
- package/dist/server/pty-manager.js +354 -0
- package/dist/server/pty-manager.js.map +1 -0
- package/dist/server/routes/_schemas.js +73 -0
- package/dist/server/routes/_schemas.js.map +1 -0
- package/dist/server/routes/auth.js +164 -0
- package/dist/server/routes/auth.js.map +1 -0
- package/dist/server/routes/config.js +1163 -0
- package/dist/server/routes/config.js.map +1 -0
- package/dist/server/routes/control.js +464 -0
- package/dist/server/routes/control.js.map +1 -0
- package/dist/server/routes/exec.js +217 -0
- package/dist/server/routes/exec.js.map +1 -0
- package/dist/server/routes/files.js +847 -0
- package/dist/server/routes/files.js.map +1 -0
- package/dist/server/routes/git.js +837 -0
- package/dist/server/routes/git.js.map +1 -0
- package/dist/server/routes/health.js +97 -0
- package/dist/server/routes/health.js.map +1 -0
- package/dist/server/routes/mcp.js +300 -0
- package/dist/server/routes/mcp.js.map +1 -0
- package/dist/server/routes/projects.js +259 -0
- package/dist/server/routes/projects.js.map +1 -0
- package/dist/server/routes/prompt.js +496 -0
- package/dist/server/routes/prompt.js.map +1 -0
- package/dist/server/routes/sessions.js +783 -0
- package/dist/server/routes/sessions.js.map +1 -0
- package/dist/server/routes/stream.js +69 -0
- package/dist/server/routes/stream.js.map +1 -0
- package/dist/server/routes/terminal.js +335 -0
- package/dist/server/routes/terminal.js.map +1 -0
- package/dist/server/session-registry.js +1197 -0
- package/dist/server/session-registry.js.map +1 -0
- package/dist/server/skill-overrides.js +151 -0
- package/dist/server/skill-overrides.js.map +1 -0
- package/dist/server/skills-export.js +257 -0
- package/dist/server/skills-export.js.map +1 -0
- package/dist/server/sse-bridge.js +220 -0
- package/dist/server/sse-bridge.js.map +1 -0
- package/dist/server/tool-overrides.js +277 -0
- package/dist/server/tool-overrides.js.map +1 -0
- package/dist/server/turn-diff-builder.js +280 -0
- package/dist/server/turn-diff-builder.js.map +1 -0
- package/package.json +53 -12
|
@@ -0,0 +1,528 @@
|
|
|
1
|
+
import { mkdir, readFile, rename, unlink, writeFile } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { randomUUID } from "node:crypto";
|
|
4
|
+
import { AuthStorage, ModelRegistry, loadSkills } from "@mariozechner/pi-coding-agent";
|
|
5
|
+
import { config } from "./config.js";
|
|
6
|
+
import { makeLock } from "./concurrency.js";
|
|
7
|
+
import { discoverExtensionResources } from "./extensions-discovery.js";
|
|
8
|
+
import { getProjectSkillState, readSkillOverrides, setProjectSkillOverride, } from "./skill-overrides.js";
|
|
9
|
+
const MODELS_FILE = () => join(config.piConfigDir, "models.json");
|
|
10
|
+
const AUTH_FILE = () => join(config.piConfigDir, "auth.json");
|
|
11
|
+
const SETTINGS_FILE = () => join(config.piConfigDir, "settings.json");
|
|
12
|
+
async function ensureConfigDir() {
|
|
13
|
+
await mkdir(config.piConfigDir, { recursive: true });
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Keys we refuse to allow user-supplied input to set on any JSON-shaped
|
|
17
|
+
* config blob. Without filtering, a request body like
|
|
18
|
+
* `{"__proto__": {"polluted": true}}` flows through `JSON.parse` (where
|
|
19
|
+
* Node decodes `__proto__` as an own data property — safe) and then
|
|
20
|
+
* through a property-write somewhere downstream that *does* hit the
|
|
21
|
+
* prototype chain — corrupting `Object.prototype` process-wide.
|
|
22
|
+
*
|
|
23
|
+
* We filter at every JSON-write boundary as defense in depth, not just
|
|
24
|
+
* at the one route the original audit caught.
|
|
25
|
+
*/
|
|
26
|
+
const DANGEROUS_KEYS = new Set(["__proto__", "prototype", "constructor"]);
|
|
27
|
+
/**
|
|
28
|
+
* Recursively strip dangerous keys from a value before persisting. Used
|
|
29
|
+
* by `writeModelsJson` and any other path that round-trips
|
|
30
|
+
* user-supplied JSON to disk.
|
|
31
|
+
*/
|
|
32
|
+
function stripDangerousKeys(input) {
|
|
33
|
+
if (Array.isArray(input)) {
|
|
34
|
+
return input.map((v) => stripDangerousKeys(v));
|
|
35
|
+
}
|
|
36
|
+
if (typeof input !== "object" || input === null)
|
|
37
|
+
return input;
|
|
38
|
+
const cleaned = {};
|
|
39
|
+
for (const [k, v] of Object.entries(input)) {
|
|
40
|
+
if (DANGEROUS_KEYS.has(k))
|
|
41
|
+
continue;
|
|
42
|
+
Object.defineProperty(cleaned, k, {
|
|
43
|
+
value: stripDangerousKeys(v),
|
|
44
|
+
enumerable: true,
|
|
45
|
+
writable: true,
|
|
46
|
+
configurable: true,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
return cleaned;
|
|
50
|
+
}
|
|
51
|
+
async function atomicWriteJson(path, data) {
|
|
52
|
+
await ensureConfigDir();
|
|
53
|
+
const tmp = `${path}.${randomUUID()}.tmp`;
|
|
54
|
+
await writeFile(tmp, JSON.stringify(data, null, 2), "utf8");
|
|
55
|
+
try {
|
|
56
|
+
await rename(tmp, path);
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
// Cross-fs rename, perms, source vanished — clean up the leftover
|
|
60
|
+
// tmp file before rethrowing. Without this, repeated failures would
|
|
61
|
+
// leave `<path>.<uuid>.tmp` files accumulating in the config dir.
|
|
62
|
+
await unlink(tmp).catch(() => undefined);
|
|
63
|
+
throw err;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
async function readJsonOr(path, fallback) {
|
|
67
|
+
try {
|
|
68
|
+
const raw = await readFile(path, "utf8");
|
|
69
|
+
if (raw.trim().length === 0)
|
|
70
|
+
return fallback;
|
|
71
|
+
return JSON.parse(raw);
|
|
72
|
+
}
|
|
73
|
+
catch (err) {
|
|
74
|
+
if (err.code === "ENOENT")
|
|
75
|
+
return fallback;
|
|
76
|
+
throw err;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// ---------------------------------------------------------------------------
|
|
80
|
+
// models.json
|
|
81
|
+
export async function readModelsJson() {
|
|
82
|
+
const data = await readJsonOr(MODELS_FILE(), { providers: {} });
|
|
83
|
+
if (typeof data !== "object" || data === null || !("providers" in data)) {
|
|
84
|
+
return { providers: {} };
|
|
85
|
+
}
|
|
86
|
+
const r = data;
|
|
87
|
+
if (typeof r.providers !== "object" || r.providers === null) {
|
|
88
|
+
return { providers: {} };
|
|
89
|
+
}
|
|
90
|
+
return { providers: r.providers };
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Like readModelsJson but with secret-shaped fields replaced with a literal
|
|
94
|
+
* sentinel. Used by the GET /config/models route so an inline `apiKey` in
|
|
95
|
+
* models.json (the pi SDK accepts both inline keys and `apiKeyCommand`) is
|
|
96
|
+
* never echoed back to a browser or to an operator's log shipper.
|
|
97
|
+
*
|
|
98
|
+
* The persisted file is unchanged — writeModelsJson takes the actual
|
|
99
|
+
* shape; this redaction is purely on the read path.
|
|
100
|
+
*/
|
|
101
|
+
const SECRET_PLACEHOLDER = "***REDACTED***";
|
|
102
|
+
export async function readModelsJsonRedacted() {
|
|
103
|
+
const raw = await readModelsJson();
|
|
104
|
+
const out = {};
|
|
105
|
+
for (const [name, provider] of Object.entries(raw.providers)) {
|
|
106
|
+
out[name] = redactProviderConfig(provider);
|
|
107
|
+
}
|
|
108
|
+
return { providers: out };
|
|
109
|
+
}
|
|
110
|
+
function redactProviderConfig(p) {
|
|
111
|
+
const { apiKey, apiKeyCommand, ...rest } = p;
|
|
112
|
+
const redacted = { ...rest };
|
|
113
|
+
if (apiKey !== undefined)
|
|
114
|
+
redacted.apiKey = SECRET_PLACEHOLDER;
|
|
115
|
+
if (apiKeyCommand !== undefined)
|
|
116
|
+
redacted.apiKeyCommand = SECRET_PLACEHOLDER;
|
|
117
|
+
return redacted;
|
|
118
|
+
}
|
|
119
|
+
export async function writeModelsJson(data) {
|
|
120
|
+
// Round-trip secret protection: GET /config/models redacts inline
|
|
121
|
+
// `apiKey` / `apiKeyCommand` to a sentinel string. If the editor
|
|
122
|
+
// PUTs the body back unchanged, the literal sentinel would
|
|
123
|
+
// overwrite the real secret on disk and the next request would go
|
|
124
|
+
// out with `Authorization: Bearer ***REDACTED***`. Pre-merge here
|
|
125
|
+
// so the sentinel means "keep the existing value" — same semantics
|
|
126
|
+
// auth.json already uses for its presence-only API.
|
|
127
|
+
const existing = await readModelsJson().catch(() => ({ providers: {} }));
|
|
128
|
+
const safe = { providers: {} };
|
|
129
|
+
for (const [name, provider] of Object.entries(data.providers ?? {})) {
|
|
130
|
+
if (DANGEROUS_KEYS.has(name))
|
|
131
|
+
continue;
|
|
132
|
+
const cleaned = stripDangerousKeys(provider);
|
|
133
|
+
const prior = existing.providers[name];
|
|
134
|
+
if (cleaned.apiKey === SECRET_PLACEHOLDER) {
|
|
135
|
+
if (prior?.apiKey !== undefined)
|
|
136
|
+
cleaned.apiKey = prior.apiKey;
|
|
137
|
+
else
|
|
138
|
+
delete cleaned.apiKey;
|
|
139
|
+
}
|
|
140
|
+
if (cleaned.apiKeyCommand === SECRET_PLACEHOLDER) {
|
|
141
|
+
if (prior?.apiKeyCommand !== undefined)
|
|
142
|
+
cleaned.apiKeyCommand = prior.apiKeyCommand;
|
|
143
|
+
else
|
|
144
|
+
delete cleaned.apiKeyCommand;
|
|
145
|
+
}
|
|
146
|
+
safe.providers[name] = cleaned;
|
|
147
|
+
}
|
|
148
|
+
await atomicWriteJson(MODELS_FILE(), safe);
|
|
149
|
+
}
|
|
150
|
+
// ---------------------------------------------------------------------------
|
|
151
|
+
// auth.json — uses the SDK's AuthStorage for locking + presence semantics.
|
|
152
|
+
function authStorage() {
|
|
153
|
+
return AuthStorage.create(AUTH_FILE());
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Build a fresh ModelRegistry seeded with the on-disk auth + models.json.
|
|
157
|
+
* Exposed so route handlers can resolve a provider+modelId pair to a typed
|
|
158
|
+
* Model<Api> WITHOUT going through pi-ai's static `getModel`, which only
|
|
159
|
+
* knows built-in providers and silently returns undefined for anything
|
|
160
|
+
* defined in models.json.
|
|
161
|
+
*/
|
|
162
|
+
export function liveModelRegistry() {
|
|
163
|
+
return ModelRegistry.create(authStorage(), MODELS_FILE());
|
|
164
|
+
}
|
|
165
|
+
export function readAuthSummary() {
|
|
166
|
+
const store = authStorage();
|
|
167
|
+
const providers = {};
|
|
168
|
+
// `list()` enumerates providers stored in auth.json. Augment each with the
|
|
169
|
+
// typed `getAuthStatus` shape so the response surface matches what the UI
|
|
170
|
+
// would render (configured + source + label, no key value).
|
|
171
|
+
for (const provider of store.list()) {
|
|
172
|
+
const status = store.getAuthStatus(provider);
|
|
173
|
+
providers[provider] = {
|
|
174
|
+
configured: status.configured,
|
|
175
|
+
source: status.source,
|
|
176
|
+
label: status.label,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
return { providers };
|
|
180
|
+
}
|
|
181
|
+
export function writeApiKey(provider, apiKey) {
|
|
182
|
+
if (provider.length === 0)
|
|
183
|
+
throw new Error("provider name cannot be empty");
|
|
184
|
+
if (apiKey.length === 0)
|
|
185
|
+
throw new Error("api key cannot be empty");
|
|
186
|
+
const store = authStorage();
|
|
187
|
+
store.set(provider, { type: "api_key", key: apiKey });
|
|
188
|
+
}
|
|
189
|
+
export class AuthProviderNotFoundError extends Error {
|
|
190
|
+
constructor(provider) {
|
|
191
|
+
super(`auth provider not found: ${provider}`);
|
|
192
|
+
this.name = "AuthProviderNotFoundError";
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
export function removeApiKey(provider) {
|
|
196
|
+
const store = authStorage();
|
|
197
|
+
if (!store.has(provider))
|
|
198
|
+
throw new AuthProviderNotFoundError(provider);
|
|
199
|
+
store.remove(provider);
|
|
200
|
+
}
|
|
201
|
+
// ---------------------------------------------------------------------------
|
|
202
|
+
// settings.json
|
|
203
|
+
export async function readSettings() {
|
|
204
|
+
return readJsonOr(SETTINGS_FILE(), {});
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Serialise all read-modify-write sequences over settings.json. Without
|
|
208
|
+
* this, two concurrent PUT /config/settings requests can read the same
|
|
209
|
+
* baseline and race the rename(), losing one write. Also covers the
|
|
210
|
+
* snapshot+restore dance in routes/control.ts:setModel — exported so
|
|
211
|
+
* that route can wrap the entire snapshot → setModel → restore sequence
|
|
212
|
+
* as a single critical section. Single-process / single-tenant only.
|
|
213
|
+
*/
|
|
214
|
+
export const withSettingsLock = makeLock();
|
|
215
|
+
/**
|
|
216
|
+
* Atomically replace settings.json with `settings`. Used by the
|
|
217
|
+
* per-session model route to roll back the SDK's side effects on
|
|
218
|
+
* `session.setModel(...)`. The SDK touches more keys than just
|
|
219
|
+
* defaultProvider/defaultModel (defaultThinkingLevel, etc.), so a
|
|
220
|
+
* key-by-key restore was leaking SDK-written values into the file
|
|
221
|
+
* and resetting users' manually-curated settings to whatever the
|
|
222
|
+
* SDK happened to write.
|
|
223
|
+
*
|
|
224
|
+
* Note: this function does NOT take `withSettingsLock`. The Promise-
|
|
225
|
+
* chain lock is non-reentrant, so callers that need to write under an
|
|
226
|
+
* already-held lock (e.g. `routes/control.ts:setModel` doing a
|
|
227
|
+
* snapshot+restore inside its own critical section) would deadlock.
|
|
228
|
+
* `atomicWriteJson` is itself crash-safe; the lock only matters for
|
|
229
|
+
* read-modify-write coherency, which is owned by the caller.
|
|
230
|
+
*/
|
|
231
|
+
export async function writeSettings(settings) {
|
|
232
|
+
await atomicWriteJson(SETTINGS_FILE(), settings);
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Partial-merge update: shallow merge of `patch` over the existing settings.
|
|
236
|
+
* Pass `null` for any key in `patch` to delete that key. Atomic write.
|
|
237
|
+
*
|
|
238
|
+
* Refuses prototype-pollution keys (`__proto__`, `prototype`,
|
|
239
|
+
* `constructor`) — `JSON.parse` itself decodes these as own-properties
|
|
240
|
+
* (which is why the simple `next[k] = v` write would actually corrupt
|
|
241
|
+
* `Object.prototype`); we filter them at the boundary.
|
|
242
|
+
*/
|
|
243
|
+
export async function updateSettings(patch) {
|
|
244
|
+
return withSettingsLock(async () => {
|
|
245
|
+
const current = await readSettings();
|
|
246
|
+
const next = { ...current };
|
|
247
|
+
for (const [k, v] of Object.entries(patch)) {
|
|
248
|
+
if (DANGEROUS_KEYS.has(k))
|
|
249
|
+
continue;
|
|
250
|
+
if (v === null) {
|
|
251
|
+
delete next[k];
|
|
252
|
+
}
|
|
253
|
+
else {
|
|
254
|
+
// defineProperty avoids a setter-trap if the prototype chain
|
|
255
|
+
// somehow contains an accessor for this key.
|
|
256
|
+
Object.defineProperty(next, k, {
|
|
257
|
+
value: v,
|
|
258
|
+
writable: true,
|
|
259
|
+
enumerable: true,
|
|
260
|
+
configurable: true,
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
await atomicWriteJson(SETTINGS_FILE(), next);
|
|
265
|
+
return next;
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
// ---------------------------------------------------------------------------
|
|
269
|
+
// providers — live from ModelRegistry. Builds a fresh registry per call so a
|
|
270
|
+
// PUT /config/models is reflected on the next GET /config/providers without
|
|
271
|
+
// needing a restart.
|
|
272
|
+
export async function liveProvidersListing() {
|
|
273
|
+
const store = authStorage();
|
|
274
|
+
const registry = ModelRegistry.create(store, MODELS_FILE());
|
|
275
|
+
const all = registry.getAll();
|
|
276
|
+
// When HIDE_BUILTIN_PROVIDERS is on, restrict to providers whose
|
|
277
|
+
// name appears as a key in models.json. Built-ins (anthropic,
|
|
278
|
+
// openai, etc. the SDK ships with) drop out, leaving only the
|
|
279
|
+
// operator-added custom providers.
|
|
280
|
+
const customOnly = config.hideBuiltinProviders
|
|
281
|
+
? new Set(Object.keys((await readModelsJson()).providers))
|
|
282
|
+
: undefined;
|
|
283
|
+
const grouped = new Map();
|
|
284
|
+
for (const m of all) {
|
|
285
|
+
if (customOnly !== undefined && !customOnly.has(m.provider))
|
|
286
|
+
continue;
|
|
287
|
+
let entry = grouped.get(m.provider);
|
|
288
|
+
if (entry === undefined) {
|
|
289
|
+
entry = { provider: m.provider, models: [] };
|
|
290
|
+
grouped.set(m.provider, entry);
|
|
291
|
+
}
|
|
292
|
+
entry.models.push({
|
|
293
|
+
id: m.id,
|
|
294
|
+
name: m.name,
|
|
295
|
+
contextWindow: m.contextWindow,
|
|
296
|
+
maxTokens: m.maxTokens,
|
|
297
|
+
reasoning: m.reasoning,
|
|
298
|
+
input: m.input,
|
|
299
|
+
hasAuth: registry.hasConfiguredAuth(m),
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
return { providers: Array.from(grouped.values()) };
|
|
303
|
+
}
|
|
304
|
+
export async function listSkills(workspacePath, projectId) {
|
|
305
|
+
// Pi packages can contribute skill directories or files via
|
|
306
|
+
// `package.json#pi.skills`, resolved by DefaultPackageManager.
|
|
307
|
+
// discoverExtensionResources returns those resolved paths so
|
|
308
|
+
// loadSkills can scan them alongside the SDK's default global /
|
|
309
|
+
// project dirs.
|
|
310
|
+
const extResources = await discoverExtensionResources(workspacePath);
|
|
311
|
+
const extensionSkillPaths = extResources.skillPaths.map((s) => s.skillPath);
|
|
312
|
+
const result = loadSkills({
|
|
313
|
+
cwd: workspacePath,
|
|
314
|
+
agentDir: config.piConfigDir,
|
|
315
|
+
skillPaths: extensionSkillPaths,
|
|
316
|
+
includeDefaults: true,
|
|
317
|
+
});
|
|
318
|
+
const settings = await readSettings();
|
|
319
|
+
// Pi's `settings.skills` is a list of override patterns, NOT a list
|
|
320
|
+
// of enabled names. A skill is enabled at the global scope unless
|
|
321
|
+
// an `!<name>` (or `-<name>`) pattern targets it. See the doc-comment
|
|
322
|
+
// on `effectiveSkillsForProject` for the full pattern semantics.
|
|
323
|
+
const globalDisabled = disabledNamesFromPatterns(settings.skills ?? []);
|
|
324
|
+
const overrides = await readSkillOverrides();
|
|
325
|
+
// Map registered skill paths → owning package source (e.g.
|
|
326
|
+
// "pi-subagents") so each summary can attribute its origin
|
|
327
|
+
// beyond the bare global / project heuristic.
|
|
328
|
+
const skillPathToPackage = new Map();
|
|
329
|
+
for (const s of extResources.skillPaths) {
|
|
330
|
+
skillPathToPackage.set(s.skillPath, s.packageSource);
|
|
331
|
+
}
|
|
332
|
+
return result.skills.map((s) => skillSummary(s, workspacePath, globalDisabled, overrides, projectId, skillPathToPackage));
|
|
333
|
+
}
|
|
334
|
+
function skillSummary(s, workspacePath, globalDisabled, overrides, projectId, skillPathToPackage) {
|
|
335
|
+
// The SDK's loadSkills puts global ones under agentDir, project ones
|
|
336
|
+
// under workspacePath/.pi/skills, and package-contributed ones under
|
|
337
|
+
// whatever path the package's `pi.skills` manifest entry resolved
|
|
338
|
+
// to (typically `~/.pi/agent/packages/<name>/skills/...`). Match
|
|
339
|
+
// against the package skill-path map FIRST — those paths usually
|
|
340
|
+
// don't fall under the project / global heuristics below, but
|
|
341
|
+
// checking explicitly is safer.
|
|
342
|
+
const packageSource = findPackageForSkill(s.baseDir, skillPathToPackage);
|
|
343
|
+
const isProject = packageSource === undefined && s.baseDir.startsWith(workspacePath);
|
|
344
|
+
const source = packageSource !== undefined ? "extension" : isProject ? "project" : "global";
|
|
345
|
+
const isEnabledGlobal = !globalDisabled.has(s.name);
|
|
346
|
+
const projectOverride = projectId !== undefined ? getProjectSkillState(overrides, projectId, s.name) : undefined;
|
|
347
|
+
const effective = projectOverride === "enabled" ? true : projectOverride === "disabled" ? false : isEnabledGlobal;
|
|
348
|
+
const summary = {
|
|
349
|
+
name: s.name,
|
|
350
|
+
description: s.description,
|
|
351
|
+
source,
|
|
352
|
+
filePath: s.filePath,
|
|
353
|
+
enabled: isEnabledGlobal,
|
|
354
|
+
effective,
|
|
355
|
+
disableModelInvocation: s.disableModelInvocation,
|
|
356
|
+
};
|
|
357
|
+
if (packageSource !== undefined)
|
|
358
|
+
summary.extensionPath = packageSource;
|
|
359
|
+
if (projectOverride !== undefined)
|
|
360
|
+
summary.projectOverride = projectOverride;
|
|
361
|
+
return summary;
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Match a skill's `baseDir` against the package-skill-path map.
|
|
365
|
+
* The skill's baseDir might be exactly a registered path or a
|
|
366
|
+
* subdirectory of one (loadSkills recurses). Pick the longest
|
|
367
|
+
* matching prefix so the closest registering package wins. Returns
|
|
368
|
+
* the package source identifier ("pi-subagents", a git URL, etc.)
|
|
369
|
+
* or `undefined` when the skill didn't come from any registered
|
|
370
|
+
* package.
|
|
371
|
+
*/
|
|
372
|
+
function findPackageForSkill(baseDir, skillPathToPackage) {
|
|
373
|
+
let best;
|
|
374
|
+
for (const [path, pkg] of skillPathToPackage) {
|
|
375
|
+
if (baseDir === path || baseDir.startsWith(path + "/")) {
|
|
376
|
+
if (best === undefined || path.length > best.path.length) {
|
|
377
|
+
best = { path, pkg };
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
return best?.pkg;
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* Returns the full per-project overrides map. Used by the Settings
|
|
385
|
+
* UI's cascade view to render override rows for projects OTHER than
|
|
386
|
+
* the active one (e.g. "this skill is disabled in 3 of 8 projects").
|
|
387
|
+
*/
|
|
388
|
+
export async function getAllSkillOverrides() {
|
|
389
|
+
return readSkillOverrides();
|
|
390
|
+
}
|
|
391
|
+
export class SkillNotFoundError extends Error {
|
|
392
|
+
constructor(name) {
|
|
393
|
+
super(`skill not found: ${name}`);
|
|
394
|
+
this.name = "SkillNotFoundError";
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* Toggle a skill's enabled state.
|
|
399
|
+
*
|
|
400
|
+
* - `scope: "global"` (the default; back-compat with the original
|
|
401
|
+
* one-arg form) writes to pi's `settings.skills` — the canonical
|
|
402
|
+
* global enable/disable list.
|
|
403
|
+
* - `scope: "project"` writes to the pi-forge-private overrides
|
|
404
|
+
* file at `${FORGE_DATA_DIR}/skills-overrides.json` for the
|
|
405
|
+
* given `projectId`. Tri-state: `enabled` / `disabled` /
|
|
406
|
+
* (passing `enabled: undefined` clears the override = inherit
|
|
407
|
+
* from global).
|
|
408
|
+
*
|
|
409
|
+
* The skill must be discoverable in the `loadSkills` result — passing
|
|
410
|
+
* a name that doesn't exist throws SkillNotFoundError so route
|
|
411
|
+
* handlers can return a clean 404.
|
|
412
|
+
*/
|
|
413
|
+
export async function setSkillEnabled(name, enabled, workspacePath, opts) {
|
|
414
|
+
const all = await listSkills(workspacePath, opts?.projectId);
|
|
415
|
+
if (!all.some((s) => s.name === name))
|
|
416
|
+
throw new SkillNotFoundError(name);
|
|
417
|
+
const scope = opts?.scope ?? "global";
|
|
418
|
+
if (scope === "project") {
|
|
419
|
+
if (opts?.projectId === undefined) {
|
|
420
|
+
throw new Error("setSkillEnabled: scope=project requires a projectId");
|
|
421
|
+
}
|
|
422
|
+
// Tri-state mapping: true → "enabled", false → "disabled",
|
|
423
|
+
// undefined → clear (inherit). Project writes don't touch pi's
|
|
424
|
+
// settings.skills so the global list stays stable across project
|
|
425
|
+
// switches and other pi clients (TUI) keep their view.
|
|
426
|
+
const state = enabled === true ? "enabled" : enabled === false ? "disabled" : undefined;
|
|
427
|
+
await setProjectSkillOverride(opts.projectId, name, state);
|
|
428
|
+
return listSkills(workspacePath, opts.projectId);
|
|
429
|
+
}
|
|
430
|
+
// global scope (existing behaviour)
|
|
431
|
+
if (enabled === undefined) {
|
|
432
|
+
throw new Error("setSkillEnabled: scope=global requires enabled to be true or false");
|
|
433
|
+
}
|
|
434
|
+
// The skills array is read-modify-write against settings.skills, so
|
|
435
|
+
// serialise the whole sequence under withSettingsLock — without this,
|
|
436
|
+
// toggling two skills in rapid succession (the UI lets the user
|
|
437
|
+
// click as fast as they want) can lose one toggle. We inline the
|
|
438
|
+
// read+merge+write here rather than calling updateSettings (which
|
|
439
|
+
// would deadlock — the lock is non-reentrant) and use atomicWriteJson
|
|
440
|
+
// directly for the write.
|
|
441
|
+
//
|
|
442
|
+
// Pattern semantics: pi auto-discovers every skill on disk and
|
|
443
|
+
// enables them by default. To DISABLE one we push `!<name>`. To
|
|
444
|
+
// re-enable we drop any `!<name>` / `-<name>` / `+<name>` for that
|
|
445
|
+
// name (absence = pi's default-on). We also drop bare-name entries
|
|
446
|
+
// a prior buggy version of this file may have left on disk — pi
|
|
447
|
+
// ignores them, so they're inert and just clutter the file.
|
|
448
|
+
await withSettingsLock(async () => {
|
|
449
|
+
const settings = await readSettings();
|
|
450
|
+
const existing = settings.skills ?? [];
|
|
451
|
+
const filtered = existing.filter((p) => {
|
|
452
|
+
// Drop inert bare entries on every rewrite.
|
|
453
|
+
if (!p.startsWith("!") && !p.startsWith("+") && !p.startsWith("-"))
|
|
454
|
+
return false;
|
|
455
|
+
// Drop any prior pattern targeting THIS skill name; we'll re-add
|
|
456
|
+
// exactly the one we want below.
|
|
457
|
+
if (p.slice(1) === name)
|
|
458
|
+
return false;
|
|
459
|
+
return true;
|
|
460
|
+
});
|
|
461
|
+
if (!enabled)
|
|
462
|
+
filtered.push(excludePattern(name));
|
|
463
|
+
const next = { ...settings, skills: filtered };
|
|
464
|
+
await atomicWriteJson(SETTINGS_FILE(), next);
|
|
465
|
+
});
|
|
466
|
+
return listSkills(workspacePath, opts?.projectId);
|
|
467
|
+
}
|
|
468
|
+
/**
|
|
469
|
+
* Pi's `settings.skills` is NOT an enabled-allowlist of skill names —
|
|
470
|
+
* it is a list of override PATTERNS with three prefix conventions:
|
|
471
|
+
*
|
|
472
|
+
* `!<name>` → exclude (skill won't load if pattern matches)
|
|
473
|
+
* `+<name>` → force include (overrides any `!`)
|
|
474
|
+
* `-<name>` → force exclude (overrides everything)
|
|
475
|
+
* bare name → silently ignored by pi's `getOverridePatterns`
|
|
476
|
+
*
|
|
477
|
+
* Pi auto-discovers every skill it finds under the user/project skill
|
|
478
|
+
* directories and they are ALL ENABLED BY DEFAULT. The only way to
|
|
479
|
+
* disable one is to push `!<name>` (or `-<name>`) into the patterns
|
|
480
|
+
* list. Writing bare names accomplishes nothing.
|
|
481
|
+
*
|
|
482
|
+
* Helpers below codify this so callers don't need to re-derive it.
|
|
483
|
+
*/
|
|
484
|
+
const excludePattern = (name) => `!${name}`;
|
|
485
|
+
const forceIncludePattern = (name) => `+${name}`;
|
|
486
|
+
/** Names that an exclude pattern (`!name` or `-name`) targets. */
|
|
487
|
+
function disabledNamesFromPatterns(patterns) {
|
|
488
|
+
const out = new Set();
|
|
489
|
+
for (const p of patterns) {
|
|
490
|
+
if (p.startsWith("!") || p.startsWith("-"))
|
|
491
|
+
out.add(p.slice(1));
|
|
492
|
+
}
|
|
493
|
+
return out;
|
|
494
|
+
}
|
|
495
|
+
/**
|
|
496
|
+
* Compute the skill-pattern list a session in `projectId` should see —
|
|
497
|
+
* a merge of pi's global patterns with our per-project overrides.
|
|
498
|
+
*
|
|
499
|
+
* Returned values are PATTERNS (`!name` / `+name`), not names. The
|
|
500
|
+
* session-registry pushes them into the SettingsManager so pi's
|
|
501
|
+
* package-manager applies them when discovering skills.
|
|
502
|
+
*
|
|
503
|
+
* Resolution rules:
|
|
504
|
+
* - Start with whatever patterns pi already has at the global scope
|
|
505
|
+
* (these come from prior `setSkillEnabled(scope:"global")` writes).
|
|
506
|
+
* - For every skill the project marked `disable`, ensure `!<name>`
|
|
507
|
+
* is in the list — even if no global exclude exists.
|
|
508
|
+
* - For every skill the project marked `enable`, push `+<name>` so
|
|
509
|
+
* it force-includes in this project's session even if a global
|
|
510
|
+
* `!<name>` would otherwise hide it.
|
|
511
|
+
*/
|
|
512
|
+
export async function effectiveSkillsForProject(projectId) {
|
|
513
|
+
const settings = await readSettings();
|
|
514
|
+
const overrides = await readSkillOverrides();
|
|
515
|
+
// Filter to only valid override patterns; drop any inert bare entries
|
|
516
|
+
// a prior buggy version of this code might have left on disk.
|
|
517
|
+
const globalPatterns = (settings.skills ?? []).filter((p) => p.startsWith("!") || p.startsWith("+") || p.startsWith("-"));
|
|
518
|
+
const result = new Set(globalPatterns);
|
|
519
|
+
const entry = overrides.projects[projectId];
|
|
520
|
+
if (entry !== undefined) {
|
|
521
|
+
for (const name of entry.disable)
|
|
522
|
+
result.add(excludePattern(name));
|
|
523
|
+
for (const name of entry.enable)
|
|
524
|
+
result.add(forceIncludePattern(name));
|
|
525
|
+
}
|
|
526
|
+
return Array.from(result);
|
|
527
|
+
}
|
|
528
|
+
//# sourceMappingURL=config-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-manager.js","sourceRoot":"","sources":["../src/config-manager.ts"],"names":[],"mappings":"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"}
|