cognitive-modules-cli 1.2.0 → 1.3.0

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/README.md CHANGED
@@ -33,17 +33,20 @@ cog list
33
33
  echo "review this code" | cog pipe --module code-reviewer
34
34
  ```
35
35
 
36
- ## 与 Python 版的区别
36
+ ## 与 Python 版的功能对比
37
37
 
38
38
  | 功能 | Python (`cogn`) | Node.js (`cog`) |
39
39
  |------|----------------|-----------------|
40
- | 包名 | `cognitive-modules` | `cognitive-modules-cli` |
40
+ | 包名 | `cognitive-modules` | `cogn` / `cognitive-modules-cli` |
41
41
  | 安装 | `pip install` | `npm install -g` |
42
- | 子代理 | ✅ `@call:module` | 暂不支持 |
43
- | MCP Server | ✅ | 暂不支持 |
44
- | HTTP Server | ✅ | 暂不支持 |
42
+ | 子代理 | ✅ `@call:module` | `@call:module` |
43
+ | MCP Server | ✅ | |
44
+ | HTTP Server | ✅ | |
45
+ | v2.2 Envelope | ✅ | ✅ |
45
46
 
46
- 两个版本共享相同的模块格式和 v2.2 规范。
47
+ 两个版本功能完全一致,共享相同的模块格式和 v2.2 规范。
48
+
49
+ **推荐使用 Node.js 版**:零安装快速体验 `npx cogn run ...`
47
50
 
48
51
  ## 支持的 Provider
49
52
 
@@ -61,14 +64,19 @@ echo "review this code" | cog pipe --module code-reviewer
61
64
  ## 命令
62
65
 
63
66
  ```bash
64
- cog list # 列出模块
67
+ # 模块操作
68
+ cog list # 列出模块
65
69
  cog run <module> --args "..." # 运行模块
