@deimoscloud/coreai 0.1.9 → 0.1.10
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/dist/cli/index.js +1 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +6 -1
- package/.prettierrc +0 -9
- package/AGENT_SPEC.md +0 -347
- package/ARCHITECTURE.md +0 -547
- package/DRAFT_PRD.md +0 -1440
- package/IMPLEMENTATION_PLAN.md +0 -256
- package/PRODUCT.md +0 -473
- package/WORKFLOWS.md +0 -295
- package/commands/core/check-inbox.md +0 -34
- package/commands/core/delegate.md +0 -30
- package/commands/core/git-commit.md +0 -144
- package/commands/core/pr-create.md +0 -193
- package/commands/core/review.md +0 -56
- package/commands/core/sprint-status.md +0 -65
- package/commands/optional/docs-update.md +0 -200
- package/commands/optional/jira-create.md +0 -200
- package/commands/optional/jira-transition.md +0 -184
- package/commands/optional/worktree-cleanup.md +0 -167
- package/commands/optional/worktree-setup.md +0 -110
- package/eslint.config.js +0 -29
- package/jest.config.js +0 -22
- package/knowledge-library/README.md +0 -118
- package/knowledge-library/android-engineer/context/current.txt +0 -42
- package/knowledge-library/android-engineer/control/decisions.txt +0 -9
- package/knowledge-library/android-engineer/control/dependencies.txt +0 -19
- package/knowledge-library/android-engineer/control/objectives.txt +0 -26
- package/knowledge-library/android-engineer/history/.gitkeep +0 -0
- package/knowledge-library/android-engineer/inbox/processed/.gitkeep +0 -0
- package/knowledge-library/android-engineer/outbox/.gitkeep +0 -0
- package/knowledge-library/android-engineer/tech/.gitkeep +0 -0
- package/knowledge-library/architecture.txt +0 -61
- package/knowledge-library/backend-engineer/context/current.txt +0 -42
- package/knowledge-library/backend-engineer/control/decisions.txt +0 -9
- package/knowledge-library/backend-engineer/control/dependencies.txt +0 -19
- package/knowledge-library/backend-engineer/control/objectives.txt +0 -26
- package/knowledge-library/backend-engineer/history/.gitkeep +0 -0
- package/knowledge-library/backend-engineer/inbox/processed/.gitkeep +0 -0
- package/knowledge-library/backend-engineer/outbox/.gitkeep +0 -0
- package/knowledge-library/backend-engineer/tech/.gitkeep +0 -0
- package/knowledge-library/context.txt +0 -52
- package/knowledge-library/devops-engineer/context/current.txt +0 -42
- package/knowledge-library/devops-engineer/control/decisions.txt +0 -9
- package/knowledge-library/devops-engineer/control/dependencies.txt +0 -19
- package/knowledge-library/devops-engineer/control/objectives.txt +0 -26
- package/knowledge-library/devops-engineer/history/.gitkeep +0 -0
- package/knowledge-library/devops-engineer/inbox/processed/.gitkeep +0 -0
- package/knowledge-library/devops-engineer/outbox/.gitkeep +0 -0
- package/knowledge-library/devops-engineer/tech/.gitkeep +0 -0
- package/knowledge-library/engineering-manager/context/current.txt +0 -40
- package/knowledge-library/engineering-manager/control/decisions.txt +0 -9
- package/knowledge-library/engineering-manager/control/objectives.txt +0 -27
- package/knowledge-library/engineering-manager/history/.gitkeep +0 -0
- package/knowledge-library/engineering-manager/inbox/processed/.gitkeep +0 -0
- package/knowledge-library/engineering-manager/outbox/.gitkeep +0 -0
- package/knowledge-library/engineering-manager/tech/.gitkeep +0 -0
- package/knowledge-library/prd.txt +0 -81
- package/knowledge-library/product-manager/context/current.txt +0 -42
- package/knowledge-library/product-manager/control/decisions.txt +0 -9
- package/knowledge-library/product-manager/control/dependencies.txt +0 -19
- package/knowledge-library/product-manager/control/objectives.txt +0 -26
- package/knowledge-library/product-manager/history/.gitkeep +0 -0
- package/knowledge-library/product-manager/inbox/processed/.gitkeep +0 -0
- package/knowledge-library/product-manager/outbox/.gitkeep +0 -0
- package/knowledge-library/product-manager/tech/.gitkeep +0 -0
- package/knowledge-library/qa-engineer/context/current.txt +0 -42
- package/knowledge-library/qa-engineer/control/decisions.txt +0 -9
- package/knowledge-library/qa-engineer/control/dependencies.txt +0 -19
- package/knowledge-library/qa-engineer/control/objectives.txt +0 -26
- package/knowledge-library/qa-engineer/history/.gitkeep +0 -0
- package/knowledge-library/qa-engineer/inbox/processed/.gitkeep +0 -0
- package/knowledge-library/qa-engineer/outbox/.gitkeep +0 -0
- package/knowledge-library/qa-engineer/tech/.gitkeep +0 -0
- package/knowledge-library/security-engineer/context/current.txt +0 -42
- package/knowledge-library/security-engineer/control/decisions.txt +0 -9
- package/knowledge-library/security-engineer/control/dependencies.txt +0 -19
- package/knowledge-library/security-engineer/control/objectives.txt +0 -26
- package/knowledge-library/security-engineer/history/.gitkeep +0 -0
- package/knowledge-library/security-engineer/inbox/processed/.gitkeep +0 -0
- package/knowledge-library/security-engineer/outbox/.gitkeep +0 -0
- package/knowledge-library/security-engineer/tech/.gitkeep +0 -0
- package/knowledge-library/solutions-architect/context/current.txt +0 -42
- package/knowledge-library/solutions-architect/control/decisions.txt +0 -9
- package/knowledge-library/solutions-architect/control/dependencies.txt +0 -19
- package/knowledge-library/solutions-architect/control/objectives.txt +0 -26
- package/knowledge-library/solutions-architect/history/.gitkeep +0 -0
- package/knowledge-library/solutions-architect/inbox/processed/.gitkeep +0 -0
- package/knowledge-library/solutions-architect/outbox/.gitkeep +0 -0
- package/knowledge-library/solutions-architect/tech/.gitkeep +0 -0
- package/knowledge-library/wearos-engineer/context/current.txt +0 -42
- package/knowledge-library/wearos-engineer/control/decisions.txt +0 -9
- package/knowledge-library/wearos-engineer/control/dependencies.txt +0 -19
- package/knowledge-library/wearos-engineer/control/objectives.txt +0 -26
- package/knowledge-library/wearos-engineer/history/.gitkeep +0 -0
- package/knowledge-library/wearos-engineer/inbox/processed/.gitkeep +0 -0
- package/knowledge-library/wearos-engineer/outbox/.gitkeep +0 -0
- package/knowledge-library/wearos-engineer/tech/.gitkeep +0 -0
- package/scripts/add-agent.sh +0 -323
- package/scripts/install.sh +0 -354
- package/src/adapters/factory.test.ts +0 -386
- package/src/adapters/factory.ts +0 -305
- package/src/adapters/index.ts +0 -113
- package/src/adapters/interfaces.ts +0 -268
- package/src/adapters/mcp/client.test.ts +0 -130
- package/src/adapters/mcp/client.ts +0 -451
- package/src/adapters/mcp/discovery.test.ts +0 -315
- package/src/adapters/mcp/discovery.ts +0 -340
- package/src/adapters/mcp/index.ts +0 -66
- package/src/adapters/mcp/mapper.test.ts +0 -218
- package/src/adapters/mcp/mapper.ts +0 -536
- package/src/adapters/mcp/registry.test.ts +0 -433
- package/src/adapters/mcp/registry.ts +0 -550
- package/src/adapters/mcp/types.ts +0 -258
- package/src/adapters/native/filesystem.test.ts +0 -350
- package/src/adapters/native/filesystem.ts +0 -393
- package/src/adapters/native/github.test.ts +0 -173
- package/src/adapters/native/github.ts +0 -627
- package/src/adapters/native/index.ts +0 -22
- package/src/adapters/native/selector.test.ts +0 -224
- package/src/adapters/native/selector.ts +0 -150
- package/src/adapters/types.ts +0 -270
- package/src/agents/compiler.test.ts +0 -410
- package/src/agents/compiler.ts +0 -424
- package/src/agents/index.ts +0 -37
- package/src/agents/loader.test.ts +0 -319
- package/src/agents/loader.ts +0 -143
- package/src/agents/resolver.test.ts +0 -282
- package/src/agents/resolver.ts +0 -262
- package/src/agents/types.ts +0 -97
- package/src/cache/index.ts +0 -38
- package/src/cache/interfaces.ts +0 -283
- package/src/cache/manager.test.ts +0 -266
- package/src/cache/manager.ts +0 -388
- package/src/cache/provider.test.ts +0 -485
- package/src/cache/provider.ts +0 -745
- package/src/cache/types.test.ts +0 -192
- package/src/cache/types.ts +0 -313
- package/src/cli/commands/build.test.ts +0 -248
- package/src/cli/commands/build.ts +0 -284
- package/src/cli/commands/cache.test.ts +0 -221
- package/src/cli/commands/cache.ts +0 -229
- package/src/cli/commands/index.ts +0 -63
- package/src/cli/commands/init.test.ts +0 -173
- package/src/cli/commands/init.ts +0 -296
- package/src/cli/commands/skills.test.ts +0 -272
- package/src/cli/commands/skills.ts +0 -348
- package/src/cli/commands/status.test.ts +0 -392
- package/src/cli/commands/status.ts +0 -332
- package/src/cli/commands/sync.test.ts +0 -213
- package/src/cli/commands/sync.ts +0 -251
- package/src/cli/commands/validate.test.ts +0 -216
- package/src/cli/commands/validate.ts +0 -340
- package/src/cli/index.test.ts +0 -190
- package/src/cli/index.ts +0 -493
- package/src/commands/context.test.ts +0 -163
- package/src/commands/context.ts +0 -111
- package/src/commands/index.ts +0 -56
- package/src/commands/loader.test.ts +0 -273
- package/src/commands/loader.ts +0 -355
- package/src/commands/registry.test.ts +0 -384
- package/src/commands/registry.ts +0 -248
- package/src/commands/runner.test.ts +0 -297
- package/src/commands/runner.ts +0 -222
- package/src/commands/types.ts +0 -361
- package/src/config/index.ts +0 -19
- package/src/config/loader.test.ts +0 -262
- package/src/config/loader.ts +0 -188
- package/src/config/types.ts +0 -154
- package/src/context/index.ts +0 -14
- package/src/context/loader.test.ts +0 -334
- package/src/context/loader.ts +0 -357
- package/src/index.test.ts +0 -13
- package/src/index.ts +0 -268
- package/src/knowledge-library/index.ts +0 -44
- package/src/knowledge-library/manager.test.ts +0 -536
- package/src/knowledge-library/manager.ts +0 -804
- package/src/knowledge-library/types.ts +0 -432
- package/src/skills/generator.test.ts +0 -602
- package/src/skills/generator.ts +0 -491
- package/src/skills/index.ts +0 -27
- package/src/skills/templates.ts +0 -520
- package/src/skills/types.ts +0 -251
- package/templates/completion-report.md +0 -72
- package/templates/feedback.md +0 -56
- package/templates/project-files/CLAUDE.md.template +0 -109
- package/templates/project-files/coreai.json.example +0 -47
- package/templates/project-files/mcp.json.template +0 -20
- package/templates/review-complete.md +0 -64
- package/templates/review-request.md +0 -67
- package/templates/task-assignment.md +0 -51
- package/tsconfig.build.json +0 -4
- package/tsconfig.json +0 -26
- package/tsup.config.ts +0 -23
|
@@ -1,384 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Command Registry Tests
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import type { CommandRegistry } from './registry.js';
|
|
6
|
-
import { createCommandRegistry, getGlobalRegistry, resetGlobalRegistry } from './registry.js';
|
|
7
|
-
import type { CommandDefinition, MarkdownCommand } from './types.js';
|
|
8
|
-
|
|
9
|
-
describe('Command Registry', () => {
|
|
10
|
-
let registry: CommandRegistry;
|
|
11
|
-
|
|
12
|
-
beforeEach(() => {
|
|
13
|
-
registry = createCommandRegistry();
|
|
14
|
-
resetGlobalRegistry();
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
describe('createCommandRegistry', () => {
|
|
18
|
-
it('should create an empty registry', () => {
|
|
19
|
-
expect(registry.size).toBe(0);
|
|
20
|
-
expect(registry.getAll()).toHaveLength(0);
|
|
21
|
-
});
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
describe('register', () => {
|
|
25
|
-
it('should register a command definition', () => {
|
|
26
|
-
const cmd: CommandDefinition = {
|
|
27
|
-
name: 'test-cmd',
|
|
28
|
-
description: 'A test command',
|
|
29
|
-
category: 'core',
|
|
30
|
-
handler: async () => ({ success: true }),
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
registry.register(cmd);
|
|
34
|
-
|
|
35
|
-
expect(registry.has('test-cmd')).toBe(true);
|
|
36
|
-
expect(registry.size).toBe(1);
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
it('should register with dependencies', () => {
|
|
40
|
-
const cmd: CommandDefinition = {
|
|
41
|
-
name: 'jira-cmd',
|
|
42
|
-
description: 'Jira command',
|
|
43
|
-
category: 'optional',
|
|
44
|
-
dependencies: [{ type: 'issue_tracker', required: true, description: 'Needs Jira' }],
|
|
45
|
-
handler: async () => ({ success: true }),
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
registry.register(cmd);
|
|
49
|
-
|
|
50
|
-
const entry = registry.get('jira-cmd');
|
|
51
|
-
expect(entry?.metadata.dependencies).toHaveLength(1);
|
|
52
|
-
expect(entry?.metadata.dependencies[0].type).toBe('issue_tracker');
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
it('should mark command unavailable if required dep missing', () => {
|
|
56
|
-
const cmd: CommandDefinition = {
|
|
57
|
-
name: 'jira-cmd',
|
|
58
|
-
description: 'Jira command',
|
|
59
|
-
category: 'optional',
|
|
60
|
-
dependencies: [{ type: 'issue_tracker', required: true }],
|
|
61
|
-
handler: async () => ({ success: true }),
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
registry.register(cmd);
|
|
65
|
-
|
|
66
|
-
const entry = registry.get('jira-cmd');
|
|
67
|
-
// Without adapter factory, required deps are considered missing
|
|
68
|
-
expect(entry?.metadata.available).toBe(false);
|
|
69
|
-
expect(entry?.metadata.unavailableReason).toContain('issue_tracker');
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
it('should mark command available if only optional deps missing', () => {
|
|
73
|
-
const cmd: CommandDefinition = {
|
|
74
|
-
name: 'enhanced-cmd',
|
|
75
|
-
description: 'Enhanced command',
|
|
76
|
-
category: 'core',
|
|
77
|
-
dependencies: [{ type: 'documentation', required: false }],
|
|
78
|
-
handler: async () => ({ success: true }),
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
registry.register(cmd);
|
|
82
|
-
|
|
83
|
-
const entry = registry.get('enhanced-cmd');
|
|
84
|
-
expect(entry?.metadata.available).toBe(true);
|
|
85
|
-
});
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
describe('registerMarkdown', () => {
|
|
89
|
-
it('should register a markdown command', () => {
|
|
90
|
-
const cmd: MarkdownCommand = {
|
|
91
|
-
metadata: {
|
|
92
|
-
name: 'delegate',
|
|
93
|
-
description: 'Delegate work',
|
|
94
|
-
category: 'core',
|
|
95
|
-
dependencies: [],
|
|
96
|
-
sourcePath: '/path/to/delegate.md',
|
|
97
|
-
available: true,
|
|
98
|
-
},
|
|
99
|
-
content: '# Delegate\n\nInstructions here.',
|
|
100
|
-
sections: {
|
|
101
|
-
title: 'Delegate',
|
|
102
|
-
},
|
|
103
|
-
};
|
|
104
|
-
|
|
105
|
-
registry.registerMarkdown(cmd);
|
|
106
|
-
|
|
107
|
-
expect(registry.has('delegate')).toBe(true);
|
|
108
|
-
const entry = registry.get('delegate');
|
|
109
|
-
expect(entry?.source).toBe('markdown');
|
|
110
|
-
expect(entry?.markdownCommand).toBe(cmd);
|
|
111
|
-
});
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
describe('registerAll', () => {
|
|
115
|
-
it('should register multiple commands', () => {
|
|
116
|
-
const cmds: CommandDefinition[] = [
|
|
117
|
-
{
|
|
118
|
-
name: 'cmd1',
|
|
119
|
-
description: 'Cmd 1',
|
|
120
|
-
category: 'core',
|
|
121
|
-
handler: async () => ({ success: true }),
|
|
122
|
-
},
|
|
123
|
-
{
|
|
124
|
-
name: 'cmd2',
|
|
125
|
-
description: 'Cmd 2',
|
|
126
|
-
category: 'core',
|
|
127
|
-
handler: async () => ({ success: true }),
|
|
128
|
-
},
|
|
129
|
-
{
|
|
130
|
-
name: 'cmd3',
|
|
131
|
-
description: 'Cmd 3',
|
|
132
|
-
category: 'optional',
|
|
133
|
-
handler: async () => ({ success: true }),
|
|
134
|
-
},
|
|
135
|
-
];
|
|
136
|
-
|
|
137
|
-
registry.registerAll(cmds);
|
|
138
|
-
|
|
139
|
-
expect(registry.size).toBe(3);
|
|
140
|
-
expect(registry.has('cmd1')).toBe(true);
|
|
141
|
-
expect(registry.has('cmd2')).toBe(true);
|
|
142
|
-
expect(registry.has('cmd3')).toBe(true);
|
|
143
|
-
});
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
describe('unregister', () => {
|
|
147
|
-
it('should unregister a command', () => {
|
|
148
|
-
const cmd: CommandDefinition = {
|
|
149
|
-
name: 'to-remove',
|
|
150
|
-
description: 'Will be removed',
|
|
151
|
-
category: 'core',
|
|
152
|
-
handler: async () => ({ success: true }),
|
|
153
|
-
};
|
|
154
|
-
|
|
155
|
-
registry.register(cmd);
|
|
156
|
-
expect(registry.has('to-remove')).toBe(true);
|
|
157
|
-
|
|
158
|
-
const result = registry.unregister('to-remove');
|
|
159
|
-
|
|
160
|
-
expect(result).toBe(true);
|
|
161
|
-
expect(registry.has('to-remove')).toBe(false);
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
it('should return false for non-existent command', () => {
|
|
165
|
-
const result = registry.unregister('non-existent');
|
|
166
|
-
expect(result).toBe(false);
|
|
167
|
-
});
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
describe('get', () => {
|
|
171
|
-
it('should return command entry', () => {
|
|
172
|
-
const cmd: CommandDefinition = {
|
|
173
|
-
name: 'my-cmd',
|
|
174
|
-
description: 'My command',
|
|
175
|
-
category: 'core',
|
|
176
|
-
handler: async () => ({ success: true }),
|
|
177
|
-
};
|
|
178
|
-
|
|
179
|
-
registry.register(cmd);
|
|
180
|
-
const entry = registry.get('my-cmd');
|
|
181
|
-
|
|
182
|
-
expect(entry).toBeDefined();
|
|
183
|
-
expect(entry?.metadata.name).toBe('my-cmd');
|
|
184
|
-
expect(entry?.definition).toBe(cmd);
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
it('should return undefined for non-existent command', () => {
|
|
188
|
-
const entry = registry.get('non-existent');
|
|
189
|
-
expect(entry).toBeUndefined();
|
|
190
|
-
});
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
describe('getAll', () => {
|
|
194
|
-
it('should return all registered commands', () => {
|
|
195
|
-
registry.registerAll([
|
|
196
|
-
{
|
|
197
|
-
name: 'cmd1',
|
|
198
|
-
description: 'C1',
|
|
199
|
-
category: 'core',
|
|
200
|
-
handler: async () => ({ success: true }),
|
|
201
|
-
},
|
|
202
|
-
{
|
|
203
|
-
name: 'cmd2',
|
|
204
|
-
description: 'C2',
|
|
205
|
-
category: 'optional',
|
|
206
|
-
handler: async () => ({ success: true }),
|
|
207
|
-
},
|
|
208
|
-
]);
|
|
209
|
-
|
|
210
|
-
const all = registry.getAll();
|
|
211
|
-
|
|
212
|
-
expect(all).toHaveLength(2);
|
|
213
|
-
});
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
describe('getAvailable / getUnavailable', () => {
|
|
217
|
-
it('should separate available and unavailable commands', () => {
|
|
218
|
-
registry.registerAll([
|
|
219
|
-
{
|
|
220
|
-
name: 'available',
|
|
221
|
-
description: 'Available',
|
|
222
|
-
category: 'core',
|
|
223
|
-
handler: async () => ({ success: true }),
|
|
224
|
-
},
|
|
225
|
-
{
|
|
226
|
-
name: 'unavailable',
|
|
227
|
-
description: 'Unavailable',
|
|
228
|
-
category: 'optional',
|
|
229
|
-
dependencies: [{ type: 'issue_tracker', required: true }],
|
|
230
|
-
handler: async () => ({ success: true }),
|
|
231
|
-
},
|
|
232
|
-
]);
|
|
233
|
-
|
|
234
|
-
const available = registry.getAvailable();
|
|
235
|
-
const unavailable = registry.getUnavailable();
|
|
236
|
-
|
|
237
|
-
expect(available).toHaveLength(1);
|
|
238
|
-
expect(available[0].metadata.name).toBe('available');
|
|
239
|
-
expect(unavailable).toHaveLength(1);
|
|
240
|
-
expect(unavailable[0].metadata.name).toBe('unavailable');
|
|
241
|
-
});
|
|
242
|
-
});
|
|
243
|
-
|
|
244
|
-
describe('getByCategory', () => {
|
|
245
|
-
it('should filter by category', () => {
|
|
246
|
-
registry.registerAll([
|
|
247
|
-
{
|
|
248
|
-
name: 'core1',
|
|
249
|
-
description: 'C1',
|
|
250
|
-
category: 'core',
|
|
251
|
-
handler: async () => ({ success: true }),
|
|
252
|
-
},
|
|
253
|
-
{
|
|
254
|
-
name: 'core2',
|
|
255
|
-
description: 'C2',
|
|
256
|
-
category: 'core',
|
|
257
|
-
handler: async () => ({ success: true }),
|
|
258
|
-
},
|
|
259
|
-
{
|
|
260
|
-
name: 'opt1',
|
|
261
|
-
description: 'O1',
|
|
262
|
-
category: 'optional',
|
|
263
|
-
handler: async () => ({ success: true }),
|
|
264
|
-
},
|
|
265
|
-
{
|
|
266
|
-
name: 'custom1',
|
|
267
|
-
description: 'Cu1',
|
|
268
|
-
category: 'custom',
|
|
269
|
-
handler: async () => ({ success: true }),
|
|
270
|
-
},
|
|
271
|
-
]);
|
|
272
|
-
|
|
273
|
-
const core = registry.getByCategory('core');
|
|
274
|
-
const optional = registry.getByCategory('optional');
|
|
275
|
-
const custom = registry.getByCategory('custom');
|
|
276
|
-
|
|
277
|
-
expect(core).toHaveLength(2);
|
|
278
|
-
expect(optional).toHaveLength(1);
|
|
279
|
-
expect(custom).toHaveLength(1);
|
|
280
|
-
});
|
|
281
|
-
});
|
|
282
|
-
|
|
283
|
-
describe('getNames', () => {
|
|
284
|
-
it('should return command names', () => {
|
|
285
|
-
registry.registerAll([
|
|
286
|
-
{
|
|
287
|
-
name: 'alpha',
|
|
288
|
-
description: 'A',
|
|
289
|
-
category: 'core',
|
|
290
|
-
handler: async () => ({ success: true }),
|
|
291
|
-
},
|
|
292
|
-
{
|
|
293
|
-
name: 'beta',
|
|
294
|
-
description: 'B',
|
|
295
|
-
category: 'core',
|
|
296
|
-
handler: async () => ({ success: true }),
|
|
297
|
-
},
|
|
298
|
-
]);
|
|
299
|
-
|
|
300
|
-
const names = registry.getNames();
|
|
301
|
-
|
|
302
|
-
expect(names).toContain('alpha');
|
|
303
|
-
expect(names).toContain('beta');
|
|
304
|
-
});
|
|
305
|
-
});
|
|
306
|
-
|
|
307
|
-
describe('clear', () => {
|
|
308
|
-
it('should remove all commands', () => {
|
|
309
|
-
registry.registerAll([
|
|
310
|
-
{
|
|
311
|
-
name: 'cmd1',
|
|
312
|
-
description: 'C1',
|
|
313
|
-
category: 'core',
|
|
314
|
-
handler: async () => ({ success: true }),
|
|
315
|
-
},
|
|
316
|
-
{
|
|
317
|
-
name: 'cmd2',
|
|
318
|
-
description: 'C2',
|
|
319
|
-
category: 'core',
|
|
320
|
-
handler: async () => ({ success: true }),
|
|
321
|
-
},
|
|
322
|
-
]);
|
|
323
|
-
|
|
324
|
-
expect(registry.size).toBe(2);
|
|
325
|
-
|
|
326
|
-
registry.clear();
|
|
327
|
-
|
|
328
|
-
expect(registry.size).toBe(0);
|
|
329
|
-
});
|
|
330
|
-
});
|
|
331
|
-
|
|
332
|
-
describe('getDependencyStatus', () => {
|
|
333
|
-
it('should return dependency status', () => {
|
|
334
|
-
registry.register({
|
|
335
|
-
name: 'cmd-with-deps',
|
|
336
|
-
description: 'Has deps',
|
|
337
|
-
category: 'optional',
|
|
338
|
-
dependencies: [
|
|
339
|
-
{ type: 'issue_tracker', required: true },
|
|
340
|
-
{ type: 'documentation', required: false },
|
|
341
|
-
],
|
|
342
|
-
handler: async () => ({ success: true }),
|
|
343
|
-
});
|
|
344
|
-
|
|
345
|
-
const status = registry.getDependencyStatus('cmd-with-deps');
|
|
346
|
-
|
|
347
|
-
expect(status).not.toBeNull();
|
|
348
|
-
// Only required deps are counted as missing when no adapter factory
|
|
349
|
-
expect(status?.missing).toHaveLength(1);
|
|
350
|
-
expect(status?.missing[0].type).toBe('issue_tracker');
|
|
351
|
-
expect(status?.satisfied).toHaveLength(1); // Optional dep not counted as missing
|
|
352
|
-
});
|
|
353
|
-
|
|
354
|
-
it('should return null for non-existent command', () => {
|
|
355
|
-
const status = registry.getDependencyStatus('non-existent');
|
|
356
|
-
expect(status).toBeNull();
|
|
357
|
-
});
|
|
358
|
-
});
|
|
359
|
-
|
|
360
|
-
describe('Global Registry', () => {
|
|
361
|
-
it('should return same instance', () => {
|
|
362
|
-
const reg1 = getGlobalRegistry();
|
|
363
|
-
const reg2 = getGlobalRegistry();
|
|
364
|
-
|
|
365
|
-
expect(reg1).toBe(reg2);
|
|
366
|
-
});
|
|
367
|
-
|
|
368
|
-
it('should reset global registry', () => {
|
|
369
|
-
const reg1 = getGlobalRegistry();
|
|
370
|
-
reg1.register({
|
|
371
|
-
name: 'test',
|
|
372
|
-
description: 'Test',
|
|
373
|
-
category: 'core',
|
|
374
|
-
handler: async () => ({ success: true }),
|
|
375
|
-
});
|
|
376
|
-
|
|
377
|
-
resetGlobalRegistry();
|
|
378
|
-
|
|
379
|
-
const reg2 = getGlobalRegistry();
|
|
380
|
-
expect(reg2).not.toBe(reg1);
|
|
381
|
-
expect(reg2.size).toBe(0);
|
|
382
|
-
});
|
|
383
|
-
});
|
|
384
|
-
});
|
package/src/commands/registry.ts
DELETED
|
@@ -1,248 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Command Registry
|
|
3
|
-
*
|
|
4
|
-
* Central registry for command registration and discovery.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import type {
|
|
8
|
-
CommandDefinition,
|
|
9
|
-
CommandMetadata,
|
|
10
|
-
MarkdownCommand,
|
|
11
|
-
RegistryEntry,
|
|
12
|
-
CommandCategory,
|
|
13
|
-
IntegrationDependency,
|
|
14
|
-
} from './types.js';
|
|
15
|
-
import type { AdapterFactory } from '../adapters/factory.js';
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Command Registry
|
|
19
|
-
*
|
|
20
|
-
* Manages registration and lookup of commands.
|
|
21
|
-
*/
|
|
22
|
-
export class CommandRegistry {
|
|
23
|
-
private commands = new Map<string, RegistryEntry>();
|
|
24
|
-
private adapterFactory: AdapterFactory | null = null;
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Set the adapter factory for dependency checking
|
|
28
|
-
*/
|
|
29
|
-
setAdapterFactory(factory: AdapterFactory | null): void {
|
|
30
|
-
this.adapterFactory = factory;
|
|
31
|
-
// Re-evaluate availability of all commands
|
|
32
|
-
this.updateAvailability();
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Register a programmatic command
|
|
37
|
-
*/
|
|
38
|
-
register(definition: CommandDefinition): void {
|
|
39
|
-
const metadata: CommandMetadata = {
|
|
40
|
-
name: definition.name,
|
|
41
|
-
description: definition.description,
|
|
42
|
-
category: definition.category,
|
|
43
|
-
dependencies: definition.dependencies ?? [],
|
|
44
|
-
sourcePath: '<programmatic>',
|
|
45
|
-
available: true,
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
// Check availability
|
|
49
|
-
this.checkAvailability(metadata);
|
|
50
|
-
|
|
51
|
-
this.commands.set(definition.name, {
|
|
52
|
-
metadata,
|
|
53
|
-
definition,
|
|
54
|
-
source: 'programmatic',
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Register a markdown command
|
|
60
|
-
*/
|
|
61
|
-
registerMarkdown(command: MarkdownCommand): void {
|
|
62
|
-
// Check availability
|
|
63
|
-
this.checkAvailability(command.metadata);
|
|
64
|
-
|
|
65
|
-
this.commands.set(command.metadata.name, {
|
|
66
|
-
metadata: command.metadata,
|
|
67
|
-
markdownCommand: command,
|
|
68
|
-
source: 'markdown',
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Register multiple commands
|
|
74
|
-
*/
|
|
75
|
-
registerAll(definitions: CommandDefinition[]): void {
|
|
76
|
-
for (const def of definitions) {
|
|
77
|
-
this.register(def);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Register multiple markdown commands
|
|
83
|
-
*/
|
|
84
|
-
registerAllMarkdown(commands: MarkdownCommand[]): void {
|
|
85
|
-
for (const cmd of commands) {
|
|
86
|
-
this.registerMarkdown(cmd);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Unregister a command
|
|
92
|
-
*/
|
|
93
|
-
unregister(name: string): boolean {
|
|
94
|
-
return this.commands.delete(name);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Get a command by name
|
|
99
|
-
*/
|
|
100
|
-
get(name: string): RegistryEntry | undefined {
|
|
101
|
-
return this.commands.get(name);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Check if a command exists
|
|
106
|
-
*/
|
|
107
|
-
has(name: string): boolean {
|
|
108
|
-
return this.commands.has(name);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Get all registered commands
|
|
113
|
-
*/
|
|
114
|
-
getAll(): RegistryEntry[] {
|
|
115
|
-
return Array.from(this.commands.values());
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* Get available commands (dependencies satisfied)
|
|
120
|
-
*/
|
|
121
|
-
getAvailable(): RegistryEntry[] {
|
|
122
|
-
return this.getAll().filter((entry) => entry.metadata.available);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* Get unavailable commands
|
|
127
|
-
*/
|
|
128
|
-
getUnavailable(): RegistryEntry[] {
|
|
129
|
-
return this.getAll().filter((entry) => !entry.metadata.available);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Get commands by category
|
|
134
|
-
*/
|
|
135
|
-
getByCategory(category: CommandCategory): RegistryEntry[] {
|
|
136
|
-
return this.getAll().filter((entry) => entry.metadata.category === category);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* Get command names
|
|
141
|
-
*/
|
|
142
|
-
getNames(): string[] {
|
|
143
|
-
return Array.from(this.commands.keys());
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Clear all registered commands
|
|
148
|
-
*/
|
|
149
|
-
clear(): void {
|
|
150
|
-
this.commands.clear();
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* Get the number of registered commands
|
|
155
|
-
*/
|
|
156
|
-
get size(): number {
|
|
157
|
-
return this.commands.size;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* Check and update availability for a command metadata
|
|
162
|
-
*/
|
|
163
|
-
private checkAvailability(metadata: CommandMetadata): void {
|
|
164
|
-
const missingDeps = this.getMissingDependencies(metadata.dependencies);
|
|
165
|
-
|
|
166
|
-
if (missingDeps.length > 0) {
|
|
167
|
-
const requiredMissing = missingDeps.filter((d) => d.required);
|
|
168
|
-
if (requiredMissing.length > 0) {
|
|
169
|
-
metadata.available = false;
|
|
170
|
-
metadata.unavailableReason = `Missing required integrations: ${requiredMissing.map((d) => d.type).join(', ')}`;
|
|
171
|
-
} else {
|
|
172
|
-
// Optional deps missing, still available but may degrade
|
|
173
|
-
metadata.available = true;
|
|
174
|
-
}
|
|
175
|
-
} else {
|
|
176
|
-
metadata.available = true;
|
|
177
|
-
delete metadata.unavailableReason;
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
/**
|
|
182
|
-
* Get missing dependencies
|
|
183
|
-
*/
|
|
184
|
-
private getMissingDependencies(dependencies: IntegrationDependency[]): IntegrationDependency[] {
|
|
185
|
-
const factory = this.adapterFactory;
|
|
186
|
-
if (!factory) {
|
|
187
|
-
// No adapter factory, assume all required deps are missing
|
|
188
|
-
return dependencies.filter((d) => d.required);
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
return dependencies.filter((dep) => !factory.hasIntegration(dep.type));
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* Update availability for all commands
|
|
196
|
-
*/
|
|
197
|
-
private updateAvailability(): void {
|
|
198
|
-
for (const entry of this.commands.values()) {
|
|
199
|
-
this.checkAvailability(entry.metadata);
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* Get dependency status for a command
|
|
205
|
-
*/
|
|
206
|
-
getDependencyStatus(name: string): {
|
|
207
|
-
satisfied: IntegrationDependency[];
|
|
208
|
-
missing: IntegrationDependency[];
|
|
209
|
-
} | null {
|
|
210
|
-
const entry = this.commands.get(name);
|
|
211
|
-
if (!entry) return null;
|
|
212
|
-
|
|
213
|
-
const deps = entry.metadata.dependencies;
|
|
214
|
-
const missing = this.getMissingDependencies(deps);
|
|
215
|
-
const satisfied = deps.filter((d) => !missing.includes(d));
|
|
216
|
-
|
|
217
|
-
return { satisfied, missing };
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
/**
|
|
222
|
-
* Create a new command registry
|
|
223
|
-
*/
|
|
224
|
-
export function createCommandRegistry(): CommandRegistry {
|
|
225
|
-
return new CommandRegistry();
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
/**
|
|
229
|
-
* Global command registry instance
|
|
230
|
-
*/
|
|
231
|
-
let globalRegistry: CommandRegistry | null = null;
|
|
232
|
-
|
|
233
|
-
/**
|
|
234
|
-
* Get or create the global command registry
|
|
235
|
-
*/
|
|
236
|
-
export function getGlobalRegistry(): CommandRegistry {
|
|
237
|
-
if (!globalRegistry) {
|
|
238
|
-
globalRegistry = new CommandRegistry();
|
|
239
|
-
}
|
|
240
|
-
return globalRegistry;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
/**
|
|
244
|
-
* Reset the global registry (primarily for testing)
|
|
245
|
-
*/
|
|
246
|
-
export function resetGlobalRegistry(): void {
|
|
247
|
-
globalRegistry = null;
|
|
248
|
-
}
|