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,408 @@
1
+ /**
2
+ * Operations Parsing Tests - Match busy-python Operation model
3
+ *
4
+ * Operations in busy-python have:
5
+ * - name: string
6
+ * - inputs: list[str]
7
+ * - outputs: list[str]
8
+ * - steps: list[Step] where Step has stepNumber, instruction, operationReferences
9
+ * - checklist: Optional[Checklist] with items list
10
+ */
11
+
12
+ import { describe, it, expect } from 'vitest';
13
+ import { parseOperations, parseSteps, parseChecklist } from '../parsers/operations';
14
+ import type { Operation, Step } from '../types/schema';
15
+
16
+ describe('parseSteps', () => {
17
+ it('should parse numbered steps with step numbers', () => {
18
+ const content = `
19
+ ### [Steps]
20
+ 1. Parse the document frontmatter
21
+ 2. Resolve all imports
22
+ 3. Execute the setup section
23
+ `;
24
+
25
+ const steps = parseSteps(content);
26
+ expect(steps).toHaveLength(3);
27
+ expect(steps[0]).toEqual({
28
+ stepNumber: 1,
29
+ instruction: 'Parse the document frontmatter',
30
+ operationReferences: undefined, // undefined when no references (matches busy-python Optional)
31
+ });
32
+ expect(steps[1].stepNumber).toBe(2);
33
+ expect(steps[2].stepNumber).toBe(3);
34
+ });
35
+
36
+ it('should extract operation references from step text', () => {
37
+ const content = `
38
+ ### [Steps]
39
+ 1. Run [ValidateInput] to check data
40
+ 2. Execute [ProcessData] and then [SaveResults]
41
+ 3. Call [SendNotification] on completion
42
+ `;
43
+
44
+ const steps = parseSteps(content);
45
+ expect(steps[0].operationReferences).toEqual(['ValidateInput']);
46
+ expect(steps[1].operationReferences).toEqual(['ProcessData', 'SaveResults']);
47
+ expect(steps[2].operationReferences).toEqual(['SendNotification']);
48
+ });
49
+
50
+ it('should handle multi-line step instructions', () => {
51
+ const content = `
52
+ ### [Steps]
53
+ 1. First step that continues
54
+ on the next line with more detail
55
+ 2. Second step is single line
56
+ `;
57
+
58
+ const steps = parseSteps(content);
59
+ expect(steps).toHaveLength(2);
60
+ expect(steps[0].instruction).toContain('continues');
61
+ expect(steps[0].instruction).toContain('more detail');
62
+ });
63
+
64
+ it('should handle steps without Steps heading (just numbered list)', () => {
65
+ const content = `
66
+ ## OperationName
67
+
68
+ 1. Do first thing
69
+ 2. Do second thing
70
+ 3. Do third thing
71
+ `;
72
+
73
+ const steps = parseSteps(content);
74
+ expect(steps).toHaveLength(3);
75
+ });
76
+
77
+ it('should return empty array for content with no steps', () => {
78
+ const content = `
79
+ ## OperationName
80
+
81
+ Just some description without steps.
82
+ `;
83
+
84
+ const steps = parseSteps(content);
85
+ expect(steps).toHaveLength(0);
86
+ });
87
+
88
+ it('should not include checklist items as steps', () => {
89
+ const content = `
90
+ ### [Steps]
91
+ 1. Execute task
92
+
93
+ ### [Checklist]
94
+ - Task completed
95
+ - Output verified
96
+ `;
97
+
98
+ const steps = parseSteps(content);
99
+ expect(steps).toHaveLength(1);
100
+ expect(steps[0].instruction).toBe('Execute task');
101
+ });
102
+
103
+ it('should handle operation references with various formats', () => {
104
+ const content = `
105
+ ### [Steps]
106
+ 1. Run [Simple]
107
+ 2. Execute [Multi Word Operation]
108
+ 3. Call [run-with-dashes]
109
+ 4. Use [CamelCase123]
110
+ `;
111
+
112
+ const steps = parseSteps(content);
113
+ expect(steps[0].operationReferences).toEqual(['Simple']);
114
+ expect(steps[1].operationReferences).toEqual(['Multi Word Operation']);
115
+ expect(steps[2].operationReferences).toEqual(['run-with-dashes']);
116
+ expect(steps[3].operationReferences).toEqual(['CamelCase123']);
117
+ });
118
+ });
119
+
120
+ describe('parseChecklist', () => {
121
+ it('should parse checklist items from bullet list', () => {
122
+ const content = `
123
+ ### [Checklist]
124
+ - Input validated
125
+ - Processing complete
126
+ - Output written
127
+ `;
128
+
129
+ const checklist = parseChecklist(content);
130
+ expect(checklist).not.toBeNull();
131
+ expect(checklist?.items).toHaveLength(3);
132
+ expect(checklist?.items).toEqual([
133
+ 'Input validated',
134
+ 'Processing complete',
135
+ 'Output written',
136
+ ]);
137
+ });
138
+
139
+ it('should handle checklist with asterisk bullets', () => {
140
+ const content = `
141
+ ### [Checklist]
142
+ * First item
143
+ * Second item
144
+ `;
145
+
146
+ const checklist = parseChecklist(content);
147
+ expect(checklist?.items).toHaveLength(2);
148
+ });
149
+
150
+ it('should return null for content without checklist', () => {
151
+ const content = `
152
+ ### [Steps]
153
+ 1. Do something
154
+ `;
155
+
156
+ const checklist = parseChecklist(content);
157
+ expect(checklist).toBeNull();
158
+ });
159
+
160
+ it('should handle checklist without bracket notation', () => {
161
+ const content = `
162
+ ### Checklist
163
+ - Item one
164
+ - Item two
165
+ `;
166
+
167
+ const checklist = parseChecklist(content);
168
+ expect(checklist?.items).toHaveLength(2);
169
+ });
170
+
171
+ it('should handle multi-line checklist items', () => {
172
+ const content = `
173
+ ### [Checklist]
174
+ - First item that continues
175
+ on the next line
176
+ - Second item
177
+ `;
178
+
179
+ const checklist = parseChecklist(content);
180
+ expect(checklist?.items).toHaveLength(2);
181
+ expect(checklist?.items[0]).toContain('continues');
182
+ });
183
+ });
184
+
185
+ describe('parseOperations', () => {
186
+ it('should parse operation with all sections', () => {
187
+ const content = `
188
+ # [Operations]
189
+
190
+ ## EvaluateDocument
191
+
192
+ Load and evaluate a BUSY document.
193
+
194
+ ### [Inputs]
195
+ - document_path: Path to the document
196
+ - context: Execution context
197
+
198
+ ### [Outputs]
199
+ - parsed_document: The parsed document object
200
+ - errors: List of any errors
201
+
202
+ ### [Steps]
203
+ 1. Parse frontmatter
204
+ 2. Resolve imports
205
+ 3. Execute setup
206
+
207
+ ### [Checklist]
208
+ - Frontmatter valid
209
+ - Imports resolved
210
+ - Setup complete
211
+ `;
212
+
213
+ const operations = parseOperations(content);
214
+ expect(operations).toHaveLength(1);
215
+
216
+ const op = operations[0];
217
+ expect(op.name).toBe('EvaluateDocument');
218
+ expect(op.inputs).toHaveLength(2);
219
+ expect(op.inputs[0]).toBe('document_path: Path to the document');
220
+ expect(op.outputs).toHaveLength(2);
221
+ expect(op.steps).toHaveLength(3);
222
+ expect(op.steps[0].stepNumber).toBe(1);
223
+ expect(op.checklist?.items).toHaveLength(3);
224
+ });
225
+
226
+ it('should parse multiple operations', () => {
227
+ const content = `
228
+ # [Operations]
229
+
230
+ ## FirstOperation
231
+
232
+ ### [Steps]
233
+ 1. Do first thing
234
+
235
+ ## SecondOperation
236
+
237
+ ### [Steps]
238
+ 1. Do second thing
239
+
240
+ ## ThirdOperation
241
+
242
+ ### [Steps]
243
+ 1. Do third thing
244
+ `;
245
+
246
+ const operations = parseOperations(content);
247
+ expect(operations).toHaveLength(3);
248
+ expect(operations.map((o) => o.name)).toEqual([
249
+ 'FirstOperation',
250
+ 'SecondOperation',
251
+ 'ThirdOperation',
252
+ ]);
253
+ });
254
+
255
+ it('should handle operation without inputs/outputs', () => {
256
+ const content = `
257
+ # [Operations]
258
+
259
+ ## SimpleOp
260
+
261
+ ### [Steps]
262
+ 1. Just do it
263
+ `;
264
+
265
+ const operations = parseOperations(content);
266
+ expect(operations).toHaveLength(1);
267
+ expect(operations[0].inputs).toEqual([]);
268
+ expect(operations[0].outputs).toEqual([]);
269
+ });
270
+
271
+ it('should handle operation without checklist', () => {
272
+ const content = `
273
+ # [Operations]
274
+
275
+ ## NoChecklist
276
+
277
+ ### [Steps]
278
+ 1. Do something
279
+ 2. Do something else
280
+ `;
281
+
282
+ const operations = parseOperations(content);
283
+ expect(operations).toHaveLength(1);
284
+ expect(operations[0].checklist).toBeUndefined();
285
+ });
286
+
287
+ it('should parse inputs and outputs as string arrays', () => {
288
+ const content = `
289
+ # [Operations]
290
+
291
+ ## ProcessData
292
+
293
+ ### [Inputs]
294
+ - data: The input data to process
295
+ - options: Processing options (optional)
296
+
297
+ ### [Outputs]
298
+ - result: Processed result
299
+ - metadata: Processing metadata
300
+ `;
301
+
302
+ const operations = parseOperations(content);
303
+ const op = operations[0];
304
+
305
+ expect(op.inputs).toEqual([
306
+ 'data: The input data to process',
307
+ 'options: Processing options (optional)',
308
+ ]);
309
+ expect(op.outputs).toEqual([
310
+ 'result: Processed result',
311
+ 'metadata: Processing metadata',
312
+ ]);
313
+ });
314
+
315
+ it('should handle Operations section without bracket notation', () => {
316
+ const content = `
317
+ # Operations
318
+
319
+ ## TestOp
320
+
321
+ ### Steps
322
+ 1. Test step
323
+ `;
324
+
325
+ const operations = parseOperations(content);
326
+ expect(operations).toHaveLength(1);
327
+ });
328
+
329
+ it('should return empty array for document without Operations section', () => {
330
+ const content = `
331
+ # [Setup]
332
+
333
+ Just setup content.
334
+
335
+ # [Local Definitions]
336
+
337
+ ## SomeDef
338
+
339
+ Definition content.
340
+ `;
341
+
342
+ const operations = parseOperations(content);
343
+ expect(operations).toHaveLength(0);
344
+ });
345
+
346
+ it('should extract operation references from all steps', () => {
347
+ const content = `
348
+ # [Operations]
349
+
350
+ ## Orchestrator
351
+
352
+ ### [Steps]
353
+ 1. First run [ValidateInput]
354
+ 2. Then execute [ProcessData] with [Transform]
355
+ 3. Finally call [SaveOutput]
356
+ `;
357
+
358
+ const operations = parseOperations(content);
359
+ const op = operations[0];
360
+
361
+ expect(op.steps[0].operationReferences).toEqual(['ValidateInput']);
362
+ expect(op.steps[1].operationReferences).toEqual(['ProcessData', 'Transform']);
363
+ expect(op.steps[2].operationReferences).toEqual(['SaveOutput']);
364
+ });
365
+
366
+ it('should handle operation names with spaces (using bracket notation)', () => {
367
+ const content = `
368
+ # [Operations]
369
+
370
+ ## [Run Full Analysis][Operation]
371
+
372
+ ### [Steps]
373
+ 1. Analyze data
374
+ `;
375
+
376
+ const operations = parseOperations(content);
377
+ expect(operations).toHaveLength(1);
378
+ // Should extract "Run Full Analysis" as the name
379
+ expect(operations[0].name).toBe('Run Full Analysis');
380
+ });
381
+ });
382
+
383
+ describe('Operation Step Number Validation', () => {
384
+ it('should ensure step numbers are sequential starting from 1', () => {
385
+ const content = `
386
+ ### [Steps]
387
+ 1. First
388
+ 2. Second
389
+ 3. Third
390
+ `;
391
+
392
+ const steps = parseSteps(content);
393
+ expect(steps.map((s) => s.stepNumber)).toEqual([1, 2, 3]);
394
+ });
395
+
396
+ it('should handle non-sequential step numbers (preserve original)', () => {
397
+ const content = `
398
+ ### [Steps]
399
+ 1. First
400
+ 3. Third (skipped 2)
401
+ 5. Fifth
402
+ `;
403
+
404
+ const steps = parseSteps(content);
405
+ // Should preserve the actual numbers from the document
406
+ expect(steps.map((s) => s.stepNumber)).toEqual([1, 3, 5]);
407
+ });
408
+ });