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.
- package/CHANGELOG.md +11 -0
- package/LICENSE +21 -0
- package/README.md +35 -29
- package/dist/cli.js +519 -23
- package/dist/commands/add.d.ts +33 -14
- package/dist/commands/add.js +383 -16
- package/dist/commands/compose.js +60 -23
- package/dist/commands/index.d.ts +4 -0
- package/dist/commands/index.js +4 -0
- package/dist/commands/init.js +23 -1
- package/dist/commands/migrate.d.ts +30 -0
- package/dist/commands/migrate.js +650 -0
- package/dist/commands/pipe.d.ts +1 -0
- package/dist/commands/pipe.js +31 -11
- package/dist/commands/remove.js +33 -2
- package/dist/commands/run.d.ts +2 -0
- package/dist/commands/run.js +61 -28
- package/dist/commands/search.d.ts +28 -0
- package/dist/commands/search.js +143 -0
- package/dist/commands/test.d.ts +65 -0
- package/dist/commands/test.js +454 -0
- package/dist/commands/update.d.ts +1 -0
- package/dist/commands/update.js +106 -14
- package/dist/commands/validate.d.ts +36 -0
- package/dist/commands/validate.js +97 -0
- package/dist/errors/index.d.ts +225 -0
- package/dist/errors/index.js +420 -0
- package/dist/mcp/server.js +84 -79
- package/dist/modules/composition.js +97 -32
- package/dist/modules/loader.js +4 -2
- package/dist/modules/runner.d.ts +72 -5
- package/dist/modules/runner.js +306 -59
- package/dist/modules/subagent.d.ts +6 -1
- package/dist/modules/subagent.js +18 -13
- package/dist/modules/validator.js +14 -6
- package/dist/providers/anthropic.d.ts +15 -0
- package/dist/providers/anthropic.js +147 -5
- package/dist/providers/base.d.ts +11 -0
- package/dist/providers/base.js +18 -0
- package/dist/providers/gemini.d.ts +15 -0
- package/dist/providers/gemini.js +122 -5
- package/dist/providers/ollama.d.ts +15 -0
- package/dist/providers/ollama.js +111 -3
- package/dist/providers/openai.d.ts +11 -0
- package/dist/providers/openai.js +133 -0
- package/dist/registry/client.d.ts +212 -0
- package/dist/registry/client.js +359 -0
- package/dist/registry/index.d.ts +4 -0
- package/dist/registry/index.js +4 -0
- package/dist/registry/tar.d.ts +8 -0
- package/dist/registry/tar.js +353 -0
- package/dist/server/http.js +301 -45
- package/dist/server/index.d.ts +2 -0
- package/dist/server/index.js +1 -0
- package/dist/server/sse.d.ts +13 -0
- package/dist/server/sse.js +22 -0
- package/dist/types.d.ts +32 -1
- package/dist/types.js +4 -1
- package/dist/version.d.ts +1 -0
- package/dist/version.js +4 -0
- package/package.json +31 -7
- package/dist/modules/composition.test.d.ts +0 -11
- package/dist/modules/composition.test.js +0 -450
- package/dist/modules/policy.test.d.ts +0 -10
- package/dist/modules/policy.test.js +0 -369
- package/src/cli.ts +0 -471
- package/src/commands/add.ts +0 -315
- package/src/commands/compose.ts +0 -185
- package/src/commands/index.ts +0 -13
- package/src/commands/init.ts +0 -94
- package/src/commands/list.ts +0 -33
- package/src/commands/pipe.ts +0 -76
- package/src/commands/remove.ts +0 -57
- package/src/commands/run.ts +0 -80
- package/src/commands/update.ts +0 -130
- package/src/commands/versions.ts +0 -79
- package/src/index.ts +0 -90
- package/src/mcp/index.ts +0 -5
- package/src/mcp/server.ts +0 -403
- package/src/modules/composition.test.ts +0 -558
- package/src/modules/composition.ts +0 -1674
- package/src/modules/index.ts +0 -9
- package/src/modules/loader.ts +0 -508
- package/src/modules/policy.test.ts +0 -455
- package/src/modules/runner.ts +0 -1983
- package/src/modules/subagent.ts +0 -277
- package/src/modules/validator.ts +0 -700
- package/src/providers/anthropic.ts +0 -89
- package/src/providers/base.ts +0 -29
- package/src/providers/deepseek.ts +0 -83
- package/src/providers/gemini.ts +0 -117
- package/src/providers/index.ts +0 -78
- package/src/providers/minimax.ts +0 -81
- package/src/providers/moonshot.ts +0 -82
- package/src/providers/ollama.ts +0 -83
- package/src/providers/openai.ts +0 -84
- package/src/providers/qwen.ts +0 -82
- package/src/server/http.ts +0 -316
- package/src/server/index.ts +0 -6
- package/src/types.ts +0 -599
- package/tsconfig.json +0 -17
|
@@ -0,0 +1,650 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* cog migrate - Migrate modules to v2.2 format
|
|
3
|
+
*
|
|
4
|
+
* Aligns with Python CLI's `cog migrate` command.
|
|
5
|
+
* Performs migration from v0/v1/v2.1 to v2.2 format.
|
|
6
|
+
*/
|
|
7
|
+
import * as fs from 'node:fs/promises';
|
|
8
|
+
import * as path from 'node:path';
|
|
9
|
+
import yaml from 'js-yaml';
|
|
10
|
+
import { findModule, getDefaultSearchPaths } from '../modules/index.js';
|
|
11
|
+
/**
|
|
12
|
+
* Migrate a single module to v2.2 format.
|
|
13
|
+
*/
|
|
14
|
+
export async function migrate(nameOrPath, ctx, options = {}) {
|
|
15
|
+
const dryRun = options.dryRun ?? false;
|
|
16
|
+
const backup = options.backup ?? true;
|
|
17
|
+
try {
|
|
18
|
+
let modulePath;
|
|
19
|
+
let moduleName;
|
|
20
|
+
// Try to find as a named module first
|
|
21
|
+
const searchPaths = getDefaultSearchPaths(ctx.cwd);
|
|
22
|
+
const module = await findModule(nameOrPath, searchPaths);
|
|
23
|
+
if (module) {
|
|
24
|
+
modulePath = module.location;
|
|
25
|
+
moduleName = module.name;
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
// Treat as a path
|
|
29
|
+
modulePath = nameOrPath;
|
|
30
|
+
moduleName = path.basename(nameOrPath);
|
|
31
|
+
}
|
|
32
|
+
// Check if path exists
|
|
33
|
+
try {
|
|
34
|
+
await fs.access(modulePath);
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return {
|
|
38
|
+
success: false,
|
|
39
|
+
error: `Module not found: ${modulePath}`,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
// Detect format and migrate
|
|
43
|
+
const result = await migrateModule(modulePath, moduleName, dryRun, backup);
|
|
44
|
+
return {
|
|
45
|
+
success: result.success,
|
|
46
|
+
data: result,
|
|
47
|
+
error: result.success ? undefined : result.warnings.join('; '),
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
catch (e) {
|
|
51
|
+
return {
|
|
52
|
+
success: false,
|
|
53
|
+
error: e instanceof Error ? e.message : String(e),
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Migrate all modules to v2.2 format.
|
|
59
|
+
*/
|
|
60
|
+
export async function migrateAll(ctx, options = {}) {
|
|
61
|
+
const dryRun = options.dryRun ?? false;
|
|
62
|
+
const backup = options.backup ?? true;
|
|
63
|
+
try {
|
|
64
|
+
const { listModules } = await import('../modules/loader.js');
|
|
65
|
+
const searchPaths = getDefaultSearchPaths(ctx.cwd);
|
|
66
|
+
const modules = await listModules(searchPaths);
|
|
67
|
+
const results = [];
|
|
68
|
+
let allSuccess = true;
|
|
69
|
+
for (const module of modules) {
|
|
70
|
+
const result = await migrateModule(module.location, module.name, dryRun, backup);
|
|
71
|
+
results.push(result);
|
|
72
|
+
if (!result.success) {
|
|
73
|
+
allSuccess = false;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return {
|
|
77
|
+
success: allSuccess,
|
|
78
|
+
data: {
|
|
79
|
+
total: modules.length,
|
|
80
|
+
migrated: results.filter(r => r.success && r.changes.length > 0).length,
|
|
81
|
+
skipped: results.filter(r => r.success && r.changes.length === 0).length,
|
|
82
|
+
failed: results.filter(r => !r.success).length,
|
|
83
|
+
results,
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
catch (e) {
|
|
88
|
+
return {
|
|
89
|
+
success: false,
|
|
90
|
+
error: e instanceof Error ? e.message : String(e),
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
// =============================================================================
|
|
95
|
+
// Internal Migration Logic
|
|
96
|
+
// =============================================================================
|
|
97
|
+
async function migrateModule(modulePath, moduleName, dryRun, backup) {
|
|
98
|
+
const changes = [];
|
|
99
|
+
const warnings = [];
|
|
100
|
+
// Detect format
|
|
101
|
+
const format = await detectFormat(modulePath);
|
|
102
|
+
if (!format) {
|
|
103
|
+
return {
|
|
104
|
+
moduleName,
|
|
105
|
+
modulePath,
|
|
106
|
+
success: false,
|
|
107
|
+
changes: [],
|
|
108
|
+
warnings: ['Could not detect module format'],
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
// Check if already v2.2
|
|
112
|
+
if (format === 'v2') {
|
|
113
|
+
const moduleYamlPath = path.join(modulePath, 'module.yaml');
|
|
114
|
+
try {
|
|
115
|
+
const content = await fs.readFile(moduleYamlPath, 'utf-8');
|
|
116
|
+
const manifest = yaml.load(content);
|
|
117
|
+
if (manifest.tier !== undefined) {
|
|
118
|
+
warnings.push('Module appears to already be v2.2 format');
|
|
119
|
+
return { moduleName, modulePath, success: true, changes: [], warnings };
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
// Continue with migration
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
// Create backup if needed
|
|
127
|
+
if (backup && !dryRun) {
|
|
128
|
+
const backupPath = await createBackup(modulePath);
|
|
129
|
+
changes.push(`Created backup: ${backupPath}`);
|
|
130
|
+
}
|
|
131
|
+
// Perform migration based on format
|
|
132
|
+
switch (format) {
|
|
133
|
+
case 'v0':
|
|
134
|
+
return migrateFromV0(modulePath, moduleName, dryRun, changes, warnings);
|
|
135
|
+
case 'v1':
|
|
136
|
+
return migrateFromV1(modulePath, moduleName, dryRun, changes, warnings);
|
|
137
|
+
case 'v2':
|
|
138
|
+
return migrateFromV2(modulePath, moduleName, dryRun, changes, warnings);
|
|
139
|
+
default:
|
|
140
|
+
return {
|
|
141
|
+
moduleName,
|
|
142
|
+
modulePath,
|
|
143
|
+
success: false,
|
|
144
|
+
changes: [],
|
|
145
|
+
warnings: [`Unknown format: ${format}`],
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
async function detectFormat(modulePath) {
|
|
150
|
+
const hasModuleYaml = await fileExists(path.join(modulePath, 'module.yaml'));
|
|
151
|
+
const hasModuleMd = await fileExists(path.join(modulePath, 'MODULE.md'));
|
|
152
|
+
const hasOldModuleMd = await fileExists(path.join(modulePath, 'module.md'));
|
|
153
|
+
if (hasModuleYaml)
|
|
154
|
+
return 'v2';
|
|
155
|
+
if (hasModuleMd)
|
|
156
|
+
return 'v1';
|
|
157
|
+
if (hasOldModuleMd)
|
|
158
|
+
return 'v0';
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
async function fileExists(filepath) {
|
|
162
|
+
try {
|
|
163
|
+
await fs.access(filepath);
|
|
164
|
+
return true;
|
|
165
|
+
}
|
|
166
|
+
catch {
|
|
167
|
+
return false;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
async function createBackup(modulePath) {
|
|
171
|
+
const timestamp = new Date().toISOString().replace(/[:-]/g, '').slice(0, 15);
|
|
172
|
+
const backupPath = `${modulePath}_backup_${timestamp}`;
|
|
173
|
+
await fs.cp(modulePath, backupPath, { recursive: true });
|
|
174
|
+
return backupPath;
|
|
175
|
+
}
|
|
176
|
+
// =============================================================================
|
|
177
|
+
// v0 Migration (6-file format)
|
|
178
|
+
// =============================================================================
|
|
179
|
+
async function migrateFromV0(modulePath, moduleName, dryRun, changes, warnings) {
|
|
180
|
+
warnings.push('v0 format migration requires manual review');
|
|
181
|
+
try {
|
|
182
|
+
// Load module.md
|
|
183
|
+
const moduleMdPath = path.join(modulePath, 'module.md');
|
|
184
|
+
const moduleMdContent = await fs.readFile(moduleMdPath, 'utf-8');
|
|
185
|
+
const frontmatter = parseFrontmatter(moduleMdContent);
|
|
186
|
+
// Load prompt
|
|
187
|
+
const promptPath = path.join(modulePath, 'prompt.txt');
|
|
188
|
+
const prompt = await fs.readFile(promptPath, 'utf-8');
|
|
189
|
+
// Load schemas
|
|
190
|
+
const inputSchemaPath = path.join(modulePath, 'input.schema.json');
|
|
191
|
+
const outputSchemaPath = path.join(modulePath, 'output.schema.json');
|
|
192
|
+
const inputSchema = JSON.parse(await fs.readFile(inputSchemaPath, 'utf-8'));
|
|
193
|
+
const outputSchema = JSON.parse(await fs.readFile(outputSchemaPath, 'utf-8'));
|
|
194
|
+
// Create v2.2 manifest
|
|
195
|
+
const manifest = createV22Manifest(frontmatter);
|
|
196
|
+
// Create combined schema
|
|
197
|
+
const schema = createV22Schema(inputSchema, outputSchema);
|
|
198
|
+
// Create prompt.md
|
|
199
|
+
const promptMd = createV22Prompt(frontmatter, prompt);
|
|
200
|
+
if (dryRun) {
|
|
201
|
+
changes.push('[DRY RUN] Would create module.yaml');
|
|
202
|
+
changes.push('[DRY RUN] Would create schema.json (combined)');
|
|
203
|
+
changes.push('[DRY RUN] Would create prompt.md');
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
await writeYaml(path.join(modulePath, 'module.yaml'), manifest);
|
|
207
|
+
changes.push('Created module.yaml');
|
|
208
|
+
await writeJson(path.join(modulePath, 'schema.json'), schema);
|
|
209
|
+
changes.push('Created schema.json (combined)');
|
|
210
|
+
await fs.writeFile(path.join(modulePath, 'prompt.md'), promptMd);
|
|
211
|
+
changes.push('Created prompt.md');
|
|
212
|
+
}
|
|
213
|
+
return { moduleName, modulePath, success: true, changes, warnings };
|
|
214
|
+
}
|
|
215
|
+
catch (e) {
|
|
216
|
+
warnings.push(`Migration error: ${e instanceof Error ? e.message : e}`);
|
|
217
|
+
return { moduleName, modulePath, success: false, changes, warnings };
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
// =============================================================================
|
|
221
|
+
// v1 Migration (MODULE.md + schema.json)
|
|
222
|
+
// =============================================================================
|
|
223
|
+
async function migrateFromV1(modulePath, moduleName, dryRun, changes, warnings) {
|
|
224
|
+
try {
|
|
225
|
+
// Load MODULE.md
|
|
226
|
+
const moduleMdPath = path.join(modulePath, 'MODULE.md');
|
|
227
|
+
const moduleMdContent = await fs.readFile(moduleMdPath, 'utf-8');
|
|
228
|
+
const { frontmatter, body } = parseFrontmatterWithBody(moduleMdContent);
|
|
229
|
+
// Load schema.json if exists
|
|
230
|
+
const schemaPath = path.join(modulePath, 'schema.json');
|
|
231
|
+
let inputSchema = {};
|
|
232
|
+
let outputSchema = {};
|
|
233
|
+
if (await fileExists(schemaPath)) {
|
|
234
|
+
const schema = JSON.parse(await fs.readFile(schemaPath, 'utf-8'));
|
|
235
|
+
inputSchema = schema.input || {};
|
|
236
|
+
outputSchema = schema.output || {};
|
|
237
|
+
}
|
|
238
|
+
// Create v2.2 manifest
|
|
239
|
+
const manifest = createV22Manifest(frontmatter);
|
|
240
|
+
// Create/update schema with meta
|
|
241
|
+
const newSchema = createV22Schema(inputSchema, outputSchema);
|
|
242
|
+
// Create prompt.md
|
|
243
|
+
const promptMd = createV22Prompt(frontmatter, body);
|
|
244
|
+
if (dryRun) {
|
|
245
|
+
changes.push('[DRY RUN] Would create module.yaml');
|
|
246
|
+
changes.push('[DRY RUN] Would update schema.json (add meta)');
|
|
247
|
+
changes.push('[DRY RUN] Would create prompt.md');
|
|
248
|
+
}
|
|
249
|
+
else {
|
|
250
|
+
await writeYaml(path.join(modulePath, 'module.yaml'), manifest);
|
|
251
|
+
changes.push('Created module.yaml');
|
|
252
|
+
await writeJson(path.join(modulePath, 'schema.json'), newSchema);
|
|
253
|
+
changes.push('Updated schema.json (added meta)');
|
|
254
|
+
await fs.writeFile(path.join(modulePath, 'prompt.md'), promptMd);
|
|
255
|
+
changes.push('Created prompt.md');
|
|
256
|
+
changes.push('Preserved MODULE.md (backward compatibility)');
|
|
257
|
+
}
|
|
258
|
+
return { moduleName, modulePath, success: true, changes, warnings };
|
|
259
|
+
}
|
|
260
|
+
catch (e) {
|
|
261
|
+
warnings.push(`Migration error: ${e instanceof Error ? e.message : e}`);
|
|
262
|
+
return { moduleName, modulePath, success: false, changes, warnings };
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
// =============================================================================
|
|
266
|
+
// v2.0/v2.1 Migration
|
|
267
|
+
// =============================================================================
|
|
268
|
+
async function migrateFromV2(modulePath, moduleName, dryRun, changes, warnings) {
|
|
269
|
+
try {
|
|
270
|
+
// Load module.yaml
|
|
271
|
+
const moduleYamlPath = path.join(modulePath, 'module.yaml');
|
|
272
|
+
const manifest = yaml.load(await fs.readFile(moduleYamlPath, 'utf-8'));
|
|
273
|
+
// Load schema.json
|
|
274
|
+
const schemaPath = path.join(modulePath, 'schema.json');
|
|
275
|
+
let schema = {};
|
|
276
|
+
if (await fileExists(schemaPath)) {
|
|
277
|
+
schema = JSON.parse(await fs.readFile(schemaPath, 'utf-8'));
|
|
278
|
+
}
|
|
279
|
+
// Load prompt.md
|
|
280
|
+
const promptPath = path.join(modulePath, 'prompt.md');
|
|
281
|
+
let prompt = '';
|
|
282
|
+
if (await fileExists(promptPath)) {
|
|
283
|
+
prompt = await fs.readFile(promptPath, 'utf-8');
|
|
284
|
+
}
|
|
285
|
+
// Track changes
|
|
286
|
+
const manifestChanges = [];
|
|
287
|
+
const schemaChanges = [];
|
|
288
|
+
const promptChanges = [];
|
|
289
|
+
// Upgrade manifest to v2.2
|
|
290
|
+
if (!('tier' in manifest)) {
|
|
291
|
+
manifest.tier = 'decision';
|
|
292
|
+
manifestChanges.push('Added tier: decision');
|
|
293
|
+
}
|
|
294
|
+
if (!('schema_strictness' in manifest)) {
|
|
295
|
+
manifest.schema_strictness = 'medium';
|
|
296
|
+
manifestChanges.push('Added schema_strictness: medium');
|
|
297
|
+
}
|
|
298
|
+
if (!('overflow' in manifest)) {
|
|
299
|
+
const schemaStrictness = manifest.schema_strictness || 'medium';
|
|
300
|
+
const strictnessMaxItems = { high: 0, medium: 5, low: 20 };
|
|
301
|
+
const defaultMaxItems = strictnessMaxItems[schemaStrictness] ?? 5;
|
|
302
|
+
const defaultEnabled = schemaStrictness !== 'high';
|
|
303
|
+
manifest.overflow = {
|
|
304
|
+
enabled: defaultEnabled,
|
|
305
|
+
recoverable: true,
|
|
306
|
+
max_items: defaultMaxItems,
|
|
307
|
+
require_suggested_mapping: true,
|
|
308
|
+
};
|
|
309
|
+
manifestChanges.push(`Added overflow config (max_items=${defaultMaxItems})`);
|
|
310
|
+
}
|
|
311
|
+
if (!('enums' in manifest)) {
|
|
312
|
+
manifest.enums = { strategy: 'extensible' };
|
|
313
|
+
manifestChanges.push('Added enums config');
|
|
314
|
+
}
|
|
315
|
+
if (!('compat' in manifest)) {
|
|
316
|
+
manifest.compat = {
|
|
317
|
+
accepts_v21_payload: true,
|
|
318
|
+
runtime_auto_wrap: true,
|
|
319
|
+
schema_output_alias: 'data',
|
|
320
|
+
};
|
|
321
|
+
manifestChanges.push('Added compat config');
|
|
322
|
+
}
|
|
323
|
+
if (!('io' in manifest)) {
|
|
324
|
+
manifest.io = {
|
|
325
|
+
input: './schema.json#/input',
|
|
326
|
+
data: './schema.json#/data',
|
|
327
|
+
meta: './schema.json#/meta',
|
|
328
|
+
error: './schema.json#/error',
|
|
329
|
+
};
|
|
330
|
+
manifestChanges.push('Added io references');
|
|
331
|
+
}
|
|
332
|
+
// Upgrade schema to v2.2
|
|
333
|
+
if (!('meta' in schema)) {
|
|
334
|
+
schema.meta = createMetaSchema();
|
|
335
|
+
schemaChanges.push('Added meta schema');
|
|
336
|
+
}
|
|
337
|
+
if ('output' in schema && !('data' in schema)) {
|
|
338
|
+
schema.data = schema.output;
|
|
339
|
+
delete schema.output;
|
|
340
|
+
schemaChanges.push('Renamed output to data');
|
|
341
|
+
}
|
|
342
|
+
if ('data' in schema) {
|
|
343
|
+
const dataSchema = schema.data;
|
|
344
|
+
const dataRequired = dataSchema.required || [];
|
|
345
|
+
if (!dataRequired.includes('rationale')) {
|
|
346
|
+
dataRequired.push('rationale');
|
|
347
|
+
dataSchema.required = dataRequired;
|
|
348
|
+
schemaChanges.push('Added rationale to data.required');
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
const overflowConfig = manifest.overflow;
|
|
352
|
+
if (overflowConfig?.enabled && !('$defs' in schema)) {
|
|
353
|
+
schema.$defs = { extensions: createExtensionsSchema() };
|
|
354
|
+
schemaChanges.push('Added $defs.extensions');
|
|
355
|
+
}
|
|
356
|
+
// Update prompt if needed
|
|
357
|
+
if (!prompt.toLowerCase().includes('meta') || !prompt.toLowerCase().includes('envelope')) {
|
|
358
|
+
prompt = addV22InstructionsToPrompt(prompt, manifest);
|
|
359
|
+
promptChanges.push('Added v2.2 envelope instructions');
|
|
360
|
+
}
|
|
361
|
+
// Apply changes
|
|
362
|
+
if (dryRun) {
|
|
363
|
+
if (manifestChanges.length > 0) {
|
|
364
|
+
changes.push(`[DRY RUN] Would update module.yaml: ${manifestChanges.join(', ')}`);
|
|
365
|
+
}
|
|
366
|
+
if (schemaChanges.length > 0) {
|
|
367
|
+
changes.push(`[DRY RUN] Would update schema.json: ${schemaChanges.join(', ')}`);
|
|
368
|
+
}
|
|
369
|
+
if (promptChanges.length > 0) {
|
|
370
|
+
changes.push(`[DRY RUN] Would update prompt.md: ${promptChanges.join(', ')}`);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
else {
|
|
374
|
+
if (manifestChanges.length > 0) {
|
|
375
|
+
await writeYaml(moduleYamlPath, manifest);
|
|
376
|
+
changes.push(`Updated module.yaml: ${manifestChanges.join(', ')}`);
|
|
377
|
+
}
|
|
378
|
+
if (schemaChanges.length > 0) {
|
|
379
|
+
await writeJson(schemaPath, schema);
|
|
380
|
+
changes.push(`Updated schema.json: ${schemaChanges.join(', ')}`);
|
|
381
|
+
}
|
|
382
|
+
if (promptChanges.length > 0) {
|
|
383
|
+
await fs.writeFile(promptPath, prompt);
|
|
384
|
+
changes.push(`Updated prompt.md: ${promptChanges.join(', ')}`);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
return { moduleName, modulePath, success: true, changes, warnings };
|
|
388
|
+
}
|
|
389
|
+
catch (e) {
|
|
390
|
+
warnings.push(`Migration error: ${e instanceof Error ? e.message : e}`);
|
|
391
|
+
return { moduleName, modulePath, success: false, changes, warnings };
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
// =============================================================================
|
|
395
|
+
// Helper Functions
|
|
396
|
+
// =============================================================================
|
|
397
|
+
function parseFrontmatter(content) {
|
|
398
|
+
if (!content.startsWith('---')) {
|
|
399
|
+
return {};
|
|
400
|
+
}
|
|
401
|
+
const parts = content.split('---');
|
|
402
|
+
if (parts.length < 3) {
|
|
403
|
+
return {};
|
|
404
|
+
}
|
|
405
|
+
try {
|
|
406
|
+
return yaml.load(parts[1]);
|
|
407
|
+
}
|
|
408
|
+
catch {
|
|
409
|
+
return {};
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
function parseFrontmatterWithBody(content) {
|
|
413
|
+
if (!content.startsWith('---')) {
|
|
414
|
+
return { frontmatter: {}, body: content };
|
|
415
|
+
}
|
|
416
|
+
const parts = content.split('---');
|
|
417
|
+
if (parts.length < 3) {
|
|
418
|
+
return { frontmatter: {}, body: content };
|
|
419
|
+
}
|
|
420
|
+
try {
|
|
421
|
+
return {
|
|
422
|
+
frontmatter: yaml.load(parts[1]),
|
|
423
|
+
body: parts.slice(2).join('---').trim(),
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
catch {
|
|
427
|
+
return { frontmatter: {}, body: content };
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
function createV22Manifest(frontmatter) {
|
|
431
|
+
return {
|
|
432
|
+
name: frontmatter.name || 'unknown',
|
|
433
|
+
version: frontmatter.version || '2.2.0',
|
|
434
|
+
responsibility: frontmatter.responsibility || '',
|
|
435
|
+
tier: 'decision',
|
|
436
|
+
schema_strictness: 'medium',
|
|
437
|
+
excludes: frontmatter.excludes || [],
|
|
438
|
+
policies: {
|
|
439
|
+
network: 'deny',
|
|
440
|
+
filesystem_write: 'deny',
|
|
441
|
+
side_effects: 'deny',
|
|
442
|
+
code_execution: 'deny',
|
|
443
|
+
},
|
|
444
|
+
tools: {
|
|
445
|
+
policy: 'deny_by_default',
|
|
446
|
+
allowed: [],
|
|
447
|
+
denied: ['write_file', 'shell', 'network'],
|
|
448
|
+
},
|
|
449
|
+
overflow: {
|
|
450
|
+
enabled: true,
|
|
451
|
+
recoverable: true,
|
|
452
|
+
max_items: 5,
|
|
453
|
+
require_suggested_mapping: true,
|
|
454
|
+
},
|
|
455
|
+
enums: {
|
|
456
|
+
strategy: 'extensible',
|
|
457
|
+
},
|
|
458
|
+
failure: {
|
|
459
|
+
contract: 'error_union',
|
|
460
|
+
partial_allowed: true,
|
|
461
|
+
must_return_error_schema: true,
|
|
462
|
+
},
|
|
463
|
+
runtime_requirements: {
|
|
464
|
+
structured_output: true,
|
|
465
|
+
max_input_tokens: 8000,
|
|
466
|
+
preferred_capabilities: ['json_mode'],
|
|
467
|
+
},
|
|
468
|
+
io: {
|
|
469
|
+
input: './schema.json#/input',
|
|
470
|
+
data: './schema.json#/data',
|
|
471
|
+
meta: './schema.json#/meta',
|
|
472
|
+
error: './schema.json#/error',
|
|
473
|
+
},
|
|
474
|
+
compat: {
|
|
475
|
+
accepts_v21_payload: true,
|
|
476
|
+
runtime_auto_wrap: true,
|
|
477
|
+
schema_output_alias: 'data',
|
|
478
|
+
},
|
|
479
|
+
...(frontmatter.constraints ? { constraints: frontmatter.constraints } : {}),
|
|
480
|
+
...(frontmatter.context ? { context: frontmatter.context } : {}),
|
|
481
|
+
};
|
|
482
|
+
}
|
|
483
|
+
function createV22Schema(inputSchema, outputSchema) {
|
|
484
|
+
return {
|
|
485
|
+
$schema: 'https://ziel-io.github.io/cognitive-modules/schema/v2.2.json',
|
|
486
|
+
meta: createMetaSchema(),
|
|
487
|
+
input: inputSchema,
|
|
488
|
+
data: addRationaleToOutput(outputSchema),
|
|
489
|
+
error: {
|
|
490
|
+
type: 'object',
|
|
491
|
+
required: ['code', 'message'],
|
|
492
|
+
properties: {
|
|
493
|
+
code: { type: 'string' },
|
|
494
|
+
message: { type: 'string' },
|
|
495
|
+
},
|
|
496
|
+
},
|
|
497
|
+
$defs: {
|
|
498
|
+
extensions: createExtensionsSchema(),
|
|
499
|
+
},
|
|
500
|
+
};
|
|
501
|
+
}
|
|
502
|
+
function createMetaSchema() {
|
|
503
|
+
return {
|
|
504
|
+
type: 'object',
|
|
505
|
+
required: ['confidence', 'risk', 'explain'],
|
|
506
|
+
properties: {
|
|
507
|
+
confidence: {
|
|
508
|
+
type: 'number',
|
|
509
|
+
minimum: 0,
|
|
510
|
+
maximum: 1,
|
|
511
|
+
description: 'Confidence score, unified across all modules',
|
|
512
|
+
},
|
|
513
|
+
risk: {
|
|
514
|
+
type: 'string',
|
|
515
|
+
enum: ['none', 'low', 'medium', 'high'],
|
|
516
|
+
description: 'Aggregated risk level',
|
|
517
|
+
},
|
|
518
|
+
explain: {
|
|
519
|
+
type: 'string',
|
|
520
|
+
maxLength: 280,
|
|
521
|
+
description: 'Short explanation for control plane',
|
|
522
|
+
},
|
|
523
|
+
trace_id: { type: 'string' },
|
|
524
|
+
model: { type: 'string' },
|
|
525
|
+
latency_ms: { type: 'number', minimum: 0 },
|
|
526
|
+
},
|
|
527
|
+
};
|
|
528
|
+
}
|
|
529
|
+
function createExtensionsSchema() {
|
|
530
|
+
return {
|
|
531
|
+
type: 'object',
|
|
532
|
+
properties: {
|
|
533
|
+
insights: {
|
|
534
|
+
type: 'array',
|
|
535
|
+
maxItems: 5,
|
|
536
|
+
items: {
|
|
537
|
+
type: 'object',
|
|
538
|
+
required: ['text', 'suggested_mapping'],
|
|
539
|
+
properties: {
|
|
540
|
+
text: { type: 'string' },
|
|
541
|
+
suggested_mapping: { type: 'string' },
|
|
542
|
+
evidence: { type: 'string' },
|
|
543
|
+
},
|
|
544
|
+
},
|
|
545
|
+
},
|
|
546
|
+
},
|
|
547
|
+
};
|
|
548
|
+
}
|
|
549
|
+
function addRationaleToOutput(outputSchema) {
|
|
550
|
+
const schema = { ...outputSchema };
|
|
551
|
+
// Ensure required includes rationale
|
|
552
|
+
const required = schema.required || [];
|
|
553
|
+
if (!required.includes('rationale')) {
|
|
554
|
+
required.push('rationale');
|
|
555
|
+
}
|
|
556
|
+
schema.required = required;
|
|
557
|
+
// Ensure properties includes rationale
|
|
558
|
+
const properties = schema.properties || {};
|
|
559
|
+
if (!properties.rationale) {
|
|
560
|
+
properties.rationale = {
|
|
561
|
+
type: 'string',
|
|
562
|
+
description: 'Detailed explanation for audit and human review',
|
|
563
|
+
};
|
|
564
|
+
}
|
|
565
|
+
// Add extensions reference
|
|
566
|
+
if (!properties.extensions) {
|
|
567
|
+
properties.extensions = { $ref: '#/$defs/extensions' };
|
|
568
|
+
}
|
|
569
|
+
schema.properties = properties;
|
|
570
|
+
return schema;
|
|
571
|
+
}
|
|
572
|
+
function createV22Prompt(frontmatter, promptBody) {
|
|
573
|
+
const name = frontmatter.name || 'Module';
|
|
574
|
+
const title = name.replace(/-/g, ' ').replace(/\b\w/g, c => c.toUpperCase());
|
|
575
|
+
return `# ${title}
|
|
576
|
+
|
|
577
|
+
${promptBody}
|
|
578
|
+
|
|
579
|
+
## Response Format (Envelope v2.2)
|
|
580
|
+
|
|
581
|
+
You MUST wrap your response in the v2.2 envelope format with separate meta and data sections.
|
|
582
|
+
|
|
583
|
+
### Success Response
|
|
584
|
+
|
|
585
|
+
\`\`\`json
|
|
586
|
+
{
|
|
587
|
+
"ok": true,
|
|
588
|
+
"meta": {
|
|
589
|
+
"confidence": 0.9,
|
|
590
|
+
"risk": "low",
|
|
591
|
+
"explain": "Short summary (max 280 chars) for routing and UI display."
|
|
592
|
+
},
|
|
593
|
+
"data": {
|
|
594
|
+
"...your output fields...",
|
|
595
|
+
"rationale": "Detailed explanation for audit and human review..."
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
\`\`\`
|
|
599
|
+
|
|
600
|
+
### Error Response
|
|
601
|
+
|
|
602
|
+
\`\`\`json
|
|
603
|
+
{
|
|
604
|
+
"ok": false,
|
|
605
|
+
"meta": {
|
|
606
|
+
"confidence": 0.0,
|
|
607
|
+
"risk": "high",
|
|
608
|
+
"explain": "Brief error summary."
|
|
609
|
+
},
|
|
610
|
+
"error": {
|
|
611
|
+
"code": "ERROR_CODE",
|
|
612
|
+
"message": "Detailed error description"
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
\`\`\`
|
|
616
|
+
|
|
617
|
+
## Important
|
|
618
|
+
|
|
619
|
+
- \`meta.explain\` is for **quick decisions** (≤280 chars)
|
|
620
|
+
- \`data.rationale\` is for **audit and review** (no limit)
|
|
621
|
+
- Both must be present in successful responses
|
|
622
|
+
`;
|
|
623
|
+
}
|
|
624
|
+
function addV22InstructionsToPrompt(prompt, _manifest) {
|
|
625
|
+
const v22Section = `
|
|
626
|
+
|
|
627
|
+
## Response Format (Envelope v2.2)
|
|
628
|
+
|
|
629
|
+
You MUST wrap your response in the v2.2 envelope format with separate meta and data sections:
|
|
630
|
+
|
|
631
|
+
- Success: \`{ "ok": true, "meta": { "confidence": 0.9, "risk": "low", "explain": "≤280 chars" }, "data": { ...payload... } }\`
|
|
632
|
+
- Error: \`{ "ok": false, "meta": { ... }, "error": { "code": "...", "message": "..." } }\`
|
|
633
|
+
|
|
634
|
+
Important:
|
|
635
|
+
- \`meta.explain\` is for quick routing (≤280 chars)
|
|
636
|
+
- \`data.rationale\` is for detailed audit (no limit)
|
|
637
|
+
`;
|
|
638
|
+
return prompt + v22Section;
|
|
639
|
+
}
|
|
640
|
+
async function writeYaml(filepath, data) {
|
|
641
|
+
const content = '# Cognitive Module Manifest v2.2\n' + yaml.dump(data, {
|
|
642
|
+
noRefs: true,
|
|
643
|
+
sortKeys: false,
|
|
644
|
+
lineWidth: 100,
|
|
645
|
+
});
|
|
646
|
+
await fs.writeFile(filepath, content);
|
|
647
|
+
}
|
|
648
|
+
async function writeJson(filepath, data) {
|
|
649
|
+
await fs.writeFile(filepath, JSON.stringify(data, null, 2) + '\n');
|
|
650
|
+
}
|