@ekkos/cli 0.2.9 → 0.2.10
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/cache/LocalSessionStore.d.ts +34 -21
- package/dist/cache/LocalSessionStore.js +169 -53
- package/dist/cache/capture.d.ts +19 -11
- package/dist/cache/capture.js +243 -76
- package/dist/cache/types.d.ts +14 -1
- package/dist/commands/doctor.d.ts +10 -0
- package/dist/commands/doctor.js +148 -73
- package/dist/commands/hooks.d.ts +109 -0
- package/dist/commands/hooks.js +668 -0
- package/dist/commands/run.d.ts +1 -0
- package/dist/commands/run.js +69 -21
- package/dist/index.js +42 -1
- package/dist/restore/RestoreOrchestrator.d.ts +17 -3
- package/dist/restore/RestoreOrchestrator.js +64 -22
- package/dist/utils/paths.d.ts +125 -0
- package/dist/utils/paths.js +283 -0
- package/package.json +1 -1
- package/templates/ekkos-manifest.json +223 -0
- package/templates/helpers/json-parse.cjs +101 -0
- package/templates/hooks/assistant-response.ps1 +256 -0
- package/templates/hooks/assistant-response.sh +124 -64
- package/templates/hooks/session-start.ps1 +107 -2
- package/templates/hooks/session-start.sh +201 -166
- package/templates/hooks/stop.ps1 +124 -3
- package/templates/hooks/stop.sh +470 -843
- package/templates/hooks/user-prompt-submit.ps1 +107 -22
- package/templates/hooks/user-prompt-submit.sh +403 -393
- package/templates/project-stubs/session-start.ps1 +63 -0
- package/templates/project-stubs/session-start.sh +55 -0
- package/templates/project-stubs/stop.ps1 +63 -0
- package/templates/project-stubs/stop.sh +55 -0
- package/templates/project-stubs/user-prompt-submit.ps1 +63 -0
- package/templates/project-stubs/user-prompt-submit.sh +55 -0
- package/templates/shared/hooks-enabled.json +22 -0
- package/templates/shared/session-words.json +45 -0
package/dist/commands/doctor.js
CHANGED
|
@@ -1,4 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* ekkOS CLI: doctor command
|
|
4
|
+
* Checks system prerequisites for ekkOS
|
|
5
|
+
*
|
|
6
|
+
* Per ekkOS Onboarding Spec v1.2 + Addendum:
|
|
7
|
+
* - Node gate: Node >= 18 required (FAIL if missing)
|
|
8
|
+
* - PTY gate: WARN on Windows if missing (monitor-only mode available)
|
|
9
|
+
* - Hooks gate: Verifies hook installation
|
|
10
|
+
* - NO jq checks (jq dependency eliminated)
|
|
11
|
+
*/
|
|
2
12
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
13
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
14
|
};
|
|
@@ -6,8 +16,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
16
|
exports.runDiagnostics = runDiagnostics;
|
|
7
17
|
exports.doctor = doctor;
|
|
8
18
|
const os_1 = require("os");
|
|
19
|
+
const path_1 = require("path");
|
|
20
|
+
const fs_1 = require("fs");
|
|
9
21
|
const child_process_1 = require("child_process");
|
|
10
22
|
const chalk_1 = __importDefault(require("chalk"));
|
|
23
|
+
const hooks_1 = require("./hooks");
|
|
11
24
|
/**
|
|
12
25
|
* Check if a command exists in PATH
|
|
13
26
|
*/
|
|
@@ -92,18 +105,42 @@ function checkMcpConfig() {
|
|
|
92
105
|
}
|
|
93
106
|
}
|
|
94
107
|
/**
|
|
95
|
-
* Check
|
|
108
|
+
* Check hooks installation status
|
|
96
109
|
*/
|
|
97
|
-
function
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
return true;
|
|
110
|
+
function checkHooksInstallation() {
|
|
111
|
+
const isWindows = (0, os_1.platform)() === 'win32';
|
|
112
|
+
const manifestData = (0, hooks_1.loadManifest)();
|
|
113
|
+
if (!manifestData) {
|
|
114
|
+
return { installed: false, details: 'Source manifest not found' };
|
|
103
115
|
}
|
|
104
|
-
|
|
105
|
-
|
|
116
|
+
const platformConfig = manifestData.manifest.platforms[(0, os_1.platform)()];
|
|
117
|
+
const globalHooksDir = (0, hooks_1.expandPath)(platformConfig.globalHooksDir);
|
|
118
|
+
const configDir = (0, hooks_1.expandPath)(platformConfig.configDir);
|
|
119
|
+
// Check installed manifest
|
|
120
|
+
const installedManifestPath = (0, path_1.join)(globalHooksDir, '.ekkos-manifest.json');
|
|
121
|
+
if (!(0, fs_1.existsSync)(installedManifestPath)) {
|
|
122
|
+
return { installed: false, details: 'No installed manifest found' };
|
|
123
|
+
}
|
|
124
|
+
// Check helper
|
|
125
|
+
const helperPath = (0, path_1.join)(configDir, '.helpers', 'json-parse.cjs');
|
|
126
|
+
if (!(0, fs_1.existsSync)(helperPath)) {
|
|
127
|
+
return { installed: false, details: 'json-parse.cjs helper missing' };
|
|
128
|
+
}
|
|
129
|
+
// Check defaults
|
|
130
|
+
const defaultsPath = (0, path_1.join)(configDir, '.defaults', 'session-words.json');
|
|
131
|
+
if (!(0, fs_1.existsSync)(defaultsPath)) {
|
|
132
|
+
return { installed: false, details: 'Default session words missing' };
|
|
106
133
|
}
|
|
134
|
+
// Check required hooks
|
|
135
|
+
const hookExt = isWindows ? '.ps1' : '.sh';
|
|
136
|
+
const requiredHooks = ['user-prompt-submit', 'stop', 'session-start'];
|
|
137
|
+
for (const hookName of requiredHooks) {
|
|
138
|
+
const hookPath = (0, path_1.join)(globalHooksDir, `${hookName}${hookExt}`);
|
|
139
|
+
if (!(0, fs_1.existsSync)(hookPath)) {
|
|
140
|
+
return { installed: false, details: `${hookName}${hookExt} missing` };
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return { installed: true, details: 'All hooks and helpers installed' };
|
|
107
144
|
}
|
|
108
145
|
/**
|
|
109
146
|
* Run diagnostic checks and return report
|
|
@@ -115,11 +152,38 @@ function runDiagnostics() {
|
|
|
115
152
|
const nodeVersion = getVersion('node') || 'Not found';
|
|
116
153
|
const claudeVersion = getVersion('claude');
|
|
117
154
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
118
|
-
// GATE 1:
|
|
155
|
+
// GATE 1: Node.js Version (>= 18 required per spec)
|
|
156
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
157
|
+
const nodeChecks = [];
|
|
158
|
+
let nodeGatePass = true;
|
|
159
|
+
const nodeMatch = nodeVersion.match(/v?(\d+)\./);
|
|
160
|
+
const nodeMajor = nodeMatch ? parseInt(nodeMatch[1], 10) : 0;
|
|
161
|
+
const nodeOk = nodeMajor >= 18;
|
|
162
|
+
nodeChecks.push({
|
|
163
|
+
name: 'Node.js version >= 18',
|
|
164
|
+
passed: nodeOk,
|
|
165
|
+
detail: nodeOk
|
|
166
|
+
? `${nodeVersion} (OK)`
|
|
167
|
+
: `${nodeVersion} (Need Node.js 18 or higher)`
|
|
168
|
+
});
|
|
169
|
+
if (!nodeOk) {
|
|
170
|
+
nodeGatePass = false;
|
|
171
|
+
}
|
|
172
|
+
gates.push({
|
|
173
|
+
id: 'node',
|
|
174
|
+
title: 'Node.js',
|
|
175
|
+
status: nodeGatePass ? 'PASS' : 'FAIL',
|
|
176
|
+
checks: nodeChecks,
|
|
177
|
+
fix: nodeGatePass ? undefined : isWindows
|
|
178
|
+
? 'winget install OpenJS.NodeJS.LTS'
|
|
179
|
+
: 'Install Node.js 20 or 22 LTS from nodejs.org'
|
|
180
|
+
});
|
|
181
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
182
|
+
// GATE 2: Interactive Claude Works
|
|
119
183
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
120
184
|
const claudeChecks = [];
|
|
121
185
|
let claudeGatePass = true;
|
|
122
|
-
// Check
|
|
186
|
+
// Check 2.1: claude command exists
|
|
123
187
|
const claudeExists = commandExists('claude');
|
|
124
188
|
claudeChecks.push({
|
|
125
189
|
name: 'Claude CLI installed',
|
|
@@ -128,7 +192,7 @@ function runDiagnostics() {
|
|
|
128
192
|
});
|
|
129
193
|
if (!claudeExists)
|
|
130
194
|
claudeGatePass = false;
|
|
131
|
-
// Check
|
|
195
|
+
// Check 2.2: claude --version works
|
|
132
196
|
if (claudeExists) {
|
|
133
197
|
const versionWorks = claudeVersion !== null;
|
|
134
198
|
claudeChecks.push({
|
|
@@ -139,15 +203,6 @@ function runDiagnostics() {
|
|
|
139
203
|
if (!versionWorks)
|
|
140
204
|
claudeGatePass = false;
|
|
141
205
|
}
|
|
142
|
-
// Check 1.3: On Windows, PTY is required for interactive mode
|
|
143
|
-
// This is checked in Gate 2, but we note it here
|
|
144
|
-
if (isWindows) {
|
|
145
|
-
claudeChecks.push({
|
|
146
|
-
name: 'Interactive mode (requires PTY)',
|
|
147
|
-
passed: true, // Will be validated in Gate 2
|
|
148
|
-
detail: 'See PTY gate below'
|
|
149
|
-
});
|
|
150
|
-
}
|
|
151
206
|
gates.push({
|
|
152
207
|
id: 'interactive-claude',
|
|
153
208
|
title: 'Interactive Claude',
|
|
@@ -156,52 +211,71 @@ function runDiagnostics() {
|
|
|
156
211
|
fix: claudeGatePass ? undefined : 'npm install -g @anthropic-ai/claude-code'
|
|
157
212
|
});
|
|
158
213
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
159
|
-
// GATE
|
|
214
|
+
// GATE 3: PTY Works (WARN on Windows if missing per spec v1.2 Addendum)
|
|
160
215
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
161
216
|
const ptyChecks = [];
|
|
162
|
-
let
|
|
163
|
-
// Check Node version (20.x or 22.x recommended)
|
|
164
|
-
const nodeMatch = nodeVersion.match(/v?(\d+)\./);
|
|
165
|
-
const nodeMajor = nodeMatch ? parseInt(nodeMatch[1], 10) : 0;
|
|
166
|
-
const nodeOk = nodeMajor >= 18 && nodeMajor <= 22;
|
|
167
|
-
ptyChecks.push({
|
|
168
|
-
name: 'Node.js version',
|
|
169
|
-
passed: nodeOk,
|
|
170
|
-
detail: nodeOk
|
|
171
|
-
? `${nodeVersion} (OK)`
|
|
172
|
-
: `${nodeVersion} (Need 20.x or 22.x LTS for PTY support)`
|
|
173
|
-
});
|
|
174
|
-
if (!nodeOk && isWindows)
|
|
175
|
-
ptyGatePass = false;
|
|
217
|
+
let ptyGateStatus = 'PASS';
|
|
176
218
|
// Check PTY availability
|
|
177
219
|
const ptyResult = checkPty();
|
|
178
220
|
ptyChecks.push({
|
|
179
221
|
name: 'node-pty loadable',
|
|
180
222
|
passed: ptyResult.available,
|
|
181
|
-
detail: ptyResult.available
|
|
223
|
+
detail: ptyResult.available
|
|
224
|
+
? isWindows ? 'ConPTY available' : 'PTY available'
|
|
225
|
+
: ptyResult.error
|
|
182
226
|
});
|
|
183
|
-
if (!ptyResult.available
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
227
|
+
if (!ptyResult.available) {
|
|
228
|
+
if (isWindows) {
|
|
229
|
+
// Per spec: Windows without PTY is WARN (monitor-only mode available)
|
|
230
|
+
ptyGateStatus = 'WARN';
|
|
231
|
+
ptyChecks.push({
|
|
232
|
+
name: 'Monitor-only mode',
|
|
233
|
+
passed: true,
|
|
234
|
+
detail: 'Auto-continue disabled; manual /clear + /continue required'
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
else {
|
|
238
|
+
// Unix has script(1) fallback
|
|
239
|
+
ptyChecks.push({
|
|
240
|
+
name: 'Unix fallback',
|
|
241
|
+
passed: true,
|
|
242
|
+
detail: 'script(1) fallback available'
|
|
243
|
+
});
|
|
244
|
+
ptyGateStatus = 'PASS';
|
|
245
|
+
}
|
|
193
246
|
}
|
|
194
247
|
gates.push({
|
|
195
248
|
id: 'pty',
|
|
196
249
|
title: 'PTY (Terminal)',
|
|
197
|
-
status:
|
|
250
|
+
status: ptyGateStatus,
|
|
198
251
|
checks: ptyChecks,
|
|
199
|
-
fix:
|
|
200
|
-
? 'npm install node-pty-prebuilt-multiarch
|
|
252
|
+
fix: ptyGateStatus === 'WARN'
|
|
253
|
+
? 'npm install node-pty-prebuilt-multiarch (optional for auto-continue)'
|
|
201
254
|
: undefined
|
|
202
255
|
});
|
|
203
256
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
204
|
-
// GATE
|
|
257
|
+
// GATE 4: Hooks Installation (per spec v1.2)
|
|
258
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
259
|
+
const hooksChecks = [];
|
|
260
|
+
let hooksGateStatus = 'PASS';
|
|
261
|
+
const hooksResult = checkHooksInstallation();
|
|
262
|
+
hooksChecks.push({
|
|
263
|
+
name: 'ekkOS hooks installed',
|
|
264
|
+
passed: hooksResult.installed,
|
|
265
|
+
detail: hooksResult.details
|
|
266
|
+
});
|
|
267
|
+
if (!hooksResult.installed) {
|
|
268
|
+
hooksGateStatus = 'WARN';
|
|
269
|
+
}
|
|
270
|
+
gates.push({
|
|
271
|
+
id: 'hooks',
|
|
272
|
+
title: 'ekkOS Hooks',
|
|
273
|
+
status: hooksGateStatus,
|
|
274
|
+
checks: hooksChecks,
|
|
275
|
+
fix: hooksGateStatus === 'WARN' ? 'ekkos hooks install --global' : undefined
|
|
276
|
+
});
|
|
277
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
278
|
+
// GATE 5: MCP Works
|
|
205
279
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
206
280
|
const mcpChecks = [];
|
|
207
281
|
let mcpGatePass = true;
|
|
@@ -227,16 +301,6 @@ function runDiagnostics() {
|
|
|
227
301
|
if (!mcpResult.configured)
|
|
228
302
|
mcpGatePass = false;
|
|
229
303
|
}
|
|
230
|
-
// Check bash on Windows (for hooks, WARN only)
|
|
231
|
-
if (isWindows) {
|
|
232
|
-
const bashOk = checkBash();
|
|
233
|
-
mcpChecks.push({
|
|
234
|
-
name: 'Bash available (for hooks)',
|
|
235
|
-
passed: bashOk,
|
|
236
|
-
detail: bashOk ? 'Git Bash/WSL detected' : 'PowerShell hooks will be used'
|
|
237
|
-
});
|
|
238
|
-
// Don't fail gate for missing bash, just note it
|
|
239
|
-
}
|
|
240
304
|
gates.push({
|
|
241
305
|
id: 'mcp',
|
|
242
306
|
title: 'MCP Configuration',
|
|
@@ -248,7 +312,6 @@ function runDiagnostics() {
|
|
|
248
312
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
249
313
|
// Calculate overall status
|
|
250
314
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
251
|
-
const allPass = gates.every(g => g.status === 'PASS');
|
|
252
315
|
const hasBlocker = gates.some(g => g.status === 'FAIL');
|
|
253
316
|
return {
|
|
254
317
|
platform: isWindows ? 'Windows' : (0, os_1.platform)() === 'darwin' ? 'macOS' : 'Linux',
|
|
@@ -263,8 +326,8 @@ function runDiagnostics() {
|
|
|
263
326
|
*/
|
|
264
327
|
function displayReport(report) {
|
|
265
328
|
console.log('');
|
|
266
|
-
console.log(chalk_1.default.cyan.bold('
|
|
267
|
-
console.log(chalk_1.default.gray('
|
|
329
|
+
console.log(chalk_1.default.cyan.bold('ekkOS Doctor'));
|
|
330
|
+
console.log(chalk_1.default.gray('-'.repeat(60)));
|
|
268
331
|
console.log('');
|
|
269
332
|
// Platform info
|
|
270
333
|
console.log(chalk_1.default.gray(`Platform: ${report.platform}`));
|
|
@@ -289,13 +352,13 @@ function displayReport(report) {
|
|
|
289
352
|
console.log(chalk_1.default.gray(` ${check.detail}`));
|
|
290
353
|
}
|
|
291
354
|
}
|
|
292
|
-
if (gate.fix && gate.status === 'FAIL') {
|
|
355
|
+
if (gate.fix && (gate.status === 'FAIL' || gate.status === 'WARN')) {
|
|
293
356
|
console.log(chalk_1.default.yellow(` → Fix: ${gate.fix}`));
|
|
294
357
|
}
|
|
295
358
|
console.log('');
|
|
296
359
|
}
|
|
297
360
|
// Summary
|
|
298
|
-
console.log(chalk_1.default.gray('
|
|
361
|
+
console.log(chalk_1.default.gray('-'.repeat(60)));
|
|
299
362
|
const blockers = report.gates.filter(g => g.status === 'FAIL').length;
|
|
300
363
|
const warnings = report.gates.filter(g => g.status === 'WARN').length;
|
|
301
364
|
if (blockers > 0) {
|
|
@@ -307,7 +370,7 @@ function displayReport(report) {
|
|
|
307
370
|
console.log(chalk_1.default.green('ekkOS can run, but some features may be limited.'));
|
|
308
371
|
}
|
|
309
372
|
else {
|
|
310
|
-
console.log(chalk_1.default.green.bold('
|
|
373
|
+
console.log(chalk_1.default.green.bold('All systems operational'));
|
|
311
374
|
console.log(chalk_1.default.green('ekkOS is ready to use.'));
|
|
312
375
|
}
|
|
313
376
|
console.log('');
|
|
@@ -340,7 +403,6 @@ async function attemptAutoFixes(report) {
|
|
|
340
403
|
// Try prebuilt PTY first (safe, non-admin)
|
|
341
404
|
console.log(chalk_1.default.yellow('\nAttempting to install prebuilt PTY...'));
|
|
342
405
|
try {
|
|
343
|
-
// Try homebridge prebuilt first
|
|
344
406
|
(0, child_process_1.execSync)('npm install -g @homebridge/node-pty-prebuilt-multiarch', {
|
|
345
407
|
stdio: 'inherit',
|
|
346
408
|
timeout: 60000
|
|
@@ -352,6 +414,19 @@ async function attemptAutoFixes(report) {
|
|
|
352
414
|
manual.push('If that fails: Install VS Build Tools, then: npm rebuild node-pty');
|
|
353
415
|
}
|
|
354
416
|
break;
|
|
417
|
+
case 'hooks':
|
|
418
|
+
// Try to install hooks
|
|
419
|
+
console.log(chalk_1.default.yellow('\nAttempting to install hooks...'));
|
|
420
|
+
try {
|
|
421
|
+
// Import and call directly
|
|
422
|
+
const { hooksInstall } = require('./hooks');
|
|
423
|
+
await hooksInstall({ global: true, verbose: false });
|
|
424
|
+
fixed.push('Hooks installed');
|
|
425
|
+
}
|
|
426
|
+
catch {
|
|
427
|
+
manual.push('ekkos hooks install --global');
|
|
428
|
+
}
|
|
429
|
+
break;
|
|
355
430
|
case 'mcp':
|
|
356
431
|
// Try to configure MCP (safe)
|
|
357
432
|
console.log(chalk_1.default.yellow('\nAttempting to configure MCP...'));
|
|
@@ -388,26 +463,26 @@ async function doctor(options = {}) {
|
|
|
388
463
|
displayReport(report);
|
|
389
464
|
// Fix mode - attempt safe auto-fixes
|
|
390
465
|
if (options.fix && !report.canProceed) {
|
|
391
|
-
console.log(chalk_1.default.cyan.bold('\
|
|
466
|
+
console.log(chalk_1.default.cyan.bold('\nAttempting auto-fixes...\n'));
|
|
392
467
|
const { fixed, manual } = await attemptAutoFixes(report);
|
|
393
468
|
if (fixed.length > 0) {
|
|
394
469
|
console.log(chalk_1.default.green('\n✓ Auto-fixed:'));
|
|
395
470
|
for (const f of fixed) {
|
|
396
|
-
console.log(chalk_1.default.green(`
|
|
471
|
+
console.log(chalk_1.default.green(` - ${f}`));
|
|
397
472
|
}
|
|
398
473
|
}
|
|
399
474
|
if (manual.length > 0) {
|
|
400
|
-
console.log(chalk_1.default.yellow('\
|
|
475
|
+
console.log(chalk_1.default.yellow('\nManual steps required:'));
|
|
401
476
|
for (const m of manual) {
|
|
402
477
|
console.log(chalk_1.default.white(` ${m}`));
|
|
403
478
|
}
|
|
404
479
|
}
|
|
405
480
|
// Re-run diagnostics to check if fixes worked
|
|
406
|
-
console.log(chalk_1.default.cyan('\
|
|
481
|
+
console.log(chalk_1.default.cyan('\nRe-checking...'));
|
|
407
482
|
const recheck = runDiagnostics();
|
|
408
483
|
displayReport(recheck);
|
|
409
484
|
if (recheck.canProceed) {
|
|
410
|
-
console.log(chalk_1.default.green.bold('
|
|
485
|
+
console.log(chalk_1.default.green.bold('All issues resolved!'));
|
|
411
486
|
}
|
|
412
487
|
process.exit(recheck.canProceed ? 0 : 1);
|
|
413
488
|
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ekkOS CLI: hooks subcommand
|
|
3
|
+
* Implements: ekkos hooks install | verify | status
|
|
4
|
+
*
|
|
5
|
+
* Per ekkOS Onboarding Spec v1.2 + Addendum:
|
|
6
|
+
* - Manifest-driven deployment
|
|
7
|
+
* - SHA256 checksum verification
|
|
8
|
+
* - Installed-state manifest tracking
|
|
9
|
+
*/
|
|
10
|
+
interface ManifestFile {
|
|
11
|
+
source: string;
|
|
12
|
+
destination: string;
|
|
13
|
+
description: string;
|
|
14
|
+
checksum: string | null;
|
|
15
|
+
overwrite?: 'always' | 'createOnly';
|
|
16
|
+
executable?: boolean;
|
|
17
|
+
}
|
|
18
|
+
interface Manifest {
|
|
19
|
+
$schema?: string;
|
|
20
|
+
manifestVersion: string;
|
|
21
|
+
generatedAt: string | null;
|
|
22
|
+
platforms: {
|
|
23
|
+
darwin: {
|
|
24
|
+
configDir: string;
|
|
25
|
+
globalHooksDir: string;
|
|
26
|
+
shell: string;
|
|
27
|
+
};
|
|
28
|
+
linux: {
|
|
29
|
+
configDir: string;
|
|
30
|
+
globalHooksDir: string;
|
|
31
|
+
shell: string;
|
|
32
|
+
};
|
|
33
|
+
win32: {
|
|
34
|
+
configDir: string;
|
|
35
|
+
globalHooksDir: string;
|
|
36
|
+
shell: string;
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
files: {
|
|
40
|
+
managed: ManifestFile[];
|
|
41
|
+
helpers: ManifestFile[];
|
|
42
|
+
userEditable: ManifestFile[];
|
|
43
|
+
hooks: {
|
|
44
|
+
bash: ManifestFile[];
|
|
45
|
+
powershell: ManifestFile[];
|
|
46
|
+
lib: ManifestFile[];
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
projectStubs?: {
|
|
50
|
+
description?: string;
|
|
51
|
+
bash: ManifestFile[];
|
|
52
|
+
powershell: ManifestFile[];
|
|
53
|
+
};
|
|
54
|
+
cli: {
|
|
55
|
+
minVersion: string;
|
|
56
|
+
legacySupported: boolean;
|
|
57
|
+
requiredCommands: Record<string, string[]>;
|
|
58
|
+
};
|
|
59
|
+
validation: {
|
|
60
|
+
requiredFiles: string[];
|
|
61
|
+
checksumAlgorithm: string;
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
interface VerifyResult {
|
|
65
|
+
status: 'PASS' | 'WARN' | 'FAIL';
|
|
66
|
+
issues: Array<{
|
|
67
|
+
severity: 'error' | 'warning';
|
|
68
|
+
file?: string;
|
|
69
|
+
message: string;
|
|
70
|
+
}>;
|
|
71
|
+
}
|
|
72
|
+
declare function expandPath(p: string): string;
|
|
73
|
+
/**
|
|
74
|
+
* Find the ekkos-manifest.json file
|
|
75
|
+
* Search order per spec:
|
|
76
|
+
* 1. <packageRoot>/templates/ekkos-manifest.json
|
|
77
|
+
* 2. <distRoot>/../templates/ekkos-manifest.json
|
|
78
|
+
* 3. In monorepo dev: <repoRoot>/templates/ekkos-manifest.json
|
|
79
|
+
*/
|
|
80
|
+
export declare function findManifest(): {
|
|
81
|
+
path: string;
|
|
82
|
+
templatesDir: string;
|
|
83
|
+
} | null;
|
|
84
|
+
/**
|
|
85
|
+
* Load manifest from disk
|
|
86
|
+
*/
|
|
87
|
+
export declare function loadManifest(): {
|
|
88
|
+
manifest: Manifest;
|
|
89
|
+
path: string;
|
|
90
|
+
templatesDir: string;
|
|
91
|
+
} | null;
|
|
92
|
+
declare function findProjectRoot(startDir?: string): string;
|
|
93
|
+
interface InstallOptions {
|
|
94
|
+
global?: boolean;
|
|
95
|
+
project?: boolean;
|
|
96
|
+
verbose?: boolean;
|
|
97
|
+
}
|
|
98
|
+
export declare function hooksInstall(options: InstallOptions): Promise<void>;
|
|
99
|
+
interface VerifyOptions {
|
|
100
|
+
global?: boolean;
|
|
101
|
+
project?: boolean;
|
|
102
|
+
verbose?: boolean;
|
|
103
|
+
}
|
|
104
|
+
export declare function hooksVerify(options: VerifyOptions): Promise<VerifyResult>;
|
|
105
|
+
interface StatusOptions {
|
|
106
|
+
verbose?: boolean;
|
|
107
|
+
}
|
|
108
|
+
export declare function hooksStatus(options: StatusOptions): Promise<void>;
|
|
109
|
+
export { findProjectRoot, expandPath };
|