zigrix 0.1.0-alpha.9 → 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.
Files changed (82) hide show
  1. package/README.md +85 -182
  2. package/dist/agents/registry.js +14 -0
  3. package/dist/config/defaults.d.ts +87 -6
  4. package/dist/config/defaults.js +82 -51
  5. package/dist/config/load.d.ts +5 -3
  6. package/dist/config/load.js +69 -30
  7. package/dist/config/schema.d.ts +21 -1
  8. package/dist/config/schema.js +15 -1
  9. package/dist/configure.d.ts +1 -0
  10. package/dist/configure.js +24 -14
  11. package/dist/dashboard/.next/BUILD_ID +1 -1
  12. package/dist/dashboard/.next/app-build-manifest.json +21 -21
  13. package/dist/dashboard/.next/app-path-routes-manifest.json +7 -7
  14. package/dist/dashboard/.next/build-manifest.json +2 -2
  15. package/dist/dashboard/.next/prerender-manifest.json +10 -10
  16. package/dist/dashboard/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  17. package/dist/dashboard/.next/server/app/_not-found.html +1 -1
  18. package/dist/dashboard/.next/server/app/_not-found.rsc +1 -1
  19. package/dist/dashboard/.next/server/app/api/auth/login/route.js +1 -1
  20. package/dist/dashboard/.next/server/app/api/auth/login/route_client-reference-manifest.js +1 -1
  21. package/dist/dashboard/.next/server/app/api/auth/logout/route.js +1 -1
  22. package/dist/dashboard/.next/server/app/api/auth/logout/route_client-reference-manifest.js +1 -1
  23. package/dist/dashboard/.next/server/app/api/auth/session/route.js +1 -1
  24. package/dist/dashboard/.next/server/app/api/auth/session/route_client-reference-manifest.js +1 -1
  25. package/dist/dashboard/.next/server/app/api/auth/setup/route.js +1 -1
  26. package/dist/dashboard/.next/server/app/api/auth/setup/route_client-reference-manifest.js +1 -1
  27. package/dist/dashboard/.next/server/app/api/overview/route_client-reference-manifest.js +1 -1
  28. package/dist/dashboard/.next/server/app/api/stream/route_client-reference-manifest.js +1 -1
  29. package/dist/dashboard/.next/server/app/api/tasks/[taskId]/cancel/route_client-reference-manifest.js +1 -1
  30. package/dist/dashboard/.next/server/app/api/tasks/[taskId]/conversation/route_client-reference-manifest.js +1 -1
  31. package/dist/dashboard/.next/server/app/api/tasks/[taskId]/route_client-reference-manifest.js +1 -1
  32. package/dist/dashboard/.next/server/app/login/page_client-reference-manifest.js +1 -1
  33. package/dist/dashboard/.next/server/app/login.html +1 -1
  34. package/dist/dashboard/.next/server/app/login.rsc +1 -1
  35. package/dist/dashboard/.next/server/app/page.js +2 -2
  36. package/dist/dashboard/.next/server/app/page_client-reference-manifest.js +1 -1
  37. package/dist/dashboard/.next/server/app/setup/page_client-reference-manifest.js +1 -1
  38. package/dist/dashboard/.next/server/app/setup.html +1 -1
  39. package/dist/dashboard/.next/server/app/setup.rsc +1 -1
  40. package/dist/dashboard/.next/server/app-paths-manifest.json +7 -7
  41. package/dist/dashboard/.next/server/chunks/972.js +1 -1
  42. package/dist/dashboard/.next/server/functions-config-manifest.json +4 -4
  43. package/dist/dashboard/.next/server/middleware.js +1 -1
  44. package/dist/dashboard/.next/server/pages/404.html +1 -1
  45. package/dist/dashboard/.next/server/pages/500.html +1 -1
  46. package/dist/dashboard/.next/static/chunks/app/page-0314989c31e18b4b.js +1 -0
  47. package/dist/dashboard/.next/static/css/{94d75aff24d0c077.css → c3a7306cb2ba3f6c.css} +1 -1
  48. package/dist/dashboard.js +47 -0
  49. package/dist/doctor.js +28 -5
  50. package/dist/index.js +170 -170
  51. package/dist/onboard.d.ts +60 -0
  52. package/dist/onboard.js +403 -18
  53. package/dist/orchestration/dispatch.d.ts +1 -0
  54. package/dist/orchestration/dispatch.js +17 -5
  55. package/dist/orchestration/evidence.js +18 -5
  56. package/dist/orchestration/finalize.d.ts +1 -0
  57. package/dist/orchestration/finalize.js +5 -3
  58. package/dist/orchestration/report.js +4 -1
  59. package/dist/orchestration/worker.d.ts +1 -1
  60. package/dist/orchestration/worker.js +53 -18
  61. package/dist/state/tasks.d.ts +5 -0
  62. package/dist/state/tasks.js +7 -0
  63. package/package.json +23 -2
  64. package/rules/defaults/README.md +9 -9
  65. package/rules/defaults/{back-zig.md → backend-agent.md} +4 -4
  66. package/rules/defaults/{front-zig.md → frontend-agent.md} +4 -4
  67. package/rules/defaults/orchestrator-agent.md +261 -0
  68. package/rules/defaults/{qa-zig.md → qa-agent.md} +11 -11
  69. package/rules/defaults/{sec-zig.md → security-agent.md} +4 -4
  70. package/rules/defaults/{sys-zig.md → system-agent.md} +8 -9
  71. package/rules/defaults/worker-common.md +25 -19
  72. package/skills/zigrix-doctor/SKILL.md +4 -2
  73. package/skills/zigrix-evidence/SKILL.md +7 -3
  74. package/skills/zigrix-main-agent-guide/SKILL.md +38 -28
  75. package/skills/zigrix-shared/SKILL.md +27 -3
  76. package/skills/zigrix-task-create/SKILL.md +8 -2
  77. package/skills/zigrix-task-status/SKILL.md +5 -2
  78. package/skills/zigrix-worker/SKILL.md +12 -4
  79. package/dist/dashboard/.next/static/chunks/app/page-25f54e54e74fb3af.js +0 -1
  80. package/rules/defaults/pro-zig.md +0 -238
  81. /package/dist/dashboard/.next/static/{TlUj0t8APzTccK13DVZZW → PT4hYxzrqxj-Zq4ZjtKNg}/_buildManifest.js +0 -0
  82. /package/dist/dashboard/.next/static/{TlUj0t8APzTccK13DVZZW → PT4hYxzrqxj-Zq4ZjtKNg}/_ssgManifest.js +0 -0
