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.
- package/README.md +129 -0
- package/dist/builders/context.d.ts +50 -0
- package/dist/builders/context.d.ts.map +1 -0
- package/dist/builders/context.js +190 -0
- package/dist/cache/index.d.ts +100 -0
- package/dist/cache/index.d.ts.map +1 -0
- package/dist/cache/index.js +270 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +463 -0
- package/dist/commands/package.d.ts +96 -0
- package/dist/commands/package.d.ts.map +1 -0
- package/dist/commands/package.js +285 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/loader.d.ts +6 -0
- package/dist/loader.d.ts.map +1 -0
- package/dist/loader.js +361 -0
- package/dist/merge.d.ts +16 -0
- package/dist/merge.d.ts.map +1 -0
- package/dist/merge.js +102 -0
- package/dist/package/manifest.d.ts +59 -0
- package/dist/package/manifest.d.ts.map +1 -0
- package/dist/package/manifest.js +265 -0
- package/dist/parser.d.ts +28 -0
- package/dist/parser.d.ts.map +1 -0
- package/dist/parser.js +220 -0
- package/dist/parsers/frontmatter.d.ts +14 -0
- package/dist/parsers/frontmatter.d.ts.map +1 -0
- package/dist/parsers/frontmatter.js +110 -0
- package/dist/parsers/imports.d.ts +48 -0
- package/dist/parsers/imports.d.ts.map +1 -0
- package/dist/parsers/imports.js +147 -0
- package/dist/parsers/links.d.ts +12 -0
- package/dist/parsers/links.d.ts.map +1 -0
- package/dist/parsers/links.js +79 -0
- package/dist/parsers/localdefs.d.ts +6 -0
- package/dist/parsers/localdefs.d.ts.map +1 -0
- package/dist/parsers/localdefs.js +132 -0
- package/dist/parsers/operations.d.ts +32 -0
- package/dist/parsers/operations.d.ts.map +1 -0
- package/dist/parsers/operations.js +313 -0
- package/dist/parsers/sections.d.ts +15 -0
- package/dist/parsers/sections.d.ts.map +1 -0
- package/dist/parsers/sections.js +173 -0
- package/dist/parsers/tools.d.ts +30 -0
- package/dist/parsers/tools.d.ts.map +1 -0
- package/dist/parsers/tools.js +178 -0
- package/dist/parsers/triggers.d.ts +35 -0
- package/dist/parsers/triggers.d.ts.map +1 -0
- package/dist/parsers/triggers.js +219 -0
- package/dist/providers/base.d.ts +60 -0
- package/dist/providers/base.d.ts.map +1 -0
- package/dist/providers/base.js +34 -0
- package/dist/providers/github.d.ts +18 -0
- package/dist/providers/github.d.ts.map +1 -0
- package/dist/providers/github.js +109 -0
- package/dist/providers/gitlab.d.ts +18 -0
- package/dist/providers/gitlab.d.ts.map +1 -0
- package/dist/providers/gitlab.js +101 -0
- package/dist/providers/index.d.ts +13 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +17 -0
- package/dist/providers/local.d.ts +31 -0
- package/dist/providers/local.d.ts.map +1 -0
- package/dist/providers/local.js +116 -0
- package/dist/providers/url.d.ts +16 -0
- package/dist/providers/url.d.ts.map +1 -0
- package/dist/providers/url.js +45 -0
- package/dist/registry/index.d.ts +99 -0
- package/dist/registry/index.d.ts.map +1 -0
- package/dist/registry/index.js +320 -0
- package/dist/types/schema.d.ts +3259 -0
- package/dist/types/schema.d.ts.map +1 -0
- package/dist/types/schema.js +258 -0
- package/dist/utils/logger.d.ts +19 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +23 -0
- package/dist/utils/slugify.d.ts +14 -0
- package/dist/utils/slugify.d.ts.map +1 -0
- package/dist/utils/slugify.js +28 -0
- package/package.json +61 -0
- package/src/__tests__/cache.test.ts +393 -0
- package/src/__tests__/cli-package.test.ts +667 -0
- package/src/__tests__/fixtures/automated-workflow.busy.md +84 -0
- package/src/__tests__/fixtures/concept.busy.md +30 -0
- package/src/__tests__/fixtures/document.busy.md +44 -0
- package/src/__tests__/fixtures/simple-operation.busy.md +45 -0
- package/src/__tests__/fixtures/tool-document.busy.md +71 -0
- package/src/__tests__/fixtures/tool.busy.md +54 -0
- package/src/__tests__/imports.test.ts +244 -0
- package/src/__tests__/integration.test.ts +432 -0
- package/src/__tests__/operations.test.ts +408 -0
- package/src/__tests__/package-manifest.test.ts +455 -0
- package/src/__tests__/providers.test.ts +672 -0
- package/src/__tests__/registry.test.ts +402 -0
- package/src/__tests__/schema.test.ts +467 -0
- package/src/__tests__/tools.test.ts +376 -0
- package/src/__tests__/triggers.test.ts +312 -0
- package/src/builders/context.ts +294 -0
- package/src/cache/index.ts +312 -0
- package/src/cli/index.ts +514 -0
- package/src/commands/package.ts +392 -0
- package/src/index.ts +46 -0
- package/src/loader.ts +474 -0
- package/src/merge.ts +126 -0
- package/src/package/manifest.ts +349 -0
- package/src/parser.ts +278 -0
- package/src/parsers/frontmatter.ts +135 -0
- package/src/parsers/imports.ts +196 -0
- package/src/parsers/links.ts +108 -0
- package/src/parsers/localdefs.ts +166 -0
- package/src/parsers/operations.ts +404 -0
- package/src/parsers/sections.ts +230 -0
- package/src/parsers/tools.ts +215 -0
- package/src/parsers/triggers.ts +252 -0
- package/src/providers/base.ts +77 -0
- package/src/providers/github.ts +129 -0
- package/src/providers/gitlab.ts +121 -0
- package/src/providers/index.ts +25 -0
- package/src/providers/local.ts +129 -0
- package/src/providers/url.ts +56 -0
- package/src/registry/index.ts +408 -0
- package/src/types/schema.ts +369 -0
- package/src/utils/logger.ts +25 -0
- package/src/utils/slugify.ts +31 -0
- package/tsconfig.json +21 -0
|
@@ -0,0 +1,402 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Package Registry Tests
|
|
3
|
+
*
|
|
4
|
+
* Tests for package.busy.md parsing and manipulation.
|
|
5
|
+
* TDD approach for package manager implementation.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
9
|
+
import { promises as fs } from 'node:fs';
|
|
10
|
+
import * as path from 'node:path';
|
|
11
|
+
import * as os from 'node:os';
|
|
12
|
+
|
|
13
|
+
// We'll implement these after tests
|
|
14
|
+
import {
|
|
15
|
+
PackageRegistry,
|
|
16
|
+
PackageEntry,
|
|
17
|
+
parsePackageRegistry,
|
|
18
|
+
deriveEntryId,
|
|
19
|
+
deriveCategory,
|
|
20
|
+
} from '../registry/index.js';
|
|
21
|
+
|
|
22
|
+
const SAMPLE_PACKAGE_BUSY_MD = `---
|
|
23
|
+
Name: package
|
|
24
|
+
Type: Document
|
|
25
|
+
Description: Package registry for this workspace
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
# Local Definitions
|
|
29
|
+
|
|
30
|
+
## Dependency
|
|
31
|
+
|
|
32
|
+
An installed BUSY package.
|
|
33
|
+
|
|
34
|
+
| Field | Required | Description |
|
|
35
|
+
|-------|----------|-------------|
|
|
36
|
+
| Source | Yes | URL to package.busy.md or file |
|
|
37
|
+
| Provider | Yes | github, gitlab, url |
|
|
38
|
+
| Cached | Yes | Local path in .libraries/ |
|
|
39
|
+
| Version | Yes | Semantic version or tag |
|
|
40
|
+
| Fetched | Yes | ISO 8601 timestamp |
|
|
41
|
+
| Integrity | No | sha256:{hash} |
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
# Dependencies
|
|
46
|
+
|
|
47
|
+
## Core Library
|
|
48
|
+
|
|
49
|
+
### executeprompt
|
|
50
|
+
|
|
51
|
+
Execute a prompt operation.
|
|
52
|
+
|
|
53
|
+
| Field | Value |
|
|
54
|
+
|-------|-------|
|
|
55
|
+
| Source | https://github.com/Bravo-Tensor/busy-lang/blob/v0.3.1/busy-v2/core/prompt.md#executeprompt |
|
|
56
|
+
| Provider | github |
|
|
57
|
+
| Cached | .libraries/busy-lang/busy-v2/core/prompt.md |
|
|
58
|
+
| Version | v0.3.1 |
|
|
59
|
+
| Fetched | 2026-01-21T10:30:00Z |
|
|
60
|
+
| Integrity | sha256:abc123def456 |
|
|
61
|
+
|
|
62
|
+
[Source][executeprompt_src] | [Local][executeprompt_local]
|
|
63
|
+
|
|
64
|
+
[executeprompt_src]: https://github.com/Bravo-Tensor/busy-lang/blob/v0.3.1/busy-v2/core/prompt.md#executeprompt
|
|
65
|
+
[executeprompt_local]: .libraries/busy-lang/busy-v2/core/prompt.md
|
|
66
|
+
|
|
67
|
+
## Tools
|
|
68
|
+
|
|
69
|
+
### emit-event
|
|
70
|
+
|
|
71
|
+
Emit an event to the runtime.
|
|
72
|
+
|
|
73
|
+
| Field | Value |
|
|
74
|
+
|-------|-------|
|
|
75
|
+
| Source | https://github.com/Bravo-Tensor/busy-lang/blob/v0.3.1/busy-v2/tools/emit-event.busy.md |
|
|
76
|
+
| Provider | github |
|
|
77
|
+
| Cached | .libraries/busy-lang/busy-v2/tools/emit-event.busy.md |
|
|
78
|
+
| Version | v0.3.1 |
|
|
79
|
+
| Fetched | 2026-01-21T10:30:00Z |
|
|
80
|
+
`;
|
|
81
|
+
|
|
82
|
+
describe('parsePackageRegistry', () => {
|
|
83
|
+
it('should parse frontmatter', () => {
|
|
84
|
+
const registry = parsePackageRegistry(SAMPLE_PACKAGE_BUSY_MD);
|
|
85
|
+
|
|
86
|
+
expect(registry.metadata.name).toBe('package');
|
|
87
|
+
expect(registry.metadata.type).toBe('Document');
|
|
88
|
+
expect(registry.metadata.description).toBe('Package registry for this workspace');
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('should parse package entries', () => {
|
|
92
|
+
const registry = parsePackageRegistry(SAMPLE_PACKAGE_BUSY_MD);
|
|
93
|
+
|
|
94
|
+
expect(registry.packages).toHaveLength(2);
|
|
95
|
+
|
|
96
|
+
const executeprompt = registry.packages.find(p => p.id === 'executeprompt');
|
|
97
|
+
expect(executeprompt).toBeDefined();
|
|
98
|
+
expect(executeprompt?.source).toBe('https://github.com/Bravo-Tensor/busy-lang/blob/v0.3.1/busy-v2/core/prompt.md#executeprompt');
|
|
99
|
+
expect(executeprompt?.provider).toBe('github');
|
|
100
|
+
expect(executeprompt?.cached).toBe('.libraries/busy-lang/busy-v2/core/prompt.md');
|
|
101
|
+
expect(executeprompt?.version).toBe('v0.3.1');
|
|
102
|
+
expect(executeprompt?.fetched).toBe('2026-01-21T10:30:00Z');
|
|
103
|
+
expect(executeprompt?.integrity).toBe('sha256:abc123def456');
|
|
104
|
+
expect(executeprompt?.category).toBe('Core Library');
|
|
105
|
+
expect(executeprompt?.description).toBe('Execute a prompt operation.');
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('should parse entries without optional fields', () => {
|
|
109
|
+
const registry = parsePackageRegistry(SAMPLE_PACKAGE_BUSY_MD);
|
|
110
|
+
|
|
111
|
+
const emitEvent = registry.packages.find(p => p.id === 'emit-event');
|
|
112
|
+
expect(emitEvent).toBeDefined();
|
|
113
|
+
expect(emitEvent?.integrity).toBeUndefined();
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it('should handle empty registry', () => {
|
|
117
|
+
const emptyRegistry = `---
|
|
118
|
+
Name: package
|
|
119
|
+
Type: Document
|
|
120
|
+
Description: Empty package registry
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
# Local Definitions
|
|
124
|
+
|
|
125
|
+
## Dependency
|
|
126
|
+
|
|
127
|
+
| Field | Required | Description |
|
|
128
|
+
|-------|----------|-------------|
|
|
129
|
+
| Source | Yes | URL |
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
# Dependencies
|
|
134
|
+
|
|
135
|
+
No dependencies installed.
|
|
136
|
+
`;
|
|
137
|
+
|
|
138
|
+
const registry = parsePackageRegistry(emptyRegistry);
|
|
139
|
+
|
|
140
|
+
expect(registry.packages).toHaveLength(0);
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
describe('PackageRegistry', () => {
|
|
145
|
+
let tempDir: string;
|
|
146
|
+
let registry: PackageRegistry;
|
|
147
|
+
|
|
148
|
+
beforeEach(async () => {
|
|
149
|
+
tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'busy-registry-test-'));
|
|
150
|
+
registry = new PackageRegistry(tempDir);
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
afterEach(async () => {
|
|
154
|
+
await fs.rm(tempDir, { recursive: true, force: true });
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
describe('init', () => {
|
|
158
|
+
it('should create package.busy.md with defaults', async () => {
|
|
159
|
+
await registry.init();
|
|
160
|
+
|
|
161
|
+
const packagePath = path.join(tempDir, 'package.busy.md');
|
|
162
|
+
const exists = await fs.stat(packagePath).then(() => true).catch(() => false);
|
|
163
|
+
expect(exists).toBe(true);
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it('should not overwrite existing package.busy.md', async () => {
|
|
167
|
+
const packagePath = path.join(tempDir, 'package.busy.md');
|
|
168
|
+
await fs.writeFile(packagePath, 'existing content');
|
|
169
|
+
|
|
170
|
+
await registry.init();
|
|
171
|
+
|
|
172
|
+
const content = await fs.readFile(packagePath, 'utf-8');
|
|
173
|
+
expect(content).toBe('existing content');
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
describe('load', () => {
|
|
178
|
+
it('should load existing package.busy.md', async () => {
|
|
179
|
+
const packagePath = path.join(tempDir, 'package.busy.md');
|
|
180
|
+
await fs.writeFile(packagePath, SAMPLE_PACKAGE_BUSY_MD);
|
|
181
|
+
|
|
182
|
+
await registry.load();
|
|
183
|
+
|
|
184
|
+
const packages = registry.getPackages();
|
|
185
|
+
expect(packages).toHaveLength(2);
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
it('should throw if package.busy.md does not exist', async () => {
|
|
189
|
+
await expect(registry.load()).rejects.toThrow();
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
describe('getPackage', () => {
|
|
194
|
+
beforeEach(async () => {
|
|
195
|
+
const packagePath = path.join(tempDir, 'package.busy.md');
|
|
196
|
+
await fs.writeFile(packagePath, SAMPLE_PACKAGE_BUSY_MD);
|
|
197
|
+
await registry.load();
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
it('should get package by id', () => {
|
|
201
|
+
const pkg = registry.getPackage('executeprompt');
|
|
202
|
+
|
|
203
|
+
expect(pkg).toBeDefined();
|
|
204
|
+
expect(pkg?.source).toContain('prompt.md#executeprompt');
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
it('should return undefined for non-existent package', () => {
|
|
208
|
+
const pkg = registry.getPackage('nonexistent');
|
|
209
|
+
expect(pkg).toBeUndefined();
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
describe('addPackage', () => {
|
|
214
|
+
beforeEach(async () => {
|
|
215
|
+
await registry.init();
|
|
216
|
+
await registry.load();
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
it('should add a new package', () => {
|
|
220
|
+
const entry: PackageEntry = {
|
|
221
|
+
id: 'new-package',
|
|
222
|
+
description: 'A new package',
|
|
223
|
+
source: 'https://github.com/org/repo/blob/main/file.md',
|
|
224
|
+
provider: 'github',
|
|
225
|
+
cached: '.libraries/repo/file.md',
|
|
226
|
+
version: 'v1.0.0',
|
|
227
|
+
fetched: new Date().toISOString(),
|
|
228
|
+
category: 'Packages',
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
registry.addPackage(entry);
|
|
232
|
+
|
|
233
|
+
const pkg = registry.getPackage('new-package');
|
|
234
|
+
expect(pkg).toEqual(entry);
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
it('should update existing package', () => {
|
|
238
|
+
const entry: PackageEntry = {
|
|
239
|
+
id: 'test-package',
|
|
240
|
+
description: 'Test',
|
|
241
|
+
source: 'https://example.com/file.md',
|
|
242
|
+
provider: 'url',
|
|
243
|
+
cached: '.libraries/file.md',
|
|
244
|
+
version: 'v1.0.0',
|
|
245
|
+
fetched: new Date().toISOString(),
|
|
246
|
+
category: 'Packages',
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
registry.addPackage(entry);
|
|
250
|
+
|
|
251
|
+
const updatedEntry = { ...entry, version: 'v2.0.0' };
|
|
252
|
+
registry.addPackage(updatedEntry);
|
|
253
|
+
|
|
254
|
+
const pkg = registry.getPackage('test-package');
|
|
255
|
+
expect(pkg?.version).toBe('v2.0.0');
|
|
256
|
+
});
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
describe('removePackage', () => {
|
|
260
|
+
beforeEach(async () => {
|
|
261
|
+
const packagePath = path.join(tempDir, 'package.busy.md');
|
|
262
|
+
await fs.writeFile(packagePath, SAMPLE_PACKAGE_BUSY_MD);
|
|
263
|
+
await registry.load();
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
it('should remove package by id', () => {
|
|
267
|
+
const removed = registry.removePackage('executeprompt');
|
|
268
|
+
|
|
269
|
+
expect(removed).toBe(true);
|
|
270
|
+
expect(registry.getPackage('executeprompt')).toBeUndefined();
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
it('should return false for non-existent package', () => {
|
|
274
|
+
const removed = registry.removePackage('nonexistent');
|
|
275
|
+
expect(removed).toBe(false);
|
|
276
|
+
});
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
describe('save', () => {
|
|
280
|
+
beforeEach(async () => {
|
|
281
|
+
await registry.init();
|
|
282
|
+
await registry.load();
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
it('should save changes to package.busy.md', async () => {
|
|
286
|
+
const entry: PackageEntry = {
|
|
287
|
+
id: 'new-package',
|
|
288
|
+
description: 'A new package',
|
|
289
|
+
source: 'https://github.com/org/repo/blob/main/file.md',
|
|
290
|
+
provider: 'github',
|
|
291
|
+
cached: '.libraries/repo/file.md',
|
|
292
|
+
version: 'v1.0.0',
|
|
293
|
+
fetched: '2026-01-21T10:00:00Z',
|
|
294
|
+
category: 'Packages',
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
registry.addPackage(entry);
|
|
298
|
+
await registry.save();
|
|
299
|
+
|
|
300
|
+
// Reload and verify
|
|
301
|
+
const newRegistry = new PackageRegistry(tempDir);
|
|
302
|
+
await newRegistry.load();
|
|
303
|
+
|
|
304
|
+
const pkg = newRegistry.getPackage('new-package');
|
|
305
|
+
expect(pkg).toBeDefined();
|
|
306
|
+
expect(pkg?.version).toBe('v1.0.0');
|
|
307
|
+
});
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
describe('getPackagesByCategory', () => {
|
|
311
|
+
beforeEach(async () => {
|
|
312
|
+
const packagePath = path.join(tempDir, 'package.busy.md');
|
|
313
|
+
await fs.writeFile(packagePath, SAMPLE_PACKAGE_BUSY_MD);
|
|
314
|
+
await registry.load();
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
it('should return packages in category', () => {
|
|
318
|
+
const corePackages = registry.getPackagesByCategory('Core Library');
|
|
319
|
+
expect(corePackages).toHaveLength(1);
|
|
320
|
+
expect(corePackages[0].id).toBe('executeprompt');
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
it('should return empty array for non-existent category', () => {
|
|
324
|
+
const packages = registry.getPackagesByCategory('Nonexistent');
|
|
325
|
+
expect(packages).toHaveLength(0);
|
|
326
|
+
});
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
describe('getCategories', () => {
|
|
330
|
+
beforeEach(async () => {
|
|
331
|
+
const packagePath = path.join(tempDir, 'package.busy.md');
|
|
332
|
+
await fs.writeFile(packagePath, SAMPLE_PACKAGE_BUSY_MD);
|
|
333
|
+
await registry.load();
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
it('should return all categories', () => {
|
|
337
|
+
const categories = registry.getCategories();
|
|
338
|
+
|
|
339
|
+
expect(categories).toContain('Core Library');
|
|
340
|
+
expect(categories).toContain('Tools');
|
|
341
|
+
});
|
|
342
|
+
});
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
describe('deriveEntryId', () => {
|
|
346
|
+
it('should use anchor if present', () => {
|
|
347
|
+
const url = 'https://github.com/org/repo/blob/main/file.md#executeprompt';
|
|
348
|
+
expect(deriveEntryId(url)).toBe('executeprompt');
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
it('should use filename without extension if no anchor', () => {
|
|
352
|
+
const url = 'https://github.com/org/repo/blob/main/emit-event.busy.md';
|
|
353
|
+
expect(deriveEntryId(url)).toBe('emit-event');
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
it('should handle .md extension', () => {
|
|
357
|
+
const url = 'https://github.com/org/repo/blob/main/prompt.md';
|
|
358
|
+
expect(deriveEntryId(url)).toBe('prompt');
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
it('should handle nested paths', () => {
|
|
362
|
+
const url = 'https://github.com/org/repo/blob/main/tools/emit-event.busy.md';
|
|
363
|
+
expect(deriveEntryId(url)).toBe('emit-event');
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
it('should slugify the result', () => {
|
|
367
|
+
const url = 'https://github.com/org/repo/blob/main/My File.md';
|
|
368
|
+
expect(deriveEntryId(url)).toBe('my-file');
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
it('should handle uppercase anchors', () => {
|
|
372
|
+
const url = 'https://github.com/org/repo/blob/main/file.md#ExecutePrompt';
|
|
373
|
+
expect(deriveEntryId(url)).toBe('executeprompt');
|
|
374
|
+
});
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
describe('deriveCategory', () => {
|
|
378
|
+
it('should return Core Library for /core/ path', () => {
|
|
379
|
+
const url = 'https://github.com/org/repo/blob/main/core/prompt.md';
|
|
380
|
+
expect(deriveCategory(url)).toBe('Core Library');
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
it('should return Tools for /tools/ path', () => {
|
|
384
|
+
const url = 'https://github.com/org/repo/blob/main/tools/emit.md';
|
|
385
|
+
expect(deriveCategory(url)).toBe('Tools');
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
it('should return Concepts for /concepts/ path', () => {
|
|
389
|
+
const url = 'https://github.com/org/repo/blob/main/concepts/operation.md';
|
|
390
|
+
expect(deriveCategory(url)).toBe('Concepts');
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
it('should return Packages as default', () => {
|
|
394
|
+
const url = 'https://github.com/org/repo/blob/main/other/file.md';
|
|
395
|
+
expect(deriveCategory(url)).toBe('Packages');
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
it('should handle case insensitively', () => {
|
|
399
|
+
const url = 'https://github.com/org/repo/blob/main/CORE/prompt.md';
|
|
400
|
+
expect(deriveCategory(url)).toBe('Core Library');
|
|
401
|
+
});
|
|
402
|
+
});
|