66
- cog add <url> -m <module> # 从 GitHub 添加模块
67
- cog update <module> # 更新模块
68
- cog remove <module> # 删除模块
69
- cog versions <url> # 查看可用版本
70
- cog init <name> # 创建新模块
71
- cog pipe --module <name> # 管道模式
70
+ cog add <url> -m <module> # 从 GitHub 添加模块
71
+ cog update <module> # 更新模块
72
+ cog remove <module> # 删除模块
73
+ cog versions <url> # 查看可用版本
74
+ cog init <name> # 创建新模块
75
+ cog pipe --module <name> # 管道模式
76
+
77
+ # 服务器
78
+ cog serve --port 8000 # 启动 HTTP API 服务
79
+ cog mcp # 启动 MCP 服务(Claude Code / Cursor)
72
80
  ```
73
81
 
74
82
  ## 开发
package/dist/cli.js CHANGED
@@ -16,7 +16,7 @@
16
16
  import { parseArgs } from 'node:util';
17
17
  import { getProvider, listProviders } from './providers/index.js';
18
18
  import { run, list, pipe, init, add, update, remove, versions } from './commands/index.js';
19
- const VERSION = '1.0.1';
19
+ const VERSION = '1.3.0';
20
20
  async function main() {
21
21
  const args = process.argv.slice(2);
22
22
  const command = args[0];
@@ -45,6 +45,9 @@ async function main() {
45
45
  tag: { type: 'string', short: 't' },
46
46
  branch: { type: 'string', short: 'b' },
47
47
  limit: { type: 'string', short: 'l' },
48
+ // Server options
49
+ host: { type: 'string', short: 'H' },
50
+ port: { type: 'string', short: 'P' },
48
51
  },
49
52
  allowPositionals: true,
50
53
  });
@@ -249,6 +252,29 @@ async function main() {
249
252
  }
250
253
  break;
251
254
  }
255
+ case 'serve': {
256
+ const { serve } = await import('./server/http.js');
257
+ const port = values.port ? parseInt(values.port, 10) : 8000;
258
+ const host = values.host || '0.0.0.0';
259
+ console.log('Starting Cognitive Modules HTTP Server...');
260
+ await serve({ host, port, cwd: ctx.cwd });
261
+ break;
262
+ }
263
+ case 'mcp': {
264
+ try {
265
+ const { serve: serveMcp } = await import('./mcp/server.js');
266
+ await serveMcp();
267
+ }
268
+ catch (e) {
269
+ if (e instanceof Error && e.message.includes('Cannot find module')) {
270
+ console.error('MCP dependencies not installed.');
271
+ console.error('Install with: npm install @modelcontextprotocol/sdk');
272
+ process.exit(1);
273
+ }
274
+ throw e;
275
+ }
276
+ break;
277
+ }
252
278
  default:
253
279
  console.error(`Unknown command: ${command}`);
254
280
  console.error('Run "cog --help" for usage.');
@@ -280,6 +306,8 @@ COMMANDS:
280
306
  versions <url> List available versions
281
307
  pipe Pipe mode (stdin/stdout)
282
308
  init [name] Initialize project or create module
309
+ serve Start HTTP API server
310
+ mcp Start MCP server (for Claude Code, Cursor)
283
311
  doctor Check configuration
284
312
 
285
313
  OPTIONS:
@@ -294,6 +322,8 @@ OPTIONS:
294
322
  --pretty Pretty-print JSON output
295
323
  -V, --verbose Verbose output
296
324
  --no-validate Skip schema validation
325
+ -H, --host <host> Server host (default: 0.0.0.0)
326
+ -P, --port <port> Server port (default: 8000)
297
327
  -v, --version Show version
298
328
  -h, --help Show this help
299
329
 
@@ -312,6 +342,10 @@ EXAMPLES:
312
342
  cog run code-reviewer --provider openai --model gpt-4o --args "..."
313
343
  cog list
314
344
 
345
+ # Servers
346
+ cog serve --port 8080
347
+ cog mcp
348
+
315
349
  # Other
316
350
  echo "review this code" | cog pipe --module code-reviewer
317
351
  cog init my-module
@@ -0,0 +1,4 @@
1
+ /**
2
+ * MCP Server - Re-export all MCP functionality
3
+ */
4
+ export { serve } from './server.js';
@@ -0,0 +1,4 @@
1
+ /**
2
+ * MCP Server - Re-export all MCP functionality
3
+ */
4
+ export { serve } from './server.js';
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Cognitive Modules MCP Server
3
+ *
4
+ * Provides MCP (Model Context Protocol) interface for Claude Code, Cursor, etc.
5
+ *
6
+ * Start with:
7
+ * cog mcp
8
+ */
9
+ export declare function serve(): Promise<void>;
@@ -0,0 +1,344 @@
1
+ /**
2
+ * Cognitive Modules MCP Server
3
+ *
4
+ * Provides MCP (Model Context Protocol) interface for Claude Code, Cursor, etc.
5
+ *
6
+ * Start with:
7
+ * cog mcp
8
+ */
9
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
10
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
11
+ import { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
12
+ import { findModule, listModules, getDefaultSearchPaths } from '../modules/loader.js';
13
+ import { runModule } from '../modules/runner.js';
14
+ import { getProvider } from '../providers/index.js';
15
+ // =============================================================================
16
+ // Server Setup
17
+ // =============================================================================
18
+ const server = new Server({
19
+ name: 'cognitive-modules',
20
+ version: '1.2.0',
21
+ }, {
22
+ capabilities: {
23
+ tools: {},
24
+ resources: {},
25
+ prompts: {},
26
+ },
27
+ });
28
+ const cwd = process.cwd();
29
+ const searchPaths = getDefaultSearchPaths(cwd);
30
+ // =============================================================================
31
+ // Tools
32
+ // =============================================================================
33
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
34
+ return {
35
+ tools: [
36
+ {
37
+ name: 'cognitive_run',
38
+ description: 'Run a Cognitive Module to get structured AI analysis results',
39
+ inputSchema: {
40
+ type: 'object',
41
+ properties: {
42
+ module: {
43
+ type: 'string',
44
+ description: 'Module name, e.g. "code-reviewer", "task-prioritizer"',
45
+ },
46
+ args: {
47
+ type: 'string',
48
+ description: 'Input arguments, e.g. code snippet or task list',
49
+ },
50
+ provider: {
51
+ type: 'string',
52
+ description: 'LLM provider (optional), e.g. "openai", "anthropic"',
53
+ },
54
+ model: {
55
+ type: 'string',
56
+ description: 'Model name (optional), e.g. "gpt-4o", "claude-3-5-sonnet"',
57
+ },
58
+ },
59
+ required: ['module', 'args'],
60
+ },
61
+ },
62
+ {
63
+ name: 'cognitive_list',
64
+ description: 'List all installed Cognitive Modules',
65
+ inputSchema: {
66
+ type: 'object',
67
+ properties: {},
68
+ },
69
+ },
70
+ {
71
+ name: 'cognitive_info',
72
+ description: 'Get detailed information about a Cognitive Module',
73
+ inputSchema: {
74
+ type: 'object',
75
+ properties: {
76
+ module: {
77
+ type: 'string',
78
+ description: 'Module name',
79
+ },
80
+ },
81
+ required: ['module'],
82
+ },
83
+ },
84
+ ],
85
+ };
86
+ });
87
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
88
+ const { name, arguments: args } = request.params;
89
+ try {
90
+ switch (name) {
91
+ case 'cognitive_run': {
92
+ const { module: moduleName, args: inputArgs, provider: providerName, model } = args;
93
+ // Find module
94
+ const moduleData = await findModule(moduleName, searchPaths);
95
+ if (!moduleData) {
96
+ return {
97
+ content: [
98
+ {
99
+ type: 'text',
100
+ text: JSON.stringify({ ok: false, error: `Module '${moduleName}' not found` }),
101
+ },
102
+ ],
103
+ };
104
+ }
105
+ // Create provider
106
+ const provider = getProvider(providerName, model);
107
+ // Run module
108
+ const result = await runModule(moduleData, provider, {
109
+ input: { query: inputArgs, code: inputArgs },
110
+ useV22: true,
111
+ });
112
+ return {
113
+ content: [
114
+ {
115
+ type: 'text',
116
+ text: JSON.stringify(result, null, 2),
117
+ },
118
+ ],
119
+ };
120
+ }
121
+ case 'cognitive_list': {
122
+ const modules = await listModules(searchPaths);
123
+ return {
124
+ content: [
125
+ {
126
+ type: 'text',
127
+ text: JSON.stringify({
128
+ modules: modules.map((m) => ({
129
+ name: m.name,
130
+ location: m.location,
131
+ format: m.format,
132
+ tier: m.tier,
133
+ })),
134
+ count: modules.length,
135
+ }, null, 2),
136
+ },
137
+ ],
138
+ };
139
+ }
140
+ case 'cognitive_info': {
141
+ const { module: moduleName } = args;
142
+ const moduleData = await findModule(moduleName, searchPaths);
143
+ if (!moduleData) {
144
+ return {
145
+ content: [
146
+ {
147
+ type: 'text',
148
+ text: JSON.stringify({ ok: false, error: `Module '${moduleName}' not found` }),
149
+ },
150
+ ],
151
+ };
152
+ }
153
+ return {
154
+ content: [
155
+ {
156
+ type: 'text',
157
+ text: JSON.stringify({
158
+ ok: true,
159
+ name: moduleData.name,
160
+ version: moduleData.version,
161
+ responsibility: moduleData.responsibility,
162
+ tier: moduleData.tier,
163
+ format: moduleData.format,
164
+ inputSchema: moduleData.inputSchema,
165
+ outputSchema: moduleData.outputSchema,
166
+ }, null, 2),
167
+ },
168
+ ],
169
+ };
170
+ }
171
+ default:
172
+ return {
173
+ content: [
174
+ {
175
+ type: 'text',
176
+ text: JSON.stringify({ ok: false, error: `Unknown tool: ${name}` }),
177
+ },
178
+ ],
179
+ };
180
+ }
181
+ }
182
+ catch (error) {
183
+ return {
184
+ content: [
185
+ {
186
+ type: 'text',
187
+ text: JSON.stringify({
188
+ ok: false,
189
+ error: error instanceof Error ? error.message : String(error),
190
+ }),
191
+ },
192
+ ],
193
+ };
194
+ }
195
+ });
196
+ // =============================================================================
197
+ // Resources
198
+ // =============================================================================
199
+ server.setRequestHandler(ListResourcesRequestSchema, async () => {
200
+ const modules = await listModules(searchPaths);
201
+ return {
202
+ resources: [
203
+ {
204
+ uri: 'cognitive://modules',
205
+ name: 'All Modules',
206
+ description: 'List of all installed Cognitive Modules',
207
+ mimeType: 'application/json',
208
+ },
209
+ ...modules.map((m) => ({
210
+ uri: `cognitive://module/${m.name}`,
211
+ name: m.name,
212
+ description: m.responsibility || `Cognitive Module: ${m.name}`,
213
+ mimeType: 'text/markdown',
214
+ })),
215
+ ],
216
+ };
217
+ });
218
+ server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
219
+ const { uri } = request.params;
220
+ if (uri === 'cognitive://modules') {
221
+ const modules = await listModules(searchPaths);
222
+ return {
223
+ contents: [
224
+ {
225
+ uri,
226
+ mimeType: 'application/json',
227
+ text: JSON.stringify(modules.map((m) => m.name), null, 2),
228
+ },
229
+ ],
230
+ };
231
+ }
232
+ const match = uri.match(/^cognitive:\/\/module\/(.+)$/);
233
+ if (match) {
234
+ const moduleName = match[1];
235
+ const moduleData = await findModule(moduleName, searchPaths);
236
+ if (!moduleData) {
237
+ return {
238
+ contents: [
239
+ {
240
+ uri,
241
+ mimeType: 'text/plain',
242
+ text: `Module '${moduleName}' not found`,
243
+ },
244
+ ],
245
+ };
246
+ }
247
+ return {
248
+ contents: [
249
+ {
250
+ uri,
251
+ mimeType: 'text/markdown',
252
+ text: moduleData.prompt,
253
+ },
254
+ ],
255
+ };
256
+ }
257
+ return {
258
+ contents: [
259
+ {
260
+ uri,
261
+ mimeType: 'text/plain',
262
+ text: `Unknown resource: ${uri}`,
263
+ },
264
+ ],
265
+ };
266
+ });
267
+ // =============================================================================
268
+ // Prompts
269
+ // =============================================================================
270
+ server.setRequestHandler(ListPromptsRequestSchema, async () => {
271
+ return {
272
+ prompts: [
273
+ {
274
+ name: 'code_review',
275
+ description: 'Generate a code review prompt',
276
+ arguments: [
277
+ {
278
+ name: 'code',
279
+ description: 'The code to review',
280
+ required: true,
281
+ },
282
+ ],
283
+ },
284
+ {
285
+ name: 'task_prioritize',
286
+ description: 'Generate a task prioritization prompt',
287
+ arguments: [
288
+ {
289
+ name: 'tasks',
290
+ description: 'The tasks to prioritize',
291
+ required: true,
292
+ },
293
+ ],
294
+ },
295
+ ],
296
+ };
297
+ });
298
+ server.setRequestHandler(GetPromptRequestSchema, async (request) => {
299
+ const { name, arguments: args } = request.params;
300
+ switch (name) {
301
+ case 'code_review': {
302
+ const code = args?.code ?? '';
303
+ return {
304
+ messages: [
305
+ {
306
+ role: 'user',
307
+ content: {
308
+ type: 'text',
309
+ text: `Please use the cognitive_run tool to review the following code:\n\n\`\`\`\n${code}\n\`\`\`\n\nCall: cognitive_run("code-reviewer", "${code.slice(0, 100)}...")`,
310
+ },
311
+ },
312
+ ],
313
+ };
314
+ }
315
+ case 'task_prioritize': {
316
+ const tasks = args?.tasks ?? '';
317
+ return {
318
+ messages: [
319
+ {
320
+ role: 'user',
321
+ content: {
322
+ type: 'text',
323
+ text: `Please use the cognitive_run tool to prioritize the following tasks:\n\n${tasks}\n\nCall: cognitive_run("task-prioritizer", "${tasks}")`,
324
+ },
325
+ },
326
+ ],
327
+ };
328
+ }
329
+ default:
330
+ throw new Error(`Unknown prompt: ${name}`);
331
+ }
332
+ });
333
+ // =============================================================================
334
+ // Server Start
335
+ // =============================================================================
336
+ export async function serve() {
337
+ const transport = new StdioServerTransport();
338
+ await server.connect(transport);
339
+ console.error('Cognitive Modules MCP Server started');
340
+ }
341
+ // Allow running directly
342
+ if (import.meta.url === `file://${process.argv[1]}`) {
343
+ serve().catch(console.error);
344
+ }
@@ -3,3 +3,4 @@
3
3
  */
