cognitive-modules-cli 2.2.1 → 2.2.7

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 (101) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/LICENSE +21 -0
  3. package/README.md +35 -29
  4. package/dist/cli.js +519 -23
  5. package/dist/commands/add.d.ts +33 -14
  6. package/dist/commands/add.js +383 -16
  7. package/dist/commands/compose.js +60 -23
  8. package/dist/commands/index.d.ts +4 -0
  9. package/dist/commands/index.js +4 -0
  10. package/dist/commands/init.js +23 -1
  11. package/dist/commands/migrate.d.ts +30 -0
  12. package/dist/commands/migrate.js +650 -0
  13. package/dist/commands/pipe.d.ts +1 -0
  14. package/dist/commands/pipe.js +31 -11
  15. package/dist/commands/remove.js +33 -2
  16. package/dist/commands/run.d.ts +2 -0
  17. package/dist/commands/run.js +61 -28
  18. package/dist/commands/search.d.ts +28 -0
  19. package/dist/commands/search.js +143 -0
  20. package/dist/commands/test.d.ts +65 -0
  21. package/dist/commands/test.js +454 -0
  22. package/dist/commands/update.d.ts +1 -0
  23. package/dist/commands/update.js +106 -14
  24. package/dist/commands/validate.d.ts +36 -0
  25. package/dist/commands/validate.js +97 -0
  26. package/dist/errors/index.d.ts +225 -0
  27. package/dist/errors/index.js +420 -0
  28. package/dist/mcp/server.js +84 -79
  29. package/dist/modules/composition.js +97 -32
  30. package/dist/modules/loader.js +4 -2
  31. package/dist/modules/runner.d.ts +72 -5
  32. package/dist/modules/runner.js +306 -59
  33. package/dist/modules/subagent.d.ts +6 -1
  34. package/dist/modules/subagent.js +18 -13
  35. package/dist/modules/validator.js +14 -6
  36. package/dist/providers/anthropic.d.ts +15 -0
  37. package/dist/providers/anthropic.js +147 -5
  38. package/dist/providers/base.d.ts +11 -0
  39. package/dist/providers/base.js +18 -0
  40. package/dist/providers/gemini.d.ts +15 -0
  41. package/dist/providers/gemini.js +122 -5
  42. package/dist/providers/ollama.d.ts +15 -0
  43. package/dist/providers/ollama.js +111 -3
  44. package/dist/providers/openai.d.ts +11 -0
  45. package/dist/providers/openai.js +133 -0
  46. package/dist/registry/client.d.ts +212 -0
  47. package/dist/registry/client.js +359 -0
  48. package/dist/registry/index.d.ts +4 -0
  49. package/dist/registry/index.js +4 -0
  50. package/dist/registry/tar.d.ts +8 -0
  51. package/dist/registry/tar.js +353 -0
  52. package/dist/server/http.js +301 -45
  53. package/dist/server/index.d.ts +2 -0
  54. package/dist/server/index.js +1 -0
  55. package/dist/server/sse.d.ts +13 -0
  56. package/dist/server/sse.js +22 -0
  57. package/dist/types.d.ts +32 -1
  58. package/dist/types.js +4 -1
  59. package/dist/version.d.ts +1 -0
  60. package/dist/version.js +4 -0
  61. package/package.json +31 -7
  62. package/dist/modules/composition.test.d.ts +0 -11
  63. package/dist/modules/composition.test.js +0 -450
  64. package/dist/modules/policy.test.d.ts +0 -10
  65. package/dist/modules/policy.test.js +0 -369
  66. package/src/cli.ts +0 -471
  67. package/src/commands/add.ts +0 -315
  68. package/src/commands/compose.ts +0 -185
  69. package/src/commands/index.ts +0 -13
  70. package/src/commands/init.ts +0 -94
  71. package/src/commands/list.ts +0 -33
  72. package/src/commands/pipe.ts +0 -76
  73. package/src/commands/remove.ts +0 -57
  74. package/src/commands/run.ts +0 -80
  75. package/src/commands/update.ts +0 -130
  76. package/src/commands/versions.ts +0 -79
  77. package/src/index.ts +0 -90
  78. package/src/mcp/index.ts +0 -5
  79. package/src/mcp/server.ts +0 -403
  80. package/src/modules/composition.test.ts +0 -558
  81. package/src/modules/composition.ts +0 -1674
  82. package/src/modules/index.ts +0 -9
  83. package/src/modules/loader.ts +0 -508
  84. package/src/modules/policy.test.ts +0 -455
  85. package/src/modules/runner.ts +0 -1983
  86. package/src/modules/subagent.ts +0 -277
  87. package/src/modules/validator.ts +0 -700
  88. package/src/providers/anthropic.ts +0 -89
  89. package/src/providers/base.ts +0 -29
  90. package/src/providers/deepseek.ts +0 -83
  91. package/src/providers/gemini.ts +0 -117
  92. package/src/providers/index.ts +0 -78
  93. package/src/providers/minimax.ts +0 -81
  94. package/src/providers/moonshot.ts +0 -82
  95. package/src/providers/ollama.ts +0 -83
  96. package/src/providers/openai.ts +0 -84
  97. package/src/providers/qwen.ts +0 -82
  98. package/src/server/http.ts +0 -316
  99. package/src/server/index.ts +0 -6
  100. package/src/types.ts +0 -599
  101. package/tsconfig.json +0 -17
