busy-cli 0.1.2

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 (128) hide show
  1. package/README.md +129 -0
  2. package/dist/builders/context.d.ts +50 -0
  3. package/dist/builders/context.d.ts.map +1 -0
  4. package/dist/builders/context.js +190 -0
  5. package/dist/cache/index.d.ts +100 -0
  6. package/dist/cache/index.d.ts.map +1 -0
  7. package/dist/cache/index.js +270 -0
  8. package/dist/cli/index.d.ts +3 -0
  9. package/dist/cli/index.d.ts.map +1 -0
  10. package/dist/cli/index.js +463 -0
  11. package/dist/commands/package.d.ts +96 -0
  12. package/dist/commands/package.d.ts.map +1 -0
  13. package/dist/commands/package.js +285 -0
  14. package/dist/index.d.ts +7 -0
  15. package/dist/index.d.ts.map +1 -0
  16. package/dist/index.js +7 -0
  17. package/dist/loader.d.ts +6 -0
  18. package/dist/loader.d.ts.map +1 -0
  19. package/dist/loader.js +361 -0
  20. package/dist/merge.d.ts +16 -0
  21. package/dist/merge.d.ts.map +1 -0
  22. package/dist/merge.js +102 -0
  23. package/dist/package/manifest.d.ts +59 -0
  24. package/dist/package/manifest.d.ts.map +1 -0
  25. package/dist/package/manifest.js +265 -0
  26. package/dist/parser.d.ts +28 -0
  27. package/dist/parser.d.ts.map +1 -0
  28. package/dist/parser.js +220 -0
  29. package/dist/parsers/frontmatter.d.ts +14 -0
  30. package/dist/parsers/frontmatter.d.ts.map +1 -0
  31. package/dist/parsers/frontmatter.js +110 -0
  32. package/dist/parsers/imports.d.ts +48 -0
  33. package/dist/parsers/imports.d.ts.map +1 -0
  34. package/dist/parsers/imports.js +147 -0
  35. package/dist/parsers/links.d.ts +12 -0
  36. package/dist/parsers/links.d.ts.map +1 -0
  37. package/dist/parsers/links.js +79 -0
  38. package/dist/parsers/localdefs.d.ts +6 -0
  39. package/dist/parsers/localdefs.d.ts.map +1 -0
  40. package/dist/parsers/localdefs.js +132 -0
  41. package/dist/parsers/operations.d.ts +32 -0
  42. package/dist/parsers/operations.d.ts.map +1 -0
  43. package/dist/parsers/operations.js +313 -0
  44. package/dist/parsers/sections.d.ts +15 -0
  45. package/dist/parsers/sections.d.ts.map +1 -0
  46. package/dist/parsers/sections.js +173 -0
  47. package/dist/parsers/tools.d.ts +30 -0
  48. package/dist/parsers/tools.d.ts.map +1 -0
  49. package/dist/parsers/tools.js +178 -0
  50. package/dist/parsers/triggers.d.ts +35 -0
  51. package/dist/parsers/triggers.d.ts.map +1 -0
  52. package/dist/parsers/triggers.js +219 -0
  53. package/dist/providers/base.d.ts +60 -0
  54. package/dist/providers/base.d.ts.map +1 -0
  55. package/dist/providers/base.js +34 -0
  56. package/dist/providers/github.d.ts +18 -0
  57. package/dist/providers/github.d.ts.map +1 -0
  58. package/dist/providers/github.js +109 -0
  59. package/dist/providers/gitlab.d.ts +18 -0
  60. package/dist/providers/gitlab.d.ts.map +1 -0
  61. package/dist/providers/gitlab.js +101 -0
  62. package/dist/providers/index.d.ts +13 -0
  63. package/dist/providers/index.d.ts.map +1 -0
  64. package/dist/providers/index.js +17 -0
  65. package/dist/providers/local.d.ts +31 -0
  66. package/dist/providers/local.d.ts.map +1 -0
  67. package/dist/providers/local.js +116 -0
  68. package/dist/providers/url.d.ts +16 -0
  69. package/dist/providers/url.d.ts.map +1 -0
  70. package/dist/providers/url.js +45 -0
  71. package/dist/registry/index.d.ts +99 -0
  72. package/dist/registry/index.d.ts.map +1 -0
  73. package/dist/registry/index.js +320 -0
  74. package/dist/types/schema.d.ts +3259 -0
  75. package/dist/types/schema.d.ts.map +1 -0
  76. package/dist/types/schema.js +258 -0
  77. package/dist/utils/logger.d.ts +19 -0
  78. package/dist/utils/logger.d.ts.map +1 -0
  79. package/dist/utils/logger.js +23 -0
  80. package/dist/utils/slugify.d.ts +14 -0
  81. package/dist/utils/slugify.d.ts.map +1 -0
  82. package/dist/utils/slugify.js +28 -0
  83. package/package.json +61 -0
  84. package/src/__tests__/cache.test.ts +393 -0
  85. package/src/__tests__/cli-package.test.ts +667 -0
  86. package/src/__tests__/fixtures/automated-workflow.busy.md +84 -0
  87. package/src/__tests__/fixtures/concept.busy.md +30 -0
  88. package/src/__tests__/fixtures/document.busy.md +44 -0
  89. package/src/__tests__/fixtures/simple-operation.busy.md +45 -0
  90. package/src/__tests__/fixtures/tool-document.busy.md +71 -0
  91. package/src/__tests__/fixtures/tool.busy.md +54 -0
  92. package/src/__tests__/imports.test.ts +244 -0
  93. package/src/__tests__/integration.test.ts +432 -0
  94. package/src/__tests__/operations.test.ts +408 -0
  95. package/src/__tests__/package-manifest.test.ts +455 -0
  96. package/src/__tests__/providers.test.ts +672 -0
  97. package/src/__tests__/registry.test.ts +402 -0
  98. package/src/__tests__/schema.test.ts +467 -0
  99. package/src/__tests__/tools.test.ts +376 -0
  100. package/src/__tests__/triggers.test.ts +312 -0
  101. package/src/builders/context.ts +294 -0
  102. package/src/cache/index.ts +312 -0
  103. package/src/cli/index.ts +514 -0
  104. package/src/commands/package.ts +392 -0
  105. package/src/index.ts +46 -0
  106. package/src/loader.ts +474 -0
  107. package/src/merge.ts +126 -0
  108. package/src/package/manifest.ts +349 -0
  109. package/src/parser.ts +278 -0
  110. package/src/parsers/frontmatter.ts +135 -0
  111. package/src/parsers/imports.ts +196 -0
  112. package/src/parsers/links.ts +108 -0
  113. package/src/parsers/localdefs.ts +166 -0
  114. package/src/parsers/operations.ts +404 -0
  115. package/src/parsers/sections.ts +230 -0
  116. package/src/parsers/tools.ts +215 -0
  117. package/src/parsers/triggers.ts +252 -0
  118. package/src/providers/base.ts +77 -0
  119. package/src/providers/github.ts +129 -0
  120. package/src/providers/gitlab.ts +121 -0
  121. package/src/providers/index.ts +25 -0
  122. package/src/providers/local.ts +129 -0
  123. package/src/providers/url.ts +56 -0
  124. package/src/registry/index.ts +408 -0
  125. package/src/types/schema.ts +369 -0
  126. package/src/utils/logger.ts +25 -0
  127. package/src/utils/slugify.ts +31 -0
  128. package/tsconfig.json +21 -0