4
4
  export * from './loader.js';
5
5
  export * from './runner.js';
6
+ export * from './subagent.js';
@@ -3,3 +3,4 @@
3
3
  */
4
4
  export * from './loader.js';
5
5
  export * from './runner.js';
6
+ export * from './subagent.js';
@@ -103,11 +103,16 @@ async function loadModuleV2(modulePath) {
103
103
  runtime_auto_wrap: compatRaw.runtime_auto_wrap ?? true,
104
104
  schema_output_alias: compatRaw.schema_output_alias ?? 'data'
105
105
  };
106
- // Parse meta config (including risk_rule)
106
+ // Parse meta config (including risk_rule) with validation
107
107
  const metaRaw = manifest.meta || {};
108
+ const rawRiskRule = metaRaw.risk_rule;
109
+ const validRiskRules = ['max_changes_risk', 'max_issues_risk', 'explicit'];
110
+ const validatedRiskRule = rawRiskRule && validRiskRules.includes(rawRiskRule)
111
+ ? rawRiskRule
112
+ : undefined;
108
113
  const metaConfig = {
109
114
  required: metaRaw.required,
110
- risk_rule: metaRaw.risk_rule,
115
+ risk_rule: validatedRiskRule,
111
116
  };
112
117
  return {
113
118
  name: manifest.name || path.basename(modulePath),
@@ -34,9 +34,14 @@ function repairEnvelope(response, riskRule = 'max_changes_risk', maxExplainLengt
34
34
  if (!meta.risk) {
35
35
  meta.risk = aggregateRisk(data, riskRule);
36
36
  }
37
- // Trim whitespace only (lossless), do NOT invent new values
37
+ // Trim whitespace only (lossless), validate is valid RiskLevel
38
38
  if (typeof meta.risk === 'string') {
39
- meta.risk = meta.risk.trim().toLowerCase();
39
+ const trimmedRisk = meta.risk.trim().toLowerCase();
40
+ const validRisks = ['none', 'low', 'medium', 'high'];
41
+ meta.risk = validRisks.includes(trimmedRisk) ? trimmedRisk : 'medium';
42
+ }
43
+ else {
44
+ meta.risk = 'medium'; // Default for invalid type
40
45
  }
41
46
  // Repair explain
42
47
  if (typeof meta.explain !== 'string') {
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Subagent - Orchestrate module calls with isolated execution contexts.
3
+ *
4
+ * Supports:
5
+ * - @call:module-name - Call another module
6
+ * - @call:module-name(args) - Call with arguments
7
+ * - context: fork - Isolated execution (no shared state)
8
+ * - context: main - Shared execution (default)
9
+ */
10
+ import type { ModuleResult, ModuleInput, Provider } from '../types.js';
11
+ export interface SubagentContext {
12
+ parentId: string | null;
13
+ depth: number;
14
+ maxDepth: number;
15
+ results: Record<string, unknown>;
16
+ isolated: boolean;
17
+ }
18
+ export interface CallDirective {
19
+ module: string;
20
+ args: string;
21
+ match: string;
22
+ }
23
+ export interface SubagentRunOptions {
24
+ input?: ModuleInput;
25
+ validateInput?: boolean;
26
+ validateOutput?: boolean;
27
+ maxDepth?: number;
28
+ }
29
+ /**
30
+ * Create a new root context
31
+ */
32
+ export declare function createContext(maxDepth?: number): SubagentContext;
33
+ /**
34
+ * Fork context (isolated - no inherited results)
35
+ */
36
+ export declare function forkContext(ctx: SubagentContext, moduleName: string): SubagentContext;
37
+ /**
38
+ * Extend context (shared - inherits results)
39
+ */
40
+ export declare function extendContext(ctx: SubagentContext, moduleName: string): SubagentContext;
41
+ /**
42
+ * Parse @call directives from text
43
+ */
44
+ export declare function parseCalls(text: string): CallDirective[];
45
+ /**
46
+ * Replace @call directives with their results
47
+ */
48
+ export declare function substituteCallResults(text: string, callResults: Record<string, unknown>): string;
49
+ export declare class SubagentOrchestrator {
50
+ private provider;
51
+ private running;
52
+ private cwd;
53
+ constructor(provider: Provider, cwd?: string);
54
+ /**
55
+ * Run a module with subagent support.
56
+ * Recursively resolves @call directives before final execution.
57
+ */
58
+ run(moduleName: string, options?: SubagentRunOptions, context?: SubagentContext): Promise<ModuleResult>;
59
+ }
60
+ /**
61
+ * Convenience function to run a module with subagent support
62
+ */
63
+ export declare function runWithSubagents(moduleName: string, provider: Provider, options?: SubagentRunOptions & {
64
+ cwd?: string;
65
+ }): Promise<ModuleResult>;