loadouts 0.1.11

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 (261) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +108 -0
  3. package/bundled/loadouts/loadouts.yaml +5 -0
  4. package/bundled/skills/loadout-usage/SKILL.md +110 -0
  5. package/dist/builtins/index.d.ts +14 -0
  6. package/dist/builtins/index.d.ts.map +1 -0
  7. package/dist/builtins/index.js +58 -0
  8. package/dist/builtins/index.js.map +1 -0
  9. package/dist/builtins/kinds/extension.d.ts +3 -0
  10. package/dist/builtins/kinds/extension.d.ts.map +1 -0
  11. package/dist/builtins/kinds/extension.js +9 -0
  12. package/dist/builtins/kinds/extension.js.map +1 -0
  13. package/dist/builtins/kinds/instruction.d.ts +3 -0
  14. package/dist/builtins/kinds/instruction.d.ts.map +1 -0
  15. package/dist/builtins/kinds/instruction.js +8 -0
  16. package/dist/builtins/kinds/instruction.js.map +1 -0
  17. package/dist/builtins/kinds/prompt.d.ts +3 -0
  18. package/dist/builtins/kinds/prompt.d.ts.map +1 -0
  19. package/dist/builtins/kinds/prompt.js +8 -0
  20. package/dist/builtins/kinds/prompt.js.map +1 -0
  21. package/dist/builtins/kinds/rule.d.ts +3 -0
  22. package/dist/builtins/kinds/rule.d.ts.map +1 -0
  23. package/dist/builtins/kinds/rule.js +10 -0
  24. package/dist/builtins/kinds/rule.js.map +1 -0
  25. package/dist/builtins/kinds/skill.d.ts +3 -0
  26. package/dist/builtins/kinds/skill.d.ts.map +1 -0
  27. package/dist/builtins/kinds/skill.js +8 -0
  28. package/dist/builtins/kinds/skill.js.map +1 -0
  29. package/dist/builtins/kinds/theme.d.ts +3 -0
  30. package/dist/builtins/kinds/theme.d.ts.map +1 -0
  31. package/dist/builtins/kinds/theme.js +8 -0
  32. package/dist/builtins/kinds/theme.js.map +1 -0
  33. package/dist/builtins/tools/claude-code.d.ts +3 -0
  34. package/dist/builtins/tools/claude-code.d.ts.map +1 -0
  35. package/dist/builtins/tools/claude-code.js +30 -0
  36. package/dist/builtins/tools/claude-code.js.map +1 -0
  37. package/dist/builtins/tools/codex.d.ts +3 -0
  38. package/dist/builtins/tools/codex.d.ts.map +1 -0
  39. package/dist/builtins/tools/codex.js +17 -0
  40. package/dist/builtins/tools/codex.js.map +1 -0
  41. package/dist/builtins/tools/cursor.d.ts +3 -0
  42. package/dist/builtins/tools/cursor.d.ts.map +1 -0
  43. package/dist/builtins/tools/cursor.js +22 -0
  44. package/dist/builtins/tools/cursor.js.map +1 -0
  45. package/dist/builtins/tools/opencode.d.ts +3 -0
  46. package/dist/builtins/tools/opencode.d.ts.map +1 -0
  47. package/dist/builtins/tools/opencode.js +45 -0
  48. package/dist/builtins/tools/opencode.js.map +1 -0
  49. package/dist/builtins/tools/pi.d.ts +3 -0
  50. package/dist/builtins/tools/pi.d.ts.map +1 -0
  51. package/dist/builtins/tools/pi.js +22 -0
  52. package/dist/builtins/tools/pi.js.map +1 -0
  53. package/dist/cli/commands/activate.d.ts +12 -0
  54. package/dist/cli/commands/activate.d.ts.map +1 -0
  55. package/dist/cli/commands/activate.js +70 -0
  56. package/dist/cli/commands/activate.js.map +1 -0
  57. package/dist/cli/commands/check.d.ts +12 -0
  58. package/dist/cli/commands/check.d.ts.map +1 -0
  59. package/dist/cli/commands/check.js +152 -0
  60. package/dist/cli/commands/check.js.map +1 -0
  61. package/dist/cli/commands/clear.d.ts +12 -0
  62. package/dist/cli/commands/clear.d.ts.map +1 -0
  63. package/dist/cli/commands/clear.js +25 -0
  64. package/dist/cli/commands/clear.js.map +1 -0
  65. package/dist/cli/commands/create.d.ts +11 -0
  66. package/dist/cli/commands/create.d.ts.map +1 -0
  67. package/dist/cli/commands/create.js +113 -0
  68. package/dist/cli/commands/create.js.map +1 -0
  69. package/dist/cli/commands/deactivate.d.ts +12 -0
  70. package/dist/cli/commands/deactivate.d.ts.map +1 -0
  71. package/dist/cli/commands/deactivate.js +67 -0
  72. package/dist/cli/commands/deactivate.js.map +1 -0
  73. package/dist/cli/commands/diff.d.ts +16 -0
  74. package/dist/cli/commands/diff.d.ts.map +1 -0
  75. package/dist/cli/commands/diff.js +144 -0
  76. package/dist/cli/commands/diff.js.map +1 -0
  77. package/dist/cli/commands/docs.d.ts +12 -0
  78. package/dist/cli/commands/docs.d.ts.map +1 -0
  79. package/dist/cli/commands/docs.js +115 -0
  80. package/dist/cli/commands/docs.js.map +1 -0
  81. package/dist/cli/commands/edit.d.ts +11 -0
  82. package/dist/cli/commands/edit.d.ts.map +1 -0
  83. package/dist/cli/commands/edit.js +71 -0
  84. package/dist/cli/commands/edit.js.map +1 -0
  85. package/dist/cli/commands/fallback.d.ts +9 -0
  86. package/dist/cli/commands/fallback.d.ts.map +1 -0
  87. package/dist/cli/commands/fallback.js +35 -0
  88. package/dist/cli/commands/fallback.js.map +1 -0
  89. package/dist/cli/commands/info.d.ts +23 -0
  90. package/dist/cli/commands/info.d.ts.map +1 -0
  91. package/dist/cli/commands/info.js +314 -0
  92. package/dist/cli/commands/info.js.map +1 -0
  93. package/dist/cli/commands/init.d.ts +18 -0
  94. package/dist/cli/commands/init.d.ts.map +1 -0
  95. package/dist/cli/commands/init.js +255 -0
  96. package/dist/cli/commands/init.js.map +1 -0
  97. package/dist/cli/commands/install.d.ts +27 -0
  98. package/dist/cli/commands/install.d.ts.map +1 -0
  99. package/dist/cli/commands/install.js +586 -0
  100. package/dist/cli/commands/install.js.map +1 -0
  101. package/dist/cli/commands/instructions.d.ts +8 -0
  102. package/dist/cli/commands/instructions.d.ts.map +1 -0
  103. package/dist/cli/commands/instructions.js +218 -0
  104. package/dist/cli/commands/instructions.js.map +1 -0
  105. package/dist/cli/commands/kinds.d.ts +6 -0
  106. package/dist/cli/commands/kinds.d.ts.map +1 -0
  107. package/dist/cli/commands/kinds.js +59 -0
  108. package/dist/cli/commands/kinds.js.map +1 -0
  109. package/dist/cli/commands/list.d.ts +12 -0
  110. package/dist/cli/commands/list.d.ts.map +1 -0
  111. package/dist/cli/commands/list.js +182 -0
  112. package/dist/cli/commands/list.js.map +1 -0
  113. package/dist/cli/commands/policy.d.ts +28 -0
  114. package/dist/cli/commands/policy.d.ts.map +1 -0
  115. package/dist/cli/commands/policy.js +50 -0
  116. package/dist/cli/commands/policy.js.map +1 -0
  117. package/dist/cli/commands/remove.d.ts +24 -0
  118. package/dist/cli/commands/remove.d.ts.map +1 -0
  119. package/dist/cli/commands/remove.js +64 -0
  120. package/dist/cli/commands/remove.js.map +1 -0
  121. package/dist/cli/commands/render-engine.d.ts +36 -0
  122. package/dist/cli/commands/render-engine.d.ts.map +1 -0
  123. package/dist/cli/commands/render-engine.js +177 -0
  124. package/dist/cli/commands/render-engine.js.map +1 -0
  125. package/dist/cli/commands/rule.d.ts +11 -0
  126. package/dist/cli/commands/rule.d.ts.map +1 -0
  127. package/dist/cli/commands/rule.js +302 -0
  128. package/dist/cli/commands/rule.js.map +1 -0
  129. package/dist/cli/commands/sanitize.d.ts +14 -0
  130. package/dist/cli/commands/sanitize.d.ts.map +1 -0
  131. package/dist/cli/commands/sanitize.js +62 -0
  132. package/dist/cli/commands/sanitize.js.map +1 -0
  133. package/dist/cli/commands/skill.d.ts +11 -0
  134. package/dist/cli/commands/skill.d.ts.map +1 -0
  135. package/dist/cli/commands/skill.js +380 -0
  136. package/dist/cli/commands/skill.js.map +1 -0
  137. package/dist/cli/commands/status.d.ts +26 -0
  138. package/dist/cli/commands/status.d.ts.map +1 -0
  139. package/dist/cli/commands/status.js +454 -0
  140. package/dist/cli/commands/status.js.map +1 -0
  141. package/dist/cli/commands/sync.d.ts +14 -0
  142. package/dist/cli/commands/sync.d.ts.map +1 -0
  143. package/dist/cli/commands/sync.js +53 -0
  144. package/dist/cli/commands/sync.js.map +1 -0
  145. package/dist/cli/commands/update.d.ts +3 -0
  146. package/dist/cli/commands/update.d.ts.map +1 -0
  147. package/dist/cli/commands/update.js +48 -0
  148. package/dist/cli/commands/update.js.map +1 -0
  149. package/dist/cli/index.d.ts +11 -0
  150. package/dist/cli/index.d.ts.map +1 -0
  151. package/dist/cli/index.js +134 -0
  152. package/dist/cli/index.js.map +1 -0
  153. package/dist/core/config.d.ts +64 -0
  154. package/dist/core/config.d.ts.map +1 -0
  155. package/dist/core/config.js +166 -0
  156. package/dist/core/config.js.map +1 -0
  157. package/dist/core/discovery.d.ts +50 -0
  158. package/dist/core/discovery.d.ts.map +1 -0
  159. package/dist/core/discovery.js +249 -0
  160. package/dist/core/discovery.js.map +1 -0
  161. package/dist/core/fallback.d.ts +23 -0
  162. package/dist/core/fallback.d.ts.map +1 -0
  163. package/dist/core/fallback.js +119 -0
  164. package/dist/core/fallback.js.map +1 -0
  165. package/dist/core/import-discovery.d.ts +56 -0
  166. package/dist/core/import-discovery.d.ts.map +1 -0
  167. package/dist/core/import-discovery.js +304 -0
  168. package/dist/core/import-discovery.js.map +1 -0
  169. package/dist/core/kindLoader.d.ts +119 -0
  170. package/dist/core/kindLoader.d.ts.map +1 -0
  171. package/dist/core/kindLoader.js +141 -0
  172. package/dist/core/kindLoader.js.map +1 -0
  173. package/dist/core/manifest.d.ts +39 -0
  174. package/dist/core/manifest.d.ts.map +1 -0
  175. package/dist/core/manifest.js +167 -0
  176. package/dist/core/manifest.js.map +1 -0
  177. package/dist/core/plugin.d.ts +22 -0
  178. package/dist/core/plugin.d.ts.map +1 -0
  179. package/dist/core/plugin.js +20 -0
  180. package/dist/core/plugin.js.map +1 -0
  181. package/dist/core/registry.d.ts +115 -0
  182. package/dist/core/registry.d.ts.map +1 -0
  183. package/dist/core/registry.js +105 -0
  184. package/dist/core/registry.js.map +1 -0
  185. package/dist/core/render.d.ts +64 -0
  186. package/dist/core/render.d.ts.map +1 -0
  187. package/dist/core/render.js +457 -0
  188. package/dist/core/render.js.map +1 -0
  189. package/dist/core/resolve.d.ts +39 -0
  190. package/dist/core/resolve.d.ts.map +1 -0
  191. package/dist/core/resolve.js +128 -0
  192. package/dist/core/resolve.js.map +1 -0
  193. package/dist/core/schema.d.ts +308 -0
  194. package/dist/core/schema.d.ts.map +1 -0
  195. package/dist/core/schema.js +81 -0
  196. package/dist/core/schema.js.map +1 -0
  197. package/dist/core/scope.d.ts +74 -0
  198. package/dist/core/scope.d.ts.map +1 -0
  199. package/dist/core/scope.js +176 -0
  200. package/dist/core/scope.js.map +1 -0
  201. package/dist/core/template.d.ts +32 -0
  202. package/dist/core/template.d.ts.map +1 -0
  203. package/dist/core/template.js +32 -0
  204. package/dist/core/template.js.map +1 -0
  205. package/dist/core/tokens.d.ts +33 -0
  206. package/dist/core/tokens.d.ts.map +1 -0
  207. package/dist/core/tokens.js +97 -0
  208. package/dist/core/tokens.js.map +1 -0
  209. package/dist/core/types.d.ts +103 -0
  210. package/dist/core/types.d.ts.map +1 -0
  211. package/dist/core/types.js +10 -0
  212. package/dist/core/types.js.map +1 -0
  213. package/dist/index.d.ts +12 -0
  214. package/dist/index.d.ts.map +1 -0
  215. package/dist/index.js +24 -0
  216. package/dist/index.js.map +1 -0
  217. package/dist/lib/artifact-paths.d.ts +39 -0
  218. package/dist/lib/artifact-paths.d.ts.map +1 -0
  219. package/dist/lib/artifact-paths.js +83 -0
  220. package/dist/lib/artifact-paths.js.map +1 -0
  221. package/dist/lib/artifact-table.d.ts +126 -0
  222. package/dist/lib/artifact-table.d.ts.map +1 -0
  223. package/dist/lib/artifact-table.js +263 -0
  224. package/dist/lib/artifact-table.js.map +1 -0
  225. package/dist/lib/editor.d.ts +17 -0
  226. package/dist/lib/editor.d.ts.map +1 -0
  227. package/dist/lib/editor.js +33 -0
  228. package/dist/lib/editor.js.map +1 -0
  229. package/dist/lib/fs.d.ts +87 -0
  230. package/dist/lib/fs.d.ts.map +1 -0
  231. package/dist/lib/fs.js +229 -0
  232. package/dist/lib/fs.js.map +1 -0
  233. package/dist/lib/git.d.ts +13 -0
  234. package/dist/lib/git.d.ts.map +1 -0
  235. package/dist/lib/git.js +28 -0
  236. package/dist/lib/git.js.map +1 -0
  237. package/dist/lib/gitignore.d.ts +26 -0
  238. package/dist/lib/gitignore.d.ts.map +1 -0
  239. package/dist/lib/gitignore.js +97 -0
  240. package/dist/lib/gitignore.js.map +1 -0
  241. package/dist/lib/loadout-column.d.ts +66 -0
  242. package/dist/lib/loadout-column.d.ts.map +1 -0
  243. package/dist/lib/loadout-column.js +66 -0
  244. package/dist/lib/loadout-column.js.map +1 -0
  245. package/dist/lib/output.d.ts +15 -0
  246. package/dist/lib/output.d.ts.map +1 -0
  247. package/dist/lib/output.js +32 -0
  248. package/dist/lib/output.js.map +1 -0
  249. package/dist/lib/scope-indicators.d.ts +60 -0
  250. package/dist/lib/scope-indicators.d.ts.map +1 -0
  251. package/dist/lib/scope-indicators.js +110 -0
  252. package/dist/lib/scope-indicators.js.map +1 -0
  253. package/docs/authoring.md +182 -0
  254. package/docs/commands.md +192 -0
  255. package/docs/concepts.md +114 -0
  256. package/docs/index.md +60 -0
  257. package/docs/quickstart.md +100 -0
  258. package/docs/troubleshooting.md +147 -0
  259. package/docs/visual-language.md +251 -0
  260. package/docs/workflows.md +184 -0
  261. package/package.json +54 -0
