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.
Files changed (103) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +48 -4
  3. package/bin/pi-forge.mjs +37 -0
  4. package/dist/client/assets/CodeMirrorEditor-BqaaP1EE.js +34 -0
  5. package/dist/client/assets/CodeMirrorEditor-BqaaP1EE.js.map +1 -0
  6. package/dist/client/assets/index-B-529kgJ.css +32 -0
  7. package/dist/client/assets/index-BzKzxXFs.js +392 -0
  8. package/dist/client/assets/index-BzKzxXFs.js.map +1 -0
  9. package/dist/client/assets/workbox-window.prod.es5-BBnX5xw4.js +3 -0
  10. package/dist/client/assets/workbox-window.prod.es5-BBnX5xw4.js.map +1 -0
  11. package/dist/client/icons/icon-192.png +0 -0
  12. package/dist/client/icons/icon-512.png +0 -0
  13. package/dist/client/icons/icon-maskable-512.png +0 -0
  14. package/dist/client/icons/icon.svg +9 -0
  15. package/dist/client/index.html +24 -0
  16. package/dist/client/manifest.webmanifest +1 -0
  17. package/dist/client/offline.html +142 -0
  18. package/dist/client/sw.js +3 -0
  19. package/dist/client/sw.js.map +1 -0
  20. package/dist/client/workbox-6d7155ed.js +3 -0
  21. package/dist/client/workbox-6d7155ed.js.map +1 -0
  22. package/dist/server/agent-resource-loader.js +126 -0
  23. package/dist/server/agent-resource-loader.js.map +1 -0
  24. package/dist/server/attachment-converters.js +96 -0
  25. package/dist/server/attachment-converters.js.map +1 -0
  26. package/dist/server/auth.js +209 -0
  27. package/dist/server/auth.js.map +1 -0
  28. package/dist/server/compaction-history.js +106 -0
  29. package/dist/server/compaction-history.js.map +1 -0
  30. package/dist/server/concurrency.js +49 -0
  31. package/dist/server/concurrency.js.map +1 -0
  32. package/dist/server/config-export.js +220 -0
  33. package/dist/server/config-export.js.map +1 -0
  34. package/dist/server/config-manager.js +528 -0
  35. package/dist/server/config-manager.js.map +1 -0
  36. package/dist/server/config.js +326 -0
  37. package/dist/server/config.js.map +1 -0
  38. package/dist/server/conversion-worker.mjs +90 -0
  39. package/dist/server/diagnostics.js +137 -0
  40. package/dist/server/diagnostics.js.map +1 -0
  41. package/dist/server/extensions-discovery.js +147 -0
  42. package/dist/server/extensions-discovery.js.map +1 -0
  43. package/dist/server/file-manager.js +734 -0
  44. package/dist/server/file-manager.js.map +1 -0
  45. package/dist/server/file-references.js +215 -0
  46. package/dist/server/file-references.js.map +1 -0
  47. package/dist/server/file-searcher.js +385 -0
  48. package/dist/server/file-searcher.js.map +1 -0
  49. package/dist/server/git-runner.js +684 -0
  50. package/dist/server/git-runner.js.map +1 -0
  51. package/dist/server/index.js +468 -0
  52. package/dist/server/index.js.map +1 -0
  53. package/dist/server/mcp/config.js +133 -0
  54. package/dist/server/mcp/config.js.map +1 -0
  55. package/dist/server/mcp/manager.js +351 -0
  56. package/dist/server/mcp/manager.js.map +1 -0
  57. package/dist/server/mcp/tool-bridge.js +173 -0
  58. package/dist/server/mcp/tool-bridge.js.map +1 -0
  59. package/dist/server/project-manager.js +301 -0
  60. package/dist/server/project-manager.js.map +1 -0
  61. package/dist/server/pty-manager.js +354 -0
  62. package/dist/server/pty-manager.js.map +1 -0
  63. package/dist/server/routes/_schemas.js +73 -0
  64. package/dist/server/routes/_schemas.js.map +1 -0
  65. package/dist/server/routes/auth.js +164 -0
  66. package/dist/server/routes/auth.js.map +1 -0
  67. package/dist/server/routes/config.js +1163 -0
  68. package/dist/server/routes/config.js.map +1 -0
  69. package/dist/server/routes/control.js +464 -0
  70. package/dist/server/routes/control.js.map +1 -0
  71. package/dist/server/routes/exec.js +217 -0
  72. package/dist/server/routes/exec.js.map +1 -0
  73. package/dist/server/routes/files.js +847 -0
  74. package/dist/server/routes/files.js.map +1 -0
  75. package/dist/server/routes/git.js +837 -0
  76. package/dist/server/routes/git.js.map +1 -0
  77. package/dist/server/routes/health.js +97 -0
  78. package/dist/server/routes/health.js.map +1 -0
  79. package/dist/server/routes/mcp.js +300 -0
  80. package/dist/server/routes/mcp.js.map +1 -0
  81. package/dist/server/routes/projects.js +259 -0
  82. package/dist/server/routes/projects.js.map +1 -0
  83. package/dist/server/routes/prompt.js +496 -0
  84. package/dist/server/routes/prompt.js.map +1 -0
  85. package/dist/server/routes/sessions.js +783 -0
  86. package/dist/server/routes/sessions.js.map +1 -0
  87. package/dist/server/routes/stream.js +69 -0
  88. package/dist/server/routes/stream.js.map +1 -0
  89. package/dist/server/routes/terminal.js +335 -0
  90. package/dist/server/routes/terminal.js.map +1 -0
  91. package/dist/server/session-registry.js +1197 -0
  92. package/dist/server/session-registry.js.map +1 -0
  93. package/dist/server/skill-overrides.js +151 -0
  94. package/dist/server/skill-overrides.js.map +1 -0
  95. package/dist/server/skills-export.js +257 -0
  96. package/dist/server/skills-export.js.map +1 -0
  97. package/dist/server/sse-bridge.js +220 -0
  98. package/dist/server/sse-bridge.js.map +1 -0
  99. package/dist/server/tool-overrides.js +277 -0
  100. package/dist/server/tool-overrides.js.map +1 -0
  101. package/dist/server/turn-diff-builder.js +280 -0
  102. package/dist/server/turn-diff-builder.js.map +1 -0
  103. 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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"}