@@ -0,0 +1,320 @@
1
+ /**
2
+ * Package Registry for package.busy.md
3
+ *
4
+ * Parses and manages the package registry file.
5
+ */
6
+ import { promises as fs } from 'node:fs';
7
+ import * as path from 'node:path';
8
+ import matter from 'gray-matter';
9
+ /**
10
+ * Derive entry ID from URL
11
+ *
12
+ * If URL has #anchor, use anchor as ID
13
+ * Else, use filename without extension
14
+ * Slugify result (lowercase, hyphens)
15
+ */
16
+ export function deriveEntryId(url) {
17
+ // Check for anchor
18
+ const hashIndex = url.indexOf('#');
19
+ if (hashIndex !== -1) {
20
+ const anchor = url.slice(hashIndex + 1);
21
+ return slugify(anchor);
22
+ }
23
+ // Use filename without extension
24
+ const urlPath = url.split('?')[0]; // Remove query params
25
+ const filename = path.basename(urlPath);
26
+ const nameWithoutExt = filename.replace(/\.busy\.md$/, '').replace(/\.md$/, '');
27
+ return slugify(nameWithoutExt);
28
+ }
29
+ /**
30
+ * Derive category from URL path
31
+ */
32
+ export function deriveCategory(url) {
33
+ const lowerUrl = url.toLowerCase();
34
+ if (lowerUrl.includes('/core/')) {
35
+ return 'Core Library';
36
+ }
37
+ if (lowerUrl.includes('/tools/')) {
38
+ return 'Tools';
39
+ }
40
+ if (lowerUrl.includes('/concepts/')) {
41
+ return 'Concepts';
42
+ }
43
+ return 'Packages';
44
+ }
45
+ /**
46
+ * Slugify a string (lowercase, replace spaces with hyphens)
47
+ */
48
+ function slugify(str) {
49
+ return str
50
+ .toLowerCase()
51
+ .replace(/\s+/g, '-')
52
+ .replace(/[^a-z0-9-]/g, '')
53
+ .replace(/-+/g, '-')
54
+ .replace(/^-|-$/g, '');
55
+ }
56
+ /**
57
+ * Parse a field/value table
58
+ */
59
+ function parseFieldTable(content) {
60
+ const fields = {};
61
+ // Match table rows: | Field | Value |
62
+ const rowPattern = /\|\s*([^|]+?)\s*\|\s*([^|]+?)\s*\|/g;
63
+ let match;
64
+ while ((match = rowPattern.exec(content)) !== null) {
65
+ const field = match[1].trim();
66
+ const value = match[2].trim();
67
+ // Skip header row
68
+ if (field === 'Field' || field.startsWith('-')) {
69
+ continue;
70
+ }
71
+ fields[field] = value;
72
+ }
73
+ return fields;
74
+ }
75
+ /**
76
+ * Parse package.busy.md content
77
+ */
78
+ export function parsePackageRegistry(content) {
79
+ // Extract only first frontmatter block to avoid "multiple documents" error
80
+ const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
81
+ let frontmatter = {};
82
+ let body = content;
83
+ if (frontmatterMatch) {
84
+ const { data } = matter(frontmatterMatch[0]);
85
+ frontmatter = data;
86
+ body = content.slice(frontmatterMatch[0].length);
87
+ }
88
+ const metadata = {
89
+ name: frontmatter.Name || frontmatter.name || 'package',
90
+ type: frontmatter.Type || frontmatter.type || 'Document',
91
+ description: frontmatter.Description || frontmatter.description || '',
92
+ };
93
+ const packages = [];
94
+ // Find Dependencies section (or legacy Package Registry section)
95
+ const registryMatch = body.match(/# (?:Dependencies|Package Registry)\n([\s\S]*?)(?=\n# |$)/);
96
+ if (!registryMatch) {
97
+ return { metadata, packages };
98
+ }
99
+ const registryContent = registryMatch[1];
100
+ // Parse entries directly under Dependencies (H2 headers) or in categories (H3 headers)
101
+ // Try H2 entries first (new format: ### package-name under # Dependencies)
102
+ const h2EntryPattern = /## ([^\n]+)\n([\s\S]*?)(?=\n## |$)/g;
103
+ let h2Match;
104
+ while ((h2Match = h2EntryPattern.exec(registryContent)) !== null) {
105
+ const entryId = h2Match[1].trim();
106
+ const entryContent = h2Match[2];
107
+ // Check if this is a category with H3 entries or a direct package entry
108
+ if (entryContent.includes('### ')) {
109
+ // This is a category, parse H3 entries
110
+ const category = entryId;
111
+ const entryPattern = /### ([^\n]+)\n([\s\S]*?)(?=\n### |$)/g;
112
+ let entryMatch;
113
+ while ((entryMatch = entryPattern.exec(entryContent)) !== null) {
114
+ const pkgId = entryMatch[1].trim();
115
+ const pkgContent = entryMatch[2];
116
+ const descMatch = pkgContent.match(/^([\s\S]*?)(?=\n\|)/);
117
+ const description = descMatch ? descMatch[1].trim() : '';
118
+ const fields = parseFieldTable(pkgContent);
119
+ if (fields['Source']) {
120
+ packages.push({
121
+ id: pkgId,
122
+ description,
123
+ source: fields['Source'],
124
+ provider: fields['Provider'] || 'url',
125
+ cached: fields['Cached'] || '',
126
+ version: fields['Version'] || '',
127
+ fetched: fields['Fetched'] || '',
128
+ integrity: fields['Integrity'] || undefined,
129
+ category,
130
+ });
131
+ }
132
+ }
133
+ }
134
+ else {
135
+ // This is a direct package entry (no category)
136
+ const descMatch = entryContent.match(/^([\s\S]*?)(?=\n\|)/);
137
+ const description = descMatch ? descMatch[1].trim() : '';
138
+ const fields = parseFieldTable(entryContent);
139
+ if (fields['Source']) {
140
+ packages.push({
141
+ id: entryId,
142
+ description,
143
+ source: fields['Source'],
144
+ provider: fields['Provider'] || 'url',
145
+ cached: fields['Cached'] || '',
146
+ version: fields['Version'] || '',
147
+ fetched: fields['Fetched'] || '',
148
+ integrity: fields['Integrity'] || undefined,
149
+ category: 'Packages',
150
+ });
151
+ }
152
+ }
153
+ }
154
+ return { metadata, packages };
155
+ }
156
+ /**
157
+ * Generate package.busy.md content
158
+ */
159
+ function generateRegistryContent(metadata, packages) {
160
+ const lines = [];
161
+ // Frontmatter
162
+ lines.push('---');
163
+ lines.push(`Name: ${metadata.name}`);
164
+ lines.push(`Type: ${metadata.type}`);
165
+ lines.push(`Description: ${metadata.description}`);
166
+ lines.push('---');
167
+ lines.push('');
168
+ // Imports section
169
+ lines.push('# [Imports]');
170
+ lines.push('');
171
+ // Package Contents section
172
+ lines.push('# Package Contents');
173
+ lines.push('');
174
+ lines.push('No local documents yet.');
175
+ lines.push('');
176
+ // Dependencies section
177
+ lines.push('# Dependencies');
178
+ lines.push('');
179
+ if (packages.length === 0) {
180
+ lines.push('No dependencies installed.');
181
+ lines.push('');
182
+ return lines.join('\n');
183
+ }
184
+ // Group packages by category
185
+ const categories = new Map();
186
+ for (const pkg of packages) {
187
+ if (!categories.has(pkg.category)) {
188
+ categories.set(pkg.category, []);
189
+ }
190
+ categories.get(pkg.category).push(pkg);
191
+ }
192
+ // Render each category
193
+ for (const [category, pkgs] of categories) {
194
+ lines.push(`## ${category}`);
195
+ lines.push('');
196
+ for (const pkg of pkgs) {
197
+ lines.push(`### ${pkg.id}`);
198
+ lines.push('');
199
+ if (pkg.description) {
200
+ lines.push(pkg.description);
201
+ lines.push('');
202
+ }
203
+ lines.push('| Field | Value |');
204
+ lines.push('|-------|-------|');
205
+ lines.push(`| Source | ${pkg.source} |`);
206
+ lines.push(`| Provider | ${pkg.provider} |`);
207
+ lines.push(`| Cached | ${pkg.cached} |`);
208
+ lines.push(`| Version | ${pkg.version} |`);
209
+ lines.push(`| Fetched | ${pkg.fetched} |`);
210
+ if (pkg.integrity) {
211
+ lines.push(`| Integrity | ${pkg.integrity} |`);
212
+ }
213
+ lines.push('');
214
+ }
215
+ }
216
+ return lines.join('\n');
217
+ }
218
+ const DEFAULT_REGISTRY_CONTENT = `---
219
+ Name: workspace
220
+ Type: [Package]
221
+ Description: BUSY workspace package manifest
222
+ ---
223
+
224
+ # [Imports]
225
+
226
+ # Package Contents
227
+
228
+ No local documents yet.
229
+
230
+ # Dependencies
231
+
232
+ No dependencies installed.
233
+ `;
234
+ /**
235
+ * Package Registry Manager
236
+ *
237
+ * Manages the package.busy.md file in a workspace.
238
+ */
239
+ export class PackageRegistry {
240
+ workspaceRoot;
241
+ registryPath;
242
+ metadata;
243
+ packages;
244
+ constructor(workspaceRoot) {
245
+ this.workspaceRoot = workspaceRoot;
246
+ this.registryPath = path.join(workspaceRoot, 'package.busy.md');
247
+ this.metadata = {
248
+ name: 'workspace',
249
+ type: '[Package]',
250
+ description: 'BUSY workspace package manifest',
251
+ };
252
+ this.packages = new Map();
253
+ }
254
+ /**
255
+ * Initialize a new package.busy.md if it doesn't exist
256
+ */
257
+ async init() {
258
+ const exists = await fs.stat(this.registryPath).then(() => true).catch(() => false);
259
+ if (!exists) {
260
+ await fs.writeFile(this.registryPath, DEFAULT_REGISTRY_CONTENT, 'utf-8');
261
+ }
262
+ }
263
+ /**
264
+ * Load existing package.busy.md
265
+ */
266
+ async load() {
267
+ const content = await fs.readFile(this.registryPath, 'utf-8');
268
+ const parsed = parsePackageRegistry(content);
269
+ this.metadata = parsed.metadata;
270
+ this.packages = new Map(parsed.packages.map(p => [p.id, p]));
271
+ }
272
+ /**
273
+ * Save changes to package.busy.md
274
+ */
275
+ async save() {
276
+ const content = generateRegistryContent(this.metadata, Array.from(this.packages.values()));
277
+ await fs.writeFile(this.registryPath, content, 'utf-8');
278
+ }
279
+ /**
280
+ * Get all packages
281
+ */
282
+ getPackages() {
283
+ return Array.from(this.packages.values());
284
+ }
285
+ /**
286
+ * Get package by ID
287
+ */
288
+ getPackage(id) {
289
+ return this.packages.get(id);
290
+ }
291
+ /**
292
+ * Add or update a package
293
+ */
294
+ addPackage(entry) {
295
+ this.packages.set(entry.id, entry);
296
+ }
297
+ /**
298
+ * Remove a package by ID
299
+ */
300
+ removePackage(id) {
301
+ return this.packages.delete(id);
302
+ }
303
+ /**
304
+ * Get packages by category
305
+ */
306
+ getPackagesByCategory(category) {
307
+ return Array.from(this.packages.values()).filter(p => p.category === category);
308
+ }
309
+ /**
310
+ * Get all unique categories
311
+ */
312
+ getCategories() {
313
+ const categories = new Set();
314
+ for (const pkg of this.packages.values()) {
315
+ categories.add(pkg.category);
316
+ }
317
+ return Array.from(categories);
318
+ }
319
+ }
320
+ //# sourceMappingURL=index.js.map