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,178 @@
1
+ /**
2
+ * Tool Parser - Matches busy-python Tool and ToolDocument models
3
+ *
4
+ * Tools have:
5
+ * - name: string
6
+ * - description: string
7
+ * - inputs: list[str]
8
+ * - outputs: list[str]
9
+ * - examples: Optional[list[str]]
10
+ * - providers: Optional[dict[str, dict[str, Any]]] (provider_name -> {action, parameters})
11
+ */
12
+ /**
13
+ * Parse provider mappings from tool content
14
+ *
15
+ * @param content - Content of the tool section
16
+ * @returns Record of provider name to {action, parameters}
17
+ */
18
+ export function parseToolProviders(content) {
19
+ const providers = {};
20
+ // Find Providers section - get everything after ### Providers or ### [Providers]
21
+ // Or if content starts with #### (direct provider definitions)
22
+ let providersContent;
23
+ const providersMatch = content.match(/###\s*\[?Providers\]?\s*\n([\s\S]*)$/i);
24
+ if (providersMatch) {
25
+ providersContent = providersMatch[1];
26
+ }
27
+ else if (content.match(/^####\s+/m)) {
28
+ // Content starts with provider definitions directly
29
+ providersContent = content;
30
+ }
31
+ else {
32
+ return providers;
33
+ }
34
+ // Trim at next ### that's not #### (to stop at next H3 section)
35
+ const nextSectionMatch = providersContent.match(/\n###\s+[^\#]/);
36
+ if (nextSectionMatch) {
37
+ providersContent = providersContent.slice(0, nextSectionMatch.index);
38
+ }
39
+ // Split by #### headings (provider names)
40
+ const parts = providersContent.split(/(?=####\s+)/);
41
+ for (const part of parts) {
42
+ if (!part.trim())
43
+ continue;
44
+ // Match provider heading: #### providerName
45
+ const providerMatch = part.match(/^####\s+(\w+)\s*\n?([\s\S]*)/);
46
+ if (providerMatch) {
47
+ const providerName = providerMatch[1];
48
+ const providerContent = providerMatch[2] || '';
49
+ // Extract Action
50
+ const actionMatch = providerContent.match(/Action:\s*(.+)/i);
51
+ const action = actionMatch ? actionMatch[1].trim() : '';
52
+ // Extract Parameters
53
+ const paramsMatch = providerContent.match(/Parameters:\s*\n([\s\S]*?)(?=####|Action:|$)/i);
54
+ let parameters;
55
+ if (paramsMatch) {
56
+ parameters = parseYamlLikeParams(paramsMatch[1]);
57
+ }
58
+ if (action) {
59
+ providers[providerName] = {
60
+ action,
61
+ parameters: parameters && Object.keys(parameters).length > 0 ? parameters : undefined,
62
+ };
63
+ }
64
+ }
65
+ }
66
+ return providers;
67
+ }
68
+ /**
69
+ * Parse YAML-like indented parameters
70
+ */
71
+ function parseYamlLikeParams(content) {
72
+ const params = {};
73
+ const lines = content.split('\n');
74
+ let currentKey = '';
75
+ let currentNested = null;
76
+ for (const line of lines) {
77
+ const trimmed = line.trim();
78
+ if (!trimmed)
79
+ continue;
80
+ // Check indentation level
81
+ const leadingSpaces = line.match(/^(\s*)/)?.[1].length || 0;
82
+ // Match key: value pair
83
+ const kvMatch = trimmed.match(/^(\w+):\s*(.*)$/);
84
+ if (kvMatch) {
85
+ const key = kvMatch[1];
86
+ const value = kvMatch[2].trim();
87
+ if (leadingSpaces <= 2) {
88
+ // Top-level key
89
+ if (value) {
90
+ params[key] = value;
91
+ }
92
+ else {
93
+ // Nested object
94
+ currentKey = key;
95
+ currentNested = {};
96
+ params[key] = currentNested;
97
+ }
98
+ }
99
+ else if (currentNested && currentKey) {
100
+ // Nested key
101
+ currentNested[key] = value;
102
+ }
103
+ }
104
+ }
105
+ return params;
106
+ }
107
+ /**
108
+ * Parse bullet list items from a section
109
+ */
110
+ function parseBulletList(content, sectionName) {
111
+ const pattern = new RegExp(`###\\s*\\[?${sectionName}\\]?\\s*\\n([\\s\\S]*?)(?=\\n###|\\n##|$)`, 'i');
112
+ const match = content.match(pattern);
113
+ if (!match) {
114
+ return [];
115
+ }
116
+ const items = [];
117
+ const lines = match[1].split('\n');
118
+ for (const line of lines) {
119
+ const trimmed = line.trim();
120
+ const bulletMatch = trimmed.match(/^[-*]\s+(.+)$/);
121
+ if (bulletMatch) {
122
+ items.push(bulletMatch[1].trim());
123
+ }
124
+ }
125
+ return items;
126
+ }
127
+ /**
128
+ * Parse tools from markdown content
129
+ *
130
+ * @param content - Full markdown document content
131
+ * @returns Array of Tool objects
132
+ */
133
+ export function parseTools(content) {
134
+ const tools = [];
135
+ // Find Tools section - handle both with and without brackets
136
+ const toolsMatch = content.match(/^#\s*\[?Tools\]?\s*$/im);
137
+ if (!toolsMatch) {
138
+ return [];
139
+ }
140
+ // Get content after Tools heading until next top-level section or end
141
+ const startIndex = toolsMatch.index + toolsMatch[0].length;
142
+ const restContent = content.slice(startIndex);
143
+ // Find next top-level heading (# not ##)
144
+ const nextH1Match = restContent.match(/\n#\s+[^\#]/);
145
+ const toolsContent = nextH1Match
146
+ ? restContent.slice(0, nextH1Match.index)
147
+ : restContent;
148
+ // Split by ## headings to find individual tools
149
+ const parts = toolsContent.split(/\n(?=##\s+)/);
150
+ for (const part of parts) {
151
+ if (!part.trim())
152
+ continue;
153
+ // Match tool heading: ## tool_name
154
+ const headingMatch = part.match(/^##\s+(\S+)\s*\n([\s\S]*)/);
155
+ if (headingMatch) {
156
+ const name = headingMatch[1].trim();
157
+ const toolContent = headingMatch[2] || '';
158
+ // Extract description (first paragraph before any ### section)
159
+ const descMatch = toolContent.match(/^([^#\n][\s\S]*?)(?=\n###|$)/);
160
+ const description = descMatch ? descMatch[1].trim() : '';
161
+ // Parse sections
162
+ const inputs = parseBulletList(toolContent, 'Inputs');
163
+ const outputs = parseBulletList(toolContent, 'Outputs');
164
+ const examples = parseBulletList(toolContent, 'Examples');
165
+ const providers = parseToolProviders(toolContent);
166
+ tools.push({
167
+ name,
168
+ description,
169
+ inputs,
170
+ outputs,
171
+ examples: examples.length > 0 ? examples : undefined,
172
+ providers: Object.keys(providers).length > 0 ? providers : undefined,
173
+ });
174
+ }
175
+ }
176
+ return tools;
177
+ }
178
+ //# sourceMappingURL=tools.js.map
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Trigger Parser - Matches busy-python trigger parsing
3
+ *
4
+ * Supports two trigger formats:
5
+ * 1. Time-based (alarm): "Set alarm for <time> to run <Operation>"
6
+ * 2. Event-based: "When <event> [from <filter>], run <Operation>"
7
+ *
8
+ * Triggers can appear in:
9
+ * - # [Triggers] section as bullet points
10
+ * - Frontmatter as a Triggers array
11
+ */
12
+ import { Trigger } from '../types/schema.js';
13
+ /**
14
+ * Parse a time specification into a cron expression
15
+ *
16
+ * @param timeSpec - Time string like "6am", "3pm each day", "9am on Monday"
17
+ * @returns Cron expression string
18
+ */
19
+ export declare function parseTimeSpec(timeSpec: string): string;
20
+ /**
21
+ * Parse a trigger declaration text into a Trigger object
22
+ *
23
+ * @param text - The trigger declaration text
24
+ * @returns Trigger object
25
+ */
26
+ export declare function parseTriggerDeclaration(text: string): Trigger;
27
+ /**
28
+ * Parse triggers from markdown content
29
+ * Combines triggers from both Triggers section and frontmatter
30
+ *
31
+ * @param content - Full markdown document content
32
+ * @returns Array of Trigger objects
33
+ */
34
+ export declare function parseTriggers(content: string): Trigger[];
35
+ //# sourceMappingURL=triggers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"triggers.d.ts","sourceRoot":"","sources":["../../src/parsers/triggers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAqB7C;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAuBtD;AAqCD;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAmD7D;AAyCD;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,EAAE,CA+CxD"}
@@ -0,0 +1,219 @@
1
+ /**
2
+ * Trigger Parser - Matches busy-python trigger parsing
3
+ *
4
+ * Supports two trigger formats:
5
+ * 1. Time-based (alarm): "Set alarm for <time> to run <Operation>"
6
+ * 2. Event-based: "When <event> [from <filter>], run <Operation>"
7
+ *
8
+ * Triggers can appear in:
9
+ * - # [Triggers] section as bullet points
10
+ * - Frontmatter as a Triggers array
11
+ */
12
+ import matter from 'gray-matter';
13
+ // Weekday mapping
14
+ const WEEKDAYS = {
15
+ sunday: 0,
16
+ monday: 1,
17
+ tuesday: 2,
18
+ wednesday: 3,
19
+ thursday: 4,
20
+ friday: 5,
21
+ saturday: 6,
22
+ sun: 0,
23
+ mon: 1,
24
+ tue: 2,
25
+ wed: 3,
26
+ thu: 4,
27
+ fri: 5,
28
+ sat: 6,
29
+ };
30
+ /**
31
+ * Parse a time specification into a cron expression
32
+ *
33
+ * @param timeSpec - Time string like "6am", "3pm each day", "9am on Monday"
34
+ * @returns Cron expression string
35
+ */
36
+ export function parseTimeSpec(timeSpec) {
37
+ const spec = timeSpec.toLowerCase().trim();
38
+ // Extract hour and AM/PM
39
+ const timeMatch = spec.match(/(\d{1,2})\s*(am|pm)/i);
40
+ if (!timeMatch) {
41
+ return '* * * * *'; // Default: every minute (invalid spec)
42
+ }
43
+ let hour = parseInt(timeMatch[1], 10);
44
+ const isPM = timeMatch[2].toLowerCase() === 'pm';
45
+ // Convert to 24-hour format
46
+ if (isPM && hour !== 12) {
47
+ hour += 12;
48
+ }
49
+ else if (!isPM && hour === 12) {
50
+ hour = 0;
51
+ }
52
+ // Check for day specifications
53
+ const dayOfWeek = parseDayOfWeek(spec);
54
+ return `0 ${hour} * * ${dayOfWeek}`;
55
+ }
56
+ /**
57
+ * Parse day of week specification from time string
58
+ */
59
+ function parseDayOfWeek(spec) {
60
+ // Check for "weekdays"
61
+ if (spec.includes('weekdays')) {
62
+ return '1-5';
63
+ }
64
+ // Check for "weekends"
65
+ if (spec.includes('weekends')) {
66
+ return '0,6';
67
+ }
68
+ // Check for specific days
69
+ const days = [];
70
+ for (const [dayName, dayNum] of Object.entries(WEEKDAYS)) {
71
+ // Match full day name or abbreviation
72
+ const pattern = new RegExp(`\\b${dayName}\\b`, 'i');
73
+ if (pattern.test(spec)) {
74
+ if (!days.includes(dayNum)) {
75
+ days.push(dayNum);
76
+ }
77
+ }
78
+ }
79
+ if (days.length > 0) {
80
+ return days.sort((a, b) => a - b).join(',');
81
+ }
82
+ // Default: every day
83
+ return '*';
84
+ }
85
+ /**
86
+ * Parse a trigger declaration text into a Trigger object
87
+ *
88
+ * @param text - The trigger declaration text
89
+ * @returns Trigger object
90
+ */
91
+ export function parseTriggerDeclaration(text) {
92
+ const rawText = text.trim();
93
+ // Try to match alarm pattern: "Set alarm for <time> to run <Operation>"
94
+ const alarmMatch = rawText.match(/set\s+alarm\s+for\s+(.+?)\s+to\s+run\s+(\w+)/i);
95
+ if (alarmMatch) {
96
+ const timeSpec = alarmMatch[1];
97
+ const operation = alarmMatch[2];
98
+ const schedule = parseTimeSpec(timeSpec);
99
+ return {
100
+ rawText,
101
+ triggerType: 'alarm',
102
+ schedule,
103
+ operation,
104
+ queueWhenPaused: true,
105
+ };
106
+ }
107
+ // Try to match event pattern: "When <event> [from <filter>], run <Operation>"
108
+ const eventMatch = rawText.match(/when\s+([\w.]+)(?:\s+from\s+(.+?))?,\s*run\s+(\w+)/i);
109
+ if (eventMatch) {
110
+ const eventType = eventMatch[1];
111
+ const filterSpec = eventMatch[2];
112
+ const operation = eventMatch[3];
113
+ let filter;
114
+ if (filterSpec) {
115
+ // Treat filter as email pattern by default
116
+ filter = { from: filterSpec.trim() };
117
+ }
118
+ return {
119
+ rawText,
120
+ triggerType: 'event',
121
+ eventType,
122
+ filter,
123
+ operation,
124
+ queueWhenPaused: true,
125
+ };
126
+ }
127
+ // Fallback: couldn't parse, return minimal trigger
128
+ return {
129
+ rawText,
130
+ triggerType: 'event',
131
+ operation: 'Unknown',
132
+ queueWhenPaused: true,
133
+ };
134
+ }
135
+ /**
136
+ * Parse triggers from frontmatter data
137
+ */
138
+ function parseFrontmatterTriggers(data) {
139
+ const triggers = [];
140
+ if (!data?.Triggers || !Array.isArray(data.Triggers)) {
141
+ return [];
142
+ }
143
+ for (const item of data.Triggers) {
144
+ if (typeof item === 'object' && item !== null) {
145
+ // Handle structured trigger from frontmatter
146
+ if (item.schedule) {
147
+ // Alarm trigger with explicit cron
148
+ triggers.push({
149
+ rawText: JSON.stringify(item),
150
+ triggerType: 'alarm',
151
+ schedule: item.schedule,
152
+ operation: item.operation || 'Unknown',
153
+ queueWhenPaused: item.queue_when_paused ?? true,
154
+ });
155
+ }
156
+ else if (item.event_type) {
157
+ // Event trigger
158
+ triggers.push({
159
+ rawText: JSON.stringify(item),
160
+ triggerType: 'event',
161
+ eventType: item.event_type,
162
+ filter: item.filter,
163
+ operation: item.operation || 'Unknown',
164
+ queueWhenPaused: item.queue_when_paused ?? true,
165
+ });
166
+ }
167
+ }
168
+ }
169
+ return triggers;
170
+ }
171
+ /**
172
+ * Parse triggers from markdown content
173
+ * Combines triggers from both Triggers section and frontmatter
174
+ *
175
+ * @param content - Full markdown document content
176
+ * @returns Array of Trigger objects
177
+ */
178
+ export function parseTriggers(content) {
179
+ const triggers = [];
180
+ // Extract only first frontmatter block to avoid "multiple documents" error
181
+ const trimmedContent = content.trimStart();
182
+ const frontmatterMatch = trimmedContent.match(/^---\n([\s\S]*?)\n---/);
183
+ if (frontmatterMatch) {
184
+ try {
185
+ const { data } = matter(frontmatterMatch[0]);
186
+ if (data && typeof data === 'object') {
187
+ const frontmatterTriggers = parseFrontmatterTriggers(data);
188
+ triggers.push(...frontmatterTriggers);
189
+ }
190
+ }
191
+ catch (e) {
192
+ // Frontmatter parsing error, continue without frontmatter triggers
193
+ }
194
+ }
195
+ // Find Triggers section
196
+ const triggersMatch = content.match(/^#\s*\[?Triggers\]?\s*$/im);
197
+ if (triggersMatch) {
198
+ // Get content after Triggers heading
199
+ const startIndex = triggersMatch.index + triggersMatch[0].length;
200
+ const restContent = content.slice(startIndex);
201
+ // Find next top-level heading
202
+ const nextH1Match = restContent.match(/\n#\s+[^\#]/);
203
+ const triggersContent = nextH1Match
204
+ ? restContent.slice(0, nextH1Match.index)
205
+ : restContent;
206
+ // Parse bullet items
207
+ const lines = triggersContent.split('\n');
208
+ for (const line of lines) {
209
+ const trimmed = line.trim();
210
+ const bulletMatch = trimmed.match(/^[-*]\s+(.+)$/);
211
+ if (bulletMatch) {
212
+ const trigger = parseTriggerDeclaration(bulletMatch[1]);
213
+ triggers.push(trigger);
214
+ }
215
+ }
216
+ }
217
+ return triggers;
218
+ }
219
+ //# sourceMappingURL=triggers.js.map
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Provider system for URL handling
3
+ *
4
+ * Providers handle fetching content from different URL sources (GitHub, GitLab, generic URLs).
5
+ */
6
+ export interface ParsedURL {
7
+ provider: string;
8
+ org?: string;
9
+ repo?: string;
10
+ ref?: string;
11
+ path: string;
12
+ anchor?: string;
13
+ rawUrl?: string;
14
+ }
15
+ export interface Provider {
16
+ name: string;
17
+ /**
18
+ * Check if this provider handles the given URL
19
+ */
20
+ matches(url: string): boolean;
21
+ /**
22
+ * Parse URL into components
23
+ */
24
+ parse(url: string): ParsedURL;
25
+ /**
26
+ * Convert parsed URL to raw content URL
27
+ */
28
+ getRawUrl(parsed: ParsedURL): string;
29
+ /**
30
+ * Fetch content from URL
31
+ */
32
+ fetch(url: string): Promise<string>;
33
+ /**
34
+ * Get the latest version/tag for a repo (optional)
35
+ */
36
+ getLatestVersion?(parsed: ParsedURL): Promise<string>;
37
+ }
38
+ /**
39
+ * Provider registry - manages all URL providers
40
+ */
41
+ export declare class ProviderRegistry {
42
+ private providers;
43
+ /**
44
+ * Register a provider
45
+ */
46
+ register(provider: Provider): void;
47
+ /**
48
+ * Find provider that handles a URL
49
+ */
50
+ findProvider(url: string): Provider | undefined;
51
+ /**
52
+ * Get all registered providers
53
+ */
54
+ getProviders(): Provider[];
55
+ }
56
+ /**
57
+ * Global provider registry instance
58
+ */
59
+ export declare const providerRegistry: ProviderRegistry;
60
+ //# sourceMappingURL=base.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../src/providers/base.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IAEb;;OAEG;IACH,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IAE9B;;OAEG;IACH,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;IAE9B;;OAEG;IACH,SAAS,CAAC,MAAM,EAAE,SAAS,GAAG,MAAM,CAAC;IAErC;;OAEG;IACH,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAEpC;;OAEG;IACH,gBAAgB,CAAC,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CACvD;AAED;;GAEG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,SAAS,CAAkB;IAEnC;;OAEG;IACH,QAAQ,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;IAIlC;;OAEG;IACH,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS;IAI/C;;OAEG;IACH,YAAY,IAAI,QAAQ,EAAE;CAG3B;AAED;;GAEG;AACH,eAAO,MAAM,gBAAgB,kBAAyB,CAAC"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Provider system for URL handling
3
+ *
4
+ * Providers handle fetching content from different URL sources (GitHub, GitLab, generic URLs).
5
+ */
6
+ /**
7
+ * Provider registry - manages all URL providers
8
+ */
9
+ export class ProviderRegistry {
10
+ providers = [];
11
+ /**
12
+ * Register a provider
13
+ */
14
+ register(provider) {
15
+ this.providers.push(provider);
16
+ }
17
+ /**
18
+ * Find provider that handles a URL
19
+ */
20
+ findProvider(url) {
21
+ return this.providers.find(p => p.matches(url));
22
+ }
23
+ /**
24
+ * Get all registered providers
25
+ */
26
+ getProviders() {
27
+ return [...this.providers];
28
+ }
29
+ }
30
+ /**
31
+ * Global provider registry instance
32
+ */
33
+ export const providerRegistry = new ProviderRegistry();
34
+ //# sourceMappingURL=base.js.map
@@ -0,0 +1,18 @@
1
+ /**
2
+ * GitHub URL provider
3
+ *
4
+ * Handles URLs like:
5
+ * - https://github.com/org/repo/blob/ref/path/to/file.md
6
+ * - https://github.com/org/repo/tree/ref/path/to/dir
7
+ */
8
+ import { Provider, ParsedURL } from './base.js';
9
+ export declare class GitHubProvider implements Provider {
10
+ name: string;
11
+ matches(url: string): boolean;
12
+ parse(url: string): ParsedURL;
13
+ getRawUrl(parsed: ParsedURL): string;
14
+ fetch(url: string): Promise<string>;
15
+ getLatestVersion(parsed: ParsedURL): Promise<string>;
16
+ }
17
+ export declare const githubProvider: GitHubProvider;
18
+ //# sourceMappingURL=github.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github.d.ts","sourceRoot":"","sources":["../../src/providers/github.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAoB,MAAM,WAAW,CAAC;AAWlE,qBAAa,cAAe,YAAW,QAAQ;IAC7C,IAAI,SAAY;IAEhB,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAU7B,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS;IA+C7B,SAAS,CAAC,MAAM,EAAE,SAAS,GAAG,MAAM;IAO9B,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAYnC,gBAAgB,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC;CA0B3D;AAGD,eAAO,MAAM,cAAc,gBAAuB,CAAC"}
@@ -0,0 +1,109 @@
1
+ /**
2
+ * GitHub URL provider
3
+ *
4
+ * Handles URLs like:
5
+ * - https://github.com/org/repo/blob/ref/path/to/file.md
6
+ * - https://github.com/org/repo/tree/ref/path/to/dir
7
+ */
8
+ import { providerRegistry } from './base.js';
9
+ // Pattern for GitHub blob URLs (single file)
10
+ const BLOB_PATTERN = /github\.com\/([^/]+)\/([^/]+)\/blob\/([^/]+)\/(.+)/;
11
+ // Pattern for GitHub tree URLs (directory)
12
+ const TREE_PATTERN = /github\.com\/([^/]+)\/([^/]+)\/tree\/([^/]+)\/(.+)/;
13
+ // Pattern for raw GitHub URLs
14
+ const RAW_PATTERN = /raw\.githubusercontent\.com\/([^/]+)\/([^/]+)\/([^/]+)\/(.+)/;
15
+ export class GitHubProvider {
16
+ name = 'github';
17
+ matches(url) {
18
+ // Use proper URL parsing to check the hostname
19
+ try {
20
+ const parsed = new URL(url);
21
+ return parsed.hostname === 'github.com' || parsed.hostname === 'raw.githubusercontent.com';
22
+ }
23
+ catch {
24
+ return false;
25
+ }
26
+ }
27
+ parse(url) {
28
+ // Extract anchor if present
29
+ const [urlWithoutAnchor, anchor] = url.split('#');
30
+ // Try blob pattern first
31
+ let match = urlWithoutAnchor.match(BLOB_PATTERN);
32
+ if (match) {
33
+ return {
34
+ provider: 'github',
35
+ org: match[1],
36
+ repo: match[2],
37
+ ref: match[3],
38
+ path: match[4],
39
+ anchor,
40
+ };
41
+ }
42
+ // Try tree pattern (directory)
43
+ match = urlWithoutAnchor.match(TREE_PATTERN);
44
+ if (match) {
45
+ return {
46
+ provider: 'github',
47
+ org: match[1],
48
+ repo: match[2],
49
+ ref: match[3],
50
+ path: match[4],
51
+ anchor,
52
+ };
53
+ }
54
+ // Try raw URL pattern
55
+ match = urlWithoutAnchor.match(RAW_PATTERN);
56
+ if (match) {
57
+ return {
58
+ provider: 'github',
59
+ org: match[1],
60
+ repo: match[2],
61
+ ref: match[3],
62
+ path: match[4],
63
+ anchor,
64
+ rawUrl: urlWithoutAnchor,
65
+ };
66
+ }
67
+ throw new Error(`Cannot parse GitHub URL: ${url}`);
68
+ }
69
+ getRawUrl(parsed) {
70
+ if (parsed.rawUrl) {
71
+ return parsed.rawUrl;
72
+ }
73
+ return `https://raw.githubusercontent.com/${parsed.org}/${parsed.repo}/${parsed.ref}/${parsed.path}`;
74
+ }
75
+ async fetch(url) {
76
+ const parsed = this.parse(url);
77
+ const rawUrl = this.getRawUrl(parsed);
78
+ const response = await fetch(rawUrl);
79
+ if (!response.ok) {
80
+ throw new Error(`Failed to fetch ${rawUrl}: ${response.status} ${response.statusText}`);
81
+ }
82
+ return response.text();
83
+ }
84
+ async getLatestVersion(parsed) {
85
+ const apiUrl = `https://api.github.com/repos/${parsed.org}/${parsed.repo}/tags`;
86
+ const response = await fetch(apiUrl, {
87
+ headers: {
88
+ Accept: 'application/vnd.github.v3+json',
89
+ // Add User-Agent header as required by GitHub API
90
+ 'User-Agent': 'busy-parser',
91
+ },
92
+ });
93
+ if (!response.ok) {
94
+ throw new Error(`Failed to fetch tags from GitHub API: ${response.status}`);
95
+ }
96
+ const tags = await response.json();
97
+ if (tags.length === 0) {
98
+ throw new Error(`No tags found for ${parsed.org}/${parsed.repo}`);
99
+ }
100
+ // Return the first (latest) tag
101
+ // Note: GitHub API returns tags in reverse chronological order for most repos
102
+ // For proper semver sorting, we'd need to parse and sort the tags
103
+ return tags[0].name;
104
+ }
105
+ }
106
+ // Create and register the GitHub provider
107
+ export const githubProvider = new GitHubProvider();
108
+ providerRegistry.register(githubProvider);
109
+ //# sourceMappingURL=github.js.map
@@ -0,0 +1,18 @@
1
+ /**
2
+ * GitLab URL provider
3
+ *
4
+ * Handles URLs like:
5
+ * - https://gitlab.com/org/repo/-/blob/ref/path/to/file.md
6
+ * - https://gitlab.com/org/repo/-/tree/ref/path/to/dir
7
+ */
8
+ import { Provider, ParsedURL } from './base.js';
9
+ export declare class GitLabProvider implements Provider {
10
+ name: string;
11
+ matches(url: string): boolean;
12
+ parse(url: string): ParsedURL;
13
+ getRawUrl(parsed: ParsedURL): string;
14
+ fetch(url: string): Promise<string>;
15
+ getLatestVersion(parsed: ParsedURL): Promise<string>;
16
+ }
17
+ export declare const gitlabProvider: GitLabProvider;
18
+ //# sourceMappingURL=gitlab.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gitlab.d.ts","sourceRoot":"","sources":["../../src/providers/gitlab.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAoB,MAAM,WAAW,CAAC;AAWlE,qBAAa,cAAe,YAAW,QAAQ;IAC7C,IAAI,SAAY;IAEhB,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAU7B,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS;IA+C7B,SAAS,CAAC,MAAM,EAAE,SAAS,GAAG,MAAM;IAO9B,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAYnC,gBAAgB,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC;CAkB3D;AAGD,eAAO,MAAM,cAAc,gBAAuB,CAAC"}