zigrix 0.1.0-alpha.8 → 0.1.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/LICENSE +1 -1
- package/README.md +159 -120
- package/dist/agents/registry.js +19 -2
- package/dist/agents/roles.d.ts +10 -0
- package/dist/agents/roles.js +83 -0
- package/dist/config/defaults.d.ts +88 -6
- package/dist/config/defaults.js +82 -50
- package/dist/config/load.d.ts +5 -3
- package/dist/config/load.js +69 -30
- package/dist/config/schema.d.ts +46 -4
- package/dist/config/schema.js +49 -3
- package/dist/configure.d.ts +2 -0
- package/dist/configure.js +37 -14
- package/dist/dashboard/.next/BUILD_ID +1 -1
- package/dist/dashboard/.next/app-build-manifest.json +13 -13
- package/dist/dashboard/.next/app-path-routes-manifest.json +3 -3
- package/dist/dashboard/.next/build-manifest.json +2 -2
- package/dist/dashboard/.next/prerender-manifest.json +6 -6
- package/dist/dashboard/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dist/dashboard/.next/server/app/_not-found.html +1 -1
- package/dist/dashboard/.next/server/app/_not-found.rsc +1 -1
- package/dist/dashboard/.next/server/app/api/auth/login/route.js +1 -1
- package/dist/dashboard/.next/server/app/api/auth/login/route_client-reference-manifest.js +1 -1
- package/dist/dashboard/.next/server/app/api/auth/logout/route.js +1 -1
- package/dist/dashboard/.next/server/app/api/auth/logout/route_client-reference-manifest.js +1 -1
- package/dist/dashboard/.next/server/app/api/auth/session/route.js +1 -1
- package/dist/dashboard/.next/server/app/api/auth/session/route_client-reference-manifest.js +1 -1
- package/dist/dashboard/.next/server/app/api/auth/setup/route.js +1 -1
- package/dist/dashboard/.next/server/app/api/auth/setup/route_client-reference-manifest.js +1 -1
- package/dist/dashboard/.next/server/app/api/overview/route_client-reference-manifest.js +1 -1
- package/dist/dashboard/.next/server/app/api/stream/route_client-reference-manifest.js +1 -1
- package/dist/dashboard/.next/server/app/api/tasks/[taskId]/cancel/route_client-reference-manifest.js +1 -1
- package/dist/dashboard/.next/server/app/api/tasks/[taskId]/conversation/route_client-reference-manifest.js +1 -1
- package/dist/dashboard/.next/server/app/api/tasks/[taskId]/route_client-reference-manifest.js +1 -1
- package/dist/dashboard/.next/server/app/login/page_client-reference-manifest.js +1 -1
- package/dist/dashboard/.next/server/app/login.html +1 -1
- package/dist/dashboard/.next/server/app/login.rsc +1 -1
- package/dist/dashboard/.next/server/app/page.js +2 -2
- package/dist/dashboard/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/dashboard/.next/server/app/setup/page_client-reference-manifest.js +1 -1
- package/dist/dashboard/.next/server/app/setup.html +1 -1
- package/dist/dashboard/.next/server/app/setup.rsc +1 -1
- package/dist/dashboard/.next/server/app-paths-manifest.json +3 -3
- package/dist/dashboard/.next/server/chunks/972.js +1 -1
- package/dist/dashboard/.next/server/functions-config-manifest.json +3 -3
- package/dist/dashboard/.next/server/middleware.js +1 -1
- package/dist/dashboard/.next/server/pages/404.html +1 -1
- package/dist/dashboard/.next/server/pages/500.html +1 -1
- package/dist/dashboard/.next/static/chunks/app/page-0314989c31e18b4b.js +1 -0
- package/dist/dashboard/.next/static/css/{94d75aff24d0c077.css → c3a7306cb2ba3f6c.css} +1 -1
- package/dist/dashboard.js +47 -0
- package/dist/doctor.js +28 -5
- package/dist/index.js +175 -171
- package/dist/onboard.d.ts +76 -2
- package/dist/onboard.js +529 -25
- package/dist/orchestration/dispatch.d.ts +3 -1
- package/dist/orchestration/dispatch.js +173 -45
- package/dist/orchestration/evidence.js +31 -4
- package/dist/orchestration/finalize.d.ts +1 -0
- package/dist/orchestration/finalize.js +5 -3
- package/dist/orchestration/report.js +9 -1
- package/dist/orchestration/worker.d.ts +1 -1
- package/dist/orchestration/worker.js +58 -8
- package/dist/rules/templates.js +3 -6
- package/dist/state/tasks.d.ts +12 -0
- package/dist/state/tasks.js +7 -0
- package/package.json +23 -2
- package/rules/defaults/README.md +9 -9
- package/rules/defaults/{back-zig.md → backend-agent.md} +4 -4
- package/rules/defaults/{front-zig.md → frontend-agent.md} +4 -4
- package/rules/defaults/orchestrator-agent.md +261 -0
- package/rules/defaults/{qa-zig.md → qa-agent.md} +11 -11
- package/rules/defaults/{sec-zig.md → security-agent.md} +4 -4
- package/rules/defaults/{sys-zig.md → system-agent.md} +8 -9
- package/rules/defaults/worker-common.md +25 -19
- package/skills/zigrix-doctor/SKILL.md +4 -2
- package/skills/zigrix-evidence/SKILL.md +7 -3
- package/skills/zigrix-main-agent-guide/SKILL.md +128 -0
- package/skills/zigrix-shared/SKILL.md +27 -3
- package/skills/zigrix-task-create/SKILL.md +8 -2
- package/skills/zigrix-task-status/SKILL.md +5 -2
- package/skills/zigrix-worker/SKILL.md +12 -4
- package/dist/dashboard/.next/static/chunks/app/page-25f54e54e74fb3af.js +0 -1
- package/rules/defaults/pro-zig.md +0 -238
- /package/dist/dashboard/.next/static/{2a4glWei05xr4Jg0Ly6cp → PT4hYxzrqxj-Zq4ZjtKNg}/_buildManifest.js +0 -0
- /package/dist/dashboard/.next/static/{2a4glWei05xr4Jg0Ly6cp → PT4hYxzrqxj-Zq4ZjtKNg}/_ssgManifest.js +0 -0
package/dist/config/defaults.js
CHANGED
|
@@ -1,58 +1,90 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import os from 'node:os';
|
|
3
|
-
export const
|
|
4
|
-
export const
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
3
|
+
export const CONFIG_FILENAME = 'zigrix.config.json';
|
|
4
|
+
export const LEGACY_DEFAULT_GATEWAY_URL = 'http://127.0.0.1:18789';
|
|
5
|
+
export function expandTilde(input) {
|
|
6
|
+
const homeDir = os.homedir();
|
|
7
|
+
if (!input)
|
|
8
|
+
return homeDir;
|
|
9
|
+
if (input === '~')
|
|
10
|
+
return homeDir;
|
|
11
|
+
if (input.startsWith('~/'))
|
|
12
|
+
return path.join(homeDir, input.slice(2));
|
|
13
|
+
return input;
|
|
14
|
+
}
|
|
15
|
+
export function resolveAbsolutePath(input) {
|
|
16
|
+
return path.resolve(expandTilde(input));
|
|
17
|
+
}
|
|
18
|
+
export function resolveCanonicalConfigHome() {
|
|
19
|
+
return path.join(os.homedir(), '.zigrix');
|
|
20
|
+
}
|
|
21
|
+
export function resolveCanonicalConfigPath() {
|
|
22
|
+
return path.join(resolveCanonicalConfigHome(), CONFIG_FILENAME);
|
|
23
|
+
}
|
|
24
|
+
export function resolveDefaultWorkspaceDir(baseDir = resolveCanonicalConfigHome()) {
|
|
25
|
+
return path.join(baseDir, 'workspace');
|
|
26
|
+
}
|
|
27
|
+
export function buildDefaultConfig(baseDir = resolveCanonicalConfigHome()) {
|
|
28
|
+
return {
|
|
29
|
+
paths: {
|
|
30
|
+
baseDir,
|
|
31
|
+
tasksDir: path.join(baseDir, 'tasks'),
|
|
32
|
+
evidenceDir: path.join(baseDir, 'evidence'),
|
|
33
|
+
promptsDir: path.join(baseDir, 'prompts'),
|
|
34
|
+
eventsFile: path.join(baseDir, 'tasks.jsonl'),
|
|
35
|
+
indexFile: path.join(baseDir, 'index.json'),
|
|
36
|
+
runsDir: path.join(baseDir, 'runs'),
|
|
37
|
+
rulesDir: path.join(baseDir, 'rules'),
|
|
23
38
|
},
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
scales: {
|
|
27
|
-
simple: { requiredRoles: ['orchestrator'], optionalRoles: ['qa'] },
|
|
28
|
-
normal: { requiredRoles: ['orchestrator', 'qa'], optionalRoles: ['frontend', 'backend'] },
|
|
29
|
-
risky: { requiredRoles: ['orchestrator', 'qa', 'security'], optionalRoles: ['frontend', 'backend', 'infra'] },
|
|
39
|
+
workspace: {
|
|
40
|
+
projectsBaseDir: resolveDefaultWorkspaceDir(baseDir),
|
|
30
41
|
},
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
42
|
+
agents: {
|
|
43
|
+
registry: {},
|
|
44
|
+
orchestration: {
|
|
45
|
+
participants: [],
|
|
46
|
+
excluded: [],
|
|
47
|
+
orchestratorId: 'orchestrator',
|
|
48
|
+
},
|
|
35
49
|
},
|
|
36
|
-
|
|
37
|
-
|
|
50
|
+
rules: {
|
|
51
|
+
scales: {
|
|
52
|
+
simple: { requiredRoles: ['orchestrator'], optionalRoles: ['qa'] },
|
|
53
|
+
normal: { requiredRoles: ['orchestrator', 'qa'], optionalRoles: ['frontend', 'backend'] },
|
|
54
|
+
risky: { requiredRoles: ['orchestrator', 'qa', 'security'], optionalRoles: ['frontend', 'backend', 'system'] },
|
|
55
|
+
},
|
|
56
|
+
completion: {
|
|
57
|
+
requireQa: true,
|
|
58
|
+
requireEvidence: true,
|
|
59
|
+
requireUserReport: true,
|
|
60
|
+
},
|
|
61
|
+
stale: {
|
|
62
|
+
defaultHours: 24,
|
|
63
|
+
},
|
|
38
64
|
},
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
65
|
+
templates: {
|
|
66
|
+
workerPrompt: {
|
|
67
|
+
format: 'markdown',
|
|
68
|
+
version: 2,
|
|
69
|
+
placeholders: ['taskId', 'title', 'scale', 'agentId', 'description'],
|
|
70
|
+
body: '## Worker Assignment: {{taskId}}\n- title: {{title}}\n- scale: {{scale}}\n- agent: {{agentId}}\n- description: {{description}}\n\n### Completion\n작업 완료 후 반드시 증적을 먼저 수집하라:\n```bash\nzigrix evidence collect --task-id {{taskId}} --agent-id {{agentId}} --summary "<결과 요약>"\n```\n⚠️ 증적 없이 완료하면 finalize에서 incomplete 판정된다.',
|
|
71
|
+
},
|
|
72
|
+
finalReport: {
|
|
73
|
+
format: 'markdown',
|
|
74
|
+
version: 1,
|
|
75
|
+
placeholders: ['taskId', 'title', 'status', 'summary'],
|
|
76
|
+
body: '## Final Report: {{taskId}}\n- title: {{title}}\n- status: {{status}}\n- summary: {{summary}}',
|
|
77
|
+
},
|
|
46
78
|
},
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
body: '## Final Report: {{taskId}}\n- title: {{title}}\n- status: {{status}}\n- summary: {{summary}}',
|
|
79
|
+
openclaw: {
|
|
80
|
+
home: '',
|
|
81
|
+
binPath: null,
|
|
82
|
+
gatewayUrl: '',
|
|
52
83
|
},
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
}
|
|
58
|
-
}
|
|
84
|
+
runtime: {
|
|
85
|
+
outputMode: 'text',
|
|
86
|
+
jsonIndent: 2,
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
export const defaultConfig = buildDefaultConfig();
|
package/dist/config/load.d.ts
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
|
+
import { CONFIG_FILENAME } from './defaults.js';
|
|
1
2
|
import { type ZigrixConfig } from './schema.js';
|
|
2
3
|
export type LoadedConfig = {
|
|
3
4
|
config: ZigrixConfig;
|
|
4
|
-
configPath: string
|
|
5
|
+
configPath: string;
|
|
5
6
|
baseDir: string;
|
|
6
7
|
};
|
|
8
|
+
export declare function normalizeConfig(input: ZigrixConfig): ZigrixConfig;
|
|
7
9
|
export declare function loadConfig(options?: {
|
|
8
|
-
baseDir?: string;
|
|
9
10
|
configPath?: string;
|
|
10
11
|
}): LoadedConfig;
|
|
11
12
|
export declare function writeConfigFile(targetPath: string, config: ZigrixConfig): string;
|
|
12
|
-
export declare function writeDefaultConfig(
|
|
13
|
+
export declare function writeDefaultConfig(force?: boolean): string;
|
|
13
14
|
export declare function getConfigValue(config: ZigrixConfig, dottedPath?: string): unknown;
|
|
15
|
+
export { CONFIG_FILENAME };
|
package/dist/config/load.js
CHANGED
|
@@ -1,14 +1,8 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import process from 'node:process';
|
|
4
|
-
import
|
|
5
|
-
import { defaultConfig, ZIGRIX_HOME } from './defaults.js';
|
|
4
|
+
import { buildDefaultConfig, CONFIG_FILENAME, expandTilde, resolveAbsolutePath, resolveCanonicalConfigHome, resolveCanonicalConfigPath, resolveDefaultWorkspaceDir, } from './defaults.js';
|
|
6
5
|
import { zigrixConfigSchema } from './schema.js';
|
|
7
|
-
const CONFIG_CANDIDATES = [
|
|
8
|
-
'zigrix.config.json',
|
|
9
|
-
'zigrix.config.yaml',
|
|
10
|
-
'zigrix.config.yml',
|
|
11
|
-
];
|
|
12
6
|
function isObject(value) {
|
|
13
7
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
14
8
|
}
|
|
@@ -30,22 +24,60 @@ function deepMerge(base, override) {
|
|
|
30
24
|
}
|
|
31
25
|
function parseConfigFile(filePath) {
|
|
32
26
|
const raw = fs.readFileSync(filePath, 'utf8');
|
|
33
|
-
if (filePath.endsWith('.yaml') || filePath.endsWith('.yml')) {
|
|
34
|
-
return YAML.parse(raw);
|
|
35
|
-
}
|
|
36
27
|
return JSON.parse(raw);
|
|
37
28
|
}
|
|
38
|
-
function resolveConfigPath(
|
|
29
|
+
function resolveConfigPath(explicitPath) {
|
|
39
30
|
if (explicitPath) {
|
|
40
|
-
return
|
|
31
|
+
return resolveAbsolutePath(explicitPath);
|
|
32
|
+
}
|
|
33
|
+
return resolveCanonicalConfigPath();
|
|
34
|
+
}
|
|
35
|
+
function resolvePathLike(value, baseDir, fallback) {
|
|
36
|
+
if (typeof value !== 'string')
|
|
37
|
+
return fallback;
|
|
38
|
+
const trimmed = value.trim();
|
|
39
|
+
if (!trimmed)
|
|
40
|
+
return fallback;
|
|
41
|
+
const expanded = expandTilde(trimmed);
|
|
42
|
+
if (path.isAbsolute(expanded))
|
|
43
|
+
return path.resolve(expanded);
|
|
44
|
+
return path.resolve(baseDir, expanded);
|
|
45
|
+
}
|
|
46
|
+
function normalizeConfigPaths(config) {
|
|
47
|
+
const copy = structuredClone(config);
|
|
48
|
+
const configHome = resolveCanonicalConfigHome();
|
|
49
|
+
const resolvedBaseDir = resolvePathLike(copy.paths.baseDir, configHome, configHome);
|
|
50
|
+
copy.paths.baseDir = resolvedBaseDir;
|
|
51
|
+
copy.paths.tasksDir = resolvePathLike(copy.paths.tasksDir, resolvedBaseDir, path.join(resolvedBaseDir, 'tasks'));
|
|
52
|
+
copy.paths.evidenceDir = resolvePathLike(copy.paths.evidenceDir, resolvedBaseDir, path.join(resolvedBaseDir, 'evidence'));
|
|
53
|
+
copy.paths.promptsDir = resolvePathLike(copy.paths.promptsDir, resolvedBaseDir, path.join(resolvedBaseDir, 'prompts'));
|
|
54
|
+
copy.paths.eventsFile = resolvePathLike(copy.paths.eventsFile, resolvedBaseDir, path.join(resolvedBaseDir, 'tasks.jsonl'));
|
|
55
|
+
copy.paths.indexFile = resolvePathLike(copy.paths.indexFile, resolvedBaseDir, path.join(resolvedBaseDir, 'index.json'));
|
|
56
|
+
copy.paths.runsDir = resolvePathLike(copy.paths.runsDir, resolvedBaseDir, path.join(resolvedBaseDir, 'runs'));
|
|
57
|
+
copy.paths.rulesDir = resolvePathLike(copy.paths.rulesDir, resolvedBaseDir, path.join(resolvedBaseDir, 'rules'));
|
|
58
|
+
const configuredWorkspace = typeof copy.workspace.projectsBaseDir === 'string'
|
|
59
|
+
? copy.workspace.projectsBaseDir.trim()
|
|
60
|
+
: '';
|
|
61
|
+
copy.workspace.projectsBaseDir = configuredWorkspace.length > 0
|
|
62
|
+
? resolvePathLike(configuredWorkspace, resolvedBaseDir, resolveDefaultWorkspaceDir(resolvedBaseDir))
|
|
63
|
+
: resolveDefaultWorkspaceDir(resolvedBaseDir);
|
|
64
|
+
if (typeof copy.openclaw.home === 'string' && copy.openclaw.home.trim().length > 0) {
|
|
65
|
+
copy.openclaw.home = resolveAbsolutePath(copy.openclaw.home);
|
|
41
66
|
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
67
|
+
if (typeof copy.openclaw.binPath === 'string' && copy.openclaw.binPath.trim().length > 0) {
|
|
68
|
+
copy.openclaw.binPath = resolveAbsolutePath(copy.openclaw.binPath);
|
|
69
|
+
}
|
|
70
|
+
return copy;
|
|
71
|
+
}
|
|
72
|
+
function resolveBaseDirHint(parsed, fallback) {
|
|
73
|
+
if (isObject(parsed) && isObject(parsed.paths) && typeof parsed.paths.baseDir === 'string') {
|
|
74
|
+
const configured = parsed.paths.baseDir.trim();
|
|
75
|
+
if (configured.length > 0) {
|
|
76
|
+
const expanded = expandTilde(configured);
|
|
77
|
+
return path.isAbsolute(expanded) ? path.resolve(expanded) : path.resolve(fallback, expanded);
|
|
46
78
|
}
|
|
47
79
|
}
|
|
48
|
-
return
|
|
80
|
+
return fallback;
|
|
49
81
|
}
|
|
50
82
|
function applyEnvOverrides(config) {
|
|
51
83
|
const copy = structuredClone(config);
|
|
@@ -60,29 +92,35 @@ function applyEnvOverrides(config) {
|
|
|
60
92
|
}
|
|
61
93
|
return copy;
|
|
62
94
|
}
|
|
95
|
+
export function normalizeConfig(input) {
|
|
96
|
+
const normalized = normalizeConfigPaths(input);
|
|
97
|
+
return zigrixConfigSchema.parse(normalized);
|
|
98
|
+
}
|
|
63
99
|
export function loadConfig(options) {
|
|
64
|
-
const
|
|
65
|
-
const
|
|
66
|
-
const
|
|
67
|
-
const
|
|
100
|
+
const configPath = resolveConfigPath(options?.configPath);
|
|
101
|
+
const parsed = fs.existsSync(configPath) ? parseConfigFile(configPath) : {};
|
|
102
|
+
const defaultBaseDir = resolveBaseDirHint(parsed, resolveCanonicalConfigHome());
|
|
103
|
+
const defaults = buildDefaultConfig(defaultBaseDir);
|
|
104
|
+
const merged = deepMerge(structuredClone(defaults), parsed);
|
|
68
105
|
const withEnv = applyEnvOverrides(merged);
|
|
69
|
-
const result =
|
|
70
|
-
return { config: result, configPath, baseDir };
|
|
106
|
+
const result = normalizeConfig(withEnv);
|
|
107
|
+
return { config: result, configPath, baseDir: result.paths.baseDir };
|
|
71
108
|
}
|
|
72
109
|
export function writeConfigFile(targetPath, config) {
|
|
73
|
-
const resolvedPath =
|
|
110
|
+
const resolvedPath = resolveAbsolutePath(targetPath);
|
|
74
111
|
fs.mkdirSync(path.dirname(resolvedPath), { recursive: true });
|
|
75
|
-
|
|
112
|
+
const normalized = normalizeConfig(config);
|
|
113
|
+
fs.writeFileSync(resolvedPath, `${JSON.stringify(normalized, null, 2)}\n`, 'utf8');
|
|
76
114
|
return resolvedPath;
|
|
77
115
|
}
|
|
78
|
-
export function writeDefaultConfig(
|
|
79
|
-
const
|
|
80
|
-
const targetPath =
|
|
116
|
+
export function writeDefaultConfig(force = false) {
|
|
117
|
+
const configHome = resolveCanonicalConfigHome();
|
|
118
|
+
const targetPath = resolveCanonicalConfigPath();
|
|
81
119
|
if (fs.existsSync(targetPath) && !force) {
|
|
82
120
|
throw new Error(`config already exists: ${targetPath}`);
|
|
83
121
|
}
|
|
84
|
-
fs.mkdirSync(
|
|
85
|
-
return writeConfigFile(targetPath,
|
|
122
|
+
fs.mkdirSync(configHome, { recursive: true });
|
|
123
|
+
return writeConfigFile(targetPath, buildDefaultConfig(configHome));
|
|
86
124
|
}
|
|
87
125
|
export function getConfigValue(config, dottedPath) {
|
|
88
126
|
if (!dottedPath)
|
|
@@ -94,3 +132,4 @@ export function getConfigValue(config, dottedPath) {
|
|
|
94
132
|
return undefined;
|
|
95
133
|
}, config);
|
|
96
134
|
}
|
|
135
|
+
export { CONFIG_FILENAME };
|
package/dist/config/schema.d.ts
CHANGED
|
@@ -16,7 +16,14 @@ export declare const zigrixConfigSchema: z.ZodObject<{
|
|
|
16
16
|
agents: z.ZodObject<{
|
|
17
17
|
registry: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
18
18
|
label: z.ZodString;
|
|
19
|
-
role: z.ZodString
|
|
19
|
+
role: z.ZodPipe<z.ZodPipe<z.ZodString, z.ZodTransform<"orchestrator" | "qa" | "security" | "frontend" | "backend" | "system", string>>, z.ZodEnum<{
|
|
20
|
+
orchestrator: "orchestrator";
|
|
21
|
+
qa: "qa";
|
|
22
|
+
security: "security";
|
|
23
|
+
frontend: "frontend";
|
|
24
|
+
backend: "backend";
|
|
25
|
+
system: "system";
|
|
26
|
+
}>>;
|
|
20
27
|
runtime: z.ZodString;
|
|
21
28
|
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
22
29
|
metadata: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
@@ -24,12 +31,27 @@ export declare const zigrixConfigSchema: z.ZodObject<{
|
|
|
24
31
|
orchestration: z.ZodObject<{
|
|
25
32
|
participants: z.ZodArray<z.ZodString>;
|
|
26
33
|
excluded: z.ZodArray<z.ZodString>;
|
|
34
|
+
orchestratorId: z.ZodString;
|
|
27
35
|
}, z.core.$strip>;
|
|
28
36
|
}, z.core.$strip>;
|
|
29
37
|
rules: z.ZodObject<{
|
|
30
38
|
scales: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
31
|
-
requiredRoles: z.ZodArray<z.ZodString
|
|
32
|
-
|
|
39
|
+
requiredRoles: z.ZodArray<z.ZodPipe<z.ZodPipe<z.ZodString, z.ZodTransform<"orchestrator" | "qa" | "security" | "frontend" | "backend" | "system", string>>, z.ZodEnum<{
|
|
40
|
+
orchestrator: "orchestrator";
|
|
41
|
+
qa: "qa";
|
|
42
|
+
security: "security";
|
|
43
|
+
frontend: "frontend";
|
|
44
|
+
backend: "backend";
|
|
45
|
+
system: "system";
|
|
46
|
+
}>>>;
|
|
47
|
+
optionalRoles: z.ZodArray<z.ZodPipe<z.ZodPipe<z.ZodString, z.ZodTransform<"orchestrator" | "qa" | "security" | "frontend" | "backend" | "system", string>>, z.ZodEnum<{
|
|
48
|
+
orchestrator: "orchestrator";
|
|
49
|
+
qa: "qa";
|
|
50
|
+
security: "security";
|
|
51
|
+
frontend: "frontend";
|
|
52
|
+
backend: "backend";
|
|
53
|
+
system: "system";
|
|
54
|
+
}>>>;
|
|
33
55
|
}, z.core.$strip>>;
|
|
34
56
|
completion: z.ZodObject<{
|
|
35
57
|
requireQa: z.ZodBoolean;
|
|
@@ -60,6 +82,11 @@ export declare const zigrixConfigSchema: z.ZodObject<{
|
|
|
60
82
|
body: z.ZodString;
|
|
61
83
|
}, z.core.$strip>;
|
|
62
84
|
}, z.core.$strip>;
|
|
85
|
+
openclaw: z.ZodDefault<z.ZodObject<{
|
|
86
|
+
home: z.ZodDefault<z.ZodString>;
|
|
87
|
+
binPath: z.ZodDefault<z.ZodNullable<z.ZodString>>;
|
|
88
|
+
gatewayUrl: z.ZodDefault<z.ZodString>;
|
|
89
|
+
}, z.core.$strip>>;
|
|
63
90
|
runtime: z.ZodObject<{
|
|
64
91
|
outputMode: z.ZodEnum<{
|
|
65
92
|
text: "text";
|
|
@@ -73,7 +100,7 @@ export declare const zigrixConfigJsonSchema: {
|
|
|
73
100
|
readonly $schema: "https://json-schema.org/draft/2020-12/schema";
|
|
74
101
|
readonly title: "ZigrixConfig";
|
|
75
102
|
readonly type: "object";
|
|
76
|
-
readonly required: readonly ["paths", "workspace", "agents", "rules", "templates", "runtime"];
|
|
103
|
+
readonly required: readonly ["paths", "workspace", "agents", "rules", "templates", "openclaw", "runtime"];
|
|
77
104
|
readonly properties: {
|
|
78
105
|
readonly paths: {
|
|
79
106
|
readonly type: "object";
|
|
@@ -124,6 +151,21 @@ export declare const zigrixConfigJsonSchema: {
|
|
|
124
151
|
readonly templates: {
|
|
125
152
|
readonly type: "object";
|
|
126
153
|
};
|
|
154
|
+
readonly openclaw: {
|
|
155
|
+
readonly type: "object";
|
|
156
|
+
readonly properties: {
|
|
157
|
+
readonly home: {
|
|
158
|
+
readonly type: "string";
|
|
159
|
+
};
|
|
160
|
+
readonly binPath: {
|
|
161
|
+
readonly type: readonly ["string", "null"];
|
|
162
|
+
};
|
|
163
|
+
readonly gatewayUrl: {
|
|
164
|
+
readonly type: "string";
|
|
165
|
+
};
|
|
166
|
+
};
|
|
167
|
+
readonly additionalProperties: false;
|
|
168
|
+
};
|
|
127
169
|
readonly runtime: {
|
|
128
170
|
readonly type: "object";
|
|
129
171
|
};
|
package/dist/config/schema.js
CHANGED
|
@@ -1,9 +1,21 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
|
|
2
|
+
import { STANDARD_AGENT_ROLES, normalizeAgentRole } from '../agents/roles.js';
|
|
3
3
|
const pathSchema = z.string().min(1);
|
|
4
|
+
const standardRoleSchema = z.enum(STANDARD_AGENT_ROLES);
|
|
5
|
+
const roleSchema = z.string().min(1).transform((value, ctx) => {
|
|
6
|
+
const normalized = normalizeAgentRole(value);
|
|
7
|
+
if (!normalized) {
|
|
8
|
+
ctx.addIssue({
|
|
9
|
+
code: z.ZodIssueCode.custom,
|
|
10
|
+
message: `role must be one of: ${STANDARD_AGENT_ROLES.join(', ')}`,
|
|
11
|
+
});
|
|
12
|
+
return z.NEVER;
|
|
13
|
+
}
|
|
14
|
+
return normalized;
|
|
15
|
+
}).pipe(standardRoleSchema);
|
|
4
16
|
const agentSchema = z.object({
|
|
5
17
|
label: z.string().min(1),
|
|
6
|
-
role:
|
|
18
|
+
role: roleSchema,
|
|
7
19
|
runtime: z.string().min(1),
|
|
8
20
|
enabled: z.boolean().default(true),
|
|
9
21
|
metadata: z.record(z.string(), z.unknown()).default({}),
|
|
@@ -33,6 +45,7 @@ export const zigrixConfigSchema = z.object({
|
|
|
33
45
|
orchestration: z.object({
|
|
34
46
|
participants: z.array(z.string()),
|
|
35
47
|
excluded: z.array(z.string()),
|
|
48
|
+
orchestratorId: z.string().min(1),
|
|
36
49
|
}),
|
|
37
50
|
}).superRefine((value, ctx) => {
|
|
38
51
|
const overlap = value.orchestration.participants.filter((item) => value.orchestration.excluded.includes(item));
|
|
@@ -62,6 +75,25 @@ export const zigrixConfigSchema = z.object({
|
|
|
62
75
|
});
|
|
63
76
|
}
|
|
64
77
|
}
|
|
78
|
+
// Only validate orchestratorId against registry when agents are registered
|
|
79
|
+
// During bootstrap (addAgent one-by-one), registry may not yet include the orchestrator
|
|
80
|
+
const orchestratorId = value.orchestration.orchestratorId;
|
|
81
|
+
const hasOrchestratorInRegistry = knownAgents.has(orchestratorId);
|
|
82
|
+
const hasAnyOrchestrator = Object.values(value.registry).some((agent) => agent.role === 'orchestrator');
|
|
83
|
+
if (hasAnyOrchestrator && !hasOrchestratorInRegistry) {
|
|
84
|
+
ctx.addIssue({
|
|
85
|
+
code: z.ZodIssueCode.custom,
|
|
86
|
+
message: `orchestratorId '${orchestratorId}' must exist in registry`,
|
|
87
|
+
path: ['orchestration', 'orchestratorId'],
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
if (value.orchestration.excluded.includes(orchestratorId)) {
|
|
91
|
+
ctx.addIssue({
|
|
92
|
+
code: z.ZodIssueCode.custom,
|
|
93
|
+
message: `orchestratorId '${orchestratorId}' cannot be excluded`,
|
|
94
|
+
path: ['orchestration', 'orchestratorId'],
|
|
95
|
+
});
|
|
96
|
+
}
|
|
65
97
|
}),
|
|
66
98
|
rules: z.object({
|
|
67
99
|
scales: z.record(z.string(), z.object({
|
|
@@ -81,6 +113,11 @@ export const zigrixConfigSchema = z.object({
|
|
|
81
113
|
workerPrompt: templateSchema,
|
|
82
114
|
finalReport: templateSchema,
|
|
83
115
|
}),
|
|
116
|
+
openclaw: z.object({
|
|
117
|
+
home: z.string().default(''),
|
|
118
|
+
binPath: z.string().nullable().default(null),
|
|
119
|
+
gatewayUrl: z.string().default(''),
|
|
120
|
+
}).default({ home: '', binPath: null, gatewayUrl: '' }),
|
|
84
121
|
runtime: z.object({
|
|
85
122
|
outputMode: z.enum(['text', 'json']),
|
|
86
123
|
jsonIndent: z.number().int().min(0).max(8),
|
|
@@ -90,7 +127,7 @@ export const zigrixConfigJsonSchema = {
|
|
|
90
127
|
$schema: 'https://json-schema.org/draft/2020-12/schema',
|
|
91
128
|
title: 'ZigrixConfig',
|
|
92
129
|
type: 'object',
|
|
93
|
-
required: ['paths', 'workspace', 'agents', 'rules', 'templates', 'runtime'],
|
|
130
|
+
required: ['paths', 'workspace', 'agents', 'rules', 'templates', 'openclaw', 'runtime'],
|
|
94
131
|
properties: {
|
|
95
132
|
paths: {
|
|
96
133
|
type: 'object',
|
|
@@ -117,6 +154,15 @@ export const zigrixConfigJsonSchema = {
|
|
|
117
154
|
agents: { type: 'object' },
|
|
118
155
|
rules: { type: 'object' },
|
|
119
156
|
templates: { type: 'object' },
|
|
157
|
+
openclaw: {
|
|
158
|
+
type: 'object',
|
|
159
|
+
properties: {
|
|
160
|
+
home: { type: 'string' },
|
|
161
|
+
binPath: { type: ['string', 'null'] },
|
|
162
|
+
gatewayUrl: { type: 'string' },
|
|
163
|
+
},
|
|
164
|
+
additionalProperties: false,
|
|
165
|
+
},
|
|
120
166
|
runtime: { type: 'object' },
|
|
121
167
|
},
|
|
122
168
|
additionalProperties: false,
|
package/dist/configure.d.ts
CHANGED
|
@@ -11,6 +11,7 @@ export interface ConfigureResult {
|
|
|
11
11
|
rulesSkipped: string[];
|
|
12
12
|
skillsResult: SkillRegistrationResult | null;
|
|
13
13
|
pathResult: PathStabilizeResult | null;
|
|
14
|
+
openclawPathResult: PathStabilizeResult | null;
|
|
14
15
|
workspaceChanged: boolean;
|
|
15
16
|
warnings: string[];
|
|
16
17
|
}
|
|
@@ -19,6 +20,7 @@ export interface RunConfigureOptions {
|
|
|
19
20
|
yes?: boolean;
|
|
20
21
|
projectDir?: string;
|
|
21
22
|
projectsBaseDir?: string;
|
|
23
|
+
orchestratorId?: string;
|
|
22
24
|
silent?: boolean;
|
|
23
25
|
}
|
|
24
26
|
export declare function runConfigure(options: RunConfigureOptions): Promise<ConfigureResult>;
|
package/dist/configure.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
|
-
import os from 'node:os';
|
|
3
|
-
import path from 'node:path';
|
|
4
2
|
import { removeAgent } from './agents/registry.js';
|
|
3
|
+
import { resolveAbsolutePath } from './config/defaults.js';
|
|
5
4
|
import { loadConfig, writeConfigFile } from './config/load.js';
|
|
6
|
-
import { detectOpenClawHome, ensureZigrixInPath, filterAgents, loadOpenClawConfig, promptAgentSelection, registerAgents, registerSkills, seedRules, } from './onboard.js';
|
|
5
|
+
import { detectOpenClawHome, ensureOpenClawInPath, ensureZigrixInPath, filterAgents, loadOpenClawConfig, promptAgentSelection, ensureOrchestratorId, registerAgents, registerSkills, resolveRuleSeedSource, seedRules, } from './onboard.js';
|
|
7
6
|
import { resolvePaths } from './state/paths.js';
|
|
8
7
|
const ALL_SECTIONS = ['agents', 'rules', 'workspace', 'path', 'skills'];
|
|
9
8
|
// ─── Configure ────────────────────────────────────────────────────────────────
|
|
@@ -12,11 +11,7 @@ export async function runConfigure(options) {
|
|
|
12
11
|
const silent = options.silent ?? false;
|
|
13
12
|
const log = (msg) => { if (!silent)
|
|
14
13
|
console.log(msg); };
|
|
15
|
-
|
|
16
|
-
const runtimeBaseDir = process.env.ZIGRIX_HOME
|
|
17
|
-
? path.resolve(process.env.ZIGRIX_HOME)
|
|
18
|
-
: path.join(os.homedir(), '.zigrix');
|
|
19
|
-
const loaded = loadConfig({ baseDir: runtimeBaseDir });
|
|
14
|
+
const loaded = loadConfig();
|
|
20
15
|
if (!loaded.configPath || !fs.existsSync(loaded.configPath)) {
|
|
21
16
|
throw new Error('zigrix not initialized. Run `zigrix onboard` first.');
|
|
22
17
|
}
|
|
@@ -33,6 +28,7 @@ export async function runConfigure(options) {
|
|
|
33
28
|
let rulesSkipped = [];
|
|
34
29
|
let skillsResult = null;
|
|
35
30
|
let pathResult = null;
|
|
31
|
+
let openclawPathResult = null;
|
|
36
32
|
let workspaceChanged = false;
|
|
37
33
|
let configDirty = false;
|
|
38
34
|
// ─── agents ───────────────────────────────────────────────────────────
|
|
@@ -81,9 +77,22 @@ export async function runConfigure(options) {
|
|
|
81
77
|
log(`⚠️ ${warnings[warnings.length - 1]}`);
|
|
82
78
|
}
|
|
83
79
|
}
|
|
80
|
+
// ─── orchestrator ────────────────────────────────────────────────────
|
|
81
|
+
if (sections.includes('agents') || options.orchestratorId) {
|
|
82
|
+
const orchResult = ensureOrchestratorId(config, options.orchestratorId);
|
|
83
|
+
config = orchResult.config;
|
|
84
|
+
if (orchResult.changed) {
|
|
85
|
+
configDirty = true;
|
|
86
|
+
log(`✅ Orchestrator set to: ${config.agents.orchestration.orchestratorId}`);
|
|
87
|
+
}
|
|
88
|
+
if (orchResult.warning) {
|
|
89
|
+
warnings.push(orchResult.warning);
|
|
90
|
+
log(`⚠️ ${orchResult.warning}`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
84
93
|
// ─── workspace ────────────────────────────────────────────────────────
|
|
85
94
|
if (sections.includes('workspace') && options.projectsBaseDir) {
|
|
86
|
-
const resolved =
|
|
95
|
+
const resolved = resolveAbsolutePath(options.projectsBaseDir);
|
|
87
96
|
if (config.workspace.projectsBaseDir !== resolved) {
|
|
88
97
|
config.workspace.projectsBaseDir = resolved;
|
|
89
98
|
configDirty = true;
|
|
@@ -93,10 +102,12 @@ export async function runConfigure(options) {
|
|
|
93
102
|
}
|
|
94
103
|
// ─── rules ────────────────────────────────────────────────────────────
|
|
95
104
|
if (sections.includes('rules')) {
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
105
|
+
const ruleSeed = resolveRuleSeedSource(options.projectDir);
|
|
106
|
+
if (ruleSeed.sourceDir) {
|
|
107
|
+
if (options.projectDir && ruleSeed.source === 'bundled') {
|
|
108
|
+
log(`ℹ️ No external rule templates found under ${options.projectDir}; using bundled defaults.`);
|
|
109
|
+
}
|
|
110
|
+
const result = seedRules(ruleSeed.sourceDir, paths.rulesDir);
|
|
100
111
|
rulesCopied = result.copied;
|
|
101
112
|
rulesSkipped = result.skipped;
|
|
102
113
|
if (rulesCopied.length > 0)
|
|
@@ -105,7 +116,7 @@ export async function runConfigure(options) {
|
|
|
105
116
|
log(`⏭️ Rules unchanged: ${rulesSkipped.join(', ')}`);
|
|
106
117
|
}
|
|
107
118
|
else {
|
|
108
|
-
log(
|
|
119
|
+
log('ℹ️ No bundled rule templates available — rule seeding skipped.');
|
|
109
120
|
}
|
|
110
121
|
}
|
|
111
122
|
// ─── path ─────────────────────────────────────────────────────────────
|
|
@@ -121,6 +132,17 @@ export async function runConfigure(options) {
|
|
|
121
132
|
warnings.push(pathResult.warning);
|
|
122
133
|
log(`⚠️ ${pathResult.warning}`);
|
|
123
134
|
}
|
|
135
|
+
openclawPathResult = ensureOpenClawInPath();
|
|
136
|
+
if (openclawPathResult.symlinkCreated) {
|
|
137
|
+
log(`✅ openclaw symlinked to ${openclawPathResult.symlinkPath}`);
|
|
138
|
+
}
|
|
139
|
+
else if (openclawPathResult.alreadyInPath) {
|
|
140
|
+
log('✅ openclaw already in PATH');
|
|
141
|
+
}
|
|
142
|
+
if (openclawPathResult.warning) {
|
|
143
|
+
warnings.push(openclawPathResult.warning);
|
|
144
|
+
log(`⚠️ ${openclawPathResult.warning}`);
|
|
145
|
+
}
|
|
124
146
|
}
|
|
125
147
|
// ─── skills ───────────────────────────────────────────────────────────
|
|
126
148
|
if (sections.includes('skills')) {
|
|
@@ -158,6 +180,7 @@ export async function runConfigure(options) {
|
|
|
158
180
|
rulesSkipped,
|
|
159
181
|
skillsResult,
|
|
160
182
|
pathResult,
|
|
183
|
+
openclawPathResult,
|
|
161
184
|
workspaceChanged,
|
|
162
185
|
warnings,
|
|
163
186
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
PT4hYxzrqxj-Zq4ZjtKNg
|