agentloom 0.1.2 → 0.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.
@@ -1,5 +1,4 @@
1
1
  import fs from "node:fs";
2
- import os from "node:os";
3
2
  import path from "node:path";
4
3
  import { cancel, isCancel, multiselect } from "@clack/prompts";
5
4
  import TOML from "@iarna/toml";
@@ -10,6 +9,7 @@ import { parseCommandsDir } from "../core/commands.js";
10
9
  import { ensureDir, isObject, readJsonIfExists, relativePosix, removeFileIfExists, slugify, toPosixPath, writeJsonAtomic, writeTextAtomic, } from "../core/fs.js";
11
10
  import { readManifest, writeManifest } from "../core/manifest.js";
12
11
  import { readCanonicalMcp, resolveMcpForProvider } from "../core/mcp.js";
12
+ import { getClaudeMcpPath, getClaudeSettingsPath, getCodexAgentsDir, getCodexConfigPath, getCodexRootDir, getCopilotMcpPath, getCursorMcpPath, getGeminiSettingsPath, getOpenCodeConfigPath, getPiMcpPath, getProviderAgentsDir, getProviderCommandsDir, getVsCodeSettingsPath, } from "../core/provider-paths.js";
13
13
  import { getGlobalSettingsPath, readSettings, updateLastScope, updateLastScopeBestEffort, } from "../core/settings.js";
