@crewx/sdk 0.8.0-rc.79 → 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/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
package/dist/esm/hooks/define.js
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { ToolObserverPlugin } from './observer';
|
|
2
|
-
export function definePlugin(def) {
|
|
3
|
-
return new (class extends ToolObserverPlugin {
|
|
4
|
-
name = def.name;
|
|
5
|
-
version = def.version;
|
|
6
|
-
on = def.on;
|
|
7
|
-
run = def.run;
|
|
8
|
-
})();
|
|
9
|
-
}
|
|
10
|
-
//# sourceMappingURL=define.js.map
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
import { resolve, relative } from 'path';
|
|
2
|
-
const MAX_REASON_LENGTH = 200;
|
|
3
|
-
export function sanitizeDenyReason(reason) {
|
|
4
|
-
const cleaned = reason.replace(/[\x00-\x1f\x7f]/g, '');
|
|
5
|
-
if (cleaned.length <= MAX_REASON_LENGTH) {
|
|
6
|
-
return cleaned;
|
|
7
|
-
}
|
|
8
|
-
return cleaned.slice(0, MAX_REASON_LENGTH - 11) + ' [redacted]';
|
|
9
|
-
}
|
|
10
|
-
export function isPathSafe(pluginPath, projectRoot) {
|
|
11
|
-
const resolved = resolve(pluginPath);
|
|
12
|
-
const root = resolve(projectRoot);
|
|
13
|
-
const rel = relative(root, resolved);
|
|
14
|
-
if (rel.startsWith('..') || resolve(resolved).startsWith('/etc/') || resolve(resolved).startsWith('/usr/')) {
|
|
15
|
-
return false;
|
|
16
|
-
}
|
|
17
|
-
if (resolved.includes('node_modules')) {
|
|
18
|
-
return false;
|
|
19
|
-
}
|
|
20
|
-
return true;
|
|
21
|
-
}
|
|
22
|
-
export function buildHookContext(input, cwd) {
|
|
23
|
-
return {
|
|
24
|
-
event: 'beforeTool',
|
|
25
|
-
traceId: input.tool_use_id || '',
|
|
26
|
-
agent: { id: '', role: '', team: '' },
|
|
27
|
-
provider: 'cli/claude',
|
|
28
|
-
thread: { id: '' },
|
|
29
|
-
tool: {
|
|
30
|
-
name: input.tool_name,
|
|
31
|
-
rawName: input.tool_name,
|
|
32
|
-
input: input.tool_input,
|
|
33
|
-
},
|
|
34
|
-
cwd: cwd || input.cwd,
|
|
35
|
-
sessionId: input.session_id,
|
|
36
|
-
pass: () => ({ type: 'pass' }),
|
|
37
|
-
deny: (r) => ({ type: 'deny', reason: r }),
|
|
38
|
-
inject: (m) => ({ type: 'inject', message: m }),
|
|
39
|
-
modify: (p) => ({ type: 'modify', patch: p }),
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
export async function evaluateHook(plugin, input, cwd) {
|
|
43
|
-
const ctx = buildHookContext(input, cwd);
|
|
44
|
-
const result = await plugin.run(ctx);
|
|
45
|
-
const baseOutput = {
|
|
46
|
-
hookSpecificOutput: {
|
|
47
|
-
hookEventName: input.hook_event_name,
|
|
48
|
-
permissionDecision: 'allow',
|
|
49
|
-
},
|
|
50
|
-
};
|
|
51
|
-
switch (result.type) {
|
|
52
|
-
case 'pass':
|
|
53
|
-
return { exitCode: 0, stdout: baseOutput };
|
|
54
|
-
case 'deny': {
|
|
55
|
-
const sanitizedReason = sanitizeDenyReason(result.reason);
|
|
56
|
-
return {
|
|
57
|
-
exitCode: 2,
|
|
58
|
-
stdout: {
|
|
59
|
-
hookSpecificOutput: {
|
|
60
|
-
hookEventName: input.hook_event_name,
|
|
61
|
-
permissionDecision: 'deny',
|
|
62
|
-
permissionDecisionReason: sanitizedReason,
|
|
63
|
-
},
|
|
64
|
-
},
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
case 'inject':
|
|
68
|
-
case 'modify':
|
|
69
|
-
console.error(`[crewx] Hook result type '${result.type}' is not supported in Phase 0. ` +
|
|
70
|
-
`Plugin: ${plugin.name}. Treating as pass.`);
|
|
71
|
-
return { exitCode: 0, stdout: baseOutput };
|
|
72
|
-
default:
|
|
73
|
-
return { exitCode: 0, stdout: baseOutput };
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
//# sourceMappingURL=dispatch.js.map
|
package/dist/esm/hooks/index.js
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
export { ToolObserverPlugin } from './observer';
|
|
2
|
-
export { HookPlugin, defineHookPlugin } from './plugin';
|
|
3
|
-
export { definePlugin } from './define';
|
|
4
|
-
export { Tools } from './types';
|
|
5
|
-
export { evaluateHook, sanitizeDenyReason, isPathSafe, buildHookContext, } from './dispatch';
|
|
6
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import { CrewxPlugin } from '../plugin';
|
|
2
|
-
export class ToolObserverPlugin extends CrewxPlugin {
|
|
3
|
-
unsubs = [];
|
|
4
|
-
attach(crewx) {
|
|
5
|
-
if (this.on.beforeTool) {
|
|
6
|
-
const unsub = crewx.on('tool:observed:before', async (e) => {
|
|
7
|
-
if (!this.matchesTool(this.on.beforeTool, e.tool.name))
|
|
8
|
-
return;
|
|
9
|
-
const ctx = this.buildContext('beforeTool', e);
|
|
10
|
-
await this.run(ctx);
|
|
11
|
-
});
|
|
12
|
-
this.unsubs.push(unsub);
|
|
13
|
-
}
|
|
14
|
-
if (this.on.afterTool) {
|
|
15
|
-
const unsub = crewx.on('tool:observed:after', async (e) => {
|
|
16
|
-
if (!this.matchesTool(this.on.afterTool, e.tool.name))
|
|
17
|
-
return;
|
|
18
|
-
const ctx = this.buildContext('afterTool', e);
|
|
19
|
-
await this.run(ctx);
|
|
20
|
-
});
|
|
21
|
-
this.unsubs.push(unsub);
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
async detach(_crewx) {
|
|
25
|
-
for (const unsub of this.unsubs)
|
|
26
|
-
unsub();
|
|
27
|
-
this.unsubs = [];
|
|
28
|
-
}
|
|
29
|
-
matchesTool(filter, toolName) {
|
|
30
|
-
if (filter === true)
|
|
31
|
-
return true;
|
|
32
|
-
return filter.includes(toolName);
|
|
33
|
-
}
|
|
34
|
-
buildContext(event, e) {
|
|
35
|
-
return {
|
|
36
|
-
event,
|
|
37
|
-
traceId: e.traceId,
|
|
38
|
-
agent: {
|
|
39
|
-
id: e.agentId || e.agentRef,
|
|
40
|
-
role: '',
|
|
41
|
-
team: '',
|
|
42
|
-
},
|
|
43
|
-
provider: e.provider,
|
|
44
|
-
thread: { id: e.threadId || '' },
|
|
45
|
-
tool: {
|
|
46
|
-
name: e.tool.name,
|
|
47
|
-
rawName: e.tool.rawName,
|
|
48
|
-
input: 'input' in e.tool ? e.tool.input : undefined,
|
|
49
|
-
},
|
|
50
|
-
cwd: process.cwd(),
|
|
51
|
-
sessionId: e.sessionId || '',
|
|
52
|
-
pass: () => ({ type: 'pass' }),
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
//# sourceMappingURL=observer.js.map
|
package/dist/esm/hooks/plugin.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
export class HookPlugin {
|
|
2
|
-
capabilities = { required: [] };
|
|
3
|
-
}
|
|
4
|
-
export function defineHookPlugin(def) {
|
|
5
|
-
return new (class extends HookPlugin {
|
|
6
|
-
name = def.name;
|
|
7
|
-
version = def.version;
|
|
8
|
-
capabilities = def.capabilities ?? { required: [] };
|
|
9
|
-
run = def.run;
|
|
10
|
-
})();
|
|
11
|
-
}
|
|
12
|
-
//# sourceMappingURL=plugin.js.map
|
package/dist/esm/hooks/types.js
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @crewx/sdk browser entry point.
|
|
3
|
-
*
|
|
4
|
-
* Exports only browser-safe modules — no Node.js dependencies
|
|
5
|
-
* (child_process, fs, path, crypto, events).
|
|
6
|
-
*/
|
|
7
|
-
// Browser-safe facade
|
|
8
|
-
export { Crewx } from './facade/Crewx.browser.js';
|
|
9
|
-
// Browser-safe provider bridge (registry only, no CLI spawn)
|
|
10
|
-
export { registerProviderFactory, createProvider, ProviderError } from './provider/bridge.browser.js';
|
|
11
|
-
// Config — browser-safe (no fs import)
|
|
12
|
-
export { parseYamlContent, ConfigLoadError } from './config/loader.browser.js';
|
|
13
|
-
// Platform adapters
|
|
14
|
-
export { BrowserFsAdapter } from './platform/BrowserFsAdapter.js';
|
|
15
|
-
//# sourceMappingURL=index.browser.js.map
|
package/dist/esm/index.js
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @crewx/sdk public API surface.
|
|
3
|
-
*/
|
|
4
|
-
// Main facade
|
|
5
|
-
export { Crewx } from './facade/Crewx';
|
|
6
|
-
// Plugin system
|
|
7
|
-
export { CrewxPlugin } from './plugin';
|
|
8
|
-
// Event system
|
|
9
|
-
export { TypedEventEmitter } from './events/TypedEventEmitter';
|
|
10
|
-
// Layout system
|
|
11
|
-
export { LayoutLoader } from './layout/loader';
|
|
12
|
-
export { LayoutRenderer } from './layout/renderer';
|
|
13
|
-
export { PropsValidator } from './layout/props-validator';
|
|
14
|
-
export { LayoutLoadError, PropsValidationError } from './layout/types';
|
|
15
|
-
// Template engine
|
|
16
|
-
export { TemplateEngine } from './template/engine';
|
|
17
|
-
// Document loader
|
|
18
|
-
export { DocumentLoader } from './template/loader/DocumentLoader';
|
|
19
|
-
export { NodeFsAdapter, defaultFsAdapter } from './platform/NodeFsAdapter';
|
|
20
|
-
export { BrowserFsAdapter } from './platform/BrowserFsAdapter';
|
|
21
|
-
// P1/P2 helpers (exported for direct use if needed)
|
|
22
|
-
export { truncateHelper, lengthHelper, escapeHandlebarsHelper, formatFileSizeHelper, formatTimestampHelper, } from './template/helpers/p1p2';
|
|
23
|
-
// Exec audit log control
|
|
24
|
-
export { setAuditVerbose } from './template/helpers/exec';
|
|
25
|
-
// Config utilities
|
|
26
|
-
export { loadYamlFile, parseYamlContent, ConfigLoadError } from './config/loader';
|
|
27
|
-
// Agent utilities
|
|
28
|
-
export { resolveAgent, AgentNotFoundError } from './agent/resolver';
|
|
29
|
-
// Provider utilities
|
|
30
|
-
export { createProvider, ProviderError, ClientToolCallRequiredError, registerProviderFactory } from './provider/bridge';
|
|
31
|
-
export { VercelProviderRuntime } from './provider/vercel-runtime';
|
|
32
|
-
export { registerApiProviders } from './provider/register-api';
|
|
33
|
-
// Tools
|
|
34
|
-
export { createDelegateTool } from './tools/delegate';
|
|
35
|
-
// Env utilities
|
|
36
|
-
export { resolveCrewxCli, resolveCrewxWorkspace } from './utils/env-defaults';
|
|
37
|
-
// ID utilities (backward-compat for @crewx/* built-in packages)
|
|
38
|
-
export { generateId, generateFingerprint } from './utils/id';
|
|
39
|
-
// Workspace utilities
|
|
40
|
-
export { hashWorkspaceId, normalizeWorkspacePath } from './utils/workspace';
|
|
41
|
-
// Boxing module
|
|
42
|
-
export { SdkBoxService } from './boxing/box.service';
|
|
43
|
-
export { buildContext } from './boxing/context-builder';
|
|
44
|
-
// Parsers
|
|
45
|
-
export { parseStdoutEvent } from './parsers/router';
|
|
46
|
-
// Provider utilities
|
|
47
|
-
export { parseUsage } from './provider/parse-usage';
|
|
48
|
-
// Parallel execution
|
|
49
|
-
export { ParallelRunner, ParallelRunnerTimeoutError } from './parallel/parallel-runner';
|
|
50
|
-
export { runQueriesParallel, runExecutesParallel } from './parallel/helpers';
|
|
51
|
-
export { AgentRuntime } from './parallel/agent-runtime';
|
|
52
|
-
// Plugin provider module
|
|
53
|
-
export { PluginProviderRuntime, createPluginProviderFactory } from './plugin/plugin-provider';
|
|
54
|
-
// Remote agent module
|
|
55
|
-
export { RemoteProviderRuntime, createRemoteProviderFactory } from './remote/remote-provider';
|
|
56
|
-
export { RemoteAgentManager } from './remote/remote-agent-manager';
|
|
57
|
-
export { McpHttpTransport } from './remote/remote-transport';
|
|
58
|
-
// Server module (MCP handler)
|
|
59
|
-
export { createHandler } from './server/handler';
|
|
60
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1,268 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* LayoutLoader — loads layout templates from templates/agents/*.yaml files.
|
|
3
|
-
* Ported 1:1 from packages/sdk-bak/src/services/layout-loader.service.ts.
|
|
4
|
-
* Only import paths and DEFAULT_OPTIONS.templatesPath are changed.
|
|
5
|
-
*/
|
|
6
|
-
import { readFileSync, readdirSync, existsSync } from 'fs';
|
|
7
|
-
import * as path from 'path';
|
|
8
|
-
import { load as loadYaml } from 'js-yaml';
|
|
9
|
-
import { LayoutLoadError, } from './types';
|
|
10
|
-
/**
|
|
11
|
-
* Default loader options — points to SDK's bundled templates directory.
|
|
12
|
-
*/
|
|
13
|
-
const DEFAULT_OPTIONS = {
|
|
14
|
-
templatesPath: path.join(__dirname, '../../../templates/agents'),
|
|
15
|
-
validationMode: 'lenient',
|
|
16
|
-
fallbackLayoutId: 'crewx/default',
|
|
17
|
-
};
|
|
18
|
-
/**
|
|
19
|
-
* Layout loader service.
|
|
20
|
-
* Loads and caches layout definitions from YAML files.
|
|
21
|
-
* Provides fallback mechanism and prop override support.
|
|
22
|
-
*/
|
|
23
|
-
export class LayoutLoader {
|
|
24
|
-
layouts = new Map();
|
|
25
|
-
options;
|
|
26
|
-
constructor(options) {
|
|
27
|
-
this.options = { ...DEFAULT_OPTIONS, ...options };
|
|
28
|
-
this.loadAllLayouts();
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* Load a layout by ID with optional props override.
|
|
32
|
-
*/
|
|
33
|
-
load(layoutId, propsOverride) {
|
|
34
|
-
let layout = this.layouts.get(layoutId);
|
|
35
|
-
if (!layout) {
|
|
36
|
-
const normalizedId = this.normalizeLayoutId(layoutId);
|
|
37
|
-
layout = this.layouts.get(normalizedId);
|
|
38
|
-
}
|
|
39
|
-
if (!layout) {
|
|
40
|
-
console.warn(`Layout not found: ${layoutId}, falling back to ${this.options.fallbackLayoutId}`);
|
|
41
|
-
layout = this.layouts.get(this.options.fallbackLayoutId);
|
|
42
|
-
if (!layout) {
|
|
43
|
-
throw new LayoutLoadError(`Fallback layout not found: ${this.options.fallbackLayoutId}`, this.options.fallbackLayoutId);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
if (propsOverride && Object.keys(propsOverride).length > 0) {
|
|
47
|
-
return {
|
|
48
|
-
...layout,
|
|
49
|
-
defaultProps: { ...layout.defaultProps, ...propsOverride },
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
return layout;
|
|
53
|
-
}
|
|
54
|
-
getLayoutIds() {
|
|
55
|
-
return Array.from(this.layouts.keys());
|
|
56
|
-
}
|
|
57
|
-
hasLayout(layoutId) {
|
|
58
|
-
if (this.layouts.has(layoutId))
|
|
59
|
-
return true;
|
|
60
|
-
const normalizedId = this.normalizeLayoutId(layoutId);
|
|
61
|
-
return this.layouts.has(normalizedId);
|
|
62
|
-
}
|
|
63
|
-
reload() {
|
|
64
|
-
this.layouts.clear();
|
|
65
|
-
this.loadAllLayouts();
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* Register or override a layout at runtime.
|
|
69
|
-
*/
|
|
70
|
-
registerLayout(layoutId, layoutConfig) {
|
|
71
|
-
if (!layoutId || typeof layoutId !== 'string') {
|
|
72
|
-
throw new LayoutLoadError('Layout ID must be a non-empty string', layoutId);
|
|
73
|
-
}
|
|
74
|
-
const config = typeof layoutConfig === 'string'
|
|
75
|
-
? { template: layoutConfig }
|
|
76
|
-
: layoutConfig;
|
|
77
|
-
const template = typeof config.template === 'string' ? config.template : '';
|
|
78
|
-
if (!template || template.trim().length === 0) {
|
|
79
|
-
throw new LayoutLoadError(`Custom layout template is empty for ${layoutId}`, layoutId);
|
|
80
|
-
}
|
|
81
|
-
const propsSchemaRaw = config.propsSchema || {};
|
|
82
|
-
const defaultPropsFromSchema = this.extractDefaultProps(propsSchemaRaw);
|
|
83
|
-
const explicitDefaults = config.defaultProps || {};
|
|
84
|
-
const layoutDefinition = {
|
|
85
|
-
id: layoutId,
|
|
86
|
-
version: config.version || '1.0.0',
|
|
87
|
-
description: config.description || `Custom layout ${layoutId}`,
|
|
88
|
-
template,
|
|
89
|
-
propsSchema: this.parsePropsSchema(propsSchemaRaw),
|
|
90
|
-
defaultProps: { ...defaultPropsFromSchema, ...explicitDefaults },
|
|
91
|
-
};
|
|
92
|
-
const existingLayout = this.layouts.get(layoutId);
|
|
93
|
-
const templatesEqual = existingLayout?.template === template &&
|
|
94
|
-
JSON.stringify(existingLayout?.defaultProps ?? {}) === JSON.stringify(layoutDefinition.defaultProps ?? {}) &&
|
|
95
|
-
JSON.stringify(existingLayout?.propsSchema ?? {}) === JSON.stringify(layoutDefinition.propsSchema ?? {});
|
|
96
|
-
this.layouts.set(layoutId, layoutDefinition);
|
|
97
|
-
if (process.env.CREWX_VERBOSE === '1') {
|
|
98
|
-
if (!existingLayout) {
|
|
99
|
-
console.error(`Registered custom layout: ${layoutId}`);
|
|
100
|
-
}
|
|
101
|
-
else if (!templatesEqual) {
|
|
102
|
-
console.error(`Updated custom layout: ${layoutId}`);
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
/**
|
|
107
|
-
* Register multiple layouts from a map.
|
|
108
|
-
*/
|
|
109
|
-
registerLayouts(layoutsMap) {
|
|
110
|
-
for (const [id, config] of Object.entries(layoutsMap)) {
|
|
111
|
-
try {
|
|
112
|
-
this.registerLayout(id, config);
|
|
113
|
-
}
|
|
114
|
-
catch (error) {
|
|
115
|
-
console.warn(`Failed to register custom layout ${id}:`, error instanceof Error ? error.message : error);
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
loadAllLayouts() {
|
|
120
|
-
const layoutsDir = this.options.templatesPath;
|
|
121
|
-
if (!existsSync(layoutsDir)) {
|
|
122
|
-
throw new LayoutLoadError(`Templates directory not found: ${layoutsDir}`, undefined, new Error(`Directory does not exist: ${layoutsDir}`));
|
|
123
|
-
}
|
|
124
|
-
try {
|
|
125
|
-
const files = readdirSync(layoutsDir).filter(f => f.endsWith('.yaml') || f.endsWith('.yml'));
|
|
126
|
-
if (files.length === 0) {
|
|
127
|
-
console.warn(`No layout files found in ${layoutsDir}`);
|
|
128
|
-
}
|
|
129
|
-
for (const file of files) {
|
|
130
|
-
const layoutName = file.replace(/\.(yaml|yml)$/, '');
|
|
131
|
-
const layoutPath = path.join(layoutsDir, file);
|
|
132
|
-
try {
|
|
133
|
-
const layout = this.loadLayoutFile(layoutPath, layoutName);
|
|
134
|
-
const layoutId = `crewx/${layoutName}`;
|
|
135
|
-
this.layouts.set(layoutId, layout);
|
|
136
|
-
if (layoutId !== 'crewx/minimal') {
|
|
137
|
-
if (process.env.CREWX_VERBOSE === '1')
|
|
138
|
-
console.error(`Loaded layout: ${layoutId} from ${file}`);
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
catch (error) {
|
|
142
|
-
console.error(`Failed to load layout file ${file}:`, error);
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
if (process.env.CREWX_VERBOSE === '1')
|
|
146
|
-
console.error(`Loaded ${this.layouts.size} layouts from ${layoutsDir}`);
|
|
147
|
-
}
|
|
148
|
-
catch (error) {
|
|
149
|
-
throw new LayoutLoadError(`Failed to read layouts directory: ${layoutsDir}`, undefined, error instanceof Error ? error : new Error(String(error)));
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
loadLayoutFile(filePath, layoutName) {
|
|
153
|
-
try {
|
|
154
|
-
const content = readFileSync(filePath, 'utf-8');
|
|
155
|
-
if (!content || content.trim().length === 0) {
|
|
156
|
-
console.warn(`Empty YAML file: ${filePath}, will use fallback`);
|
|
157
|
-
throw new LayoutLoadError(`Empty YAML file: ${filePath}`, layoutName, new Error('File content is empty'));
|
|
158
|
-
}
|
|
159
|
-
const parsed = loadYaml(content);
|
|
160
|
-
if (!parsed || typeof parsed !== 'object') {
|
|
161
|
-
console.warn(`Invalid YAML content in ${filePath} (parsed as ${typeof parsed}), will use fallback`);
|
|
162
|
-
throw new LayoutLoadError(`Invalid or empty YAML in ${filePath}`, layoutName, new Error('YAML parsing returned null/undefined or non-object'));
|
|
163
|
-
}
|
|
164
|
-
// Format 2: layouts map (templates/agents/default.yaml format)
|
|
165
|
-
if (parsed.layouts && typeof parsed.layouts === 'object') {
|
|
166
|
-
const entry = this.resolveLayoutEntry(parsed.layouts, layoutName);
|
|
167
|
-
if (!entry || entry.template.trim().length === 0) {
|
|
168
|
-
console.warn(`Empty or missing layout template in ${filePath} for ${layoutName}`);
|
|
169
|
-
throw new LayoutLoadError(`Layout template not found or empty in layouts map: ${layoutName}`, layoutName);
|
|
170
|
-
}
|
|
171
|
-
// propsSchema may be inline in the layout entry object (e.g. default.yaml) or at the top level
|
|
172
|
-
const propsSchemaRaw = entry.propsSchema || parsed.propsSchema || {};
|
|
173
|
-
return {
|
|
174
|
-
id: `crewx/${layoutName}`,
|
|
175
|
-
version: parsed.version || '1.0.0',
|
|
176
|
-
description: parsed.description || `CrewX ${layoutName} layout`,
|
|
177
|
-
template: entry.template,
|
|
178
|
-
propsSchema: this.parsePropsSchema(propsSchemaRaw),
|
|
179
|
-
defaultProps: this.extractDefaultProps(propsSchemaRaw),
|
|
180
|
-
};
|
|
181
|
-
}
|
|
182
|
-
else {
|
|
183
|
-
// Format 1: direct layout definition
|
|
184
|
-
if (!parsed.template || (typeof parsed.template === 'string' && parsed.template.trim().length === 0)) {
|
|
185
|
-
console.warn(`Empty or missing template field in ${filePath}`);
|
|
186
|
-
throw new LayoutLoadError(`Layout template is missing or empty in ${filePath}`, layoutName);
|
|
187
|
-
}
|
|
188
|
-
return {
|
|
189
|
-
id: parsed.id || `crewx/${layoutName}`,
|
|
190
|
-
version: parsed.version || '1.0.0',
|
|
191
|
-
description: parsed.description || '',
|
|
192
|
-
template: parsed.template,
|
|
193
|
-
propsSchema: this.parsePropsSchema(parsed.propsSchema || {}),
|
|
194
|
-
defaultProps: this.extractDefaultProps(parsed.propsSchema || {}),
|
|
195
|
-
};
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
catch (error) {
|
|
199
|
-
throw new LayoutLoadError(`Failed to load layout file: ${filePath}`, layoutName, error instanceof Error ? error : new Error(String(error)));
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
parsePropsSchema(raw) {
|
|
203
|
-
const schema = {};
|
|
204
|
-
for (const [key, value] of Object.entries(raw)) {
|
|
205
|
-
if (typeof value === 'object' && value !== null) {
|
|
206
|
-
schema[key] = value;
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
return schema;
|
|
210
|
-
}
|
|
211
|
-
extractDefaultProps(propsSchema) {
|
|
212
|
-
const defaults = {};
|
|
213
|
-
for (const [key, schema] of Object.entries(propsSchema)) {
|
|
214
|
-
if (schema && typeof schema === 'object') {
|
|
215
|
-
if ('defaultValue' in schema) {
|
|
216
|
-
defaults[key] = schema.defaultValue;
|
|
217
|
-
}
|
|
218
|
-
else if ('default' in schema) {
|
|
219
|
-
defaults[key] = schema.default;
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
return defaults;
|
|
224
|
-
}
|
|
225
|
-
normalizeLayoutId(layoutId) {
|
|
226
|
-
if (!layoutId)
|
|
227
|
-
return this.options.fallbackLayoutId;
|
|
228
|
-
if (layoutId.includes('/'))
|
|
229
|
-
return layoutId;
|
|
230
|
-
return `crewx/${layoutId}`;
|
|
231
|
-
}
|
|
232
|
-
resolveLayoutEntry(layoutsMap, layoutName) {
|
|
233
|
-
const candidates = new Set();
|
|
234
|
-
if (layoutName) {
|
|
235
|
-
candidates.add(layoutName);
|
|
236
|
-
if (layoutName.includes('/')) {
|
|
237
|
-
const parts = layoutName.split('/');
|
|
238
|
-
const last = parts[parts.length - 1];
|
|
239
|
-
if (last)
|
|
240
|
-
candidates.add(last);
|
|
241
|
-
}
|
|
242
|
-
else {
|
|
243
|
-
candidates.add(`crewx/${layoutName}`);
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
candidates.add('default');
|
|
247
|
-
for (const key of candidates) {
|
|
248
|
-
const value = layoutsMap[key];
|
|
249
|
-
if (typeof value === 'string' && value.trim().length > 0) {
|
|
250
|
-
return { template: value };
|
|
251
|
-
}
|
|
252
|
-
if (value && typeof value === 'object' && typeof value.template === 'string' && value.template.trim().length > 0) {
|
|
253
|
-
return { template: value.template, propsSchema: value.propsSchema };
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
for (const value of Object.values(layoutsMap)) {
|
|
257
|
-
if (typeof value === 'string' && value.trim().length > 0) {
|
|
258
|
-
return { template: value };
|
|
259
|
-
}
|
|
260
|
-
const v = value;
|
|
261
|
-
if (v && typeof v === 'object' && typeof v.template === 'string' && v.template.trim().length > 0) {
|
|
262
|
-
return { template: v.template, propsSchema: v.propsSchema };
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
return undefined;
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
//# sourceMappingURL=loader.js.map
|