@@ -1,59 +1,90 @@
1
1
  import path from 'node:path';
2
2
  import os from 'node:os';
3
- export const ZIGRIX_HOME = process.env.ZIGRIX_HOME ?? path.join(os.homedir(), '.zigrix');
4
- export const defaultConfig = {
5
- paths: {
6
- baseDir: ZIGRIX_HOME,
7
- tasksDir: path.join(ZIGRIX_HOME, 'tasks'),
8
- evidenceDir: path.join(ZIGRIX_HOME, 'evidence'),
9
- promptsDir: path.join(ZIGRIX_HOME, 'prompts'),
10
- eventsFile: path.join(ZIGRIX_HOME, 'tasks.jsonl'),
11
- indexFile: path.join(ZIGRIX_HOME, 'index.json'),
12
- runsDir: path.join(ZIGRIX_HOME, 'runs'),
13
- rulesDir: path.join(ZIGRIX_HOME, 'rules'),
14
- },
15
- workspace: {
16
- projectsBaseDir: '',
17
- },
18
- agents: {
19
- registry: {},
20
- orchestration: {
21
- participants: [],
22
- excluded: [],
23
- orchestratorId: 'pro-zig',
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'),
24
38
  },
25
- },
26
- rules: {
27
- scales: {
28
- simple: { requiredRoles: ['orchestrator'], optionalRoles: ['qa'] },
29
- normal: { requiredRoles: ['orchestrator', 'qa'], optionalRoles: ['frontend', 'backend'] },
30
- risky: { requiredRoles: ['orchestrator', 'qa', 'security'], optionalRoles: ['frontend', 'backend', 'system'] },
39
+ workspace: {
40
+ projectsBaseDir: resolveDefaultWorkspaceDir(baseDir),
31
41
  },
32
- completion: {
33
- requireQa: true,
34
- requireEvidence: true,
35
- requireUserReport: true,
42
+ agents: {
43
+ registry: {},
44
+ orchestration: {
45
+ participants: [],
46
+ excluded: [],
47
+ orchestratorId: 'orchestrator',
48
+ },
36
49
  },
37
- stale: {
38
- defaultHours: 24,
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
+ },
39
64
  },
40
- },
41
- templates: {
42
- workerPrompt: {
43
- format: 'markdown',
44
- version: 1,
45
- placeholders: ['taskId', 'title', 'scale', 'agentId', 'description'],
46
- body: '## Worker Assignment: {{taskId}}\n- title: {{title}}\n- scale: {{scale}}\n- agent: {{agentId}}\n- description: {{description}}',
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
+ },
47
78
  },
48
- finalReport: {
49
- format: 'markdown',
50
- version: 1,
51
- placeholders: ['taskId', 'title', 'status', 'summary'],
52
- body: '## Final Report: {{taskId}}\n- title: {{title}}\n- status: {{status}}\n- summary: {{summary}}',
79
+ openclaw: {
80
+ home: '',
81
+ binPath: null,
82
+ gatewayUrl: '',
53
83
  },
54
- },
55
- runtime: {
56
- outputMode: 'text',
57
- jsonIndent: 2,
58
- },
59
- };
84
+ runtime: {
85
+ outputMode: 'text',
86
+ jsonIndent: 2,
87
+ },
88
+ };
89
+ }
90
+ export const defaultConfig = buildDefaultConfig();
@@ -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 | null;
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(baseDir?: string, force?: boolean): string;
13
+ export declare function writeDefaultConfig(force?: boolean): string;
13
14
  export declare function getConfigValue(config: ZigrixConfig, dottedPath?: string): unknown;
