@agent-loom/loom 1.0.0
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/README.md +144 -0
- package/dist/apply.d.ts +56 -0
- package/dist/apply.d.ts.map +1 -0
- package/dist/apply.js +97 -0
- package/dist/apply.js.map +1 -0
- package/dist/cli.d.ts +9 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +503 -0
- package/dist/cli.js.map +1 -0
- package/dist/clone.d.ts +38 -0
- package/dist/clone.d.ts.map +1 -0
- package/dist/clone.js +68 -0
- package/dist/clone.js.map +1 -0
- package/dist/config.d.ts +14 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +55 -0
- package/dist/config.js.map +1 -0
- package/dist/manifest.d.ts +41 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +454 -0
- package/dist/manifest.js.map +1 -0
- package/dist/renderers/claude.d.ts +15 -0
- package/dist/renderers/claude.d.ts.map +1 -0
- package/dist/renderers/claude.js +180 -0
- package/dist/renderers/claude.js.map +1 -0
- package/dist/renderers/copilot.d.ts +16 -0
- package/dist/renderers/copilot.d.ts.map +1 -0
- package/dist/renderers/copilot.js +191 -0
- package/dist/renderers/copilot.js.map +1 -0
- package/dist/repo-clone.d.ts +72 -0
- package/dist/repo-clone.d.ts.map +1 -0
- package/dist/repo-clone.js +197 -0
- package/dist/repo-clone.js.map +1 -0
- package/dist/resolve-template.d.ts +32 -0
- package/dist/resolve-template.d.ts.map +1 -0
- package/dist/resolve-template.js +75 -0
- package/dist/resolve-template.js.map +1 -0
- package/dist/search-registry.d.ts +31 -0
- package/dist/search-registry.d.ts.map +1 -0
- package/dist/search-registry.js +96 -0
- package/dist/search-registry.js.map +1 -0
- package/dist/search.d.ts +20 -0
- package/dist/search.d.ts.map +1 -0
- package/dist/search.js +51 -0
- package/dist/search.js.map +1 -0
- package/dist/skill-fetcher.d.ts +40 -0
- package/dist/skill-fetcher.d.ts.map +1 -0
- package/dist/skill-fetcher.js +99 -0
- package/dist/skill-fetcher.js.map +1 -0
- package/dist/types.d.ts +297 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +18 -0
- package/dist/types.js.map +1 -0
- package/dist/validate.d.ts +42 -0
- package/dist/validate.d.ts.map +1 -0
- package/dist/validate.js +191 -0
- package/dist/validate.js.map +1 -0
- package/dist/workspaces.d.ts +17 -0
- package/dist/workspaces.d.ts.map +1 -0
- package/dist/workspaces.js +72 -0
- package/dist/workspaces.js.map +1 -0
- package/package.json +42 -0
package/dist/cli.js
ADDED
|
@@ -0,0 +1,503 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Loom CLI — Entry Point
|
|
4
|
+
*
|
|
5
|
+
* Template engine for coding agent workspaces.
|
|
6
|
+
* Supports GitHub Copilot, Claude Code, and Cursor targets.
|
|
7
|
+
*/
|
|
8
|
+
import { Command } from 'commander';
|
|
9
|
+
import chalk from 'chalk';
|
|
10
|
+
import { createInterface } from 'node:readline';
|
|
11
|
+
import { execSync } from 'node:child_process';
|
|
12
|
+
import { platform } from 'node:os';
|
|
13
|
+
import { createRequire } from 'node:module';
|
|
14
|
+
import { addRegistry, removeRegistry, listRegistries } from './config.js';
|
|
15
|
+
import { searchTemplates } from './search.js';
|
|
16
|
+
import { resolveRegistryIndexPaths } from './search-registry.js';
|
|
17
|
+
import { applyTemplate } from './apply.js';
|
|
18
|
+
import { cloneRegistry, resolveTemplatePath } from './clone.js';
|
|
19
|
+
import { resolveTemplateSource } from './resolve-template.js';
|
|
20
|
+
import { createCraftFetcher } from './skill-fetcher.js';
|
|
21
|
+
import { validateTemplate, validateRegistry } from './validate.js';
|
|
22
|
+
import { loadWorkspaces, filterWorkspaces, recordWorkspace, removeWorkspace, addTag, setNote, saveWorkspaces, } from './workspaces.js';
|
|
23
|
+
const require = createRequire(import.meta.url);
|
|
24
|
+
const { version } = require('../package.json');
|
|
25
|
+
const program = new Command();
|
|
26
|
+
program
|
|
27
|
+
.name('loom')
|
|
28
|
+
.description('Template engine for coding agent workspaces')
|
|
29
|
+
.version(version);
|
|
30
|
+
// =============================================================================
|
|
31
|
+
// registry
|
|
32
|
+
// =============================================================================
|
|
33
|
+
const registry = program
|
|
34
|
+
.command('registry')
|
|
35
|
+
.description('Manage template registries');
|
|
36
|
+
registry
|
|
37
|
+
.command('add <name> <url>')
|
|
38
|
+
.description('Add a template registry')
|
|
39
|
+
.action(async (name, url) => {
|
|
40
|
+
try {
|
|
41
|
+
await addRegistry(name, url);
|
|
42
|
+
console.log(chalk.green(`✓ Registry "${name}" added.`));
|
|
43
|
+
}
|
|
44
|
+
catch (err) {
|
|
45
|
+
console.error(chalk.red(err.message));
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
registry
|
|
50
|
+
.command('list')
|
|
51
|
+
.description('List configured registries')
|
|
52
|
+
.action(async () => {
|
|
53
|
+
const regs = await listRegistries();
|
|
54
|
+
if (regs.length === 0) {
|
|
55
|
+
console.log(chalk.yellow('No registries configured. Use: loom registry add <name> <url>'));
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
for (const r of regs) {
|
|
59
|
+
console.log(` ${chalk.bold(r.name)} ${r.url}`);
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
registry
|
|
63
|
+
.command('remove <name>')
|
|
64
|
+
.description('Remove a template registry')
|
|
65
|
+
.action(async (name) => {
|
|
66
|
+
try {
|
|
67
|
+
await removeRegistry(name);
|
|
68
|
+
console.log(chalk.green(`✓ Registry "${name}" removed.`));
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
console.error(chalk.red(err.message));
|
|
72
|
+
process.exit(1);
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
// =============================================================================
|
|
76
|
+
// search
|
|
77
|
+
// =============================================================================
|
|
78
|
+
program
|
|
79
|
+
.command('search <keyword>')
|
|
80
|
+
.description('Search templates across registries')
|
|
81
|
+
.option('-i, --index <path>', 'Path to index.yaml file (legacy)')
|
|
82
|
+
.option('-r, --registry <name>', 'Search a specific registered registry by name')
|
|
83
|
+
.option('--all', 'Search all configured registries')
|
|
84
|
+
.action(async (keyword, opts) => {
|
|
85
|
+
try {
|
|
86
|
+
let indexPaths;
|
|
87
|
+
if (opts.index) {
|
|
88
|
+
// Legacy mode: explicit path
|
|
89
|
+
indexPaths = [{ name: 'local', path: opts.index }];
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
// Registry resolution mode
|
|
93
|
+
const registryName = opts.registry;
|
|
94
|
+
indexPaths = await resolveRegistryIndexPaths({
|
|
95
|
+
registryName,
|
|
96
|
+
workspaceDir: process.cwd(),
|
|
97
|
+
includeWorkspaceRoot: true,
|
|
98
|
+
});
|
|
99
|
+
if (indexPaths.length === 0) {
|
|
100
|
+
if (registryName) {
|
|
101
|
+
console.log(chalk.yellow(`Registry "${registryName}" not found or not cached.\n` +
|
|
102
|
+
` Add it with: loom registry add ${registryName} <url>\n` +
|
|
103
|
+
` Or provide a path: loom search ${keyword} -i <path/to/index.yaml>`));
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
console.log(chalk.yellow('No registries configured or cached.\n' +
|
|
107
|
+
' Add a registry: loom registry add <name> <url>\n' +
|
|
108
|
+
' Or provide a path: loom search <keyword> -i <path/to/index.yaml>'));
|
|
109
|
+
}
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
const results = await searchTemplates(indexPaths, keyword);
|
|
114
|
+
if (results.length === 0) {
|
|
115
|
+
console.log(chalk.yellow(`No templates found for "${keyword}".`));
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
let hasTeamWithAgents = false;
|
|
119
|
+
for (const t of results) {
|
|
120
|
+
if (t.matchedAgent) {
|
|
121
|
+
// Agent-level match
|
|
122
|
+
console.log(` ${chalk.dim(t.id)} > ${chalk.bold(t.matchedAgent.id)} ${t.matchedAgent.name} ${chalk.dim(`[${t.registry}]`)}`);
|
|
123
|
+
console.log(` ${chalk.dim(t.matchedAgent.description)}`);
|
|
124
|
+
if (t.matchedAgent.tags.length > 0) {
|
|
125
|
+
console.log(` tags: ${t.matchedAgent.tags.join(', ')}`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
// Team-level match
|
|
130
|
+
const agents = t.agents ?? [];
|
|
131
|
+
const agentCount = agents.length;
|
|
132
|
+
const agentSuffix = agentCount > 0 ? chalk.dim(` (${agentCount} agents)`) : '';
|
|
133
|
+
console.log(` ${chalk.bold(t.id)} ${t.name}${agentSuffix} ${chalk.dim(`[${t.registry}]`)}`);
|
|
134
|
+
console.log(` ${chalk.dim(t.description)}`);
|
|
135
|
+
if (t.tags.length > 0) {
|
|
136
|
+
console.log(` tags: ${t.tags.join(', ')}`);
|
|
137
|
+
}
|
|
138
|
+
// Show nested agents when a team matches
|
|
139
|
+
if (agentCount > 0) {
|
|
140
|
+
hasTeamWithAgents = true;
|
|
141
|
+
const maxShow = 8;
|
|
142
|
+
const shown = agents.slice(0, maxShow);
|
|
143
|
+
console.log(` ${chalk.cyan('agents:')}`);
|
|
144
|
+
for (const a of shown) {
|
|
145
|
+
const aTags = a.tags.length > 0 ? chalk.dim(` [${a.tags.join(', ')}]`) : '';
|
|
146
|
+
console.log(` ${chalk.bold(a.id)} ${chalk.dim(a.name)}${aTags}`);
|
|
147
|
+
}
|
|
148
|
+
if (agentCount > maxShow) {
|
|
149
|
+
console.log(chalk.dim(` ... and ${agentCount - maxShow} more`));
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
console.log();
|
|
154
|
+
}
|
|
155
|
+
// Show --agent hint when results include teams with agents
|
|
156
|
+
if (hasTeamWithAgents) {
|
|
157
|
+
console.log(chalk.dim(` Tip: Use ${chalk.reset('--agent <id>')} with ${chalk.reset('loom apply')} to apply a specific agent.`));
|
|
158
|
+
console.log(chalk.dim(` Example: loom apply functions --agent functions-dotnet-dev --registry <url>`));
|
|
159
|
+
console.log();
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
catch (err) {
|
|
163
|
+
console.error(chalk.red(err.message));
|
|
164
|
+
process.exit(1);
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
// =============================================================================
|
|
168
|
+
// apply
|
|
169
|
+
// =============================================================================
|
|
170
|
+
program
|
|
171
|
+
.command('apply <template>')
|
|
172
|
+
.description('Apply a template to the current workspace. <template> can be a local path, a template ID (auto-resolved from configured registries), or used with --registry <url>.')
|
|
173
|
+
.option('-t, --target <target>', 'Target agent: copilot | claude | cursor', 'copilot')
|
|
174
|
+
.option('-o, --output <dir>', 'Output directory', '.')
|
|
175
|
+
.option('--registry-root <dir>', 'Registry root directory (local path)')
|
|
176
|
+
.option('--registry <url>', 'Clone registry from URL into .loom/registries/ and use it')
|
|
177
|
+
.option('--registry-name <name>', 'Name for the cloned registry (derived from URL if omitted)')
|
|
178
|
+
.option('--clone-repos [mode]', 'Clone manifest repos: auto (default), all, or none', false)
|
|
179
|
+
.option('--clone-mode <strategy>', 'Clone strategy: full (default) or partial (blobless)')
|
|
180
|
+
.option('--agent <agents>', 'Select specific agent(s) by ID (comma-separated)')
|
|
181
|
+
.option('--agents <agents>', '(alias for --agent)')
|
|
182
|
+
.action(async (template, opts) => {
|
|
183
|
+
const target = opts.target;
|
|
184
|
+
const outputDir = opts.output;
|
|
185
|
+
// Support both --agent and --agents
|
|
186
|
+
const agentArg = opts.agent ?? opts.agents;
|
|
187
|
+
let templateDir;
|
|
188
|
+
let registryRoot;
|
|
189
|
+
if (opts.registry) {
|
|
190
|
+
// Clone-based mode: clone registry to .loom/registries/, resolve template ID
|
|
191
|
+
const wsDir = outputDir === '.' ? process.cwd() : outputDir;
|
|
192
|
+
console.log(chalk.blue(`Cloning registry into .loom/registries/...`));
|
|
193
|
+
const cloneResult = await cloneRegistry({
|
|
194
|
+
workspaceDir: wsDir,
|
|
195
|
+
url: opts.registry,
|
|
196
|
+
name: opts.registryName,
|
|
197
|
+
});
|
|
198
|
+
if (cloneResult.alreadyExists) {
|
|
199
|
+
console.log(chalk.dim(` Registry already cloned at ${cloneResult.registryDir}`));
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
console.log(chalk.green(` ✓ Registry cloned to ${cloneResult.registryDir}`));
|
|
203
|
+
}
|
|
204
|
+
registryRoot = cloneResult.registryDir;
|
|
205
|
+
templateDir = resolveTemplatePath(cloneResult.registryDir, template);
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
// Auto-resolve: local path first, then configured registries
|
|
209
|
+
const wsDir = outputDir === '.' ? process.cwd() : outputDir;
|
|
210
|
+
const resolved = await resolveTemplateSource(template, wsDir, opts.registryRoot);
|
|
211
|
+
templateDir = resolved.templateDir;
|
|
212
|
+
registryRoot = resolved.registryRoot;
|
|
213
|
+
if (resolved.fromRegistry) {
|
|
214
|
+
if (resolved.alreadyCloned) {
|
|
215
|
+
console.log(chalk.dim(` Using cached registry at ${registryRoot}`));
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
console.log(chalk.green(` ✓ Registry cloned to ${registryRoot}`));
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
try {
|
|
223
|
+
console.log(chalk.blue(`Applying template for ${chalk.bold(target)}...`));
|
|
224
|
+
// Resolve --clone-repos flag
|
|
225
|
+
// Default to 'auto' when --registry is used (remote mode), undefined otherwise
|
|
226
|
+
let cloneReposMode;
|
|
227
|
+
if (opts.cloneRepos === true || opts.cloneRepos === '') {
|
|
228
|
+
cloneReposMode = 'auto';
|
|
229
|
+
}
|
|
230
|
+
else if (typeof opts.cloneRepos === 'string' && ['auto', 'all', 'none'].includes(opts.cloneRepos)) {
|
|
231
|
+
cloneReposMode = opts.cloneRepos;
|
|
232
|
+
}
|
|
233
|
+
else if (opts.registry && opts.cloneRepos === false) {
|
|
234
|
+
// --registry used but --clone-repos not explicitly set → default to auto
|
|
235
|
+
cloneReposMode = 'auto';
|
|
236
|
+
}
|
|
237
|
+
// Create interactive prompt function
|
|
238
|
+
const promptFn = async (message, _choices) => {
|
|
239
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
240
|
+
return new Promise((resolve) => {
|
|
241
|
+
rl.question(chalk.yellow(` ${message}\n [clone / skip / enter path to existing clone]: `), (answer) => {
|
|
242
|
+
rl.close();
|
|
243
|
+
resolve(answer.trim() || 'skip');
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
};
|
|
247
|
+
// Create platform-appropriate junction/symlink function
|
|
248
|
+
const linkFn = async (target, linkPath) => {
|
|
249
|
+
if (platform() === 'win32') {
|
|
250
|
+
execSync(`cmd /c mklink /J "${linkPath}" "${target}"`, { stdio: 'pipe' });
|
|
251
|
+
}
|
|
252
|
+
else {
|
|
253
|
+
const { symlink } = await import('node:fs/promises');
|
|
254
|
+
await symlink(target, linkPath, 'junction');
|
|
255
|
+
}
|
|
256
|
+
};
|
|
257
|
+
const result = await applyTemplate({
|
|
258
|
+
templateDir,
|
|
259
|
+
registryRoot,
|
|
260
|
+
outputDir,
|
|
261
|
+
target,
|
|
262
|
+
skillFetcher: createCraftFetcher({
|
|
263
|
+
tokenFn: () => {
|
|
264
|
+
try {
|
|
265
|
+
return execSync('gh auth token', { stdio: 'pipe', encoding: 'utf-8' }).trim();
|
|
266
|
+
}
|
|
267
|
+
catch {
|
|
268
|
+
return undefined;
|
|
269
|
+
}
|
|
270
|
+
},
|
|
271
|
+
}),
|
|
272
|
+
cloneRepos: cloneReposMode,
|
|
273
|
+
cloneMode: opts.cloneMode ? (() => {
|
|
274
|
+
if (!['full', 'partial'].includes(opts.cloneMode)) {
|
|
275
|
+
throw new Error(`Invalid --clone-mode "${opts.cloneMode}". Must be "full" or "partial".`);
|
|
276
|
+
}
|
|
277
|
+
return opts.cloneMode === 'partial' ? 'partial' : undefined;
|
|
278
|
+
})() : undefined,
|
|
279
|
+
promptFn: cloneReposMode ? promptFn : undefined,
|
|
280
|
+
linkFn: cloneReposMode ? linkFn : undefined,
|
|
281
|
+
agents: agentArg ? agentArg.split(',').map((s) => s.trim()) : undefined,
|
|
282
|
+
});
|
|
283
|
+
console.log(chalk.green(`✓ Template "${result.template}" applied for ${result.target}.`));
|
|
284
|
+
if (result.localizedSkills.length > 0) {
|
|
285
|
+
console.log(chalk.green('\nSkills installed locally:'));
|
|
286
|
+
for (const skill of result.localizedSkills) {
|
|
287
|
+
const loc = target === 'copilot'
|
|
288
|
+
? `.github/skills/${skill.name}/SKILL.md`
|
|
289
|
+
: `.claude/skills/${skill.name}/SKILL.md`;
|
|
290
|
+
console.log(` ✓ ${skill.name} (${skill.registry}:${skill.ref}) → ${loc}`);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
if (result.registrySkills.length > 0) {
|
|
294
|
+
console.log(chalk.yellow('\nExternal skills (could not be fetched — install manually):'));
|
|
295
|
+
for (const skill of result.registrySkills) {
|
|
296
|
+
console.log(` ${skill.registry}:${skill.ref}`);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
// Print repo clone results
|
|
300
|
+
if (result.repoCloneResult) {
|
|
301
|
+
const r = result.repoCloneResult;
|
|
302
|
+
if (r.cloned.length > 0) {
|
|
303
|
+
console.log(chalk.green('\nRepos cloned:'));
|
|
304
|
+
for (const c of r.cloned) {
|
|
305
|
+
const link = c.linkPath ? ` (linked: ${c.linkPath})` : '';
|
|
306
|
+
const sparse = c.repo.sparse && c.repo.paths?.length
|
|
307
|
+
? ` (sparse: ${c.repo.paths.join(', ')})`
|
|
308
|
+
: '';
|
|
309
|
+
console.log(` ✓ ${c.repo.name ?? c.repo.url} → ${c.path}${link}${sparse}`);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
if (r.skipped.length > 0) {
|
|
313
|
+
console.log(chalk.dim('\nRepos skipped:'));
|
|
314
|
+
for (const s of r.skipped) {
|
|
315
|
+
console.log(` ─ ${s.repo.name ?? s.repo.url}: ${s.reason}`);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
if (r.deferred.length > 0) {
|
|
319
|
+
console.log(chalk.yellow('\nRepos deferred to agent:'));
|
|
320
|
+
for (const d of r.deferred) {
|
|
321
|
+
console.log(` ⤳ ${d.repo.name ?? d.repo.url}: ${d.reason}`);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
// Record workspace
|
|
326
|
+
await recordWorkspace({
|
|
327
|
+
path: outputDir === '.' ? process.cwd() : outputDir,
|
|
328
|
+
template: result.template,
|
|
329
|
+
registry: registryRoot,
|
|
330
|
+
appliedAt: new Date().toISOString(),
|
|
331
|
+
tags: [],
|
|
332
|
+
notes: '',
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
catch (err) {
|
|
336
|
+
console.error(chalk.red(`Error: ${err.message}`));
|
|
337
|
+
process.exit(1);
|
|
338
|
+
}
|
|
339
|
+
});
|
|
340
|
+
// =============================================================================
|
|
341
|
+
// workspaces
|
|
342
|
+
// =============================================================================
|
|
343
|
+
const ws = program
|
|
344
|
+
.command('workspaces')
|
|
345
|
+
.description('Manage tracked workspaces');
|
|
346
|
+
ws
|
|
347
|
+
.command('list')
|
|
348
|
+
.description('List tracked workspaces')
|
|
349
|
+
.option('--template <name>', 'Filter by template name')
|
|
350
|
+
.option('--tag <tag>', 'Filter by tag')
|
|
351
|
+
.option('--recent <n>', 'Show only N most recent', parseInt)
|
|
352
|
+
.action(async (opts) => {
|
|
353
|
+
const data = await loadWorkspaces();
|
|
354
|
+
const results = filterWorkspaces(data.workspaces, {
|
|
355
|
+
template: opts.template,
|
|
356
|
+
tag: opts.tag,
|
|
357
|
+
recent: opts.recent,
|
|
358
|
+
});
|
|
359
|
+
if (results.length === 0) {
|
|
360
|
+
console.log(chalk.yellow('No workspaces found.'));
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
for (const w of results) {
|
|
364
|
+
console.log(` ${chalk.bold(w.path)}`);
|
|
365
|
+
console.log(` template: ${w.template} applied: ${w.appliedAt}`);
|
|
366
|
+
if (w.tags.length > 0) {
|
|
367
|
+
console.log(` tags: ${w.tags.join(', ')}`);
|
|
368
|
+
}
|
|
369
|
+
if (w.notes) {
|
|
370
|
+
console.log(` notes: ${w.notes}`);
|
|
371
|
+
}
|
|
372
|
+
console.log();
|
|
373
|
+
}
|
|
374
|
+
});
|
|
375
|
+
ws
|
|
376
|
+
.command('tag <path> <tag>')
|
|
377
|
+
.description('Add a tag to a workspace')
|
|
378
|
+
.action(async (path, tag) => {
|
|
379
|
+
const data = await loadWorkspaces();
|
|
380
|
+
const entry = data.workspaces.find((w) => w.path === path);
|
|
381
|
+
if (!entry) {
|
|
382
|
+
console.error(chalk.red(`Workspace "${path}" not found.`));
|
|
383
|
+
process.exit(1);
|
|
384
|
+
}
|
|
385
|
+
addTag(entry, tag);
|
|
386
|
+
await saveWorkspaces(data);
|
|
387
|
+
console.log(chalk.green(`✓ Tag "${tag}" added.`));
|
|
388
|
+
});
|
|
389
|
+
ws
|
|
390
|
+
.command('note <path> <note>')
|
|
391
|
+
.description('Set a note on a workspace')
|
|
392
|
+
.action(async (path, note) => {
|
|
393
|
+
const data = await loadWorkspaces();
|
|
394
|
+
const entry = data.workspaces.find((w) => w.path === path);
|
|
395
|
+
if (!entry) {
|
|
396
|
+
console.error(chalk.red(`Workspace "${path}" not found.`));
|
|
397
|
+
process.exit(1);
|
|
398
|
+
}
|
|
399
|
+
setNote(entry, note);
|
|
400
|
+
await saveWorkspaces(data);
|
|
401
|
+
console.log(chalk.green(`✓ Note updated.`));
|
|
402
|
+
});
|
|
403
|
+
ws
|
|
404
|
+
.command('remove <path>')
|
|
405
|
+
.description('Remove a workspace entry (does not delete files)')
|
|
406
|
+
.action(async (path) => {
|
|
407
|
+
const removed = await removeWorkspace(path);
|
|
408
|
+
if (removed) {
|
|
409
|
+
console.log(chalk.green(`✓ Workspace entry removed.`));
|
|
410
|
+
}
|
|
411
|
+
else {
|
|
412
|
+
console.error(chalk.red(`Workspace "${path}" not found.`));
|
|
413
|
+
process.exit(1);
|
|
414
|
+
}
|
|
415
|
+
});
|
|
416
|
+
// =============================================================================
|
|
417
|
+
// validate
|
|
418
|
+
// =============================================================================
|
|
419
|
+
program
|
|
420
|
+
.command('validate [template-dir]')
|
|
421
|
+
.description('Validate manifest.yaml schema and references')
|
|
422
|
+
.option('-r, --registry-root <dir>', 'Registry root directory (for resolving shared/ refs)')
|
|
423
|
+
.option('--all', 'Validate all templates in registry (requires --registry-root)')
|
|
424
|
+
.action(async (templateDir, opts) => {
|
|
425
|
+
try {
|
|
426
|
+
if (opts.all) {
|
|
427
|
+
const registryRoot = opts.registryRoot ?? '.';
|
|
428
|
+
const results = await validateRegistry(registryRoot);
|
|
429
|
+
let hasError = false;
|
|
430
|
+
const templateResults = results.filter((r) => r.templateId !== '__registry__');
|
|
431
|
+
const registryResults = results.filter((r) => r.templateId === '__registry__');
|
|
432
|
+
// Print registry-level errors first
|
|
433
|
+
for (const r of registryResults) {
|
|
434
|
+
for (const e of r.errors) {
|
|
435
|
+
console.log(chalk.red(` ✗ ${e.message}`));
|
|
436
|
+
hasError = true;
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
// Print per-template results
|
|
440
|
+
const validCount = templateResults.filter((r) => r.errors.length === 0).length;
|
|
441
|
+
console.log(chalk.blue(`\nValidating registry (${templateResults.length} templates)`));
|
|
442
|
+
for (const r of templateResults) {
|
|
443
|
+
if (r.errors.length === 0) {
|
|
444
|
+
console.log(chalk.green(` ✓ ${r.templateId} ......... OK`));
|
|
445
|
+
}
|
|
446
|
+
else {
|
|
447
|
+
hasError = true;
|
|
448
|
+
console.log(chalk.red(` ✗ ${r.templateId} ......... ${r.errors.length} error(s)`));
|
|
449
|
+
for (const e of r.errors) {
|
|
450
|
+
console.log(chalk.red(` → ${e.message}`));
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
console.log(`\nSummary: ${validCount}/${templateResults.length} templates valid`);
|
|
455
|
+
if (hasError)
|
|
456
|
+
process.exit(1);
|
|
457
|
+
}
|
|
458
|
+
else {
|
|
459
|
+
if (!templateDir) {
|
|
460
|
+
console.error(chalk.red('Please provide a template directory or use --all'));
|
|
461
|
+
process.exit(1);
|
|
462
|
+
}
|
|
463
|
+
const registryRoot = opts.registryRoot ?? templateDir.replace(/[/\\]templates[/\\].*$/, '');
|
|
464
|
+
const result = await validateTemplate(templateDir, registryRoot);
|
|
465
|
+
console.log(chalk.blue(`\nValidating template: ${result.templateId}`));
|
|
466
|
+
if (result.errors.length === 0) {
|
|
467
|
+
console.log(chalk.green(' ✓ manifest.yaml valid'));
|
|
468
|
+
const s = result.summary;
|
|
469
|
+
if (s.instructions > 0)
|
|
470
|
+
console.log(chalk.green(` ✓ ${s.instructions} instructions resolved`));
|
|
471
|
+
if (s.skills > 0)
|
|
472
|
+
console.log(chalk.green(` ✓ ${s.skills} skills`));
|
|
473
|
+
if (s.agents > 0)
|
|
474
|
+
console.log(chalk.green(` ✓ ${s.agents} agents resolved`));
|
|
475
|
+
if (s.mcp > 0)
|
|
476
|
+
console.log(chalk.green(` ✓ ${s.mcp} MCP servers resolved`));
|
|
477
|
+
if (s.repos > 0)
|
|
478
|
+
console.log(chalk.green(` ✓ ${s.repos} repos resolved`));
|
|
479
|
+
if (s.prompts > 0)
|
|
480
|
+
console.log(chalk.green(` ✓ ${s.prompts} prompts resolved`));
|
|
481
|
+
if (s.prerequisites > 0)
|
|
482
|
+
console.log(chalk.green(` ✓ ${s.prerequisites} prerequisites resolved`));
|
|
483
|
+
console.log(chalk.green('\n0 errors'));
|
|
484
|
+
}
|
|
485
|
+
else {
|
|
486
|
+
for (const e of result.errors) {
|
|
487
|
+
console.log(chalk.red(` ✗ [${e.level}] ${e.field}: ${e.message}`));
|
|
488
|
+
}
|
|
489
|
+
console.log(chalk.red(`\n${result.errors.length} error(s)`));
|
|
490
|
+
process.exit(1);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
catch (err) {
|
|
495
|
+
console.error(chalk.red(`Error: ${err.message}`));
|
|
496
|
+
process.exit(1);
|
|
497
|
+
}
|
|
498
|
+
});
|
|
499
|
+
// =============================================================================
|
|
500
|
+
// Run
|
|
501
|
+
// =============================================================================
|
|
502
|
+
program.parse();
|
|
503
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/clone.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Clone — Manages registry cloning into workspace-local .loom/registries/<name>/
|
|
3
|
+
*
|
|
4
|
+
* Instead of cloning registries at the workspace root, Loom places them under
|
|
5
|
+
* .loom/registries/ so users can add ".loom/" to .gitignore cleanly.
|
|
6
|
+
*/
|
|
7
|
+
/** The local directory inside a workspace where Loom state lives */
|
|
8
|
+
export declare const LOOM_LOCAL_DIR = ".loom";
|
|
9
|
+
export interface CloneOptions {
|
|
10
|
+
/** Workspace root directory */
|
|
11
|
+
workspaceDir: string;
|
|
12
|
+
/** Git URL of the registry */
|
|
13
|
+
url: string;
|
|
14
|
+
/** Short name for the registry (optional — derived from URL if omitted) */
|
|
15
|
+
name?: string;
|
|
16
|
+
/** Inject exec function for testing (defaults to execSync) */
|
|
17
|
+
execFn?: (cmd: string) => void;
|
|
18
|
+
}
|
|
19
|
+
export interface CloneResult {
|
|
20
|
+
registryDir: string;
|
|
21
|
+
alreadyExists: boolean;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Get the directory path where a registry will be cloned.
|
|
25
|
+
*/
|
|
26
|
+
export declare function getRegistryDir(workspaceDir: string, name: string): string;
|
|
27
|
+
/**
|
|
28
|
+
* Resolve a template path within a registry directory.
|
|
29
|
+
*/
|
|
30
|
+
export declare function resolveTemplatePath(registryDir: string, templateId: string): string;
|
|
31
|
+
/**
|
|
32
|
+
* Clone a registry into .loom/registries/<name>/ within the workspace.
|
|
33
|
+
*
|
|
34
|
+
* If the registry directory already exists and contains an index.yaml,
|
|
35
|
+
* the clone is skipped (returns alreadyExists: true).
|
|
36
|
+
*/
|
|
37
|
+
export declare function cloneRegistry(options: CloneOptions): Promise<CloneResult>;
|
|
38
|
+
//# sourceMappingURL=clone.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clone.d.ts","sourceRoot":"","sources":["../src/clone.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,oEAAoE;AACpE,eAAO,MAAM,cAAc,UAAU,CAAC;AAEtC,MAAM,WAAW,YAAY;IAC3B,+BAA+B;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,8BAA8B;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,2EAA2E;IAC3E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,8DAA8D;IAC9D,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAChC;AAED,MAAM,WAAW,WAAW;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,OAAO,CAAC;CACxB;AAmBD;;GAEG;AACH,wBAAgB,cAAc,CAAC,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAEzE;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAEnF;AAED;;;;;GAKG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CAsB/E"}
|
package/dist/clone.js
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Clone — Manages registry cloning into workspace-local .loom/registries/<name>/
|
|
3
|
+
*
|
|
4
|
+
* Instead of cloning registries at the workspace root, Loom places them under
|
|
5
|
+
* .loom/registries/ so users can add ".loom/" to .gitignore cleanly.
|
|
6
|
+
*/
|
|
7
|
+
import { mkdir, stat } from 'node:fs/promises';
|
|
8
|
+
import { join } from 'node:path';
|
|
9
|
+
import { execSync } from 'node:child_process';
|
|
10
|
+
/** The local directory inside a workspace where Loom state lives */
|
|
11
|
+
export const LOOM_LOCAL_DIR = '.loom';
|
|
12
|
+
/**
|
|
13
|
+
* Normalize a registry name to a filesystem-safe directory name.
|
|
14
|
+
* Replaces "/" with "--" to handle org/repo format.
|
|
15
|
+
*/
|
|
16
|
+
function normalizeName(name) {
|
|
17
|
+
return name.replace(/\//g, '--');
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Derive a registry name from a git URL.
|
|
21
|
+
* e.g. "https://github.com/org/repo.git" → "repo"
|
|
22
|
+
*/
|
|
23
|
+
function deriveNameFromUrl(url) {
|
|
24
|
+
const match = url.match(/\/([^/]+?)(?:\.git)?$/);
|
|
25
|
+
return match ? match[1] : 'registry';
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Get the directory path where a registry will be cloned.
|
|
29
|
+
*/
|
|
30
|
+
export function getRegistryDir(workspaceDir, name) {
|
|
31
|
+
return join(workspaceDir, LOOM_LOCAL_DIR, 'registries', normalizeName(name));
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Resolve a template path within a registry directory.
|
|
35
|
+
*/
|
|
36
|
+
export function resolveTemplatePath(registryDir, templateId) {
|
|
37
|
+
return join(registryDir, 'templates', templateId);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Clone a registry into .loom/registries/<name>/ within the workspace.
|
|
41
|
+
*
|
|
42
|
+
* If the registry directory already exists and contains an index.yaml,
|
|
43
|
+
* the clone is skipped (returns alreadyExists: true).
|
|
44
|
+
*/
|
|
45
|
+
export async function cloneRegistry(options) {
|
|
46
|
+
const { workspaceDir, url, execFn = defaultExec } = options;
|
|
47
|
+
const name = options.name ?? deriveNameFromUrl(url);
|
|
48
|
+
const registryDir = getRegistryDir(workspaceDir, name);
|
|
49
|
+
// Check if already cloned
|
|
50
|
+
try {
|
|
51
|
+
const s = await stat(join(registryDir, 'index.yaml'));
|
|
52
|
+
if (s.isFile()) {
|
|
53
|
+
return { registryDir, alreadyExists: true };
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
// Not yet cloned — proceed
|
|
58
|
+
}
|
|
59
|
+
// Create parent directories
|
|
60
|
+
await mkdir(join(workspaceDir, LOOM_LOCAL_DIR, 'registries'), { recursive: true });
|
|
61
|
+
// Clone
|
|
62
|
+
execFn(`git clone --depth 1 "${url}" "${registryDir}"`);
|
|
63
|
+
return { registryDir, alreadyExists: false };
|
|
64
|
+
}
|
|
65
|
+
function defaultExec(cmd) {
|
|
66
|
+
execSync(cmd, { stdio: 'pipe', timeout: 60_000 });
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=clone.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clone.js","sourceRoot":"","sources":["../src/clone.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAE9C,oEAAoE;AACpE,MAAM,CAAC,MAAM,cAAc,GAAG,OAAO,CAAC;AAkBtC;;;GAGG;AACH,SAAS,aAAa,CAAC,IAAY;IACjC,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;AACnC,CAAC;AAED;;;GAGG;AACH,SAAS,iBAAiB,CAAC,GAAW;IACpC,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC;IACjD,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC;AACvC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,YAAoB,EAAE,IAAY;IAC/D,OAAO,IAAI,CAAC,YAAY,EAAE,cAAc,EAAE,YAAY,EAAE,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC;AAC/E,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,mBAAmB,CAAC,WAAmB,EAAE,UAAkB;IACzE,OAAO,IAAI,CAAC,WAAW,EAAE,WAAW,EAAE,UAAU,CAAC,CAAC;AACpD,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,OAAqB;IACvD,MAAM,EAAE,YAAY,EAAE,GAAG,EAAE,MAAM,GAAG,WAAW,EAAE,GAAG,OAAO,CAAC;IAC5D,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,iBAAiB,CAAC,GAAG,CAAC,CAAC;IACpD,MAAM,WAAW,GAAG,cAAc,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;IAEvD,0BAA0B;IAC1B,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC,CAAC;QACtD,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC;YACf,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;QAC9C,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,2BAA2B;IAC7B,CAAC;IAED,4BAA4B;IAC5B,MAAM,KAAK,CAAC,IAAI,CAAC,YAAY,EAAE,cAAc,EAAE,YAAY,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAEnF,QAAQ;IACR,MAAM,CAAC,wBAAwB,GAAG,MAAM,WAAW,GAAG,CAAC,CAAC;IAExD,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,KAAK,EAAE,CAAC;AAC/C,CAAC;AAED,SAAS,WAAW,CAAC,GAAW;IAC9B,QAAQ,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;AACpD,CAAC"}
|