14
14
  export async function resolveProvidersForSync(options) {
15
15
  const settings = readSettings(options.paths.settingsPath);
@@ -150,6 +150,7 @@ const PROVIDER_LABELS = {
150
150
  opencode: "OpenCode",
151
151
  gemini: "Gemini",
152
152
  copilot: "Copilot",
153
+ pi: "Pi",
153
154
  };
154
155
  const MULTISELECT_HELP_TEXT = "↑↓ move, space select, enter confirm";
155
156
  function withMultiselectHelp(message) {
@@ -226,38 +227,6 @@ function buildProviderAgentContent(provider, agent, providerConfig) {
226
227
  const fm = YAML.stringify(frontmatter).trimEnd();
227
228
  return `---\n${fm}\n---\n\n${agent.body.trimStart()}${agent.body.endsWith("\n") ? "" : "\n"}`;
228
229
  }
229
- function getProviderAgentsDir(paths, provider) {
230
- const workspaceRoot = paths.workspaceRoot;
231
- const home = paths.homeDir;
232
- switch (provider) {
233
- case "cursor":
234
- return paths.scope === "local"
235
- ? path.join(workspaceRoot, ".cursor", "agents")
236
- : path.join(home, ".cursor", "agents");
237
- case "claude":
238
- return paths.scope === "local"
239
- ? path.join(workspaceRoot, ".claude", "agents")
240
- : path.join(home, ".claude", "agents");
241
- case "codex":
242
- return paths.scope === "local"
243
- ? path.join(workspaceRoot, ".codex", "agents")
244
- : path.join(home, ".codex", "agents");
245
- case "opencode":
246
- return paths.scope === "local"
247
- ? path.join(workspaceRoot, ".opencode", "agents")
248
- : path.join(home, ".config", "opencode", "agents");
249
- case "gemini":
250
- return paths.scope === "local"
251
- ? path.join(workspaceRoot, ".gemini", "agents")
252
- : path.join(home, ".gemini", "agents");
253
- case "copilot":
254
- return paths.scope === "local"
255
- ? path.join(workspaceRoot, ".github", "agents")
256
- : path.join(home, ".vscode", "chatmodes");
257
- default:
258
- return path.join(workspaceRoot, ".agents", "unknown");
259
- }
260
- }
261
230
  function syncProviderCommands(options) {
262
231
  const providerDir = getProviderCommandsDir(options.paths, options.provider);
263
232
  for (const command of options.commands) {
@@ -292,45 +261,13 @@ function mapProviderCommandFileName(provider, fileName) {
292
261
  }
293
262
  return fileName;
294
263
  }
295
- function getProviderCommandsDir(paths, provider) {
296
- const workspaceRoot = paths.workspaceRoot;
297
- const home = paths.homeDir;
298
- switch (provider) {
299
- case "cursor":
300
- return paths.scope === "local"
301
- ? path.join(workspaceRoot, ".cursor", "commands")
302
- : path.join(home, ".cursor", "commands");
303
- case "claude":
304
- return paths.scope === "local"
305
- ? path.join(workspaceRoot, ".claude", "commands")
306
- : path.join(home, ".claude", "commands");
307
- case "codex":
308
- return path.join(home, ".codex", "prompts");
309
- case "opencode":
310
- return paths.scope === "local"
311
- ? path.join(workspaceRoot, ".opencode", "commands")
312
- : path.join(home, ".config", "opencode", "commands");
313
- case "gemini":
314
- return paths.scope === "local"
315
- ? path.join(workspaceRoot, ".gemini", "commands")
316
- : path.join(home, ".gemini", "commands");
317
- case "copilot":
318
- return paths.scope === "local"
319
- ? path.join(workspaceRoot, ".github", "prompts")
320
- : path.join(home, ".github", "prompts");
321
- default:
322
- return path.join(workspaceRoot, ".agents", "unknown", "commands");
323
- }
324
- }
325
264
  function syncProviderMcp(options) {
326
265
  for (const provider of options.providers) {
327
266
  if (provider === "codex")
328
267
  continue;
329
268
  const resolved = resolveMcpForProvider(options.mcp, provider);
330
269
  if (provider === "cursor") {
331
- const outputPath = options.paths.scope === "local"
332
- ? path.join(options.paths.workspaceRoot, ".cursor", "mcp.json")
333
- : path.join(options.paths.homeDir, ".cursor", "mcp.json");
270
+ const outputPath = getCursorMcpPath(options.paths);
334
271
  const payload = {
335
272
  mcpServers: mapMcpServers(resolved, ["url", "command", "args", "env"]),
336
273
  };
@@ -339,12 +276,8 @@ function syncProviderMcp(options) {
339
276
  continue;
340
277
  }
341
278
  if (provider === "claude") {
342
- const mcpPath = options.paths.scope === "local"
343
- ? path.join(options.paths.workspaceRoot, ".mcp.json")
344
- : path.join(options.paths.homeDir, ".mcp.json");
345
- const settingsPath = options.paths.scope === "local"
346
- ? path.join(options.paths.workspaceRoot, ".claude", "settings.json")
347
- : path.join(options.paths.homeDir, ".claude.json");
279
+ const mcpPath = getClaudeMcpPath(options.paths);
280
+ const settingsPath = getClaudeSettingsPath(options.paths);
348
281
  const claudeServers = mapMcpServers(resolved, [
349
282
  "type",
350
283
  "url",
@@ -366,9 +299,7 @@ function syncProviderMcp(options) {
366
299
  continue;
367
300
  }
368
301
  if (provider === "opencode") {
369
- const outputPath = options.paths.scope === "local"
370
- ? path.join(options.paths.workspaceRoot, ".opencode", "opencode.json")
371
- : path.join(options.paths.homeDir, ".config", "opencode", "opencode.json");
302
+ const outputPath = getOpenCodeConfigPath(options.paths);
372
303
  const existing = readJsonIfExists(outputPath) ?? {};
373
304
  const mcp = {};
374
305
  for (const [serverName, config] of Object.entries(resolved)) {
@@ -398,9 +329,7 @@ function syncProviderMcp(options) {
398
329
  continue;
399
330
  }
400
331
  if (provider === "gemini") {
401
- const outputPath = options.paths.scope === "local"
402
- ? path.join(options.paths.workspaceRoot, ".gemini", "settings.json")
403
- : path.join(options.paths.homeDir, ".gemini", "settings.json");
332
+ const outputPath = getGeminiSettingsPath(options.paths);
404
333
  const existing = readJsonIfExists(outputPath) ?? {};
405
334
  const experimental = isObject(existing.experimental)
406
335
  ? { ...existing.experimental }
@@ -429,9 +358,7 @@ function syncProviderMcp(options) {
429
358
  continue;
430
359
  }
431
360
  if (provider === "copilot") {
432
- const profileMcpPath = options.paths.scope === "local"
433
- ? path.join(options.paths.workspaceRoot, ".vscode", "mcp.json")
434
- : path.join(options.paths.homeDir, ".vscode", "mcp.json");
361
+ const profileMcpPath = getCopilotMcpPath(options.paths);
435
362
  const copilotServers = mapMcpServers(resolved, [
436
363
  "type",
437
364
  "url",
@@ -458,14 +385,21 @@ function syncProviderMcp(options) {
458
385
  options.generated.add(settingsPath);
459
386
  }
460
387
  }
388
+ if (provider === "pi") {
389
+ const outputPath = getPiMcpPath(options.paths);
390
+ const payload = {
391
+ mcpServers: mapMcpServers(resolved, ["url", "command", "args", "env"]),
392
+ };
393
+ maybeWriteJson(outputPath, payload, options.dryRun);
394
+ options.generated.add(outputPath);
395
+ continue;
396
+ }
461
397
  }
462
398
  }
463
399
  function syncCodex(options) {
464
- const codexDir = options.paths.scope === "local"
465
- ? path.join(options.paths.workspaceRoot, ".codex")
466
- : path.join(options.paths.homeDir, ".codex");
467
- const codexConfigPath = path.join(codexDir, "config.toml");
468
- const codexAgentsDir = path.join(codexDir, "agents");
400
+ const codexDir = getCodexRootDir(options.paths);
401
+ const codexConfigPath = getCodexConfigPath(options.paths);
402
+ const codexAgentsDir = getCodexAgentsDir(options.paths);
469
403
  const rawConfig = fs.existsSync(codexConfigPath)
470
404
  ? fs.readFileSync(codexConfigPath, "utf8")
471
405
  : "";
@@ -631,21 +565,6 @@ async function removeStaleGeneratedFiles(options) {
631
565
  }
632
566
  return stale;
633
567
  }
634
- function getVsCodeSettingsPath(homeDir) {
635
- switch (os.platform()) {
636
- case "darwin":
637
- return path.join(homeDir, "Library", "Application Support", "Code", "User", "settings.json");
638
- case "win32": {
639
- const appData = process.env.APPDATA;
640
- if (!appData) {
641
- return path.join(homeDir, "AppData", "Roaming", "Code", "User", "settings.json");
642
- }
643
- return path.join(appData, "Code", "User", "settings.json");
644
- }
645
- default:
646
- return path.join(homeDir, ".config", "Code", "User", "settings.json");
647
- }
648
- }
649
568
  function normalizeGeneratedByEntity(manifest) {
650
569
  const source = manifest.generatedByEntity;
651
570
  if (!source || typeof source !== "object") {
@@ -695,7 +614,8 @@ function isLegacyCommandOutputPath(normalizedPath) {
695
614
  normalizedPath.includes("/.opencode/commands/") ||
696
615
  normalizedPath.includes("/.gemini/commands/") ||
697
616
  normalizedPath.includes("/.github/prompts/") ||
698
- normalizedPath.includes("/.codex/prompts/"));
617
+ normalizedPath.includes("/.codex/prompts/") ||
618
+ normalizedPath.includes("/.pi/prompts/"));
699
619
  }
700
620
  function isLegacyAgentOutputPath(normalizedPath) {
701
621
  return (normalizedPath.includes("/.cursor/agents/") ||
@@ -704,7 +624,8 @@ function isLegacyAgentOutputPath(normalizedPath) {
704
624
  normalizedPath.includes("/.opencode/agents/") ||
705
625
  normalizedPath.includes("/.gemini/agents/") ||
706
626
  normalizedPath.includes("/.github/agents/") ||
707
- normalizedPath.includes("/.codex/agents/"));
627
+ normalizedPath.includes("/.codex/agents/") ||
628
+ normalizedPath.includes("/.pi/agents/"));
708
629
  }
709
630
  function isLegacyMcpOutputPath(normalizedPath) {
710
631
  return (normalizedPath.endsWith("/.cursor/mcp.json") ||
@@ -713,7 +634,9 @@ function isLegacyMcpOutputPath(normalizedPath) {
713
634
  normalizedPath.endsWith("/.opencode/opencode.json") ||
714
635
  normalizedPath.endsWith("/.gemini/settings.json") ||
715
636
  normalizedPath.endsWith("/.vscode/mcp.json") ||
716
- normalizedPath.endsWith("/code/user/settings.json"));
637
+ normalizedPath.endsWith("/code/user/settings.json") ||
638
+ normalizedPath.endsWith("/.pi/mcp.json") ||
639
+ normalizedPath.endsWith("/.pi/agent/mcp.json"));
717
640
  }
718
641
  function isLegacyCodexConfigPath(normalizedPath) {
719
642
  return normalizedPath.endsWith("/.codex/config.toml");
package/dist/types.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export declare const ALL_PROVIDERS: readonly ["cursor", "claude", "codex", "opencode", "gemini", "copilot"];
1
+ export declare const ALL_PROVIDERS: readonly ["cursor", "claude", "codex", "opencode", "gemini", "copilot", "pi"];
2
2
  export type Provider = (typeof ALL_PROVIDERS)[number];
3
3
  export type Scope = "local" | "global";
4
4
  export type EntityType = "agent" | "command" | "mcp" | "skill";
@@ -12,6 +12,7 @@ export interface AgentFrontmatter {
12
12
  opencode?: Record<string, unknown> | false;
13
13
  gemini?: Record<string, unknown> | false;
14
14
  copilot?: Record<string, unknown> | false;
15
+ pi?: Record<string, unknown> | false;
15
16
  [key: string]: unknown;
16
17
  }
17
18
  export interface CanonicalAgent {
package/dist/types.js CHANGED
@@ -5,4 +5,5 @@ export const ALL_PROVIDERS = [
5
5
  "opencode",
6
6
  "gemini",
7
7
  "copilot",
8
+ "pi",
8
9
  ];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentloom",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "Unified agent and MCP sync CLI for multi-provider AI tooling",
5
5
  "type": "module",
6
6
  "bin": {