cognitive-modules-cli 2.2.1 → 2.2.5

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 (95) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/LICENSE +21 -0
  3. package/README.md +35 -29
  4. package/dist/cli.js +513 -22
  5. package/dist/commands/add.d.ts +33 -14
  6. package/dist/commands/add.js +222 -13
  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 +1 -0
  17. package/dist/commands/run.js +37 -27
  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 +218 -0
  27. package/dist/errors/index.js +412 -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 +65 -0
  32. package/dist/modules/runner.js +293 -49
  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 +204 -0
  47. package/dist/registry/client.js +356 -0
  48. package/dist/registry/index.d.ts +4 -0
  49. package/dist/registry/index.js +4 -0
  50. package/dist/server/http.js +173 -42
  51. package/dist/types.d.ts +32 -1
  52. package/dist/types.js +4 -1
  53. package/dist/version.d.ts +1 -0
  54. package/dist/version.js +4 -0
  55. package/package.json +31 -7
  56. package/dist/modules/composition.test.d.ts +0 -11
  57. package/dist/modules/composition.test.js +0 -450
  58. package/dist/modules/policy.test.d.ts +0 -10
  59. package/dist/modules/policy.test.js +0 -369
  60. package/src/cli.ts +0 -471
  61. package/src/commands/add.ts +0 -315
  62. package/src/commands/compose.ts +0 -185
  63. package/src/commands/index.ts +0 -13
  64. package/src/commands/init.ts +0 -94
  65. package/src/commands/list.ts +0 -33
  66. package/src/commands/pipe.ts +0 -76
  67. package/src/commands/remove.ts +0 -57
  68. package/src/commands/run.ts +0 -80
  69. package/src/commands/update.ts +0 -130
  70. package/src/commands/versions.ts +0 -79
  71. package/src/index.ts +0 -90
  72. package/src/mcp/index.ts +0 -5
  73. package/src/mcp/server.ts +0 -403
  74. package/src/modules/composition.test.ts +0 -558
  75. package/src/modules/composition.ts +0 -1674
  76. package/src/modules/index.ts +0 -9
  77. package/src/modules/loader.ts +0 -508
  78. package/src/modules/policy.test.ts +0 -455
  79. package/src/modules/runner.ts +0 -1983
  80. package/src/modules/subagent.ts +0 -277
  81. package/src/modules/validator.ts +0 -700
  82. package/src/providers/anthropic.ts +0 -89
  83. package/src/providers/base.ts +0 -29
  84. package/src/providers/deepseek.ts +0 -83
  85. package/src/providers/gemini.ts +0 -117
  86. package/src/providers/index.ts +0 -78
  87. package/src/providers/minimax.ts +0 -81
  88. package/src/providers/moonshot.ts +0 -82
  89. package/src/providers/ollama.ts +0 -83
  90. package/src/providers/openai.ts +0 -84
  91. package/src/providers/qwen.ts +0 -82
  92. package/src/server/http.ts +0 -316
  93. package/src/server/index.ts +0 -6
  94. package/src/types.ts +0 -599
  95. package/tsconfig.json +0 -17
package/dist/types.d.ts CHANGED
@@ -6,6 +6,17 @@ export interface Provider {
6
6
  name: string;
7
7
  invoke(params: InvokeParams): Promise<InvokeResult>;
8
8
  isConfigured(): boolean;
9
+ /**
10
+ * Stream-based invoke (optional).
11
+ * Returns an async generator that yields content chunks.
12
+ *
13
+ * If not implemented, falls back to non-streaming invoke.
14
+ */
15
+ invokeStream?(params: InvokeParams): AsyncGenerator<string, InvokeResult, unknown>;
16
+ /**
17
+ * Check if this provider supports streaming.
18
+ */
19
+ supportsStreaming?(): boolean;
9
20
  }
