zigrix 0.1.0-alpha.1 → 0.1.0-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/doctor.js +28 -0
- package/dist/onboard.d.ts +14 -2
- package/dist/onboard.js +54 -9
- package/package.json +1 -1
package/dist/doctor.js
CHANGED
|
@@ -19,6 +19,24 @@ export function gatherDoctor(loaded, paths) {
|
|
|
19
19
|
const ruleFiles = fs.existsSync(rulesDir)
|
|
20
20
|
? fs.readdirSync(rulesDir).filter((f) => f.endsWith('.md')).sort()
|
|
21
21
|
: [];
|
|
22
|
+
// Non-login shell PATH reachability check
|
|
23
|
+
const nonLoginShellPaths = ['/usr/local/bin', '/usr/bin', '/bin', '/usr/sbin', '/sbin'];
|
|
24
|
+
const zigrixInNonLoginPath = nonLoginShellPaths.some((dir) => {
|
|
25
|
+
try {
|
|
26
|
+
return fs.existsSync(path.join(dir, 'zigrix'));
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
const zigrixNonLoginLocation = nonLoginShellPaths.find((dir) => {
|
|
33
|
+
try {
|
|
34
|
+
return fs.existsSync(path.join(dir, 'zigrix'));
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
}) ?? null;
|
|
22
40
|
const payload = {
|
|
23
41
|
node: {
|
|
24
42
|
executable: process.execPath,
|
|
@@ -61,6 +79,11 @@ export function gatherDoctor(loaded, paths) {
|
|
|
61
79
|
skillsDir: openclawSkillsDir,
|
|
62
80
|
skillsDirExists: fs.existsSync(openclawSkillsDir),
|
|
63
81
|
},
|
|
82
|
+
pathReach: {
|
|
83
|
+
nonLoginShellPaths,
|
|
84
|
+
zigrixInNonLoginPath,
|
|
85
|
+
zigrixNonLoginLocation,
|
|
86
|
+
},
|
|
64
87
|
};
|
|
65
88
|
if (!payload.node.ok)
|
|
66
89
|
warnings.push('Node.js 22+ is required.');
|
|
@@ -74,6 +97,10 @@ export function gatherDoctor(loaded, paths) {
|
|
|
74
97
|
warnings.push('~/.openclaw not found. OpenClaw integration remains optional.');
|
|
75
98
|
if (payload.rules.count === 0)
|
|
76
99
|
warnings.push('No rule files found in rules directory. Seed from orchestration/rules/.');
|
|
100
|
+
if (!payload.pathReach.zigrixInNonLoginPath) {
|
|
101
|
+
warnings.push('zigrix is not reachable from non-login shell PATH (checked: /usr/local/bin, /usr/bin). ' +
|
|
102
|
+
'Run `zigrix onboard` or manually: sudo ln -sfn $(which zigrix) /usr/local/bin/zigrix');
|
|
103
|
+
}
|
|
77
104
|
return {
|
|
78
105
|
...payload,
|
|
79
106
|
summary: {
|
|
@@ -90,6 +117,7 @@ export function renderDoctorText(payload) {
|
|
|
90
117
|
`- Config: ${payload.paths.configPath ?? 'missing'}`,
|
|
91
118
|
`- Rules dir: ${payload.rules.dir} (${payload.rules.count} files)`,
|
|
92
119
|
`- OpenClaw home: ${payload.openclaw.home} (${payload.openclaw.exists ? 'present' : 'missing'})`,
|
|
120
|
+
`- Non-login PATH reach: ${payload.pathReach.zigrixInNonLoginPath ? `yes (${payload.pathReach.zigrixNonLoginLocation})` : 'no'}`,
|
|
93
121
|
`- Ready: ${payload.summary.ready ? 'yes' : 'no'}`,
|
|
94
122
|
];
|
|
95
123
|
for (const warning of payload.summary.warnings) {
|
package/dist/onboard.d.ts
CHANGED
|
@@ -75,6 +75,12 @@ export declare function checkZigrixInPath(): boolean;
|
|
|
75
75
|
* Works whether installed via npm link, npm install -g, or local checkout.
|
|
76
76
|
*/
|
|
77
77
|
export declare function resolveZigrixBin(): string | null;
|
|
78
|
+
/**
|
|
79
|
+
* Resolve a system-level bin directory that is writable and accessible
|
|
80
|
+
* from non-login shells (e.g., /usr/local/bin).
|
|
81
|
+
* Returns the first writable candidate, or null if none are writable.
|
|
82
|
+
*/
|
|
83
|
+
export declare function findSystemBinDir(): string | null;
|
|
78
84
|
/**
|
|
79
85
|
* Preferred user-local bin directory for symlink placement.
|
|
80
86
|
* Returns the first writable directory from a priority list,
|
|
@@ -83,9 +89,15 @@ export declare function resolveZigrixBin(): string | null;
|
|
|
83
89
|
export declare function findUserBinDir(): string;
|
|
84
90
|
/**
|
|
85
91
|
* Ensure zigrix is reachable from PATH.
|
|
86
|
-
*
|
|
92
|
+
* Priority:
|
|
93
|
+
* 1. /usr/local/bin — stable path, accessible from non-login shells (OpenClaw agents, exec)
|
|
94
|
+
* 2. ~/.local/bin — user-local fallback; may not be in PATH, shows warning if so
|
|
95
|
+
*
|
|
96
|
+
* @param opts._overrideSystemBinDir - Override system bin dir selection (for testing)
|
|
87
97
|
*/
|
|
88
|
-
export declare function ensureZigrixInPath(
|
|
98
|
+
export declare function ensureZigrixInPath(opts?: {
|
|
99
|
+
_overrideSystemBinDir?: string | null;
|
|
100
|
+
}): PathStabilizeResult;
|
|
89
101
|
/**
|
|
90
102
|
* Find the skills/ directory bundled with this zigrix package.
|
|
91
103
|
*/
|
package/dist/onboard.js
CHANGED
|
@@ -161,6 +161,26 @@ export function resolveZigrixBin() {
|
|
|
161
161
|
}
|
|
162
162
|
return null;
|
|
163
163
|
}
|
|
164
|
+
/**
|
|
165
|
+
* Resolve a system-level bin directory that is writable and accessible
|
|
166
|
+
* from non-login shells (e.g., /usr/local/bin).
|
|
167
|
+
* Returns the first writable candidate, or null if none are writable.
|
|
168
|
+
*/
|
|
169
|
+
export function findSystemBinDir() {
|
|
170
|
+
const candidates = ['/usr/local/bin', '/usr/bin'];
|
|
171
|
+
for (const dir of candidates) {
|
|
172
|
+
try {
|
|
173
|
+
if (fs.existsSync(dir)) {
|
|
174
|
+
fs.accessSync(dir, fs.constants.W_OK);
|
|
175
|
+
return dir;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
catch {
|
|
179
|
+
// not writable or inaccessible
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
164
184
|
/**
|
|
165
185
|
* Preferred user-local bin directory for symlink placement.
|
|
166
186
|
* Returns the first writable directory from a priority list,
|
|
@@ -190,9 +210,13 @@ export function findUserBinDir() {
|
|
|
190
210
|
}
|
|
191
211
|
/**
|
|
192
212
|
* Ensure zigrix is reachable from PATH.
|
|
193
|
-
*
|
|
213
|
+
* Priority:
|
|
214
|
+
* 1. /usr/local/bin — stable path, accessible from non-login shells (OpenClaw agents, exec)
|
|
215
|
+
* 2. ~/.local/bin — user-local fallback; may not be in PATH, shows warning if so
|
|
216
|
+
*
|
|
217
|
+
* @param opts._overrideSystemBinDir - Override system bin dir selection (for testing)
|
|
194
218
|
*/
|
|
195
|
-
export function ensureZigrixInPath() {
|
|
219
|
+
export function ensureZigrixInPath(opts) {
|
|
196
220
|
if (checkZigrixInPath()) {
|
|
197
221
|
return { alreadyInPath: true, symlinkCreated: false, symlinkPath: null, warning: null };
|
|
198
222
|
}
|
|
@@ -205,6 +229,31 @@ export function ensureZigrixInPath() {
|
|
|
205
229
|
warning: 'Could not locate zigrix entry point. Ensure zigrix is installed via npm.',
|
|
206
230
|
};
|
|
207
231
|
}
|
|
232
|
+
// ── Strategy 1: system bin dir (accessible from non-login shells) ──────────
|
|
233
|
+
const systemBinDir = opts !== undefined && '_overrideSystemBinDir' in opts
|
|
234
|
+
? opts._overrideSystemBinDir
|
|
235
|
+
: findSystemBinDir();
|
|
236
|
+
if (systemBinDir) {
|
|
237
|
+
const symlinkPath = path.join(systemBinDir, 'zigrix');
|
|
238
|
+
try {
|
|
239
|
+
// Remove stale entry if present
|
|
240
|
+
try {
|
|
241
|
+
if (fs.existsSync(symlinkPath) || fs.lstatSync(symlinkPath).isSymbolicLink()) {
|
|
242
|
+
fs.unlinkSync(symlinkPath);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
catch {
|
|
246
|
+
// doesn't exist — fine
|
|
247
|
+
}
|
|
248
|
+
fs.symlinkSync(binEntry, symlinkPath);
|
|
249
|
+
fs.chmodSync(symlinkPath, 0o755);
|
|
250
|
+
return { alreadyInPath: false, symlinkCreated: true, symlinkPath, warning: null };
|
|
251
|
+
}
|
|
252
|
+
catch {
|
|
253
|
+
// Fall through to user bin dir
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
// ── Strategy 2: user-local bin dir ────────────────────────────────────────
|
|
208
257
|
const userBinDir = findUserBinDir();
|
|
209
258
|
try {
|
|
210
259
|
fs.mkdirSync(userBinDir, { recursive: true });
|
|
@@ -218,8 +267,6 @@ export function ensureZigrixInPath() {
|
|
|
218
267
|
};
|
|
219
268
|
}
|
|
220
269
|
const symlinkPath = path.join(userBinDir, 'zigrix');
|
|
221
|
-
// Create a wrapper script that invokes node with the correct entry
|
|
222
|
-
const wrapper = `#!/usr/bin/env node\nimport('${binEntry.replace(/\\/g, '/')}');\n`;
|
|
223
270
|
try {
|
|
224
271
|
// Remove existing if present (stale symlink or old wrapper)
|
|
225
272
|
if (fs.existsSync(symlinkPath) || fs.lstatSync(symlinkPath).isSymbolicLink()) {
|
|
@@ -230,7 +277,6 @@ export function ensureZigrixInPath() {
|
|
|
230
277
|
// doesn't exist, fine
|
|
231
278
|
}
|
|
232
279
|
try {
|
|
233
|
-
// Prefer symlink to the actual CLI bin (simpler, no wrapper needed)
|
|
234
280
|
fs.symlinkSync(binEntry, symlinkPath);
|
|
235
281
|
fs.chmodSync(symlinkPath, 0o755);
|
|
236
282
|
}
|
|
@@ -251,10 +297,9 @@ export function ensureZigrixInPath() {
|
|
|
251
297
|
// Check if userBinDir is actually in PATH
|
|
252
298
|
const pathEnv = process.env.PATH ?? '';
|
|
253
299
|
const inPath = pathEnv.split(path.delimiter).some((d) => path.resolve(d) === path.resolve(userBinDir));
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
}
|
|
300
|
+
const warning = inPath
|
|
301
|
+
? null
|
|
302
|
+
: `Created zigrix at ${symlinkPath}, but ${userBinDir} is not in your PATH. Add it:\n export PATH="${userBinDir}:$PATH"`;
|
|
258
303
|
return { alreadyInPath: false, symlinkCreated: true, symlinkPath, warning };
|
|
259
304
|
}
|
|
260
305
|
// ─── OpenClaw skill registration ──────────────────────────────────────────────
|