@@ -1,369 +0,0 @@
1
- /**
2
- * Tests for Policy Enforcement
3
- *
4
- * Tests all policy enforcement functionality:
5
- * - Tool policy checking (allowed/denied lists)
6
- * - General policy checking (network, filesystem, etc.)
7
- * - Tool call interception
8
- * - Policy-aware executors
9
- */
10
- import { describe, it, expect, vi, beforeEach } from 'vitest';
11
- import { checkToolPolicy, checkPolicy, checkToolAllowed, validateToolsAllowed, getDeniedActions, getDeniedTools, getAllowedTools, ToolCallInterceptor, createPolicyAwareExecutor, } from './runner.js';
12
- // =============================================================================
13
- // Test Fixtures
14
- // =============================================================================
15
- function createMockModule(overrides = {}) {
16
- return {
17
- name: 'test-module',
18
- version: '1.0.0',
19
- responsibility: 'Test module',
20
- excludes: [],
21
- prompt: 'Test prompt',
22
- location: '/test',
23
- format: 'v2',
24
- ...overrides,
25
- };
26
- }
27
- // =============================================================================
28
- // checkToolPolicy Tests
29
- // =============================================================================
30
- describe('checkToolPolicy', () => {
31
- it('should allow all tools when no policy defined', () => {
32
- const module = createMockModule();
33
- expect(checkToolPolicy('write_file', module).allowed).toBe(true);
34
- expect(checkToolPolicy('shell', module).allowed).toBe(true);
35
- expect(checkToolPolicy('any_tool', module).allowed).toBe(true);
36
- });
37
- it('should deny tools in denied list', () => {
38
- const module = createMockModule({
39
- tools: {
40
- policy: 'allow_by_default',
41
- allowed: [],
42
- denied: ['write_file', 'shell', 'network'],
43
- },
44
- });
45
- const result = checkToolPolicy('write_file', module);
46
- expect(result.allowed).toBe(false);
47
- expect(result.reason).toContain('explicitly denied');
48
- expect(result.policy).toBe('tools.denied');
49
- });
50
- it('should handle case-insensitive tool names', () => {
51
- const module = createMockModule({
52
- tools: {
53
- policy: 'allow_by_default',
54
- allowed: [],
55
- denied: ['Write_File'],
56
- },
57
- });
58
- expect(checkToolPolicy('write_file', module).allowed).toBe(false);
59
- expect(checkToolPolicy('WRITE_FILE', module).allowed).toBe(false);
60
- expect(checkToolPolicy('write-file', module).allowed).toBe(false);
61
- });
62
- it('should enforce deny_by_default policy', () => {
63
- const module = createMockModule({
64
- tools: {
65
- policy: 'deny_by_default',
66
- allowed: ['read_file', 'list_dir'],
67
- },
68
- });
69
- expect(checkToolPolicy('read_file', module).allowed).toBe(true);
70
- expect(checkToolPolicy('list_dir', module).allowed).toBe(true);
71
- const result = checkToolPolicy('write_file', module);
72
- expect(result.allowed).toBe(false);
73
- expect(result.reason).toContain('not in allowed list');
74
- expect(result.policy).toBe('tools.policy');
75
- });
76
- it('should allow tools in allow_by_default mode (not in denied)', () => {
77
- const module = createMockModule({
78
- tools: {
79
- policy: 'allow_by_default',
80
- allowed: [],
81
- denied: ['shell'],
82
- },
83
- });
84
- expect(checkToolPolicy('read_file', module).allowed).toBe(true);
85
- expect(checkToolPolicy('write_file', module).allowed).toBe(true);
86
- expect(checkToolPolicy('shell', module).allowed).toBe(false);
87
- });
88
- });
89
- // =============================================================================
90
- // checkPolicy Tests
91
- // =============================================================================
92
- describe('checkPolicy', () => {
93
- it('should allow all actions when no policies defined', () => {
94
- const module = createMockModule();
95
- expect(checkPolicy('network', module).allowed).toBe(true);
96
- expect(checkPolicy('filesystem_write', module).allowed).toBe(true);
97
- expect(checkPolicy('side_effects', module).allowed).toBe(true);
98
- expect(checkPolicy('code_execution', module).allowed).toBe(true);
99
- });
100
- it('should deny actions marked as deny', () => {
101
- const module = createMockModule({
102
- policies: {
103
- network: 'deny',
104
- filesystem_write: 'deny',
105
- side_effects: 'allow',
106
- code_execution: 'deny',
107
- },
108
- });
109
- const networkResult = checkPolicy('network', module);
110
- expect(networkResult.allowed).toBe(false);
111
- expect(networkResult.reason).toContain("'network' is denied");
112
- expect(networkResult.policy).toBe('policies.network');
113
- expect(checkPolicy('filesystem_write', module).allowed).toBe(false);
114
- expect(checkPolicy('side_effects', module).allowed).toBe(true);
115
- expect(checkPolicy('code_execution', module).allowed).toBe(false);
116
- });
117
- });
118
- // =============================================================================
119
- // checkToolAllowed Tests (Combined Check)
120
- // =============================================================================
121
- describe('checkToolAllowed', () => {
122
- it('should check both tool policy and general policies', () => {
123
- const module = createMockModule({
124
- policies: {
125
- filesystem_write: 'deny',
126
- side_effects: 'deny',
127
- },
128
- tools: {
129
- policy: 'allow_by_default',
130
- allowed: [],
131
- },
132
- });
133
- // write_file maps to filesystem_write and side_effects
134
- const result = checkToolAllowed('write_file', module);
135
- expect(result.allowed).toBe(false);
136
- expect(result.reason).toContain('filesystem_write');
137
- });
138
- it('should block tools that require denied actions', () => {
139
- const module = createMockModule({
140
- policies: {
141
- network: 'deny',
142
- },
143
- });
144
- // Network tools should be blocked
145
- expect(checkToolAllowed('fetch', module).allowed).toBe(false);
146
- expect(checkToolAllowed('http', module).allowed).toBe(false);
147
- expect(checkToolAllowed('curl', module).allowed).toBe(false);
148
- // Non-network tools should be allowed
149
- expect(checkToolAllowed('read_file', module).allowed).toBe(true);
150
- });
151
- it('should block shell/exec when code_execution denied', () => {
152
- const module = createMockModule({
153
- policies: {
154
- code_execution: 'deny',
155
- },
156
- });
157
- expect(checkToolAllowed('shell', module).allowed).toBe(false);
158
- expect(checkToolAllowed('exec', module).allowed).toBe(false);
159
- expect(checkToolAllowed('code_interpreter', module).allowed).toBe(false);
160
- });
161
- it('should check explicit tools policy first', () => {
162
- const module = createMockModule({
163
- policies: {
164
- network: 'allow', // Allow network in general
165
- },
166
- tools: {
167
- policy: 'allow_by_default',
168
- allowed: [],
169
- denied: ['fetch'], // But explicitly deny fetch
170
- },
171
- });
172
- const result = checkToolAllowed('fetch', module);
173
- expect(result.allowed).toBe(false);
174
- expect(result.policy).toBe('tools.denied');
175
- });
176
- });
177
- // =============================================================================
178
- // validateToolsAllowed Tests
179
- // =============================================================================
180
- describe('validateToolsAllowed', () => {
181
- it('should return empty array when all tools allowed', () => {
182
- const module = createMockModule();
183
- const violations = validateToolsAllowed(['read_file', 'write_file', 'shell'], module);
184
- expect(violations).toHaveLength(0);
185
- });
186
- it('should return all violations', () => {
187
- const module = createMockModule({
188
- policies: {
189
- network: 'deny',
190
- code_execution: 'deny',
191
- },
192
- });
193
- const violations = validateToolsAllowed(['fetch', 'shell', 'read_file'], module);
194
- expect(violations).toHaveLength(2);
195
- expect(violations.some(v => v.reason?.includes('fetch'))).toBe(true);
196
- expect(violations.some(v => v.reason?.includes('shell'))).toBe(true);
197
- });
198
- });
199
- // =============================================================================
200
- // Helper Functions Tests
201
- // =============================================================================
202
- describe('getDeniedActions', () => {
203
- it('should return list of denied actions', () => {
204
- const module = createMockModule({
205
- policies: {
206
- network: 'deny',
207
- filesystem_write: 'deny',
208
- side_effects: 'allow',
209
- },
210
- });
211
- const denied = getDeniedActions(module);
212
- expect(denied).toContain('network');
213
- expect(denied).toContain('filesystem_write');
214
- expect(denied).not.toContain('side_effects');
215
- });
216
- it('should return empty array when no policies', () => {
217
- const module = createMockModule();
218
- expect(getDeniedActions(module)).toHaveLength(0);
219
- });
220
- });
221
- describe('getDeniedTools', () => {
222
- it('should return denied tools list', () => {
223
- const module = createMockModule({
224
- tools: {
225
- policy: 'allow_by_default',
226
- allowed: [],
227
- denied: ['shell', 'network', 'write_file'],
228
- },
229
- });
230
- const denied = getDeniedTools(module);
231
- expect(denied).toContain('shell');
232
- expect(denied).toContain('network');
233
- expect(denied).toContain('write_file');
234
- });
235
- });
236
- describe('getAllowedTools', () => {
237
- it('should return null for allow_by_default', () => {
238
- const module = createMockModule({
239
- tools: {
240
- policy: 'allow_by_default',
241
- allowed: ['read_file'],
242
- },
243
- });
244
- expect(getAllowedTools(module)).toBeNull();
245
- });
246
- it('should return allowed list for deny_by_default', () => {
247
- const module = createMockModule({
248
- tools: {
249
- policy: 'deny_by_default',
250
- allowed: ['read_file', 'list_dir'],
251
- },
252
- });
253
- const allowed = getAllowedTools(module);
254
- expect(allowed).toEqual(['read_file', 'list_dir']);
255
- });
256
- });
257
- // =============================================================================
258
- // ToolCallInterceptor Tests
259
- // =============================================================================
260
- describe('ToolCallInterceptor', () => {
261
- let module;
262
- let interceptor;
263
- beforeEach(() => {
264
- module = createMockModule({
265
- policies: {
266
- network: 'deny',
267
- filesystem_write: 'deny',
268
- },
269
- tools: {
270
- policy: 'deny_by_default',
271
- allowed: ['read_file', 'list_dir'],
272
- },
273
- });
274
- interceptor = new ToolCallInterceptor(module);
275
- });
276
- it('should check if tool is allowed', () => {
277
- expect(interceptor.checkAllowed('read_file').allowed).toBe(true);
278
- expect(interceptor.checkAllowed('write_file').allowed).toBe(false);
279
- expect(interceptor.checkAllowed('fetch').allowed).toBe(false);
280
- });
281
- it('should execute allowed tool', async () => {
282
- const mockExecutor = vi.fn().mockResolvedValue('file content');
283
- interceptor.registerTool('read_file', mockExecutor);
284
- const result = await interceptor.execute({
285
- name: 'read_file',
286
- arguments: { path: '/test.txt' },
287
- });
288
- expect(result.success).toBe(true);
289
- expect(result.result).toBe('file content');
290
- expect(mockExecutor).toHaveBeenCalledWith({ path: '/test.txt' });
291
- });
292
- it('should block denied tool', async () => {
293
- const mockExecutor = vi.fn().mockResolvedValue('done');
294
- interceptor.registerTool('write_file', mockExecutor);
295
- const result = await interceptor.execute({
296
- name: 'write_file',
297
- arguments: { path: '/test.txt', content: 'hello' },
298
- });
299
- expect(result.success).toBe(false);
300
- expect(result.error?.code).toBe('TOOL_NOT_ALLOWED');
301
- expect(mockExecutor).not.toHaveBeenCalled();
302
- });
303
- it('should log all calls', async () => {
304
- interceptor.registerTool('read_file', vi.fn().mockResolvedValue('ok'));
305
- interceptor.registerTool('write_file', vi.fn().mockResolvedValue('ok'));
306
- await interceptor.execute({ name: 'read_file', arguments: {} });
307
- await interceptor.execute({ name: 'write_file', arguments: {} });
308
- await interceptor.execute({ name: 'read_file', arguments: {} });
309
- const log = interceptor.getCallLog();
310
- expect(log).toHaveLength(3);
311
- expect(log[0].tool).toBe('read_file');
312
- expect(log[0].allowed).toBe(true);
313
- expect(log[1].tool).toBe('write_file');
314
- expect(log[1].allowed).toBe(false);
315
- });
316
- it('should get denied calls', async () => {
317
- interceptor.registerTool('read_file', vi.fn().mockResolvedValue('ok'));
318
- await interceptor.execute({ name: 'read_file', arguments: {} });
319
- await interceptor.execute({ name: 'write_file', arguments: {} });
320
- await interceptor.execute({ name: 'shell', arguments: {} });
321
- const denied = interceptor.getDeniedCalls();
322
- expect(denied).toHaveLength(2);
323
- expect(denied.some(d => d.tool === 'write_file')).toBe(true);
324
- expect(denied.some(d => d.tool === 'shell')).toBe(true);
325
- });
326
- it('should execute many and stop on policy violation', async () => {
327
- interceptor.registerTool('read_file', vi.fn().mockResolvedValue('ok'));
328
- interceptor.registerTool('list_dir', vi.fn().mockResolvedValue(['a', 'b']));
329
- const results = await interceptor.executeMany([
330
- { name: 'read_file', arguments: {} },
331
- { name: 'write_file', arguments: {} }, // Blocked
332
- { name: 'list_dir', arguments: {} }, // Should not execute
333
- ]);
334
- expect(results).toHaveLength(2);
335
- expect(results[0].success).toBe(true);
336
- expect(results[1].success).toBe(false);
337
- });
338
- it('should provide policy summary', () => {
339
- const summary = interceptor.getPolicySummary();
340
- expect(summary.deniedActions).toContain('network');
341
- expect(summary.deniedActions).toContain('filesystem_write');
342
- expect(summary.allowedTools).toEqual(['read_file', 'list_dir']);
343
- expect(summary.toolsPolicy).toBe('deny_by_default');
344
- });
345
- });
346
- // =============================================================================
347
- // createPolicyAwareExecutor Tests
348
- // =============================================================================
349
- describe('createPolicyAwareExecutor', () => {
350
- it('should execute allowed tool', async () => {
351
- const module = createMockModule();
352
- const executor = vi.fn().mockResolvedValue('result');
353
- const safeExecutor = createPolicyAwareExecutor(module, 'read_file', executor);
354
- const result = await safeExecutor({ path: '/test.txt' });
355
- expect(result).toBe('result');
356
- expect(executor).toHaveBeenCalledWith({ path: '/test.txt' });
357
- });
358
- it('should throw on policy violation', async () => {
359
- const module = createMockModule({
360
- policies: {
361
- filesystem_write: 'deny',
362
- },
363
- });
364
- const executor = vi.fn().mockResolvedValue('result');
365
- const safeExecutor = createPolicyAwareExecutor(module, 'write_file', executor);
366
- await expect(safeExecutor({ path: '/test.txt' })).rejects.toThrow('Policy violation');
367
- expect(executor).not.toHaveBeenCalled();
368
- });
369
- });