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
package/src/providers/openai.ts
DELETED
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* OpenAI Provider - OpenAI API (and compatible APIs)
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { BaseProvider } from './base.js';
|
|
6
|
-
import type { InvokeParams, InvokeResult } from '../types.js';
|
|
7
|
-
|
|
8
|
-
export class OpenAIProvider extends BaseProvider {
|
|
9
|
-
name = 'openai';
|
|
10
|
-
private apiKey: string;
|
|
11
|
-
private model: string;
|
|
12
|
-
private baseUrl: string;
|
|
13
|
-
|
|
14
|
-
constructor(apiKey?: string, model = 'gpt-5.2', baseUrl = 'https://api.openai.com/v1') {
|
|
15
|
-
super();
|
|
16
|
-
this.apiKey = apiKey || process.env.OPENAI_API_KEY || '';
|
|
17
|
-
this.model = model;
|
|
18
|
-
this.baseUrl = baseUrl;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
isConfigured(): boolean {
|
|
22
|
-
return !!this.apiKey;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
async invoke(params: InvokeParams): Promise<InvokeResult> {
|
|
26
|
-
if (!this.isConfigured()) {
|
|
27
|
-
throw new Error('OpenAI API key not configured. Set OPENAI_API_KEY environment variable.');
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const url = `${this.baseUrl}/chat/completions`;
|
|
31
|
-
|
|
32
|
-
const body: Record<string, unknown> = {
|
|
33
|
-
model: this.model,
|
|
34
|
-
messages: params.messages,
|
|
35
|
-
temperature: params.temperature ?? 0.7,
|
|
36
|
-
max_tokens: params.maxTokens ?? 4096,
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
// Add JSON mode if schema provided
|
|
40
|
-
if (params.jsonSchema) {
|
|
41
|
-
body.response_format = { type: 'json_object' };
|
|
42
|
-
// Append schema instruction to last user message
|
|
43
|
-
const lastUserIdx = params.messages.findLastIndex(m => m.role === 'user');
|
|
44
|
-
if (lastUserIdx >= 0) {
|
|
45
|
-
const messages = [...params.messages];
|
|
46
|
-
messages[lastUserIdx] = {
|
|
47
|
-
...messages[lastUserIdx],
|
|
48
|
-
content: messages[lastUserIdx].content + this.buildJsonPrompt(params.jsonSchema),
|
|
49
|
-
};
|
|
50
|
-
body.messages = messages;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const response = await fetch(url, {
|
|
55
|
-
method: 'POST',
|
|
56
|
-
headers: {
|
|
57
|
-
'Content-Type': 'application/json',
|
|
58
|
-
'Authorization': `Bearer ${this.apiKey}`,
|
|
59
|
-
},
|
|
60
|
-
body: JSON.stringify(body),
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
if (!response.ok) {
|
|
64
|
-
const error = await response.text();
|
|
65
|
-
throw new Error(`OpenAI API error: ${response.status} - ${error}`);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
const data = await response.json() as {
|
|
69
|
-
choices?: Array<{ message?: { content?: string } }>;
|
|
70
|
-
usage?: { prompt_tokens?: number; completion_tokens?: number; total_tokens?: number };
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
const content = data.choices?.[0]?.message?.content || '';
|
|
74
|
-
|
|
75
|
-
return {
|
|
76
|
-
content,
|
|
77
|
-
usage: data.usage ? {
|
|
78
|
-
promptTokens: data.usage.prompt_tokens || 0,
|
|
79
|
-
completionTokens: data.usage.completion_tokens || 0,
|
|
80
|
-
totalTokens: data.usage.total_tokens || 0,
|
|
81
|
-
} : undefined,
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
}
|
package/src/providers/qwen.ts
DELETED
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Qwen Provider - Alibaba Tongyi Qianwen (通义千问) via DashScope API
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { BaseProvider } from './base.js';
|
|
6
|
-
import type { InvokeParams, InvokeResult } from '../types.js';
|
|
7
|
-
|
|
8
|
-
export class QwenProvider extends BaseProvider {
|
|
9
|
-
name = 'qwen';
|
|
10
|
-
private apiKey: string;
|
|
11
|
-
private model: string;
|
|
12
|
-
private baseUrl = 'https://dashscope.aliyuncs.com/compatible-mode/v1';
|
|
13
|
-
|
|
14
|
-
constructor(apiKey?: string, model = 'qwen3-max') {
|
|
15
|
-
super();
|
|
16
|
-
this.apiKey = apiKey || process.env.DASHSCOPE_API_KEY || process.env.QWEN_API_KEY || '';
|
|
17
|
-
this.model = model;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
isConfigured(): boolean {
|
|
21
|
-
return !!this.apiKey;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
async invoke(params: InvokeParams): Promise<InvokeResult> {
|
|
25
|
-
if (!this.isConfigured()) {
|
|
26
|
-
throw new Error('Qwen API key not configured. Set DASHSCOPE_API_KEY or QWEN_API_KEY environment variable.');
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const url = `${this.baseUrl}/chat/completions`;
|
|
30
|
-
|
|
31
|
-
const body: Record<string, unknown> = {
|
|
32
|
-
model: this.model,
|
|
33
|
-
messages: params.messages.map(m => ({ role: m.role, content: m.content })),
|
|
34
|
-
temperature: params.temperature ?? 0.7,
|
|
35
|
-
max_tokens: params.maxTokens ?? 4096,
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
// Add JSON mode if schema provided
|
|
39
|
-
if (params.jsonSchema) {
|
|
40
|
-
body.response_format = { type: 'json_object' };
|
|
41
|
-
const lastUserIdx = params.messages.findLastIndex(m => m.role === 'user');
|
|
42
|
-
if (lastUserIdx >= 0) {
|
|
43
|
-
const messages = [...params.messages];
|
|
44
|
-
messages[lastUserIdx] = {
|
|
45
|
-
...messages[lastUserIdx],
|
|
46
|
-
content: messages[lastUserIdx].content + this.buildJsonPrompt(params.jsonSchema),
|
|
47
|
-
};
|
|
48
|
-
body.messages = messages.map(m => ({ role: m.role, content: m.content }));
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const response = await fetch(url, {
|
|
53
|
-
method: 'POST',
|
|
54
|
-
headers: {
|
|
55
|
-
'Content-Type': 'application/json',
|
|
56
|
-
'Authorization': `Bearer ${this.apiKey}`,
|
|
57
|
-
},
|
|
58
|
-
body: JSON.stringify(body),
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
if (!response.ok) {
|
|
62
|
-
const error = await response.text();
|
|
63
|
-
throw new Error(`Qwen API error: ${response.status} - ${error}`);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const data = await response.json() as {
|
|
67
|
-
choices?: Array<{ message?: { content?: string } }>;
|
|
68
|
-
usage?: { prompt_tokens?: number; completion_tokens?: number; total_tokens?: number };
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
const content = data.choices?.[0]?.message?.content || '';
|
|
72
|
-
|
|
73
|
-
return {
|
|
74
|
-
content,
|
|
75
|
-
usage: data.usage ? {
|
|
76
|
-
promptTokens: data.usage.prompt_tokens || 0,
|
|
77
|
-
completionTokens: data.usage.completion_tokens || 0,
|
|
78
|
-
totalTokens: data.usage.total_tokens || 0,
|
|
79
|
-
} : undefined,
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
}
|
package/src/server/http.ts
DELETED
|
@@ -1,316 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Cognitive Modules HTTP API Server
|
|
3
|
-
*
|
|
4
|
-
* Provides RESTful API interface for workflow platform integration.
|
|
5
|
-
*
|
|
6
|
-
* Start with:
|
|
7
|
-
* cog serve --port 8000
|
|
8
|
-
*
|
|
9
|
-
* Environment variables:
|
|
10
|
-
* COGNITIVE_API_KEY - API Key authentication (optional)
|
|
11
|
-
* OPENAI_API_KEY, ANTHROPIC_API_KEY, etc. - LLM provider keys
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
import http from 'node:http';
|
|
15
|
-
import { URL } from 'node:url';
|
|
16
|
-
import { loadModule, findModule, listModules, getDefaultSearchPaths } from '../modules/loader.js';
|
|
17
|
-
import { runModule } from '../modules/runner.js';
|
|
18
|
-
import { getProvider } from '../providers/index.js';
|
|
19
|
-
import type { CognitiveModule, Provider } from '../types.js';
|
|
20
|
-
|
|
21
|
-
// =============================================================================
|
|
22
|
-
// Types
|
|
23
|
-
// =============================================================================
|
|
24
|
-
|
|
25
|
-
interface RunRequest {
|
|
26
|
-
module: string;
|
|
27
|
-
args: string;
|
|
28
|
-
provider?: string;
|
|
29
|
-
model?: string;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
interface RunResponse {
|
|
33
|
-
ok: boolean;
|
|
34
|
-
data?: unknown;
|
|
35
|
-
meta?: unknown;
|
|
36
|
-
error?: string;
|
|
37
|
-
module: string;
|
|
38
|
-
provider?: string;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
interface ModuleInfo {
|
|
42
|
-
name: string;
|
|
43
|
-
version?: string;
|
|
44
|
-
description?: string;
|
|
45
|
-
format: string;
|
|
46
|
-
path: string;
|
|
47
|
-
responsibility?: string;
|
|
48
|
-
tier?: string;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// =============================================================================
|
|
52
|
-
// Helpers
|
|
53
|
-
// =============================================================================
|
|
54
|
-
|
|
55
|
-
function jsonResponse(res: http.ServerResponse, status: number, data: unknown): void {
|
|
56
|
-
res.writeHead(status, {
|
|
57
|
-
'Content-Type': 'application/json',
|
|
58
|
-
'Access-Control-Allow-Origin': '*',
|
|
59
|
-
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
|
|
60
|
-
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
|
|
61
|
-
});
|
|
62
|
-
res.end(JSON.stringify(data, null, 2));
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
function parseBody(req: http.IncomingMessage): Promise<string> {
|
|
66
|
-
return new Promise((resolve, reject) => {
|
|
67
|
-
let body = '';
|
|
68
|
-
req.on('data', (chunk) => (body += chunk));
|
|
69
|
-
req.on('end', () => resolve(body));
|
|
70
|
-
req.on('error', reject);
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
function verifyApiKey(req: http.IncomingMessage): boolean {
|
|
75
|
-
const expectedKey = process.env.COGNITIVE_API_KEY;
|
|
76
|
-
if (!expectedKey) return true; // No auth required
|
|
77
|
-
|
|
78
|
-
const authHeader = req.headers.authorization;
|
|
79
|
-
if (!authHeader) return false;
|
|
80
|
-
|
|
81
|
-
const token = authHeader.startsWith('Bearer ') ? authHeader.slice(7) : authHeader;
|
|
82
|
-
return token === expectedKey;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// =============================================================================
|
|
86
|
-
// Request Handlers
|
|
87
|
-
// =============================================================================
|
|
88
|
-
|
|
89
|
-
async function handleRoot(res: http.ServerResponse): Promise<void> {
|
|
90
|
-
jsonResponse(res, 200, {
|
|
91
|
-
name: 'Cognitive Modules API',
|
|
92
|
-
version: '1.3.0',
|
|
93
|
-
docs: '/docs',
|
|
94
|
-
endpoints: {
|
|
95
|
-
run: 'POST /run',
|
|
96
|
-
modules: 'GET /modules',
|
|
97
|
-
module_info: 'GET /modules/{name}',
|
|
98
|
-
health: 'GET /health',
|
|
99
|
-
},
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
async function handleHealth(res: http.ServerResponse): Promise<void> {
|
|
104
|
-
const providers = {
|
|
105
|
-
openai: Boolean(process.env.OPENAI_API_KEY),
|
|
106
|
-
anthropic: Boolean(process.env.ANTHROPIC_API_KEY),
|
|
107
|
-
minimax: Boolean(process.env.MINIMAX_API_KEY),
|
|
108
|
-
deepseek: Boolean(process.env.DEEPSEEK_API_KEY),
|
|
109
|
-
gemini: Boolean(process.env.GEMINI_API_KEY || process.env.GOOGLE_API_KEY),
|
|
110
|
-
qwen: Boolean(process.env.QWEN_API_KEY || process.env.DASHSCOPE_API_KEY),
|
|
111
|
-
};
|
|
112
|
-
|
|
113
|
-
jsonResponse(res, 200, {
|
|
114
|
-
status: 'healthy',
|
|
115
|
-
version: '1.3.0',
|
|
116
|
-
providers,
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
async function handleModules(
|
|
121
|
-
res: http.ServerResponse,
|
|
122
|
-
searchPaths: string[]
|
|
123
|
-
): Promise<void> {
|
|
124
|
-
const modules = await listModules(searchPaths);
|
|
125
|
-
|
|
126
|
-
const moduleInfos: ModuleInfo[] = modules.map((m) => ({
|
|
127
|
-
name: m.name,
|
|
128
|
-
version: m.version,
|
|
129
|
-
description: m.responsibility,
|
|
130
|
-
format: m.format,
|
|
131
|
-
path: m.location,
|
|
132
|
-
responsibility: m.responsibility,
|
|
133
|
-
tier: m.tier,
|
|
134
|
-
}));
|
|
135
|
-
|
|
136
|
-
jsonResponse(res, 200, {
|
|
137
|
-
modules: moduleInfos,
|
|
138
|
-
count: moduleInfos.length,
|
|
139
|
-
});
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
async function handleModuleInfo(
|
|
143
|
-
res: http.ServerResponse,
|
|
144
|
-
moduleName: string,
|
|
145
|
-
searchPaths: string[]
|
|
146
|
-
): Promise<void> {
|
|
147
|
-
const moduleData = await findModule(moduleName, searchPaths);
|
|
148
|
-
|
|
149
|
-
if (!moduleData) {
|
|
150
|
-
jsonResponse(res, 404, { error: `Module '${moduleName}' not found` });
|
|
151
|
-
return;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
jsonResponse(res, 200, {
|
|
155
|
-
name: moduleData.name,
|
|
156
|
-
version: moduleData.version,
|
|
157
|
-
description: moduleData.responsibility,
|
|
158
|
-
format: moduleData.format,
|
|
159
|
-
path: moduleData.location,
|
|
160
|
-
responsibility: moduleData.responsibility,
|
|
161
|
-
tier: moduleData.tier,
|
|
162
|
-
inputSchema: moduleData.inputSchema,
|
|
163
|
-
outputSchema: moduleData.outputSchema,
|
|
164
|
-
});
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
async function handleRun(
|
|
168
|
-
req: http.IncomingMessage,
|
|
169
|
-
res: http.ServerResponse,
|
|
170
|
-
searchPaths: string[]
|
|
171
|
-
): Promise<void> {
|
|
172
|
-
// Verify API key
|
|
173
|
-
if (!verifyApiKey(req)) {
|
|
174
|
-
jsonResponse(res, 401, {
|
|
175
|
-
error: 'Missing or invalid API Key. Use header: Authorization: Bearer <your-api-key>',
|
|
176
|
-
});
|
|
177
|
-
return;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
// Parse request body
|
|
181
|
-
let request: RunRequest;
|
|
182
|
-
try {
|
|
183
|
-
const body = await parseBody(req);
|
|
184
|
-
request = JSON.parse(body);
|
|
185
|
-
} catch {
|
|
186
|
-
jsonResponse(res, 400, { error: 'Invalid JSON body' });
|
|
187
|
-
return;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// Validate request
|
|
191
|
-
if (!request.module || !request.args) {
|
|
192
|
-
jsonResponse(res, 400, { error: 'Missing required fields: module, args' });
|
|
193
|
-
return;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
// Find module
|
|
197
|
-
const moduleData = await findModule(request.module, searchPaths);
|
|
198
|
-
if (!moduleData) {
|
|
199
|
-
jsonResponse(res, 404, { error: `Module '${request.module}' not found` });
|
|
200
|
-
return;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
try {
|
|
204
|
-
// Create provider
|
|
205
|
-
const provider = getProvider(request.provider, request.model);
|
|
206
|
-
|
|
207
|
-
// Run module
|
|
208
|
-
const result = await runModule(moduleData, provider, {
|
|
209
|
-
input: { query: request.args, code: request.args },
|
|
210
|
-
useV22: true,
|
|
211
|
-
});
|
|
212
|
-
|
|
213
|
-
const response: RunResponse = {
|
|
214
|
-
ok: result.ok,
|
|
215
|
-
module: request.module,
|
|
216
|
-
provider: request.provider || process.env.LLM_PROVIDER || 'openai',
|
|
217
|
-
};
|
|
218
|
-
|
|
219
|
-
if (result.ok) {
|
|
220
|
-
if ('meta' in result) response.meta = result.meta;
|
|
221
|
-
if ('data' in result) response.data = result.data;
|
|
222
|
-
} else {
|
|
223
|
-
if ('error' in result) response.error = result.error?.message;
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
jsonResponse(res, 200, response);
|
|
227
|
-
} catch (error) {
|
|
228
|
-
jsonResponse(res, 500, {
|
|
229
|
-
ok: false,
|
|
230
|
-
error: error instanceof Error ? error.message : String(error),
|
|
231
|
-
module: request.module,
|
|
232
|
-
});
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
// =============================================================================
|
|
237
|
-
// Server
|
|
238
|
-
// =============================================================================
|
|
239
|
-
|
|
240
|
-
export interface ServeOptions {
|
|
241
|
-
host?: string;
|
|
242
|
-
port?: number;
|
|
243
|
-
cwd?: string;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
export function createServer(options: ServeOptions = {}): http.Server {
|
|
247
|
-
const { cwd = process.cwd() } = options;
|
|
248
|
-
const searchPaths = getDefaultSearchPaths(cwd);
|
|
249
|
-
|
|
250
|
-
const server = http.createServer(async (req, res) => {
|
|
251
|
-
const url = new URL(req.url || '/', `http://${req.headers.host}`);
|
|
252
|
-
const path = url.pathname;
|
|
253
|
-
const method = req.method?.toUpperCase();
|
|
254
|
-
|
|
255
|
-
// Handle CORS preflight
|
|
256
|
-
if (method === 'OPTIONS') {
|
|
257
|
-
res.writeHead(204, {
|
|
258
|
-
'Access-Control-Allow-Origin': '*',
|
|
259
|
-
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
|
|
260
|
-
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
|
|
261
|
-
});
|
|
262
|
-
res.end();
|
|
263
|
-
return;
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
try {
|
|
267
|
-
// Route requests
|
|
268
|
-
if (path === '/' && method === 'GET') {
|
|
269
|
-
await handleRoot(res);
|
|
270
|
-
} else if (path === '/health' && method === 'GET') {
|
|
271
|
-
await handleHealth(res);
|
|
272
|
-
} else if (path === '/modules' && method === 'GET') {
|
|
273
|
-
await handleModules(res, searchPaths);
|
|
274
|
-
} else if (path.startsWith('/modules/') && method === 'GET') {
|
|
275
|
-
const moduleName = path.slice('/modules/'.length);
|
|
276
|
-
await handleModuleInfo(res, moduleName, searchPaths);
|
|
277
|
-
} else if (path === '/run' && method === 'POST') {
|
|
278
|
-
await handleRun(req, res, searchPaths);
|
|
279
|
-
} else {
|
|
280
|
-
jsonResponse(res, 404, { error: 'Not found' });
|
|
281
|
-
}
|
|
282
|
-
} catch (error) {
|
|
283
|
-
console.error('Server error:', error);
|
|
284
|
-
jsonResponse(res, 500, {
|
|
285
|
-
error: error instanceof Error ? error.message : 'Internal server error',
|
|
286
|
-
});
|
|
287
|
-
}
|
|
288
|
-
});
|
|
289
|
-
|
|
290
|
-
return server;
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
export async function serve(options: ServeOptions = {}): Promise<void> {
|
|
294
|
-
const { host = '0.0.0.0', port = 8000 } = options;
|
|
295
|
-
|
|
296
|
-
const server = createServer(options);
|
|
297
|
-
|
|
298
|
-
return new Promise((resolve, reject) => {
|
|
299
|
-
server.on('error', reject);
|
|
300
|
-
server.listen(port, host, () => {
|
|
301
|
-
console.log(`Cognitive Modules HTTP Server running at http://${host}:${port}`);
|
|
302
|
-
console.log('Endpoints:');
|
|
303
|
-
console.log(' GET / - API info');
|
|
304
|
-
console.log(' GET /health - Health check');
|
|
305
|
-
console.log(' GET /modules - List modules');
|
|
306
|
-
console.log(' GET /modules/:name - Module info');
|
|
307
|
-
console.log(' POST /run - Run module');
|
|
308
|
-
resolve();
|
|
309
|
-
});
|
|
310
|
-
});
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
// Allow running directly
|
|
314
|
-
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
315
|
-
serve().catch(console.error);
|
|
316
|
-
}
|