10
21
  export interface InvokeParams {
11
22
  messages: Message[];
@@ -222,14 +233,19 @@ export interface EnvelopeMeta {
222
233
  }
223
234
  /**
224
235
  * Enhanced error structure with retry and recovery info (v2.2.1).
236
+ *
237
+ * Consistent across HTTP, MCP, and CLI layers.
238
+ * See ERROR-CODES.md for error code taxonomy.
225
239
  */
226
240
  export interface EnvelopeError {
227
- /** Error code (e.g., "INVALID_INPUT", "PARSE_ERROR") */
241
+ /** Error code (E-format like "E4006" or legacy like "MODULE_NOT_FOUND") */
228
242
  code: string;
229
243
  /** Human-readable error message */
230
244
  message: string;
231
245
  /** Whether the error can be retried */
232
246
  recoverable?: boolean;
247
+ /** Suggested action to fix the error */
248
+ suggestion?: string;
233
249
  /** Suggested wait time before retry (in milliseconds) */
234
250
  retry_after_ms?: number;
235
251
  /** Additional error context */
@@ -337,11 +353,26 @@ export interface CommandContext {
337
353
  provider: Provider;
338
354
  verbose?: boolean;
339
355
  }
356
+ /**
357
+ * CLI command result (legacy format).
358
+ *
359
+ * For new code, prefer using CognitiveErrorEnvelope from errors/index.js
360
+ * for error responses to ensure cross-layer consistency.
361
+ */
340
362
  export interface CommandResult {
341
363
  success: boolean;
342
364
  data?: unknown;
343
365
  error?: string;
344
366
  }
367
+ /**
368
+ * Extended command result with unified error structure.
369
+ * Use this for commands that need full error details.
370
+ */
371
+ export interface CommandResultV2 {
372
+ ok: boolean;
373
+ data?: unknown;
374
+ error?: EnvelopeError;
375
+ }
345
376
  export interface ModuleInput {
346
377
  code?: string;
347
378
  query?: string;
package/dist/types.js CHANGED
@@ -44,7 +44,10 @@ function aggregateRiskFromList(items) {
44
44
  }
45
45
  let maxLevel = 0;
46
46
  for (const item of items) {
47
- const level = riskLevels[item.risk ?? 'medium'];
47
+ const riskKey = item.risk;
48
+ const level = typeof riskKey === 'string' && Object.prototype.hasOwnProperty.call(riskLevels, riskKey)
49
+ ? riskLevels[riskKey]
50
+ : riskLevels.medium;
48
51
  maxLevel = Math.max(maxLevel, level);
49
52
  }
50
53
  return riskNames[maxLevel];
@@ -0,0 +1 @@
1
+ export declare const VERSION: string;
@@ -0,0 +1,4 @@
1
+ import { createRequire } from 'node:module';
2
+ const require = createRequire(import.meta.url);
3
+ const pkg = require('../package.json');
4
+ export const VERSION = pkg.version ?? '0.0.0';
package/package.json CHANGED
@@ -1,18 +1,32 @@
1
1
  {
2
2
  "name": "cognitive-modules-cli",
3
- "version": "2.2.1",
3
+ "version": "2.2.5",
4
4
  "description": "Cognitive Modules - Structured AI Task Execution with version management",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ },
13
+ "./package.json": "./package.json"
14
+ },
7
15
  "bin": {
8
16
  "cognitive-modules-cli": "dist/cli.js",
9
17
  "cog": "dist/cli.js"
10
18
  },
11
19
  "scripts": {
12
- "build": "tsc",
20
+ "clean": "node -e \"import('node:fs').then(fs=>fs.rmSync('dist',{recursive:true,force:true}))\"",
21
+ "build": "npm run clean && tsc",
13
22
  "start": "node dist/cli.js",
14
23
  "dev": "tsx src/cli.ts",
15
- "prepublishOnly": "npm run build"
24
+ "test": "vitest run",
25
+ "test:watch": "vitest",
26
+ "test:coverage": "vitest run --coverage",
27
+ "pack:check": "npm pack --dry-run --json --cache ../../.npm-cache",
28
+ "release:check": "npm run build && npm test && npm run pack:check",
29
+ "prepublishOnly": "npm run release:check"
16
30
  },
17
31
  "keywords": [
18
32
  "cognitive",
@@ -25,13 +39,22 @@
25
39
  ],
26
40
  "license": "MIT",
27
41
  "author": "ziel-io",
42
+ "files": [
43
+ "dist",
44
+ "README.md",
45
+ "LICENSE",
46
+ "CHANGELOG.md"
47
+ ],
28
48
  "repository": {
29
49
  "type": "git",
30
- "url": "https://github.com/ziel-io/cognitive-modules.git"
50
+ "url": "https://github.com/Cognary/cognitive.git"
31
51
  },
32
- "homepage": "https://ziel-io.github.io/cognitive-modules/",
52
+ "homepage": "https://cognary.github.io/cognitive/",
33
53
  "bugs": {
34
- "url": "https://github.com/ziel-io/cognitive-modules/issues"
54
+ "url": "https://github.com/Cognary/cognitive/issues"
55
+ },
56
+ "publishConfig": {
57
+ "access": "public"
35
58
  },
36
59
  "engines": {
37
60
  "node": ">=18.0.0"
@@ -47,6 +70,7 @@
47
70
  "@types/js-yaml": "^4.0.9",
48
71
  "@types/node": "^22.0.0",
49
72
  "tsx": "^4.21.0",
50
- "typescript": "^5.9.3"
73
+ "typescript": "^5.9.3",
74
+ "vitest": "^2.1.0"
51
75
  }
52
76
  }
@@ -1,11 +0,0 @@
1
- /**
2
- * Tests for Composition Engine
3
- *
4
- * Tests all COMPOSITION.md specified functionality:
5
- * - JSONPath-like expression evaluation
6
- * - Condition expression evaluation
7
- * - Aggregation strategies
8
- * - Version matching
9
- * - Sequential, Parallel, Conditional, Iterative patterns
10
- */
11
- export {};
@@ -1,450 +0,0 @@
1
- /**
2
- * Tests for Composition Engine
3
- *
4
- * Tests all COMPOSITION.md specified functionality:
5
- * - JSONPath-like expression evaluation
6
- * - Condition expression evaluation
7
- * - Aggregation strategies
8
- * - Version matching
9
- * - Sequential, Parallel, Conditional, Iterative patterns
10
- */
11
- import { describe, it, expect } from 'vitest';
12
- import { evaluateJsonPath, evaluateCondition, applyMapping, aggregateResults, versionMatches, validateCompositionConfig, } from './composition.js';
13
- // =============================================================================
14
- // JSONPath Expression Tests
15
- // =============================================================================
16
- describe('evaluateJsonPath', () => {
17
- const testData = {
18
- name: 'test',
19
- nested: {
20
- value: 42,
21
- deep: {
22
- array: [1, 2, 3]
23
- }
24
- },
25
- items: [
26
- { id: 1, name: 'a' },
27
- { id: 2, name: 'b' },
28
- { id: 3, name: 'c' }
29
- ],
30
- meta: {
31
- confidence: 0.95,
32
- risk: 'low'
33
- },
34
- // Test hyphenated field names (Bug fix)
35
- 'quick-check': {
36
- meta: {
37
- confidence: 0.85
38
- },
39
- data: {
40
- result: 'success'
41
- }
42
- }
43
- };
44
- it('should return entire object for $', () => {
45
- expect(evaluateJsonPath('$', testData)).toEqual(testData);
46
- });
47
- it('should access root field with $.field', () => {
48
- expect(evaluateJsonPath('$.name', testData)).toBe('test');
49
- });
50
- it('should access nested field with $.nested.field', () => {
51
- expect(evaluateJsonPath('$.nested.value', testData)).toBe(42);
52
- expect(evaluateJsonPath('$.nested.deep.array', testData)).toEqual([1, 2, 3]);
53
- });
54
- it('should access array index with $.array[0]', () => {
55
- expect(evaluateJsonPath('$.items[0]', testData)).toEqual({ id: 1, name: 'a' });
56
- expect(evaluateJsonPath('$.items[1].name', testData)).toBe('b');
57
- expect(evaluateJsonPath('$.nested.deep.array[2]', testData)).toBe(3);
58
- });
59
- it('should map over array with $.array[*].field', () => {
60
- expect(evaluateJsonPath('$.items[*].name', testData)).toEqual(['a', 'b', 'c']);
61
- expect(evaluateJsonPath('$.items[*].id', testData)).toEqual([1, 2, 3]);
62
- });
63
- it('should return undefined for non-existent paths', () => {
64
- expect(evaluateJsonPath('$.nonexistent', testData)).toBeUndefined();
65
- expect(evaluateJsonPath('$.nested.nonexistent', testData)).toBeUndefined();
66
- expect(evaluateJsonPath('$.items[99]', testData)).toBeUndefined();
67
- });
68
- it('should return literal values for non-JSONPath strings', () => {
69
- expect(evaluateJsonPath('literal', testData)).toBe('literal');
70
- expect(evaluateJsonPath('123', testData)).toBe('123');
71
- });
72
- it('should handle hyphenated field names', () => {
73
- expect(evaluateJsonPath('$.quick-check.meta.confidence', testData)).toBe(0.85);
74
- expect(evaluateJsonPath('$.quick-check.data.result', testData)).toBe('success');
75
- });
76
- });
77
- // =============================================================================
78
- // Condition Expression Tests
79
- // =============================================================================
80
- describe('evaluateCondition', () => {
81
- const testData = {
82
- meta: {
83
- confidence: 0.85,
84
- risk: 'low'
85
- },
86
- data: {
87
- count: 5,
88
- items: [1, 2, 3],
89
- name: 'test module'
90
- }
91
- };
92
- describe('comparison operators', () => {
93
- it('should evaluate > operator', () => {
94
- expect(evaluateCondition('$.meta.confidence > 0.7', testData)).toBe(true);
95
- expect(evaluateCondition('$.meta.confidence > 0.9', testData)).toBe(false);
96
- });
97
- it('should evaluate < operator', () => {
98
- expect(evaluateCondition('$.meta.confidence < 0.9', testData)).toBe(true);
99
- expect(evaluateCondition('$.meta.confidence < 0.5', testData)).toBe(false);
100
- });
101
- it('should evaluate >= operator', () => {
102
- expect(evaluateCondition('$.meta.confidence >= 0.85', testData)).toBe(true);
103
- expect(evaluateCondition('$.meta.confidence >= 0.9', testData)).toBe(false);
104
- });
105
- it('should evaluate <= operator', () => {
106
- expect(evaluateCondition('$.meta.confidence <= 0.85', testData)).toBe(true);
107
- expect(evaluateCondition('$.meta.confidence <= 0.5', testData)).toBe(false);
108
- });
109
- it('should evaluate == operator', () => {
110
- expect(evaluateCondition('$.meta.risk == "low"', testData)).toBe(true);
111
- expect(evaluateCondition('$.meta.risk == "high"', testData)).toBe(false);
112
- expect(evaluateCondition('$.data.count == 5', testData)).toBe(true);
113
- });
114
- it('should evaluate != operator', () => {
115
- expect(evaluateCondition('$.meta.risk != "high"', testData)).toBe(true);
116
- expect(evaluateCondition('$.meta.risk != "low"', testData)).toBe(false);
117
- });
118
- });
119
- describe('logical operators', () => {
120
- it('should evaluate && operator', () => {
121
- expect(evaluateCondition('$.meta.confidence > 0.7 && $.meta.risk == "low"', testData)).toBe(true);
122
- expect(evaluateCondition('$.meta.confidence > 0.9 && $.meta.risk == "low"', testData)).toBe(false);
123
- });
124
- it('should evaluate || operator', () => {
125
- expect(evaluateCondition('$.meta.confidence > 0.9 || $.meta.risk == "low"', testData)).toBe(true);
126
- expect(evaluateCondition('$.meta.confidence > 0.9 || $.meta.risk == "high"', testData)).toBe(false);
127
- });
128
- it('should evaluate ! operator', () => {
129
- expect(evaluateCondition('!false', {})).toBe(true);
130
- expect(evaluateCondition('!true', {})).toBe(false);
131
- });
132
- });
133
- describe('special functions', () => {
134
- it('should evaluate exists() function', () => {
135
- expect(evaluateCondition('exists($.meta.confidence)', testData)).toBe(true);
136
- expect(evaluateCondition('exists($.meta.nonexistent)', testData)).toBe(false);
137
- });
138
- it('should evaluate .length property', () => {
139
- expect(evaluateCondition('$.data.items.length > 0', testData)).toBe(true);
140
- expect(evaluateCondition('$.data.items.length == 3', testData)).toBe(true);
141
- });
142
- it('should evaluate contains() for strings', () => {
143
- expect(evaluateCondition('contains($.data.name, "test")', testData)).toBe(true);
144
- expect(evaluateCondition('contains($.data.name, "xyz")', testData)).toBe(false);
145
- });
146
- it('should evaluate contains() for arrays', () => {
147
- const dataWithArray = {
148
- tags: ['javascript', 'typescript', 'node']
149
- };
150
- expect(evaluateCondition('contains($.tags, "typescript")', dataWithArray)).toBe(true);
151
- expect(evaluateCondition('contains($.tags, "python")', dataWithArray)).toBe(false);
152
- });
153
- });
154
- describe('hyphenated field names', () => {
155
- const hyphenData = {
156
- 'quick-check': {
157
- meta: { confidence: 0.85 },
158
- data: { result: 'success' }
159
- }
160
- };
161
- it('should handle hyphenated field names in conditions', () => {
162
- expect(evaluateCondition('$.quick-check.meta.confidence > 0.8', hyphenData)).toBe(true);
163
- expect(evaluateCondition('$.quick-check.meta.confidence > 0.9', hyphenData)).toBe(false);
164
- });
165
- it('should handle hyphenated fields with string comparison', () => {
166
- expect(evaluateCondition('$.quick-check.data.result == "success"', hyphenData)).toBe(true);
167
- });
168
- });
169
- });
170
- // =============================================================================
171
- // Dataflow Mapping Tests
172
- // =============================================================================
173
- describe('applyMapping', () => {
174
- const sourceData = {
175
- code: 'function test() {}',
176
- language: 'javascript',
177
- nested: {
178
- value: 42
179
- }
180
- };
181
- it('should map simple fields', () => {
182
- const mapping = {
183
- source_code: '$.code',
184
- lang: '$.language'
185
- };
186
- const result = applyMapping(mapping, sourceData);
187
- expect(result.source_code).toBe('function test() {}');
188
- expect(result.lang).toBe('javascript');
189
- });
190
- it('should map nested fields', () => {
191
- const mapping = {
192
- extracted_value: '$.nested.value'
193
- };
194
- const result = applyMapping(mapping, sourceData);
195
- expect(result.extracted_value).toBe(42);
196
- });
197
- it('should handle missing fields', () => {
198
- const mapping = {
199
- missing: '$.nonexistent'
200
- };
201
- const result = applyMapping(mapping, sourceData);
202
- expect(result.missing).toBeUndefined();
203
- });
204
- it('should pass through entire object with $', () => {
205
- const mapping = {
206
- all: '$'
207
- };
208
- const result = applyMapping(mapping, sourceData);
209
- expect(result.all).toEqual(sourceData);
210
- });
211
- });
212
- // =============================================================================
213
- // Aggregation Strategy Tests
214
- // =============================================================================
215
- describe('aggregateResults', () => {
216
- const createResult = (data, confidence, risk) => ({
217
- ok: true,
218
- meta: {
219
- confidence,
220
- risk: risk,
221
- explain: 'Test result'
222
- },
223
- data: {
224
- ...data,
225
- rationale: 'Test rationale'
226
- }
227
- });
228
- const results = [
229
- createResult({ field1: 'value1', common: 'first' }, 0.8, 'low'),
230
- createResult({ field2: 'value2', common: 'second' }, 0.9, 'medium'),
231
- createResult({ field3: 'value3', common: 'third' }, 0.7, 'none')
232
- ];
233
- describe('merge strategy', () => {
234
- it('should deep merge all results (later wins)', () => {
235
- const merged = aggregateResults(results, 'merge');
236
- expect(merged.ok).toBe(true);
237
- expect(merged.data.field1).toBe('value1');
238
- expect(merged.data.field2).toBe('value2');
239
- expect(merged.data.field3).toBe('value3');
240
- expect(merged.data.common).toBe('third'); // Last wins
241
- });
242
- it('should aggregate meta values', () => {
243
- const merged = aggregateResults(results, 'merge');
244
- // Average confidence
245
- expect(merged.meta.confidence).toBeCloseTo(0.8, 1);
246
- // Max risk
247
- expect(merged.meta.risk).toBe('medium');
248
- });
249
- });
250
- describe('array strategy', () => {
251
- it('should collect all results into array', () => {
252
- const collected = aggregateResults(results, 'array');
253
- expect(collected.ok).toBe(true);
254
- const data = collected.data;
255
- expect(data.results).toHaveLength(3);
256
- });
257
- });
258
- describe('first strategy', () => {
259
- it('should return first successful result', () => {
260
- const first = aggregateResults(results, 'first');
261
- expect(first.ok).toBe(true);
262
- expect(first.data.field1).toBe('value1');
263
- });
264
- it('should skip failed results', () => {
265
- const mixedResults = [
266
- {
267
- ok: false,
268
- meta: { confidence: 0, risk: 'high', explain: 'Failed' },
269
- error: { code: 'E1000', message: 'Error' }
270
- },
271
- createResult({ success: true }, 0.9, 'low')
272
- ];
273
- const first = aggregateResults(mixedResults, 'first');
274
- expect(first.ok).toBe(true);
275
- expect(first.data.success).toBe(true);
276
- });
277
- });
278
- describe('edge cases', () => {
279
- it('should return error for empty results', () => {
280
- const empty = aggregateResults([], 'merge');
281
- expect(empty.ok).toBe(false);
282
- });
283
- it('should return single result unchanged', () => {
284
- const single = aggregateResults([results[0]], 'merge');
285
- expect(single).toEqual(results[0]);
286
- });
287
- });
288
- });
289
- // =============================================================================
290
- // Version Matching Tests
291
- // =============================================================================
292
- describe('versionMatches', () => {
293
- describe('exact version', () => {
294
- it('should match exact version', () => {
295
- expect(versionMatches('1.0.0', '1.0.0')).toBe(true);
296
- expect(versionMatches('1.0.0', '1.0.1')).toBe(false);
297
- expect(versionMatches('2.0.0', '1.0.0')).toBe(false);
298
- });
299
- });
300
- describe('wildcard (*)', () => {
301
- it('should match any version with *', () => {
302
- expect(versionMatches('1.0.0', '*')).toBe(true);
303
- expect(versionMatches('99.99.99', '*')).toBe(true);
304
- });
305
- it('should match any version with empty pattern', () => {
306
- expect(versionMatches('1.0.0', '')).toBe(true);
307
- });
308
- });
309
- describe('>= operator', () => {
310
- it('should match versions greater than or equal', () => {
311
- expect(versionMatches('1.0.0', '>=1.0.0')).toBe(true);
312
- expect(versionMatches('1.1.0', '>=1.0.0')).toBe(true);
313
- expect(versionMatches('2.0.0', '>=1.0.0')).toBe(true);
314
- expect(versionMatches('0.9.0', '>=1.0.0')).toBe(false);
315
- });
316
- });
317
- describe('> operator', () => {
318
- it('should match versions strictly greater', () => {
319
- expect(versionMatches('1.0.1', '>1.0.0')).toBe(true);
320
- expect(versionMatches('1.1.0', '>1.0.0')).toBe(true);
321
- expect(versionMatches('1.0.0', '>1.0.0')).toBe(false);
322
- });
323
- });
324
- describe('^ (caret) operator', () => {
325
- it('should match same major version', () => {
326
- expect(versionMatches('1.2.3', '^1.0.0')).toBe(true);
327
- expect(versionMatches('1.0.0', '^1.0.0')).toBe(true);
328
- expect(versionMatches('2.0.0', '^1.0.0')).toBe(false);
329
- expect(versionMatches('0.9.0', '^1.0.0')).toBe(false);
330
- });
331
- });
332
- describe('~ (tilde) operator', () => {
333
- it('should match same major.minor version', () => {
334
- expect(versionMatches('1.0.5', '~1.0.0')).toBe(true);
335
- expect(versionMatches('1.0.0', '~1.0.0')).toBe(true);
336
- expect(versionMatches('1.1.0', '~1.0.0')).toBe(false);
337
- expect(versionMatches('2.0.0', '~1.0.0')).toBe(false);
338
- });
339
- });
340
- });
341
- // =============================================================================
342
- // Composition Config Validation Tests
343
- // =============================================================================
344
- describe('validateCompositionConfig', () => {
345
- it('should validate correct sequential config', () => {
346
- const config = {
347
- pattern: 'sequential',
348
- requires: [{ name: 'module-a' }],
349
- dataflow: [
350
- { from: 'input', to: 'module-a' },
351
- { from: 'module-a.output', to: 'output' }
352
- ]
353
- };
354
- const result = validateCompositionConfig(config);
355
- expect(result.valid).toBe(true);
356
- expect(result.errors).toHaveLength(0);
357
- });
358
- it('should validate correct parallel config', () => {
359
- const config = {
360
- pattern: 'parallel',
361
- requires: [
362
- { name: 'module-a' },
363
- { name: 'module-b' }
364
- ],
365
- dataflow: [
366
- { from: 'input', to: ['module-a', 'module-b'] },
367
- { from: ['module-a.output', 'module-b.output'], to: 'output', aggregate: 'merge' }
368
- ]
369
- };
370
- const result = validateCompositionConfig(config);
371
- expect(result.valid).toBe(true);
372
- });
373
- it('should require routing rules for conditional pattern', () => {
374
- const config = {
375
- pattern: 'conditional',
376
- dataflow: [{ from: 'input', to: 'module-a' }]
377
- };
378
- const result = validateCompositionConfig(config);
379
- expect(result.valid).toBe(false);
380
- expect(result.errors.some(e => e.includes('routing'))).toBe(true);
381
- });
382
- it('should require iteration config for iterative pattern', () => {
383
- const config = {
384
- pattern: 'iterative',
385
- dataflow: [{ from: 'input', to: 'module-a' }]
386
- };
387
- const result = validateCompositionConfig(config);
388
- expect(result.valid).toBe(false);
389
- expect(result.errors.some(e => e.includes('continue_condition') || e.includes('stop_condition'))).toBe(true);
390
- });
391
- it('should validate correct iterative config', () => {
392
- const config = {
393
- pattern: 'iterative',
394
- iteration: {
395
- max_iterations: 10,
396
- stop_condition: '$.meta.confidence > 0.9'
397
- }
398
- };
399
- const result = validateCompositionConfig(config);
400
- expect(result.valid).toBe(true);
401
- });
402
- it('should detect invalid pattern', () => {
403
- const config = {
404
- pattern: 'invalid',
405
- dataflow: []
406
- };
407
- const result = validateCompositionConfig(config);
408
- expect(result.valid).toBe(false);
409
- expect(result.errors.some(e => e.includes('Invalid pattern'))).toBe(true);
410
- });
411
- it('should detect missing dataflow fields', () => {
412
- const config = {
413
- pattern: 'sequential',
414
- dataflow: [
415
- { from: 'input' },
416
- ]
417
- };
418
- const result = validateCompositionConfig(config);
419
- expect(result.valid).toBe(false);
420
- expect(result.errors.some(e => e.includes("missing 'to'"))).toBe(true);
421
- });
422
- });
423
- // =============================================================================
424
- // Integration Test Placeholders
425
- // =============================================================================
426
- describe('CompositionOrchestrator', () => {
427
- // Note: Full integration tests require mocking Provider and modules
428
- // These are placeholder tests that should be expanded with proper mocks
429
- it.skip('should execute sequential composition', async () => {
430
- // TODO: Add integration test with mocked provider
431
- });
432
- it.skip('should execute parallel composition', async () => {
433
- // TODO: Add integration test with mocked provider
434
- });
435
- it.skip('should execute conditional composition', async () => {
436
- // TODO: Add integration test with mocked provider
437
- });
438
- it.skip('should execute iterative composition', async () => {
439
- // TODO: Add integration test with mocked provider
440
- });
441
- it.skip('should handle timeouts', async () => {
442
- // TODO: Add timeout test
443
- });
444
- it.skip('should detect circular dependencies', async () => {
445
- // TODO: Add circular dependency test
446
- });
447
- it.skip('should use fallback modules', async () => {
448
- // TODO: Add fallback test
449
- });
450
- });
@@ -1,10 +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
- export {};