agentloom 0.1.4 → 0.1.5

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.
@@ -46,7 +46,7 @@ export function parseAgentMarkdown(raw, sourcePath, fileName = path.basename(sou
46
46
  };
47
47
  }
48
48
  export function buildAgentMarkdown(frontmatter, body) {
49
- const fm = YAML.stringify(frontmatter).trimEnd();
49
+ const fm = YAML.stringify(frontmatter, { lineWidth: 0 }).trimEnd();
50
50
  const normalizedBody = body.trimStart();
51
51
  return `---\n${fm}\n---\n\n${normalizedBody}${normalizedBody.endsWith("\n") ? "" : "\n"}`;
52
52
  }
@@ -1,8 +1,10 @@
1
- import { readJsonIfExists, writeJsonAtomic } from "./fs.js";
1
+ import path from "node:path";
2
+ import { readJsonIfExists, toPosixPath, writeJsonAtomic } from "./fs.js";
2
3
  const EMPTY_MANIFEST = {
3
4
  version: 1,
4
5
  generatedFiles: [],
5
6
  };
7
+ const ENTITY_TYPES = ["agent", "command", "mcp", "skill"];
6
8
  export function readManifest(paths) {
7
9
  const manifest = readJsonIfExists(paths.manifestPath);
8
10
  if (!manifest ||
@@ -10,14 +12,129 @@ export function readManifest(paths) {
10
12
  !Array.isArray(manifest.generatedFiles)) {
11
13
  return { ...EMPTY_MANIFEST };
12
14
  }
13
- const generatedByEntity = manifest.generatedByEntity && typeof manifest.generatedByEntity === "object"
14
- ? manifest.generatedByEntity
15
- : undefined;
15
+ const generatedByEntity = normalizeGeneratedByEntityForRuntime(paths, manifest.generatedByEntity);
16
+ const codex = normalizeCodexMetadata(manifest.codex);
16
17
  return {
17
- ...manifest,
18
+ version: 1,
19
+ generatedFiles: normalizePathListForRuntime(paths, manifest.generatedFiles),
18
20
  generatedByEntity,
21
+ codex,
19
22
  };
20
23
  }
21
24
  export function writeManifest(paths, manifest) {
22
- writeJsonAtomic(paths.manifestPath, manifest);
25
+ const generatedByEntity = normalizeGeneratedByEntityForDisk(paths, manifest.generatedByEntity);
26
+ const codex = normalizeCodexMetadata(manifest.codex);
27
+ writeJsonAtomic(paths.manifestPath, {
28
+ version: 1,
29
+ generatedFiles: normalizePathListForDisk(paths, manifest.generatedFiles),
30
+ generatedByEntity,
31
+ codex,
32
+ });
33
+ }
34
+ function normalizeGeneratedByEntityForRuntime(paths, generatedByEntity) {
35
+ if (!generatedByEntity || typeof generatedByEntity !== "object") {
36
+ return undefined;
37
+ }
38
+ const normalized = {};
39
+ for (const entity of ENTITY_TYPES) {
40
+ const values = normalizePathListForRuntime(paths, generatedByEntity[entity]);
41
+ if (values.length === 0)
42
+ continue;
43
+ normalized[entity] = values;
44
+ }
45
+ return Object.keys(normalized).length > 0 ? normalized : {};
46
+ }
47
+ function normalizeGeneratedByEntityForDisk(paths, generatedByEntity) {
48
+ if (!generatedByEntity || typeof generatedByEntity !== "object") {
49
+ return undefined;
50
+ }
51
+ const normalized = {};
52
+ for (const entity of ENTITY_TYPES) {
53
+ const values = normalizePathListForDisk(paths, generatedByEntity[entity]);
54
+ if (values.length === 0)
55
+ continue;
56
+ normalized[entity] = values;
57
+ }
58
+ return Object.keys(normalized).length > 0 ? normalized : {};
59
+ }
60
+ function normalizePathListForRuntime(paths, value) {
61
+ if (!Array.isArray(value))
62
+ return [];
63
+ const normalized = value
64
+ .filter((item) => typeof item === "string")
65
+ .map((item) => resolveManifestPathForRuntime(paths, item))
66
+ .filter((item) => item.length > 0);
67
+ return [...new Set(normalized)].sort();
68
+ }
69
+ function normalizePathListForDisk(paths, value) {
70
+ if (!Array.isArray(value))
71
+ return [];
72
+ const normalized = value
73
+ .filter((item) => typeof item === "string")
74
+ .map((item) => resolveManifestPathForDisk(paths, item))
75
+ .filter((item) => item.length > 0);
76
+ return [...new Set(normalized)].sort();
77
+ }
78
+ function resolveManifestPathForRuntime(paths, filePath) {
79
+ const normalized = filePath.trim();
80
+ if (!normalized)
81
+ return "";
82
+ if (normalized === "~") {
83
+ return paths.homeDir;
84
+ }
85
+ if (normalized.startsWith("~/")) {
86
+ return path.resolve(paths.homeDir, normalized.slice(2));
87
+ }
88
+ if (path.isAbsolute(normalized)) {
89
+ return path.normalize(normalized);
90
+ }
91
+ return path.resolve(paths.workspaceRoot, normalized);
92
+ }
93
+ function resolveManifestPathForDisk(paths, filePath) {
94
+ const normalized = filePath.trim();
95
+ if (!normalized)
96
+ return "";
97
+ if (!path.isAbsolute(normalized)) {
98
+ return toPosixPath(normalized);
99
+ }
100
+ const absolutePath = path.normalize(normalized);
101
+ if (paths.scope === "global") {
102
+ if (isSubpath(paths.homeDir, absolutePath)) {
103
+ const relativePath = path.relative(paths.homeDir, absolutePath);
104
+ return relativePath ? `~/${toPosixPath(relativePath)}` : "~";
105
+ }
106
+ return toPosixPath(absolutePath);
107
+ }
108
+ if (isSubpath(paths.workspaceRoot, absolutePath)) {
109
+ const relativePath = path.relative(paths.workspaceRoot, absolutePath);
110
+ return toPosixPath(relativePath || ".");
111
+ }
112
+ if (isSubpath(paths.homeDir, absolutePath)) {
113
+ const relativePath = path.relative(paths.homeDir, absolutePath);
114
+ return relativePath ? `~/${toPosixPath(relativePath)}` : "~";
115
+ }
116
+ return toPosixPath(absolutePath);
117
+ }
118
+ function isSubpath(rootPath, candidatePath) {
119
+ const relative = path.relative(rootPath, candidatePath);
120
+ return (relative === "" ||
121
+ (!relative.startsWith("..") && !path.isAbsolute(relative)));
122
+ }
123
+ function normalizeCodexMetadata(codex) {
124
+ if (!codex || typeof codex !== "object")
125
+ return undefined;
126
+ const roles = Array.isArray(codex.roles)
127
+ ? [...new Set(codex.roles.filter((item) => !!item))].sort()
128
+ : undefined;
129
+ const mcpServers = Array.isArray(codex.mcpServers)
130
+ ? [
131
+ ...new Set(codex.mcpServers.filter((item) => !!item)),
132
+ ].sort()
133
+ : undefined;
134
+ if (!roles && !mcpServers)
135
+ return undefined;
136
+ return {
137
+ roles,
138
+ mcpServers,
139
+ };
23
140
  }
@@ -420,6 +420,11 @@ async function migrateCommands(options, summary) {
420
420
  }
421
421
  }
422
422
  function readProviderCommands(paths, provider) {
423
+ // Codex prompts are home-scoped; importing them into local canonical state
424
+ // causes unrelated global prompts to appear in fresh repositories.
425
+ if (provider === "codex" && paths.scope === "local") {
426
+ return [];
427
+ }
423
428
  const commandsDir = getProviderCommandsDir(paths, provider);
424
429
  if (!fs.existsSync(commandsDir) || !fs.statSync(commandsDir).isDirectory()) {
425
430
  return [];
@@ -224,7 +224,7 @@ function buildProviderAgentContent(provider, agent, providerConfig) {
224
224
  description: agent.description,
225
225
  ...providerConfig,
226
226
  };
227
- const fm = YAML.stringify(frontmatter).trimEnd();
227
+ const fm = YAML.stringify(frontmatter, { lineWidth: 0 }).trimEnd();
228
228
  return `---\n${fm}\n---\n\n${agent.body.trimStart()}${agent.body.endsWith("\n") ? "" : "\n"}`;
229
229
  }
230
230
  function syncProviderCommands(options) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentloom",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "Unified agent and MCP sync CLI for multi-provider AI tooling",
5
5
  "type": "module",
6
6
  "bin": {