15
+ export { CONFIG_FILENAME };
@@ -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 YAML from 'yaml';
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(baseDir, explicitPath) {
29
+ function resolveConfigPath(explicitPath) {
39
30
  if (explicitPath) {
40
- return path.resolve(explicitPath);
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
- for (const candidate of CONFIG_CANDIDATES) {
43
- const fullPath = path.join(baseDir, candidate);
44
- if (fs.existsSync(fullPath)) {
45
- return fullPath;
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 null;
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 baseDir = path.resolve(options?.baseDir ?? ZIGRIX_HOME);
65
- const configPath = resolveConfigPath(baseDir, options?.configPath);
66
- const parsed = configPath ? parseConfigFile(configPath) : {};
67
- const merged = deepMerge(structuredClone(defaultConfig), parsed);
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 = zigrixConfigSchema.parse(withEnv);
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 = path.resolve(targetPath);
110
+ const resolvedPath = resolveAbsolutePath(targetPath);
74
111
  fs.mkdirSync(path.dirname(resolvedPath), { recursive: true });
75
- fs.writeFileSync(resolvedPath, `${JSON.stringify(zigrixConfigSchema.parse(config), null, 2)}\n`, 'utf8');
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(baseDir, force = false) {
79
- const resolvedBase = path.resolve(baseDir ?? ZIGRIX_HOME);
80
- const targetPath = path.join(resolvedBase, 'zigrix.config.json');
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(resolvedBase, { recursive: true });
85
- return writeConfigFile(targetPath, structuredClone(defaultConfig));
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 };
@@ -82,6 +82,11 @@ export declare const zigrixConfigSchema: z.ZodObject<{
82
82
  body: z.ZodString;
83
83
  }, z.core.$strip>;
84
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>>;
85
90
  runtime: z.ZodObject<{
86
91
  outputMode: z.ZodEnum<{
87
92
  text: "text";
@@ -95,7 +100,7 @@ export declare const zigrixConfigJsonSchema: {
95
100
  readonly $schema: "https://json-schema.org/draft/2020-12/schema";
96
101
  readonly title: "ZigrixConfig";
97
102
  readonly type: "object";
98
- readonly required: readonly ["paths", "workspace", "agents", "rules", "templates", "runtime"];
103
+ readonly required: readonly ["paths", "workspace", "agents", "rules", "templates", "openclaw", "runtime"];
99
104
  readonly properties: {
100
105
  readonly paths: {
101
106
  readonly type: "object";
@@ -146,6 +151,21 @@ export declare const zigrixConfigJsonSchema: {
146
151
  readonly templates: {
147
152
  readonly type: "object";
148
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
+ };
149
169
  readonly runtime: {
150
170
  readonly type: "object";
151
171
  };
@@ -113,6 +113,11 @@ export const zigrixConfigSchema = z.object({
113
113
  workerPrompt: templateSchema,
114
114
  finalReport: templateSchema,
115
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: '' }),
116
121
  runtime: z.object({
117
122
  outputMode: z.enum(['text', 'json']),
118
123
  jsonIndent: z.number().int().min(0).max(8),
@@ -122,7 +127,7 @@ export const zigrixConfigJsonSchema = {
122
127
  $schema: 'https://json-schema.org/draft/2020-12/schema',
123
128
  title: 'ZigrixConfig',
124
129
  type: 'object',
125
- required: ['paths', 'workspace', 'agents', 'rules', 'templates', 'runtime'],
130
+ required: ['paths', 'workspace', 'agents', 'rules', 'templates', 'openclaw', 'runtime'],
126
131
  properties: {
127
132
  paths: {
128
133
  type: 'object',
@@ -149,6 +154,15 @@ export const zigrixConfigJsonSchema = {
149
154
  agents: { type: 'object' },
150
155
  rules: { type: 'object' },
151
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
+ },
152
166
  runtime: { type: 'object' },
153
167
  },
154
168
  additionalProperties: false,
@@ -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
  }
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, ensureOrchestratorId, 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
- // Resolve base dir at runtime (not from the static ZIGRIX_HOME constant)
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 ───────────────────────────────────────────────────────────
@@ -96,7 +92,7 @@ export async function runConfigure(options) {
96
92
  }
97
93
  // ─── workspace ────────────────────────────────────────────────────────
98
94
  if (sections.includes('workspace') && options.projectsBaseDir) {
99
- const resolved = path.resolve(options.projectsBaseDir);
95
+ const resolved = resolveAbsolutePath(options.projectsBaseDir);
100
96
  if (config.workspace.projectsBaseDir !== resolved) {
101
97
  config.workspace.projectsBaseDir = resolved;
102
98
  configDirty = true;
@@ -106,10 +102,12 @@ export async function runConfigure(options) {
106
102
  }
107
103
  // ─── rules ────────────────────────────────────────────────────────────
108
104
  if (sections.includes('rules')) {
109
- const projectDir = options.projectDir ?? process.cwd();
110
- const rulesSourceDir = path.join(projectDir, 'orchestration', 'rules');
111
- if (fs.existsSync(rulesSourceDir)) {
112
- const result = seedRules(rulesSourceDir, paths.rulesDir);
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);
113
111
  rulesCopied = result.copied;
114
112
  rulesSkipped = result.skipped;
115
113
  if (rulesCopied.length > 0)
@@ -118,7 +116,7 @@ export async function runConfigure(options) {
118
116
  log(`⏭️ Rules unchanged: ${rulesSkipped.join(', ')}`);
119
117
  }
120
118
  else {
121
- log(`ℹ️ No orchestration/rules/ at ${projectDir} — rule seeding skipped.`);
119
+ log('ℹ️ No bundled rule templates available — rule seeding skipped.');
122
120
  }
123
121
  }
124
122
  // ─── path ─────────────────────────────────────────────────────────────
@@ -134,6 +132,17 @@ export async function runConfigure(options) {
134
132
  warnings.push(pathResult.warning);
135
133
  log(`⚠️ ${pathResult.warning}`);
136
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
+ }
137
146
  }
138
147
  // ─── skills ───────────────────────────────────────────────────────────
139
148
  if (sections.includes('skills')) {
@@ -171,6 +180,7 @@ export async function runConfigure(options) {
171
180
  rulesSkipped,
172
181
  skillsResult,
173
182
  pathResult,
183
+ openclawPathResult,
174
184
  workspaceChanged,
175
185
  warnings,
176
186
  };
@@ -1 +1 @@
1
- TlUj0t8APzTccK13DVZZW
1
+ PT4hYxzrqxj-Zq4ZjtKNg
@@ -15,12 +15,12 @@
15
15
  "static/css/9f7ffdac282b0450.css",
16
16
  "static/chunks/app/layout-96206a34ff37a783.js"
17
17
  ],
18
- "/api/overview/route": [
18
+ "/api/auth/logout/route": [
19
19
  "static/chunks/webpack-1c485544eee88ef7.js",
20
20
  "static/chunks/4bd1b696-c023c6e3521b1417.js",
21
21
  "static/chunks/255-ebd51be49873d76c.js",
22
22
  "static/chunks/main-app-458501fc143f8dcb.js",
23
- "static/chunks/app/api/overview/route-aaf047a494f0055f.js"
23
+ "static/chunks/app/api/auth/logout/route-aaf047a494f0055f.js"
24
24
  ],
25
25
  "/api/auth/session/route": [
26
26
  "static/chunks/webpack-1c485544eee88ef7.js",
@@ -29,47 +29,47 @@
29
29
  "static/chunks/main-app-458501fc143f8dcb.js",
30
30
  "static/chunks/app/api/auth/session/route-aaf047a494f0055f.js"
31
31
  ],
32
- "/api/auth/login/route": [
32
+ "/api/auth/setup/route": [
33
33
  "static/chunks/webpack-1c485544eee88ef7.js",
34
34
  "static/chunks/4bd1b696-c023c6e3521b1417.js",
35
35
  "static/chunks/255-ebd51be49873d76c.js",
36
36
  "static/chunks/main-app-458501fc143f8dcb.js",
37
- "static/chunks/app/api/auth/login/route-aaf047a494f0055f.js"
37
+ "static/chunks/app/api/auth/setup/route-aaf047a494f0055f.js"
38
38
  ],
39
- "/api/auth/logout/route": [
39
+ "/api/auth/login/route": [
40
40
  "static/chunks/webpack-1c485544eee88ef7.js",
41
41
  "static/chunks/4bd1b696-c023c6e3521b1417.js",
42
42
  "static/chunks/255-ebd51be49873d76c.js",
43
43
  "static/chunks/main-app-458501fc143f8dcb.js",
44
- "static/chunks/app/api/auth/logout/route-aaf047a494f0055f.js"
44
+ "static/chunks/app/api/auth/login/route-aaf047a494f0055f.js"
45
45
  ],
46
- "/api/tasks/[taskId]/route": [
46
+ "/api/overview/route": [
47
47
  "static/chunks/webpack-1c485544eee88ef7.js",
48
48
  "static/chunks/4bd1b696-c023c6e3521b1417.js",
49
49
  "static/chunks/255-ebd51be49873d76c.js",
50
50
  "static/chunks/main-app-458501fc143f8dcb.js",
51
- "static/chunks/app/api/tasks/[taskId]/route-aaf047a494f0055f.js"
51
+ "static/chunks/app/api/overview/route-aaf047a494f0055f.js"
52
52
  ],
53
- "/api/tasks/[taskId]/conversation/route": [
53
+ "/api/tasks/[taskId]/cancel/route": [
54
54
  "static/chunks/webpack-1c485544eee88ef7.js",
55
55
  "static/chunks/4bd1b696-c023c6e3521b1417.js",
56
56
  "static/chunks/255-ebd51be49873d76c.js",
57
57
  "static/chunks/main-app-458501fc143f8dcb.js",
58
- "static/chunks/app/api/tasks/[taskId]/conversation/route-aaf047a494f0055f.js"
58
+ "static/chunks/app/api/tasks/[taskId]/cancel/route-aaf047a494f0055f.js"
59
59
  ],
60
- "/api/tasks/[taskId]/cancel/route": [
60
+ "/api/tasks/[taskId]/conversation/route": [
61
61
  "static/chunks/webpack-1c485544eee88ef7.js",
62
62
  "static/chunks/4bd1b696-c023c6e3521b1417.js",
63
63
  "static/chunks/255-ebd51be49873d76c.js",
64
64
  "static/chunks/main-app-458501fc143f8dcb.js",
65
- "static/chunks/app/api/tasks/[taskId]/cancel/route-aaf047a494f0055f.js"
65
+ "static/chunks/app/api/tasks/[taskId]/conversation/route-aaf047a494f0055f.js"
66
66
  ],
67
- "/api/auth/setup/route": [
67
+ "/api/tasks/[taskId]/route": [
68
68
  "static/chunks/webpack-1c485544eee88ef7.js",
69
69
  "static/chunks/4bd1b696-c023c6e3521b1417.js",
70
70
  "static/chunks/255-ebd51be49873d76c.js",
71
71
  "static/chunks/main-app-458501fc143f8dcb.js",
72
- "static/chunks/app/api/auth/setup/route-aaf047a494f0055f.js"
72
+ "static/chunks/app/api/tasks/[taskId]/route-aaf047a494f0055f.js"
73
73
  ],
74
74
  "/api/stream/route": [
75
75
  "static/chunks/webpack-1c485544eee88ef7.js",
@@ -86,22 +86,22 @@
86
86
  "static/css/1f406f685b1e941e.css",
87
87
  "static/chunks/app/login/page-f627cfc7a91a6d34.js"
88
88
  ],
89
- "/setup/page": [
89
+ "/page": [
90
90
  "static/chunks/webpack-1c485544eee88ef7.js",
91
91
  "static/chunks/4bd1b696-c023c6e3521b1417.js",
92
92
  "static/chunks/255-ebd51be49873d76c.js",
93
93
  "static/chunks/main-app-458501fc143f8dcb.js",
94
- "static/css/1f406f685b1e941e.css",
95
- "static/chunks/app/setup/page-a01ab6e2460293c3.js"
94
+ "static/css/c3a7306cb2ba3f6c.css",
95
+ "static/chunks/856-4671c40140d5540a.js",
96
+ "static/chunks/app/page-0314989c31e18b4b.js"
96
97
  ],
97
- "/page": [
98
+ "/setup/page": [
98
99
  "static/chunks/webpack-1c485544eee88ef7.js",
99
100
  "static/chunks/4bd1b696-c023c6e3521b1417.js",
100
101
  "static/chunks/255-ebd51be49873d76c.js",
101
102
  "static/chunks/main-app-458501fc143f8dcb.js",
102
- "static/css/94d75aff24d0c077.css",
103
- "static/chunks/856-4671c40140d5540a.js",
104
- "static/chunks/app/page-25f54e54e74fb3af.js"
103
+ "static/css/1f406f685b1e941e.css",
104
+ "static/chunks/app/setup/page-a01ab6e2460293c3.js"
105
105
  ]
106
106
  }
107
107
  }
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "/_not-found/page": "/_not-found",
3
- "/api/overview/route": "/api/overview",
3
+ "/api/auth/logout/route": "/api/auth/logout",
4
4
  "/api/auth/session/route": "/api/auth/session",
5
+ "/api/auth/setup/route": "/api/auth/setup",
5
6
  "/api/auth/login/route": "/api/auth/login",
6
- "/api/auth/logout/route": "/api/auth/logout",
7
- "/api/tasks/[taskId]/route": "/api/tasks/[taskId]",
8
- "/api/tasks/[taskId]/conversation/route": "/api/tasks/[taskId]/conversation",
7
+ "/api/overview/route": "/api/overview",
9
8
  "/api/tasks/[taskId]/cancel/route": "/api/tasks/[taskId]/cancel",
10
- "/api/auth/setup/route": "/api/auth/setup",
9
+ "/api/tasks/[taskId]/conversation/route": "/api/tasks/[taskId]/conversation",
10
+ "/api/tasks/[taskId]/route": "/api/tasks/[taskId]",
11
11
  "/api/stream/route": "/api/stream",
12
12
  "/login/page": "/login",
13
- "/setup/page": "/setup",
14
- "/page": "/"
13
+ "/page": "/",
14
+ "/setup/page": "/setup"
15
15
  }
@@ -5,8 +5,8 @@
5
5
  "devFiles": [],
6
6
  "ampDevFiles": [],
7
7
  "lowPriorityFiles": [
8
- "static/TlUj0t8APzTccK13DVZZW/_buildManifest.js",
9
- "static/TlUj0t8APzTccK13DVZZW/_ssgManifest.js"
8
+ "static/PT4hYxzrqxj-Zq4ZjtKNg/_buildManifest.js",
9
+ "static/PT4hYxzrqxj-Zq4ZjtKNg/_ssgManifest.js"
10
10
  ],
11
11
  "rootMainFiles": [
12
12
  "static/chunks/webpack-1c485544eee88ef7.js",