cognitive-modules-cli 2.2.0 → 2.2.1
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.js +65 -12
- package/dist/commands/compose.d.ts +31 -0
- package/dist/commands/compose.js +148 -0
- package/dist/commands/index.d.ts +1 -0
- package/dist/commands/index.js +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +5 -1
- package/dist/modules/composition.d.ts +251 -0
- package/dist/modules/composition.js +1265 -0
- package/dist/modules/composition.test.d.ts +11 -0
- package/dist/modules/composition.test.js +450 -0
- package/dist/modules/index.d.ts +2 -0
- package/dist/modules/index.js +2 -0
- package/dist/modules/loader.d.ts +22 -2
- package/dist/modules/loader.js +167 -4
- package/dist/modules/policy.test.d.ts +10 -0
- package/dist/modules/policy.test.js +369 -0
- package/dist/modules/runner.d.ts +357 -1
- package/dist/modules/runner.js +1221 -64
- package/dist/modules/subagent.js +2 -0
- package/dist/modules/validator.d.ts +28 -0
- package/dist/modules/validator.js +629 -0
- package/dist/types.d.ts +92 -8
- package/package.json +2 -1
- package/src/cli.ts +73 -12
- package/src/commands/compose.ts +185 -0
- package/src/commands/index.ts +1 -0
- package/src/index.ts +35 -0
- package/src/modules/composition.test.ts +558 -0
- package/src/modules/composition.ts +1674 -0
- package/src/modules/index.ts +2 -0
- package/src/modules/loader.ts +196 -6
- package/src/modules/policy.test.ts +455 -0
- package/src/modules/runner.ts +1562 -74
- package/src/modules/subagent.ts +2 -0
- package/src/modules/validator.ts +700 -0
- package/src/types.ts +112 -8
- package/tsconfig.json +1 -1
package/src/modules/index.ts
CHANGED
package/src/modules/loader.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Module Loader - Load and parse Cognitive Modules
|
|
3
|
-
* Supports
|
|
3
|
+
* Supports v0 (6-file), v1 (MODULE.md) and v2 (module.yaml + prompt.md) formats
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import * as fs from 'node:fs/promises';
|
|
@@ -19,7 +19,14 @@ import type {
|
|
|
19
19
|
CompatConfig,
|
|
20
20
|
MetaConfig,
|
|
21
21
|
ModuleTier,
|
|
22
|
-
SchemaStrictness
|
|
22
|
+
SchemaStrictness,
|
|
23
|
+
CompositionConfig,
|
|
24
|
+
CompositionPattern,
|
|
25
|
+
DependencyDeclaration,
|
|
26
|
+
DataflowStep,
|
|
27
|
+
RoutingRule,
|
|
28
|
+
AggregationStrategy,
|
|
29
|
+
IterationConfig
|
|
23
30
|
} from '../types.js';
|
|
24
31
|
|
|
25
32
|
const FRONTMATTER_REGEX = /^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n([\s\S]*))?/;
|
|
@@ -27,13 +34,26 @@ const FRONTMATTER_REGEX = /^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n([\s\S]*))?/;
|
|
|
27
34
|
/**
|
|
28
35
|
* Detect module format version
|
|
29
36
|
*/
|
|
30
|
-
async function detectFormat(modulePath: string): Promise<'v1' | 'v2'> {
|
|
37
|
+
async function detectFormat(modulePath: string): Promise<'v0' | 'v1' | 'v2'> {
|
|
31
38
|
const v2Manifest = path.join(modulePath, 'module.yaml');
|
|
39
|
+
const v1Module = path.join(modulePath, 'MODULE.md');
|
|
40
|
+
const v0Module = path.join(modulePath, 'module.md');
|
|
41
|
+
|
|
32
42
|
try {
|
|
33
43
|
await fs.access(v2Manifest);
|
|
34
44
|
return 'v2';
|
|
35
45
|
} catch {
|
|
36
|
-
|
|
46
|
+
try {
|
|
47
|
+
await fs.access(v1Module);
|
|
48
|
+
return 'v1';
|
|
49
|
+
} catch {
|
|
50
|
+
try {
|
|
51
|
+
await fs.access(v0Module);
|
|
52
|
+
return 'v0';
|
|
53
|
+
} catch {
|
|
54
|
+
throw new Error(`No module.yaml, MODULE.md, or module.md found in ${modulePath}`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
37
57
|
}
|
|
38
58
|
}
|
|
39
59
|
|
|
@@ -144,6 +164,61 @@ async function loadModuleV2(modulePath: string): Promise<CognitiveModule> {
|
|
|
144
164
|
risk_rule: validatedRiskRule,
|
|
145
165
|
};
|
|
146
166
|
|
|
167
|
+
// Parse composition config (v2.2)
|
|
168
|
+
const compositionRaw = manifest.composition as Record<string, unknown> | undefined;
|
|
169
|
+
let composition: CompositionConfig | undefined;
|
|
170
|
+
|
|
171
|
+
if (compositionRaw) {
|
|
172
|
+
// Parse pattern
|
|
173
|
+
const pattern = compositionRaw.pattern as CompositionPattern ?? 'sequential';
|
|
174
|
+
|
|
175
|
+
// Parse requires (dependencies)
|
|
176
|
+
const requiresRaw = compositionRaw.requires as Array<Record<string, unknown>> | undefined;
|
|
177
|
+
const requires: DependencyDeclaration[] | undefined = requiresRaw?.map(dep => ({
|
|
178
|
+
name: dep.name as string,
|
|
179
|
+
version: dep.version as string | undefined,
|
|
180
|
+
optional: dep.optional as boolean | undefined,
|
|
181
|
+
fallback: dep.fallback as string | null | undefined,
|
|
182
|
+
timeout_ms: dep.timeout_ms as number | undefined
|
|
183
|
+
}));
|
|
184
|
+
|
|
185
|
+
// Parse dataflow
|
|
186
|
+
const dataflowRaw = compositionRaw.dataflow as Array<Record<string, unknown>> | undefined;
|
|
187
|
+
const dataflow: DataflowStep[] | undefined = dataflowRaw?.map(step => ({
|
|
188
|
+
from: step.from as string | string[],
|
|
189
|
+
to: step.to as string | string[],
|
|
190
|
+
mapping: step.mapping as Record<string, string> | undefined,
|
|
191
|
+
condition: step.condition as string | undefined,
|
|
192
|
+
aggregate: step.aggregate as AggregationStrategy | undefined,
|
|
193
|
+
aggregator: step.aggregator as string | undefined
|
|
194
|
+
}));
|
|
195
|
+
|
|
196
|
+
// Parse routing rules
|
|
197
|
+
const routingRaw = compositionRaw.routing as Array<Record<string, unknown>> | undefined;
|
|
198
|
+
const routing: RoutingRule[] | undefined = routingRaw?.map(rule => ({
|
|
199
|
+
condition: rule.condition as string,
|
|
200
|
+
next: rule.next as string | null
|
|
201
|
+
}));
|
|
202
|
+
|
|
203
|
+
// Parse iteration config
|
|
204
|
+
const iterationRaw = compositionRaw.iteration as Record<string, unknown> | undefined;
|
|
205
|
+
const iteration: IterationConfig | undefined = iterationRaw ? {
|
|
206
|
+
max_iterations: iterationRaw.max_iterations as number | undefined,
|
|
207
|
+
continue_condition: iterationRaw.continue_condition as string | undefined,
|
|
208
|
+
stop_condition: iterationRaw.stop_condition as string | undefined
|
|
209
|
+
} : undefined;
|
|
210
|
+
|
|
211
|
+
composition = {
|
|
212
|
+
pattern,
|
|
213
|
+
requires,
|
|
214
|
+
dataflow,
|
|
215
|
+
routing,
|
|
216
|
+
max_depth: compositionRaw.max_depth as number | undefined,
|
|
217
|
+
timeout_ms: compositionRaw.timeout_ms as number | undefined,
|
|
218
|
+
iteration
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
|
|
147
222
|
return {
|
|
148
223
|
name: manifest.name as string || path.basename(modulePath),
|
|
149
224
|
version: manifest.version as string || '1.0.0',
|
|
@@ -162,6 +237,7 @@ async function loadModuleV2(modulePath: string): Promise<CognitiveModule> {
|
|
|
162
237
|
enums,
|
|
163
238
|
compat,
|
|
164
239
|
metaConfig,
|
|
240
|
+
composition,
|
|
165
241
|
// Context and prompt
|
|
166
242
|
context: manifest.context as 'fork' | 'main' | undefined,
|
|
167
243
|
prompt,
|
|
@@ -234,6 +310,73 @@ async function loadModuleV1(modulePath: string): Promise<CognitiveModule> {
|
|
|
234
310
|
};
|
|
235
311
|
}
|
|
236
312
|
|
|
313
|
+
/**
|
|
314
|
+
* Load v0 format module (6-file format - deprecated)
|
|
315
|
+
*/
|
|
316
|
+
async function loadModuleV0(modulePath: string): Promise<CognitiveModule> {
|
|
317
|
+
// Read module.md
|
|
318
|
+
const moduleFile = path.join(modulePath, 'module.md');
|
|
319
|
+
const moduleContent = await fs.readFile(moduleFile, 'utf-8');
|
|
320
|
+
|
|
321
|
+
// Parse frontmatter
|
|
322
|
+
const match = moduleContent.match(FRONTMATTER_REGEX);
|
|
323
|
+
if (!match) {
|
|
324
|
+
throw new Error(`Invalid module.md: missing YAML frontmatter in ${moduleFile}`);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
const metadata = yaml.load(match[1]) as Record<string, unknown>;
|
|
328
|
+
|
|
329
|
+
// Read schemas
|
|
330
|
+
const inputSchemaFile = path.join(modulePath, 'input.schema.json');
|
|
331
|
+
const outputSchemaFile = path.join(modulePath, 'output.schema.json');
|
|
332
|
+
const constraintsFile = path.join(modulePath, 'constraints.yaml');
|
|
333
|
+
const promptFile = path.join(modulePath, 'prompt.txt');
|
|
334
|
+
|
|
335
|
+
const inputSchemaContent = await fs.readFile(inputSchemaFile, 'utf-8');
|
|
336
|
+
const inputSchema = JSON.parse(inputSchemaContent);
|
|
337
|
+
|
|
338
|
+
const outputSchemaContent = await fs.readFile(outputSchemaFile, 'utf-8');
|
|
339
|
+
const outputSchema = JSON.parse(outputSchemaContent);
|
|
340
|
+
|
|
341
|
+
// Load constraints
|
|
342
|
+
const constraintsContent = await fs.readFile(constraintsFile, 'utf-8');
|
|
343
|
+
const constraintsRaw = yaml.load(constraintsContent) as Record<string, unknown>;
|
|
344
|
+
|
|
345
|
+
// Load prompt
|
|
346
|
+
const prompt = await fs.readFile(promptFile, 'utf-8');
|
|
347
|
+
|
|
348
|
+
// Extract constraints
|
|
349
|
+
const constraints: ModuleConstraints = {};
|
|
350
|
+
if (constraintsRaw) {
|
|
351
|
+
const operational = (constraintsRaw.operational as Record<string, boolean>) ?? {};
|
|
352
|
+
constraints.no_network = operational.no_external_network;
|
|
353
|
+
constraints.no_side_effects = operational.no_side_effects;
|
|
354
|
+
constraints.no_file_write = operational.no_file_write;
|
|
355
|
+
constraints.no_inventing_data = operational.no_inventing_data;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
return {
|
|
359
|
+
name: metadata.name as string || path.basename(modulePath),
|
|
360
|
+
version: metadata.version as string || '1.0.0',
|
|
361
|
+
responsibility: metadata.responsibility as string || '',
|
|
362
|
+
excludes: (metadata.excludes as string[]) || [],
|
|
363
|
+
constraints: Object.keys(constraints).length > 0 ? constraints : undefined,
|
|
364
|
+
prompt,
|
|
365
|
+
inputSchema,
|
|
366
|
+
outputSchema,
|
|
367
|
+
dataSchema: outputSchema, // Alias for v2.2 compat
|
|
368
|
+
// v2.2 defaults for v0 modules
|
|
369
|
+
schemaStrictness: 'medium',
|
|
370
|
+
overflow: { enabled: false },
|
|
371
|
+
enums: { strategy: 'strict' },
|
|
372
|
+
compat: { accepts_v21_payload: true, runtime_auto_wrap: true },
|
|
373
|
+
// Metadata
|
|
374
|
+
location: modulePath,
|
|
375
|
+
format: 'v0',
|
|
376
|
+
formatVersion: 'v0.0',
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
|
|
237
380
|
/**
|
|
238
381
|
* Load a Cognitive Module (auto-detects format)
|
|
239
382
|
*/
|
|
@@ -242,8 +385,10 @@ export async function loadModule(modulePath: string): Promise<CognitiveModule> {
|
|
|
242
385
|
|
|
243
386
|
if (format === 'v2') {
|
|
244
387
|
return loadModuleV2(modulePath);
|
|
245
|
-
} else {
|
|
388
|
+
} else if (format === 'v1') {
|
|
246
389
|
return loadModuleV1(modulePath);
|
|
390
|
+
} else {
|
|
391
|
+
return loadModuleV0(modulePath);
|
|
247
392
|
}
|
|
248
393
|
}
|
|
249
394
|
|
|
@@ -253,6 +398,7 @@ export async function loadModule(modulePath: string): Promise<CognitiveModule> {
|
|
|
253
398
|
async function isValidModule(modulePath: string): Promise<boolean> {
|
|
254
399
|
const v2Manifest = path.join(modulePath, 'module.yaml');
|
|
255
400
|
const v1Module = path.join(modulePath, 'MODULE.md');
|
|
401
|
+
const v0Module = path.join(modulePath, 'module.md');
|
|
256
402
|
|
|
257
403
|
try {
|
|
258
404
|
await fs.access(v2Manifest);
|
|
@@ -262,7 +408,12 @@ async function isValidModule(modulePath: string): Promise<boolean> {
|
|
|
262
408
|
await fs.access(v1Module);
|
|
263
409
|
return true;
|
|
264
410
|
} catch {
|
|
265
|
-
|
|
411
|
+
try {
|
|
412
|
+
await fs.access(v0Module);
|
|
413
|
+
return true;
|
|
414
|
+
} catch {
|
|
415
|
+
return false;
|
|
416
|
+
}
|
|
266
417
|
}
|
|
267
418
|
}
|
|
268
419
|
}
|
|
@@ -316,3 +467,42 @@ export function getDefaultSearchPaths(cwd: string): string[] {
|
|
|
316
467
|
path.join(home, '.cognitive', 'modules'),
|
|
317
468
|
];
|
|
318
469
|
}
|
|
470
|
+
|
|
471
|
+
// =============================================================================
|
|
472
|
+
// Utility Functions
|
|
473
|
+
// =============================================================================
|
|
474
|
+
|
|
475
|
+
/**
|
|
476
|
+
* Get module tier (exec, decision, exploration).
|
|
477
|
+
*/
|
|
478
|
+
export function getModuleTier(module: CognitiveModule): ModuleTier | undefined {
|
|
479
|
+
return module.tier;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
/**
|
|
483
|
+
* Get schema strictness level.
|
|
484
|
+
*/
|
|
485
|
+
export function getSchemaStrictness(module: CognitiveModule): SchemaStrictness {
|
|
486
|
+
return module.schemaStrictness ?? 'medium';
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
/**
|
|
490
|
+
* Check if overflow (extensions.insights) is enabled.
|
|
491
|
+
*/
|
|
492
|
+
export function isOverflowEnabled(module: CognitiveModule): boolean {
|
|
493
|
+
return module.overflow?.enabled ?? false;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
/**
|
|
497
|
+
* Get enum extension strategy.
|
|
498
|
+
*/
|
|
499
|
+
export function getEnumStrategy(module: CognitiveModule): 'strict' | 'extensible' {
|
|
500
|
+
return module.enums?.strategy ?? 'strict';
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
/**
|
|
504
|
+
* Check if runtime should auto-wrap v2.1 to v2.2.
|
|
505
|
+
*/
|
|
506
|
+
export function shouldAutoWrap(module: CognitiveModule): boolean {
|
|
507
|
+
return module.compat?.runtime_auto_wrap ?? true;
|
|
508
|
+
}
|