@crewx/sdk 0.8.0-rc.78 → 0.8.0-rc.80
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/plugin/plugin-provider.js +1 -1
- package/dist/provider/bridge.js +1 -0
- package/package.json +1 -1
- package/dist/esm/agent/resolver.js +0 -41
- package/dist/esm/boxing/box-storage.interface.js +0 -5
- package/dist/esm/boxing/box.service.js +0 -69
- package/dist/esm/boxing/box.types.js +0 -5
- package/dist/esm/boxing/context-builder.js +0 -76
- package/dist/esm/client/CrewxClient.js +0 -82
- package/dist/esm/client/index.js +0 -2
- package/dist/esm/config/loader.browser.js +0 -54
- package/dist/esm/config/loader.js +0 -77
- package/dist/esm/events/TypedEventEmitter.js +0 -61
- package/dist/esm/events/types.js +0 -8
- package/dist/esm/facade/Crewx.browser.js +0 -310
- package/dist/esm/facade/Crewx.js +0 -941
- package/dist/esm/hooks/define.js +0 -10
- package/dist/esm/hooks/dispatch.js +0 -76
- package/dist/esm/hooks/index.js +0 -6
- package/dist/esm/hooks/observer.js +0 -56
- package/dist/esm/hooks/plugin.js +0 -12
- package/dist/esm/hooks/types.js +0 -9
- package/dist/esm/index.browser.js +0 -15
- package/dist/esm/index.js +0 -60
- package/dist/esm/layout/loader.js +0 -268
- package/dist/esm/layout/props-validator.js +0 -297
- package/dist/esm/layout/renderer.js +0 -180
- package/dist/esm/layout/types.js +0 -31
- package/dist/esm/parallel/agent-runtime.js +0 -21
- package/dist/esm/parallel/helpers.js +0 -214
- package/dist/esm/parallel/index.js +0 -5
- package/dist/esm/parallel/parallel-runner.js +0 -221
- package/dist/esm/parallel/types.js +0 -5
- package/dist/esm/parsers/agent-call.util.js +0 -15
- package/dist/esm/parsers/claude.parser.js +0 -64
- package/dist/esm/parsers/codex.parser.js +0 -97
- package/dist/esm/parsers/copilot.parser.js +0 -63
- package/dist/esm/parsers/gemini.parser.js +0 -43
- package/dist/esm/parsers/opencode.parser.js +0 -73
- package/dist/esm/parsers/router.js +0 -53
- package/dist/esm/platform/BrowserFsAdapter.js +0 -80
- package/dist/esm/platform/IFsAdapter.js +0 -2
- package/dist/esm/platform/NodeFsAdapter.js +0 -34
- package/dist/esm/plugin/plugin-provider.js +0 -202
- package/dist/esm/plugin/types.js +0 -8
- package/dist/esm/plugin.js +0 -25
- package/dist/esm/provider/bridge.browser.js +0 -43
- package/dist/esm/provider/bridge.js +0 -373
- package/dist/esm/provider/parse-usage.js +0 -80
- package/dist/esm/provider/register-api.js +0 -21
- package/dist/esm/provider/vercel-runtime.js +0 -310
- package/dist/esm/remote/index.js +0 -10
- package/dist/esm/remote/remote-agent-manager.js +0 -194
- package/dist/esm/remote/remote-provider.js +0 -98
- package/dist/esm/remote/remote-transport.js +0 -79
- package/dist/esm/remote/types.js +0 -8
- package/dist/esm/server/auth.js +0 -31
- package/dist/esm/server/handler.js +0 -72
- package/dist/esm/server/index.js +0 -5
- package/dist/esm/server/tool-adapter.js +0 -92
- package/dist/esm/template/engine.js +0 -100
- package/dist/esm/template/helpers/exec.browser.js +0 -31
- package/dist/esm/template/helpers/exec.js +0 -220
- package/dist/esm/template/helpers/fenced_code.js +0 -17
- package/dist/esm/template/helpers/include.js +0 -20
- package/dist/esm/template/helpers/p1p2.js +0 -83
- package/dist/esm/template/loader/DocumentLoader.js +0 -124
- package/dist/esm/template/types.js +0 -5
- package/dist/esm/tools/delegate.js +0 -57
- package/dist/esm/tools/index.js +0 -5
- package/dist/esm/tools/node/builtin.js +0 -541
- package/dist/esm/tools/node/index.js +0 -54
- package/dist/esm/types/index.js +0 -27
- package/dist/esm/types/task-log.types.js +0 -5
- package/dist/esm/utils/env-defaults.js +0 -23
- package/dist/esm/utils/glob-match.js +0 -38
- package/dist/esm/utils/id.js +0 -46
- package/dist/esm/utils/workspace.js +0 -21
- package/dist/parsers/api.parser.d.ts +0 -10
- package/dist/parsers/api.parser.js +0 -26
- package/dist/provider/mastra-runtime.d.ts +0 -45
- package/dist/provider/mastra-runtime.js +0 -208
|
@@ -60,7 +60,7 @@ class PluginProviderRuntime {
|
|
|
60
60
|
};
|
|
61
61
|
const proc = (0, child_process_1.spawn)(this.config.cli_command, args, {
|
|
62
62
|
env: mergedEnv,
|
|
63
|
-
shell:
|
|
63
|
+
shell: process.platform === 'win32', // Windows: .cmd/.bat requires shell
|
|
64
64
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
65
65
|
});
|
|
66
66
|
// Write prompt to stdin when prompt_in_args is false
|
package/dist/provider/bridge.js
CHANGED
|
@@ -200,6 +200,7 @@ class CliProviderRuntime {
|
|
|
200
200
|
env: { ...process.env, ...(options?.env ?? {}) },
|
|
201
201
|
cwd: options?.cwd,
|
|
202
202
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
203
|
+
shell: process.platform === 'win32',
|
|
203
204
|
});
|
|
204
205
|
// Write message to stdin for providers that read prompt from stdin (e.g. codex)
|
|
205
206
|
// Always close stdin afterwards — some CLIs (e.g. opencode) hang waiting for
|
package/package.json
CHANGED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Agent resolver: looks up an agent from a list by ref.
|
|
3
|
-
* Supports both bare id ('claude') and @mention format ('@claude').
|
|
4
|
-
* Falls back to built-in provider shorthands (claude, gemini, copilot, codex).
|
|
5
|
-
*/
|
|
6
|
-
export class AgentNotFoundError extends Error {
|
|
7
|
-
constructor(agentRef, availableIds) {
|
|
8
|
-
const available = availableIds.length > 0
|
|
9
|
-
? ` Available: ${availableIds.join(', ')}`
|
|
10
|
-
: '';
|
|
11
|
-
super(`Agent not found: "${agentRef}".${available}`);
|
|
12
|
-
this.name = 'AgentNotFoundError';
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
/** Built-in provider shorthands that can be used without a crewx.yaml entry. */
|
|
16
|
-
const BUILTIN_PROVIDERS = {
|
|
17
|
-
claude: { id: 'claude', provider: 'cli/claude' },
|
|
18
|
-
gemini: { id: 'gemini', provider: 'cli/gemini' },
|
|
19
|
-
copilot: { id: 'copilot', provider: 'cli/copilot' },
|
|
20
|
-
codex: { id: 'codex', provider: 'cli/codex' },
|
|
21
|
-
};
|
|
22
|
-
/**
|
|
23
|
-
* Resolve an agent by reference.
|
|
24
|
-
* @param agentRef - Agent reference: '@claude', 'claude', '@my_agent', etc.
|
|
25
|
-
* @param agents - List of available agent configs.
|
|
26
|
-
* @returns The matching AgentConfig.
|
|
27
|
-
* @throws AgentNotFoundError when no match is found.
|
|
28
|
-
*/
|
|
29
|
-
export function resolveAgent(agentRef, agents) {
|
|
30
|
-
const agentId = agentRef.startsWith('@') ? agentRef.slice(1) : agentRef;
|
|
31
|
-
// 1. Look in YAML-defined agents first
|
|
32
|
-
const agent = agents.find(a => a.id === agentId);
|
|
33
|
-
if (agent)
|
|
34
|
-
return agent;
|
|
35
|
-
// 2. Fall back to built-in provider shorthands
|
|
36
|
-
const builtin = BUILTIN_PROVIDERS[agentId];
|
|
37
|
-
if (builtin)
|
|
38
|
-
return builtin;
|
|
39
|
-
throw new AgentNotFoundError(agentRef, agents.map(a => a.id));
|
|
40
|
-
}
|
|
41
|
-
//# sourceMappingURL=resolver.js.map
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* SdkBoxService — manages box creation, retrieval, and listing.
|
|
3
|
-
*/
|
|
4
|
-
import { generateId } from '../utils/id';
|
|
5
|
-
const ID_PATTERN = /^[a-zA-Z0-9._-]+$/;
|
|
6
|
-
export class SdkBoxService {
|
|
7
|
-
storage;
|
|
8
|
-
constructor(storage) {
|
|
9
|
-
this.storage = storage;
|
|
10
|
-
}
|
|
11
|
-
listBoxes(threadId) {
|
|
12
|
-
this.validateId(threadId);
|
|
13
|
-
const rows = this.storage.listBoxes(threadId);
|
|
14
|
-
const boxes = rows.map((row) => this.toBoxResponse(row));
|
|
15
|
-
return { boxes, total: boxes.length };
|
|
16
|
-
}
|
|
17
|
-
getBox(threadId, boxId) {
|
|
18
|
-
this.validateId(threadId);
|
|
19
|
-
this.validateId(boxId);
|
|
20
|
-
const row = this.storage.findBox(threadId, boxId);
|
|
21
|
-
if (!row)
|
|
22
|
-
return null;
|
|
23
|
-
return this.toBoxResponse(row);
|
|
24
|
-
}
|
|
25
|
-
createBox(threadId, params) {
|
|
26
|
-
this.validateId(threadId);
|
|
27
|
-
const id = this.generateBoxId();
|
|
28
|
-
const createdAt = new Date().toISOString();
|
|
29
|
-
const row = this.storage.insertBox(threadId, {
|
|
30
|
-
id,
|
|
31
|
-
seq: params.seq,
|
|
32
|
-
firstTaskId: params.firstTaskId,
|
|
33
|
-
midTaskId: params.midTaskId,
|
|
34
|
-
lastTaskId: params.lastTaskId,
|
|
35
|
-
taskCount: params.taskCount,
|
|
36
|
-
summary: params.summary ?? null,
|
|
37
|
-
sourceTokens: params.sourceTokens,
|
|
38
|
-
summaryTokens: params.summaryTokens ?? null,
|
|
39
|
-
createdAt,
|
|
40
|
-
});
|
|
41
|
-
return this.toBoxResponse(row);
|
|
42
|
-
}
|
|
43
|
-
toBoxResponse(row) {
|
|
44
|
-
return {
|
|
45
|
-
id: row.id,
|
|
46
|
-
threadId: row.thread_id,
|
|
47
|
-
seq: row.seq,
|
|
48
|
-
firstTaskId: row.first_task_id,
|
|
49
|
-
lastTaskId: row.last_task_id,
|
|
50
|
-
taskCount: row.task_count,
|
|
51
|
-
sourceTokens: row.source_tokens,
|
|
52
|
-
summaryTokens: row.summary_tokens,
|
|
53
|
-
summary: row.summary,
|
|
54
|
-
previewFirst: this.storage.getTaskPreview(row.first_task_id, 200),
|
|
55
|
-
previewMid: this.storage.getTaskPreview(row.mid_task_id, 200),
|
|
56
|
-
previewLast: this.storage.getTaskPreview(row.last_task_id, 200),
|
|
57
|
-
createdAt: row.created_at,
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
validateId(id) {
|
|
61
|
-
if (!ID_PATTERN.test(id)) {
|
|
62
|
-
throw new Error(`Invalid ID format: ${id}`);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
generateBoxId() {
|
|
66
|
-
return generateId('box');
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
//# sourceMappingURL=box.service.js.map
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* buildContext() — builds hot/warm context windows from thread messages and box summaries.
|
|
3
|
-
*/
|
|
4
|
-
export function buildContext(threadId, taskReader, boxService, params, tokenizer) {
|
|
5
|
-
const { maxTokens, hotzoneRatio, warmzoneRatio } = params;
|
|
6
|
-
const hotBudget = maxTokens * hotzoneRatio;
|
|
7
|
-
const warmBudget = maxTokens * warmzoneRatio;
|
|
8
|
-
const totalBudget = hotBudget + warmBudget;
|
|
9
|
-
const tasks = taskReader.getThreadMessages(threadId);
|
|
10
|
-
const hotMessages = [];
|
|
11
|
-
let hotTokens = 0;
|
|
12
|
-
let hotOverflow = false;
|
|
13
|
-
const taskPairs = [];
|
|
14
|
-
for (let i = 0; i < tasks.length; i += 2) {
|
|
15
|
-
const userMsg = tasks[i];
|
|
16
|
-
const assistantMsg = tasks[i + 1];
|
|
17
|
-
const prompt = userMsg?.content || '';
|
|
18
|
-
const result = assistantMsg?.content || '';
|
|
19
|
-
const tokens = tokenizer.countTokens(prompt + result);
|
|
20
|
-
const msgs = [];
|
|
21
|
-
if (userMsg)
|
|
22
|
-
msgs.push(userMsg);
|
|
23
|
-
if (assistantMsg)
|
|
24
|
-
msgs.push(assistantMsg);
|
|
25
|
-
taskPairs.push({ messages: msgs, tokens });
|
|
26
|
-
}
|
|
27
|
-
for (let i = taskPairs.length - 1; i >= 0; i--) {
|
|
28
|
-
const pair = taskPairs[i];
|
|
29
|
-
if (hotTokens + pair.tokens > hotBudget) {
|
|
30
|
-
hotOverflow = true;
|
|
31
|
-
break;
|
|
32
|
-
}
|
|
33
|
-
hotTokens += pair.tokens;
|
|
34
|
-
hotMessages.unshift(...pair.messages);
|
|
35
|
-
}
|
|
36
|
-
const warmBoxes = [];
|
|
37
|
-
let warmTokens = 0;
|
|
38
|
-
if (hotOverflow && warmBudget > 0) {
|
|
39
|
-
try {
|
|
40
|
-
const { boxes } = boxService.listBoxes(threadId);
|
|
41
|
-
for (let i = boxes.length - 1; i >= 0; i--) {
|
|
42
|
-
const box = boxes[i];
|
|
43
|
-
const tokens = box.summaryTokens ?? box.sourceTokens;
|
|
44
|
-
if (warmTokens + tokens > warmBudget)
|
|
45
|
-
break;
|
|
46
|
-
warmTokens += tokens;
|
|
47
|
-
warmBoxes.unshift({
|
|
48
|
-
boxId: box.id,
|
|
49
|
-
seq: box.seq,
|
|
50
|
-
taskCount: box.taskCount,
|
|
51
|
-
sourceTokens: box.sourceTokens,
|
|
52
|
-
summary: box.summary,
|
|
53
|
-
previewFirst: box.previewFirst,
|
|
54
|
-
previewMid: box.previewMid,
|
|
55
|
-
previewLast: box.previewLast,
|
|
56
|
-
createdAt: box.createdAt,
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
catch (error) {
|
|
61
|
-
if (error instanceof Error && !/not found/i.test(error.message)) {
|
|
62
|
-
throw error;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
return {
|
|
67
|
-
hot: hotMessages,
|
|
68
|
-
warm: warmBoxes,
|
|
69
|
-
hotTokens,
|
|
70
|
-
warmTokens,
|
|
71
|
-
hotOverflow,
|
|
72
|
-
totalBudget,
|
|
73
|
-
config: { maxTokens, hotzoneRatio, warmzoneRatio },
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
//# sourceMappingURL=context-builder.js.map
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* CrewxClient — Browser client for CrewX SDK.
|
|
3
|
-
*
|
|
4
|
-
* Communicates with a server running CrewX SDK via HTTP.
|
|
5
|
-
* Handles the Client-Intercept pattern automatically:
|
|
6
|
-
* registerTool() + query() — that's it.
|
|
7
|
-
*
|
|
8
|
-
* @example
|
|
9
|
-
* ```ts
|
|
10
|
-
* import { CrewxClient } from '@crewx/sdk/client';
|
|
11
|
-
*
|
|
12
|
-
* const crewx = new CrewxClient('http://localhost:3000');
|
|
13
|
-
* crewx.registerTool('browser_storage_read', {
|
|
14
|
-
* execute: async ({ key }) => localStorage.getItem(key),
|
|
15
|
-
* });
|
|
16
|
-
*
|
|
17
|
-
* const result = await crewx.query('assistant', 'read my settings');
|
|
18
|
-
* console.log(result.data);
|
|
19
|
-
* ```
|
|
20
|
-
*/
|
|
21
|
-
export class CrewxClient {
|
|
22
|
-
baseUrl;
|
|
23
|
-
tools = new Map();
|
|
24
|
-
constructor(baseUrl) {
|
|
25
|
-
this.baseUrl = baseUrl.replace(/\/$/, '');
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Register a browser-side tool.
|
|
29
|
-
* When the server agent calls a tool with this name (and no server-side execute),
|
|
30
|
-
* CrewxClient automatically runs it locally and sends the result back.
|
|
31
|
-
*/
|
|
32
|
-
registerTool(name, definition) {
|
|
33
|
-
this.tools.set(name, definition);
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* Send a message to an agent.
|
|
37
|
-
* The requires_action loop is handled automatically — if the agent calls a
|
|
38
|
-
* client tool, CrewxClient executes it locally and continues the conversation.
|
|
39
|
-
*/
|
|
40
|
-
async query(agent, message, callbacks) {
|
|
41
|
-
let response = await this._post('/api/chat', { agent, message });
|
|
42
|
-
while (response.status === 'requires_action') {
|
|
43
|
-
const { toolCall, threadId } = response;
|
|
44
|
-
if (!toolCall)
|
|
45
|
-
break;
|
|
46
|
-
const tool = this.tools.get(toolCall.toolName);
|
|
47
|
-
if (callbacks?.onToolCall) {
|
|
48
|
-
callbacks.onToolCall(toolCall);
|
|
49
|
-
}
|
|
50
|
-
let toolResult;
|
|
51
|
-
if (tool?.execute) {
|
|
52
|
-
try {
|
|
53
|
-
const raw = await tool.execute(toolCall.args);
|
|
54
|
-
toolResult = typeof raw === 'string' ? raw : JSON.stringify(raw);
|
|
55
|
-
}
|
|
56
|
-
catch (err) {
|
|
57
|
-
toolResult = `Error: ${err.message}`;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
else {
|
|
61
|
-
toolResult = `Error: No client handler for tool "${toolCall.toolName}"`;
|
|
62
|
-
}
|
|
63
|
-
response = await this._post('/api/chat/continue', {
|
|
64
|
-
threadId,
|
|
65
|
-
toolCallId: toolCall.toolCallId,
|
|
66
|
-
result: toolResult,
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
return response;
|
|
70
|
-
}
|
|
71
|
-
async _post(path, body) {
|
|
72
|
-
const res = await fetch(`${this.baseUrl}${path}`, {
|
|
73
|
-
method: 'POST',
|
|
74
|
-
headers: { 'Content-Type': 'application/json' },
|
|
75
|
-
body: JSON.stringify(body),
|
|
76
|
-
});
|
|
77
|
-
if (!res.ok)
|
|
78
|
-
throw new Error(`HTTP ${res.status}`);
|
|
79
|
-
return res.json();
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
//# sourceMappingURL=CrewxClient.js.map
|
package/dist/esm/client/index.js
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Browser-safe YAML config loader.
|
|
3
|
-
* Only parseYamlContent — no file I/O.
|
|
4
|
-
*/
|
|
5
|
-
import { load as loadYaml } from 'js-yaml';
|
|
6
|
-
import { CrewxProjectConfigSchema } from '../types/index.js';
|
|
7
|
-
export class ConfigLoadError extends Error {
|
|
8
|
-
cause;
|
|
9
|
-
constructor(message, cause) {
|
|
10
|
-
super(message);
|
|
11
|
-
this.cause = cause;
|
|
12
|
-
this.name = 'ConfigLoadError';
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
/**
|
|
16
|
-
* Parse YAML string into a validated CrewxProjectConfig.
|
|
17
|
-
*/
|
|
18
|
-
export function parseYamlContent(yamlString) {
|
|
19
|
-
if (!yamlString || typeof yamlString !== 'string' || !yamlString.trim()) {
|
|
20
|
-
throw new ConfigLoadError('YAML content must be a non-empty string');
|
|
21
|
-
}
|
|
22
|
-
let raw;
|
|
23
|
-
try {
|
|
24
|
-
raw = loadYaml(yamlString);
|
|
25
|
-
}
|
|
26
|
-
catch (err) {
|
|
27
|
-
throw new ConfigLoadError(`YAML parse error: ${err.message}`, err);
|
|
28
|
-
}
|
|
29
|
-
const normalized = normalizeRaw(raw);
|
|
30
|
-
const result = CrewxProjectConfigSchema.safeParse(normalized);
|
|
31
|
-
if (!result.success) {
|
|
32
|
-
throw new ConfigLoadError(`Config validation error: ${result.error.message}`);
|
|
33
|
-
}
|
|
34
|
-
return result.data;
|
|
35
|
-
}
|
|
36
|
-
function normalizeRaw(raw) {
|
|
37
|
-
if (!raw || typeof raw !== 'object') {
|
|
38
|
-
return { agents: [] };
|
|
39
|
-
}
|
|
40
|
-
const obj = raw;
|
|
41
|
-
if (obj.agents && typeof obj.agents === 'object' && !Array.isArray(obj.agents)) {
|
|
42
|
-
const agentsMap = obj.agents;
|
|
43
|
-
const agentsArray = Object.entries(agentsMap).map(([id, cfg]) => {
|
|
44
|
-
const agentCfg = (cfg && typeof cfg === 'object' ? cfg : {});
|
|
45
|
-
return { id, ...agentCfg };
|
|
46
|
-
});
|
|
47
|
-
return { ...obj, agents: agentsArray };
|
|
48
|
-
}
|
|
49
|
-
if (!obj.agents) {
|
|
50
|
-
return { ...obj, agents: [] };
|
|
51
|
-
}
|
|
52
|
-
return obj;
|
|
53
|
-
}
|
|
54
|
-
//# sourceMappingURL=loader.browser.js.map
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* YAML configuration loader for CrewX projects.
|
|
3
|
-
* Reads crewx.yaml and validates it with Zod schema.
|
|
4
|
-
*/
|
|
5
|
-
import { load as loadYaml } from 'js-yaml';
|
|
6
|
-
import { readFileSync } from 'fs';
|
|
7
|
-
import { CrewxProjectConfigSchema } from '../types';
|
|
8
|
-
export class ConfigLoadError extends Error {
|
|
9
|
-
cause;
|
|
10
|
-
constructor(message, cause) {
|
|
11
|
-
super(message);
|
|
12
|
-
this.cause = cause;
|
|
13
|
-
this.name = 'ConfigLoadError';
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* Parse YAML string into a validated CrewxProjectConfig.
|
|
18
|
-
* Converts the agents record (keyed by id) into an array.
|
|
19
|
-
*/
|
|
20
|
-
export function parseYamlContent(yamlString) {
|
|
21
|
-
if (!yamlString || typeof yamlString !== 'string' || !yamlString.trim()) {
|
|
22
|
-
throw new ConfigLoadError('YAML content must be a non-empty string');
|
|
23
|
-
}
|
|
24
|
-
let raw;
|
|
25
|
-
try {
|
|
26
|
-
raw = loadYaml(yamlString);
|
|
27
|
-
}
|
|
28
|
-
catch (err) {
|
|
29
|
-
throw new ConfigLoadError(`YAML parse error: ${err.message}`, err);
|
|
30
|
-
}
|
|
31
|
-
// Normalize agents: YAML has agents as a map (Record<id, config>),
|
|
32
|
-
// but our type uses an array with 'id' field.
|
|
33
|
-
const normalized = normalizeRaw(raw);
|
|
34
|
-
const result = CrewxProjectConfigSchema.safeParse(normalized);
|
|
35
|
-
if (!result.success) {
|
|
36
|
-
throw new ConfigLoadError(`Config validation error: ${result.error.message}`);
|
|
37
|
-
}
|
|
38
|
-
return result.data;
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Load and parse crewx.yaml from a file path.
|
|
42
|
-
*/
|
|
43
|
-
export function loadYamlFile(filePath) {
|
|
44
|
-
let content;
|
|
45
|
-
try {
|
|
46
|
-
content = readFileSync(filePath, 'utf-8');
|
|
47
|
-
}
|
|
48
|
-
catch (err) {
|
|
49
|
-
throw new ConfigLoadError(`Cannot read file: ${filePath}`, err);
|
|
50
|
-
}
|
|
51
|
-
return parseYamlContent(content);
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
|
-
* Normalize raw YAML output:
|
|
55
|
-
* - agents map (Record<id, agentConfig>) → agents array ([{ id, ...agentConfig }])
|
|
56
|
-
*/
|
|
57
|
-
function normalizeRaw(raw) {
|
|
58
|
-
if (!raw || typeof raw !== 'object') {
|
|
59
|
-
return { agents: [] };
|
|
60
|
-
}
|
|
61
|
-
const obj = raw;
|
|
62
|
-
// Convert agents map to array
|
|
63
|
-
if (obj.agents && typeof obj.agents === 'object' && !Array.isArray(obj.agents)) {
|
|
64
|
-
const agentsMap = obj.agents;
|
|
65
|
-
const agentsArray = Object.entries(agentsMap).map(([id, cfg]) => {
|
|
66
|
-
const agentCfg = (cfg && typeof cfg === 'object' ? cfg : {});
|
|
67
|
-
return { id, ...agentCfg };
|
|
68
|
-
});
|
|
69
|
-
return { ...obj, agents: agentsArray };
|
|
70
|
-
}
|
|
71
|
-
// agents already array or absent
|
|
72
|
-
if (!obj.agents) {
|
|
73
|
-
return { ...obj, agents: [] };
|
|
74
|
-
}
|
|
75
|
-
return obj;
|
|
76
|
-
}
|
|
77
|
-
//# sourceMappingURL=loader.js.map
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* TypedEventEmitter — typed wrapper around Node's EventEmitter.
|
|
3
|
-
*
|
|
4
|
-
* Design:
|
|
5
|
-
* - `on` / `once` are public (callers subscribe)
|
|
6
|
-
* - `emit` is protected (only subclasses like Crewx can emit)
|
|
7
|
-
* - Async listeners are supported (fire-and-forget, errors isolated)
|
|
8
|
-
* - Returns an UnsubscribeFn from on/once for easy cleanup
|
|
9
|
-
*/
|
|
10
|
-
import { EventEmitter } from 'events';
|
|
11
|
-
/**
|
|
12
|
-
* Wraps a listener to isolate errors and support async fire-and-forget.
|
|
13
|
-
*/
|
|
14
|
-
function makeSafeListener(event, listener) {
|
|
15
|
-
return (payload) => {
|
|
16
|
-
try {
|
|
17
|
-
const result = listener(payload);
|
|
18
|
-
if (result instanceof Promise) {
|
|
19
|
-
result.catch((err) => {
|
|
20
|
-
// Fire-and-forget: isolate async listener errors
|
|
21
|
-
console.error(`[crewx] event listener error (${event}): ${err instanceof Error ? err.message : String(err)}`);
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
catch (err) {
|
|
26
|
-
// Synchronous listener error — log and continue
|
|
27
|
-
console.error(`[crewx] event listener error (${event}): ${err instanceof Error ? err.message : String(err)}`);
|
|
28
|
-
}
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
export class TypedEventEmitter {
|
|
32
|
-
_emitter = new EventEmitter();
|
|
33
|
-
/**
|
|
34
|
-
* Subscribe to an event. Returns an unsubscribe function.
|
|
35
|
-
*
|
|
36
|
-
* @example
|
|
37
|
-
* const unsub = crewx.on('task:start', (e) => console.log(e.agentRef));
|
|
38
|
-
* // later:
|
|
39
|
-
* unsub();
|
|
40
|
-
*/
|
|
41
|
-
on(event, listener) {
|
|
42
|
-
const safeListener = makeSafeListener(event, listener);
|
|
43
|
-
this._emitter.on(event, safeListener);
|
|
44
|
-
return () => this._emitter.off(event, safeListener);
|
|
45
|
-
}
|
|
46
|
-
/**
|
|
47
|
-
* Subscribe to an event exactly once.
|
|
48
|
-
*/
|
|
49
|
-
once(event, listener) {
|
|
50
|
-
const safeListener = makeSafeListener(event, listener);
|
|
51
|
-
this._emitter.once(event, safeListener);
|
|
52
|
-
return () => this._emitter.off(event, safeListener);
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
* Emit an event with payload. Only accessible to subclasses.
|
|
56
|
-
*/
|
|
57
|
-
emit(event, payload) {
|
|
58
|
-
this._emitter.emit(event, payload);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
//# sourceMappingURL=TypedEventEmitter.js.map
|
package/dist/esm/events/types.js
DELETED