@@ -0,0 +1,457 @@
1
+ /**
2
+ * Generic render pipeline.
3
+ *
4
+ * planRender() — computes what would be written without touching disk.
5
+ * renderOutput() — renders one (item, spec) pair to content + hash.
6
+ * applyPlan() — writes the plan to disk and saves state.
7
+ * removeManaged() — removes all outputs recorded in a state file.
8
+ *
9
+ * All tool/kind logic is delegated to the registry; this module contains
10
+ * no per-tool or per-kind switch statements.
11
+ */
12
+ import * as path from "node:path";
13
+ import * as os from "node:os";
14
+ import { createSymlink, writeFile, removeFile, removeDir, readFile, fileExists, isDirectory, isSymlink, findSymlinkParent, ensureDir, hashContent, walkDir, } from "../lib/fs.js";
15
+ import { updateGitignore, removeGitignoreSection } from "../lib/gitignore.js";
16
+ import { registry } from "./registry.js";
17
+ import { expandTemplate } from "./template.js";
18
+ import { isUnmanagedCollision, saveState, loadState } from "./manifest.js";
19
+ // ---------------------------------------------------------------------------
20
+ // Output spec resolution
21
+ // ---------------------------------------------------------------------------
22
+ /**
23
+ * Resolve the OutputSpec for one (item, tool) pair using the registry.
24
+ * Returns null if the tool doesn't support this kind or has no mapping.
25
+ */
26
+ export function resolveOutputSpec(toolName, item, scope) {
27
+ const mapping = registry.resolveMapping(toolName, item.kind);
28
+ if (!mapping)
29
+ return null;
30
+ const tool = registry.getTool(toolName);
31
+ const sourceExt = path.extname(item.sourcePath);
32
+ const ext = mapping.ext ?? sourceExt;
33
+ const vars = {
34
+ base: tool.basePath[scope],
35
+ home: os.homedir(),
36
+ stem: path.basename(item.sourcePath, sourceExt),
37
+ ext,
38
+ name: path.basename(item.sourcePath),
39
+ relative: item.relativePath,
40
+ kind: item.kind,
41
+ };
42
+ const targetPath = expandTemplate(mapping.path, scope, vars);
43
+ const mode = mapping.mode ??
44
+ (mapping.generate ? "generate" : mapping.transform ? "copy" : "symlink");
45
+ return {
46
+ tool: toolName,
47
+ kind: item.kind,
48
+ sourcePath: item.sourcePath,
49
+ targetPath,
50
+ mode,
51
+ };
52
+ }
53
+ // ---------------------------------------------------------------------------
54
+ // Render
55
+ // ---------------------------------------------------------------------------
56
+ /**
57
+ * Render one (item, spec) pair to content + hash.
58
+ * No disk I/O — used for planning, token estimation, and copy/generate writes.
59
+ *
60
+ * All items are now file-based (dir-layout items are expanded in planRender).
61
+ */
62
+ export async function renderOutput(item, spec) {
63
+ const kind = registry.getKind(spec.kind);
64
+ if (!kind)
65
+ throw new Error(`Unknown kind: "${spec.kind}"`);
66
+ const mapping = registry.resolveMapping(spec.tool, spec.kind);
67
+ // generate mode: produce content from a registered generator
68
+ if (mapping?.generate) {
69
+ const content = mapping.generate(item);
70
+ return { content, hash: hashContent(content) };
71
+ }
72
+ // file-layout: read source, optionally transform
73
+ const raw = readFile(item.sourcePath);
74
+ if (mapping?.transform) {
75
+ const transformFn = typeof mapping.transform === "string"
76
+ ? registry.getTransform(mapping.transform)
77
+ : mapping.transform;
78
+ if (!transformFn) {
79
+ throw new Error(`Transform "${mapping.transform}" is not registered.`);
80
+ }
81
+ const content = transformFn(raw);
82
+ return { content, hash: hashContent(content) };
83
+ }
84
+ return { content: raw, hash: hashContent(raw) };
85
+ }
86
+ // ---------------------------------------------------------------------------
87
+ // Plan
88
+ // ---------------------------------------------------------------------------
89
+ /**
90
+ * Expand a dir-layout item into individual file items.
91
+ * Preserves the subdirectory structure within the directory.
92
+ */
93
+ function expandDirItem(item, kind) {
94
+ if (kind.layout !== "dir" || !isDirectory(item.sourcePath)) {
95
+ return [item];
96
+ }
97
+ const files = walkDir(item.sourcePath);
98
+ return files.map((relativeFile) => ({
99
+ kind: item.kind,
100
+ sourcePath: path.join(item.sourcePath, relativeFile),
101
+ relativePath: path.join(item.relativePath, relativeFile),
102
+ tools: item.tools,
103
+ }));
104
+ }
105
+ /**
106
+ * Resolve output spec for an expanded file within a dir-layout item.
107
+ * Uses the base directory's mapping but adjusts paths for the specific file.
108
+ */
109
+ function resolveExpandedOutputSpec(toolName, baseItem, expandedItem, scope) {
110
+ const mapping = registry.resolveMapping(toolName, baseItem.kind);
111
+ if (!mapping)
112
+ return null;
113
+ const tool = registry.getTool(toolName);
114
+ const sourceExt = path.extname(expandedItem.sourcePath);
115
+ const ext = mapping.ext ?? sourceExt;
116
+ // Get the relative path within the skill directory
117
+ const relativeWithinDir = path.relative(baseItem.sourcePath, expandedItem.sourcePath);
118
+ const vars = {
119
+ base: tool.basePath[scope],
120
+ home: os.homedir(),
121
+ stem: path.basename(baseItem.sourcePath), // Use the directory name as stem
122
+ ext,
123
+ name: path.basename(baseItem.sourcePath),
124
+ relative: baseItem.relativePath,
125
+ kind: baseItem.kind,
126
+ };
127
+ // Expand the template to get the base target path (e.g., .cursor/skills/debug)
128
+ const baseTargetPath = expandTemplate(mapping.path, scope, vars);
129
+ // Append the relative file path within the directory
130
+ const targetPath = path.join(baseTargetPath, relativeWithinDir);
131
+ const mode = mapping.mode ??
132
+ (mapping.generate ? "generate" : mapping.transform ? "copy" : "symlink");
133
+ return {
134
+ tool: toolName,
135
+ kind: expandedItem.kind,
136
+ sourcePath: expandedItem.sourcePath,
137
+ targetPath,
138
+ mode,
139
+ };
140
+ }
141
+ /**
142
+ * Compute what would be written for a resolved loadout without touching disk.
143
+ *
144
+ * Dir-layout items (skills) are expanded into individual file outputs,
145
+ * allowing users to have custom files alongside loadout-managed ones.
146
+ */
147
+ export async function planRender(loadout, projectRoot, scope, statePath) {
148
+ // Use explicit statePath if provided, otherwise fall back to loadout's root.
149
+ // This is critical for bundled loadouts which don't have their own state file—
150
+ // they share state with the scope that activated them.
151
+ const state = loadState(statePath ?? loadout.rootPath);
152
+ const outputs = [];
153
+ const shadowed = [];
154
+ const errors = [];
155
+ for (const item of loadout.items) {
156
+ const kind = registry.getKind(item.kind);
157
+ if (!kind) {
158
+ errors.push(`${item.relativePath}: Unknown kind "${item.kind}"`);
159
+ continue;
160
+ }
161
+ // Expand dir-layout items into individual files
162
+ const expandedItems = expandDirItem(item, kind);
163
+ for (const expandedItem of expandedItems) {
164
+ for (const toolName of expandedItem.tools) {
165
+ try {
166
+ // Use expanded spec resolver for dir-layout items
167
+ const spec = kind.layout === "dir"
168
+ ? resolveExpandedOutputSpec(toolName, item, expandedItem, scope)
169
+ : resolveOutputSpec(toolName, expandedItem, scope);
170
+ if (!spec)
171
+ continue; // tool doesn't support this kind
172
+ if (isUnmanagedCollision(state, spec.targetPath, projectRoot)) {
173
+ shadowed.push({
174
+ tool: spec.tool,
175
+ kind: spec.kind,
176
+ sourcePath: spec.sourcePath,
177
+ targetPath: spec.targetPath,
178
+ });
179
+ continue;
180
+ }
181
+ const rendered = await renderOutput(expandedItem, spec);
182
+ outputs.push({ spec, item: expandedItem, hash: rendered.hash });
183
+ }
184
+ catch (err) {
185
+ errors.push(`${expandedItem.relativePath} → ${toolName}: ${err instanceof Error ? err.message : String(err)}`);
186
+ }
187
+ }
188
+ }
189
+ }
190
+ return { outputs, shadowed, errors };
191
+ }
192
+ // ---------------------------------------------------------------------------
193
+ // Apply
194
+ // ---------------------------------------------------------------------------
195
+ /**
196
+ * Resolve a target path to an absolute path.
197
+ * Handles both relative paths (project scope) and absolute paths (global scope).
198
+ */
199
+ function resolveTargetPath(targetPath, projectRoot) {
200
+ return path.isAbsolute(targetPath)
201
+ ? targetPath
202
+ : path.join(projectRoot, targetPath);
203
+ }
204
+ /**
205
+ * Apply a render plan to disk and save state.
206
+ *
207
+ * `mode` is top-level metadata recorded in the state file; per-output modes
208
+ * live on each spec and govern the actual write strategy.
209
+ */
210
+ export async function applyPlan(plan, loadout, projectRoot, mode = "symlink", scope = "project") {
211
+ // Remove stale managed outputs not included in the new plan
212
+ const existingState = loadState(loadout.rootPath);
213
+ if (existingState) {
214
+ const newTargets = new Set(plan.outputs.map((o) => o.spec.targetPath));
215
+ for (const entry of existingState.entries) {
216
+ if (!newTargets.has(entry.targetPath)) {
217
+ const fullPath = resolveTargetPath(entry.targetPath, projectRoot);
218
+ if (isDirectory(fullPath))
219
+ removeDir(fullPath);
220
+ else
221
+ removeFile(fullPath);
222
+ }
223
+ }
224
+ }
225
+ // Write each planned output
226
+ for (const { spec, item } of plan.outputs) {
227
+ const targetPath = resolveTargetPath(spec.targetPath, projectRoot);
228
+ // Clear whatever was there before (including broken symlinks)
229
+ if (fileExists(targetPath) || isDirectory(targetPath) || isSymlink(targetPath)) {
230
+ if (isDirectory(targetPath))
231
+ removeDir(targetPath);
232
+ else
233
+ removeFile(targetPath);
234
+ }
235
+ // Remove any symlinked parent directories (external symlinks)
236
+ const symlinkParent = findSymlinkParent(targetPath);
237
+ if (symlinkParent) {
238
+ removeFile(symlinkParent);
239
+ }
240
+ ensureDir(path.dirname(targetPath));
241
+ if (spec.mode === "symlink") {
242
+ createSymlink(spec.sourcePath, targetPath);
243
+ }
244
+ else {
245
+ // copy or generate — write rendered content
246
+ const rendered = await renderOutput(item, spec);
247
+ writeFile(targetPath, rendered.content);
248
+ }
249
+ }
250
+ // Build manifest entries from plan outputs, grouping tools by targetPath
251
+ const outputsByTarget = new Map();
252
+ for (const output of plan.outputs) {
253
+ const existing = outputsByTarget.get(output.spec.targetPath);
254
+ if (existing) {
255
+ existing.tools.add(output.spec.tool);
256
+ }
257
+ else {
258
+ outputsByTarget.set(output.spec.targetPath, {
259
+ output,
260
+ tools: new Set([output.spec.tool]),
261
+ });
262
+ }
263
+ }
264
+ const entries = Array.from(outputsByTarget.values()).map(({ output: { spec, hash }, tools }) => ({
265
+ tools: Array.from(tools).sort(),
266
+ kind: spec.kind,
267
+ sourcePath: spec.sourcePath,
268
+ targetPath: spec.targetPath,
269
+ mode: spec.mode,
270
+ renderedHash: hash,
271
+ }));
272
+ const newState = {
273
+ active: [loadout.name],
274
+ mode,
275
+ appliedAt: new Date().toISOString(),
276
+ entries,
277
+ shadowed: plan.shadowed,
278
+ };
279
+ saveState(loadout.rootPath, newState);
280
+ // Update .gitignore with managed paths (project scope only)
281
+ if (scope === "project") {
282
+ const managedPaths = plan.outputs.map((o) => o.spec.targetPath);
283
+ updateGitignore(projectRoot, managedPaths);
284
+ }
285
+ }
286
+ /**
287
+ * Apply multiple loadouts, merging their outputs with deduplication by targetPath.
288
+ */
289
+ export async function applyMultiPlan(plans, loadoutRoot, projectRoot, mode = "symlink", scope = "project") {
290
+ // Merge all outputs, deduplicating by targetPath but collecting all tools
291
+ const outputsByTarget = new Map();
292
+ const mergedShadowed = [];
293
+ const seenShadowedTargets = new Set();
294
+ for (const { plan } of plans) {
295
+ for (const output of plan.outputs) {
296
+ const existing = outputsByTarget.get(output.spec.targetPath);
297
+ if (existing) {
298
+ // Same target path, collect the tool
299
+ existing.tools.add(output.spec.tool);
300
+ }
301
+ else {
302
+ // First output for this target
303
+ outputsByTarget.set(output.spec.targetPath, {
304
+ output,
305
+ tools: new Set([output.spec.tool]),
306
+ });
307
+ }
308
+ }
309
+ for (const s of plan.shadowed) {
310
+ if (!seenShadowedTargets.has(s.targetPath)) {
311
+ seenShadowedTargets.add(s.targetPath);
312
+ mergedShadowed.push(s);
313
+ }
314
+ }
315
+ }
316
+ const mergedOutputs = Array.from(outputsByTarget.values());
317
+ // Detect changes
318
+ const existingState = loadState(loadoutRoot);
319
+ const oldEntries = new Map(existingState?.entries.map(e => [e.targetPath, e]) ?? []);
320
+ const newHashes = new Map(mergedOutputs.map(o => [o.output.spec.targetPath, o.output.hash]));
321
+ const updated = [];
322
+ const added = [];
323
+ const removed = [];
324
+ // Find updated and added
325
+ for (const { output } of mergedOutputs) {
326
+ const oldEntry = oldEntries.get(output.spec.targetPath);
327
+ if (!oldEntry) {
328
+ added.push(output.spec.targetPath);
329
+ }
330
+ else if (oldEntry.renderedHash !== output.hash) {
331
+ updated.push(output.spec.targetPath);
332
+ }
333
+ }
334
+ // Find removed
335
+ const newTargets = new Set(mergedOutputs.map((o) => o.output.spec.targetPath));
336
+ if (existingState) {
337
+ for (const entry of existingState.entries) {
338
+ if (!newTargets.has(entry.targetPath)) {
339
+ removed.push(entry.targetPath);
340
+ const fullPath = resolveTargetPath(entry.targetPath, projectRoot);
341
+ if (isDirectory(fullPath))
342
+ removeDir(fullPath);
343
+ else
344
+ removeFile(fullPath);
345
+ }
346
+ }
347
+ }
348
+ // Write each merged output
349
+ const byTool = new Map();
350
+ for (const { output: { spec, item } } of mergedOutputs) {
351
+ const targetPath = resolveTargetPath(spec.targetPath, projectRoot);
352
+ // Clear whatever was there before
353
+ if (fileExists(targetPath) || isDirectory(targetPath) || isSymlink(targetPath)) {
354
+ if (isDirectory(targetPath))
355
+ removeDir(targetPath);
356
+ else
357
+ removeFile(targetPath);
358
+ }
359
+ // Remove any symlinked parent directories (external symlinks)
360
+ const symlinkParent = findSymlinkParent(targetPath);
361
+ if (symlinkParent) {
362
+ removeFile(symlinkParent);
363
+ }
364
+ ensureDir(path.dirname(targetPath));
365
+ if (spec.mode === "symlink") {
366
+ createSymlink(spec.sourcePath, targetPath);
367
+ }
368
+ else {
369
+ // copy or generate — write rendered content
370
+ const rendered = await renderOutput(item, spec);
371
+ writeFile(targetPath, rendered.content);
372
+ }
373
+ byTool.set(spec.tool, (byTool.get(spec.tool) || 0) + 1);
374
+ }
375
+ // Build manifest entries with all tools that share each output
376
+ const entries = mergedOutputs.map(({ output: { spec, hash }, tools }) => ({
377
+ tools: Array.from(tools).sort(),
378
+ kind: spec.kind,
379
+ sourcePath: spec.sourcePath,
380
+ targetPath: spec.targetPath,
381
+ mode: spec.mode,
382
+ renderedHash: hash,
383
+ }));
384
+ const activeNames = plans.map((p) => p.loadout.name);
385
+ const newState = {
386
+ active: activeNames,
387
+ mode,
388
+ appliedAt: new Date().toISOString(),
389
+ entries,
390
+ shadowed: mergedShadowed,
391
+ };
392
+ saveState(loadoutRoot, newState);
393
+ // Update .gitignore with managed paths (project scope only)
394
+ if (scope === "project") {
395
+ const managedPaths = mergedOutputs.map((o) => o.output.spec.targetPath);
396
+ updateGitignore(projectRoot, managedPaths);
397
+ }
398
+ return {
399
+ totalOutputs: mergedOutputs.length,
400
+ byTool,
401
+ changes: { updated, added, removed },
402
+ };
403
+ }
404
+ // ---------------------------------------------------------------------------
405
+ // Remove
406
+ // ---------------------------------------------------------------------------
407
+ /**
408
+ * Remove all managed outputs recorded in the state file.
409
+ * Does NOT clear the state file — callers decide whether to call clearState().
410
+ * Also removes the loadout-managed section from .gitignore (project scope only).
411
+ */
412
+ export async function removeManaged(loadoutRoot, projectRoot, scope = "project") {
413
+ const state = loadState(loadoutRoot);
414
+ const removed = [];
415
+ const missing = [];
416
+ if (!state)
417
+ return { removed, missing };
418
+ for (const entry of state.entries) {
419
+ const fullPath = resolveTargetPath(entry.targetPath, projectRoot);
420
+ if (fileExists(fullPath) || isDirectory(fullPath)) {
421
+ if (isDirectory(fullPath))
422
+ removeDir(fullPath);
423
+ else
424
+ removeFile(fullPath);
425
+ removed.push(entry.targetPath);
426
+ }
427
+ else {
428
+ missing.push(entry.targetPath);
429
+ }
430
+ }
431
+ // Remove now-empty parent directories
432
+ const dirs = new Set();
433
+ for (const entry of state.entries) {
434
+ let dir = path.dirname(resolveTargetPath(entry.targetPath, projectRoot));
435
+ while (dir !== projectRoot && dir !== path.dirname(dir)) {
436
+ dirs.add(dir);
437
+ dir = path.dirname(dir);
438
+ }
439
+ }
440
+ const sortedDirs = [...dirs].sort((a, b) => b.split(path.sep).length - a.split(path.sep).length);
441
+ const fs = await import("node:fs");
442
+ for (const dir of sortedDirs) {
443
+ try {
444
+ if (fs.readdirSync(dir).length === 0)
445
+ removeDir(dir);
446
+ }
447
+ catch {
448
+ // Ignore — dir may not exist or may be unremovable
449
+ }
450
+ }
451
+ // Clean up .gitignore (project scope only)
452
+ if (scope === "project") {
453
+ removeGitignoreSection(projectRoot);
454
+ }
455
+ return { removed, missing };
456
+ }
457
+ //# sourceMappingURL=render.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render.js","sourceRoot":"","sources":["../../src/core/render.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Resolve loadout graphs and included items
3
+ */
4
+ import type { LoadoutRoot, ResolvedItem, ResolvedLoadout, Tool, RootConfig, CommandContext } from "./types.js";
5
+ /**
6
+ * Resolve a loadout by name.
7
+ */
8
+ export declare function resolveLoadout(name: string, roots: LoadoutRoot[], rootConfig?: RootConfig): ResolvedLoadout;
9
+ /**
10
+ * Check if instructions (AGENTS.md) exist in the loadout root.
11
+ */
12
+ export declare function hasInstructions(loadoutRoot: string): boolean;
13
+ /**
14
+ * Get the instruction item if it exists.
15
+ */
16
+ export declare function getInstructionItem(loadoutRoot: string, tools: Tool[]): ResolvedItem | null;
17
+ /**
18
+ * Result of loading and fully resolving a loadout for a command context.
19
+ */
20
+ export interface LoadResult {
21
+ loadout: ResolvedLoadout;
22
+ rootConfig: RootConfig;
23
+ loadoutName: string;
24
+ roots: LoadoutRoot[];
25
+ sourceWarnings: string[];
26
+ }
27
+ /**
28
+ * Discover roots, parse root config, resolve the loadout, and attach the
29
+ * instruction item if present. Throws on any failure — callers decide whether
30
+ * to exit. This consolidates the pattern previously duplicated across apply,
31
+ * diff, info, init, and global commands.
32
+ *
33
+ * Root collection order:
34
+ * 1. Primary .loadouts/ (from ctx.configPath)
35
+ * 2. Sources declared in loadout.yaml (transitively)
36
+ * 3. Global ~/.config/loadouts/ (lowest priority)
37
+ */
38
+ export declare function loadResolvedLoadout(ctx: CommandContext, name?: string): Promise<LoadResult>;
39
+ //# sourceMappingURL=resolve.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../src/core/resolve.ts"],"names":[],"mappings":"AAAA;;GAEG;AAWH,OAAO,KAAK,EACV,WAAW,EAGX,YAAY,EACZ,eAAe,EACf,IAAI,EACJ,UAAU,EACV,cAAc,EACf,MAAM,YAAY,CAAC;AAGpB;;GAEG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,WAAW,EAAE,EACpB,UAAU,CAAC,EAAE,UAAU,GACtB,eAAe,CAyBjB;AAoCD;;GAEG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAE5D;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,IAAI,EAAE,GACZ,YAAY,GAAG,IAAI,CAarB;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,eAAe,CAAC;IACzB,UAAU,EAAE,UAAU,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,mBAAmB,CACvC,GAAG,EAAE,cAAc,EACnB,IAAI,CAAC,EAAE,MAAM,GACZ,OAAO,CAAC,UAAU,CAAC,CAuCrB"}
@@ -0,0 +1,128 @@
1
+ /**
2
+ * Resolve loadout graphs and included items
3
+ */
4
+ import * as path from "node:path";
5
+ import { findLoadoutDefinition, parseRootConfig, } from "./config.js";
6
+ import { registry } from "./registry.js";
7
+ import { loadYamlKindsFromRoots } from "./kindLoader.js";
8
+ import { fileExists, isDirectory } from "../lib/fs.js";
9
+ import { discoverLoadoutRoots, getGlobalRoot, collectRootsWithSources } from "./discovery.js";
10
+ import { BUILTIN_TOOL_NAMES } from "../builtins/index.js";
11
+ /**
12
+ * Resolve a loadout by name.
13
+ */
14
+ export function resolveLoadout(name, roots, rootConfig) {
15
+ // Load any YAML-defined kinds from the discovered roots before resolving
16
+ // items, so inferKind() can match custom kinds. Idempotent.
17
+ loadYamlKindsFromRoots(roots);
18
+ const found = findLoadoutDefinition(name, roots);
19
+ if (!found) {
20
+ throw new Error(`Loadout not found: ${name}`);
21
+ }
22
+ const { definition, rootPath } = found;
23
+ const effectiveTools = definition.tools || rootConfig?.tools || [...BUILTIN_TOOL_NAMES];
24
+ const items = [];
25
+ for (const include of definition.include || []) {
26
+ items.push(resolveInclude(include, rootPath, effectiveTools));
27
+ }
28
+ return {
29
+ name,
30
+ description: definition.description,
31
+ tools: effectiveTools,
32
+ items,
33
+ rootPath,
34
+ };
35
+ }
36
+ /**
37
+ * Resolve a single include entry to a ResolvedItem.
38
+ */
39
+ function resolveInclude(include, rootPath, defaultTools) {
40
+ const relativePath = typeof include === "string" ? include : include.path;
41
+ const tools = typeof include === "object" && include.tools
42
+ ? include.tools
43
+ : defaultTools;
44
+ const sourcePath = path.join(rootPath, relativePath);
45
+ // Validate the source exists
46
+ if (!fileExists(sourcePath) && !isDirectory(sourcePath)) {
47
+ throw new Error(`Include not found: ${relativePath} (in ${rootPath})`);
48
+ }
49
+ const kind = registry.inferKind(relativePath);
50
+ if (!kind) {
51
+ throw new Error(`Cannot infer artifact kind for path: ${relativePath}`);
52
+ }
53
+ return {
54
+ kind,
55
+ sourcePath,
56
+ relativePath,
57
+ tools,
58
+ };
59
+ }
60
+ /**
61
+ * Check if instructions (AGENTS.md) exist in the loadout root.
62
+ */
63
+ export function hasInstructions(loadoutRoot) {
64
+ return fileExists(path.join(loadoutRoot, "AGENTS.md"));
65
+ }
66
+ /**
67
+ * Get the instruction item if it exists.
68
+ */
69
+ export function getInstructionItem(loadoutRoot, tools) {
70
+ const sourcePath = path.join(loadoutRoot, "AGENTS.md");
71
+ if (!fileExists(sourcePath)) {
72
+ return null;
73
+ }
74
+ return {
75
+ kind: "instruction",
76
+ sourcePath,
77
+ relativePath: "AGENTS.md",
78
+ tools,
79
+ };
80
+ }
81
+ /**
82
+ * Discover roots, parse root config, resolve the loadout, and attach the
83
+ * instruction item if present. Throws on any failure — callers decide whether
84
+ * to exit. This consolidates the pattern previously duplicated across apply,
85
+ * diff, info, init, and global commands.
86
+ *
87
+ * Root collection order:
88
+ * 1. Primary .loadouts/ (from ctx.configPath)
89
+ * 2. Sources declared in loadout.yaml (transitively)
90
+ * 3. Global ~/.config/loadouts/ (lowest priority)
91
+ */
92
+ export async function loadResolvedLoadout(ctx, name) {
93
+ let roots;
94
+ let sourceWarnings = [];
95
+ if (ctx.scope === "global") {
96
+ const globalRoot = getGlobalRoot();
97
+ if (!globalRoot) {
98
+ throw new Error("No global loadout found at ~/.config/loadouts");
99
+ }
100
+ // Global scope: just the global root, plus any sources it declares
101
+ const collected = collectRootsWithSources(globalRoot, false);
102
+ roots = collected.roots;
103
+ sourceWarnings = collected.warnings;
104
+ }
105
+ else {
106
+ // Project scope: start with the nearest .loadouts/, collect sources
107
+ const discovered = await discoverLoadoutRoots(ctx.projectRoot);
108
+ if (discovered.length === 0) {
109
+ throw new Error("No .loadouts/ directory found. Run 'loadouts init' first.");
110
+ }
111
+ const primaryRoot = discovered[0];
112
+ const collected = collectRootsWithSources(primaryRoot, true);
113
+ roots = collected.roots;
114
+ sourceWarnings = collected.warnings;
115
+ }
116
+ const rootConfig = parseRootConfig(ctx.configPath);
117
+ const loadoutName = name || rootConfig.default || "base";
118
+ const loadout = resolveLoadout(loadoutName, roots, rootConfig);
119
+ // Auto-inject AGENTS.md only when not already in the loadout's include list.
120
+ const alreadyHasInstruction = loadout.items.some((i) => i.relativePath === "AGENTS.md");
121
+ if (!alreadyHasInstruction) {
122
+ const instructionItem = getInstructionItem(ctx.configPath, loadout.tools);
123
+ if (instructionItem)
124
+ loadout.items.push(instructionItem);
125
+ }
126
+ return { loadout, rootConfig, loadoutName, roots, sourceWarnings };
127
+ }
128
+ //# sourceMappingURL=resolve.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve.js","sourceRoot":"","sources":["../../src/core/resolve.ts"],"names":[],"mappings":"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"}