portable-agent-layer 0.24.0 → 0.24.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/package.json +1 -1
- package/src/cli/index.ts +129 -0
package/package.json
CHANGED
package/src/cli/index.ts
CHANGED
|
@@ -288,6 +288,38 @@ interface HookHealth {
|
|
|
288
288
|
lastError: string | null;
|
|
289
289
|
}
|
|
290
290
|
|
|
291
|
+
function checkClaudeHooksRegistered(): boolean {
|
|
292
|
+
const settingsPath = resolve(platform.claudeDir(), "settings.json");
|
|
293
|
+
if (!existsSync(settingsPath)) return false;
|
|
294
|
+
try {
|
|
295
|
+
const settings = JSON.parse(readFileSync(settingsPath, "utf-8"));
|
|
296
|
+
const groups = settings?.hooks?.SessionStart;
|
|
297
|
+
if (!Array.isArray(groups)) return false;
|
|
298
|
+
return groups.some((g: { hooks?: { command?: string }[] }) =>
|
|
299
|
+
g?.hooks?.some((h) => h?.command?.includes("LoadContext"))
|
|
300
|
+
);
|
|
301
|
+
} catch {
|
|
302
|
+
return false;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
function checkCursorHooksRegistered(): boolean {
|
|
307
|
+
const hooksPath = resolve(platform.cursorDir(), "hooks.json");
|
|
308
|
+
if (!existsSync(hooksPath)) return false;
|
|
309
|
+
try {
|
|
310
|
+
const data = JSON.parse(readFileSync(hooksPath, "utf-8"));
|
|
311
|
+
const hooks = data?.hooks?.sessionStart;
|
|
312
|
+
if (!Array.isArray(hooks)) return false;
|
|
313
|
+
return hooks.some((h: { command?: string }) => h?.command?.includes("LoadContext"));
|
|
314
|
+
} catch {
|
|
315
|
+
return false;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
function checkOpencodePluginInstalled(): boolean {
|
|
320
|
+
return existsSync(resolve(platform.opencodeDir(), "plugins", "pal-plugin.ts"));
|
|
321
|
+
}
|
|
322
|
+
|
|
291
323
|
function checkHookHealth(home: string): HookHealth {
|
|
292
324
|
const logPath = resolve(home, "memory", "state", "debug.log");
|
|
293
325
|
|
|
@@ -375,6 +407,97 @@ function doctor(silent = false): DoctorResult {
|
|
|
375
407
|
ok(`PAL home: ${home}`);
|
|
376
408
|
telosCount > 0 ? ok(`TELOS: ${telosCount} files`) : fail("TELOS: not scaffolded");
|
|
377
409
|
|
|
410
|
+
// Identity
|
|
411
|
+
const palSettingsPath = resolve(home, "memory", "pal-settings.json");
|
|
412
|
+
if (existsSync(palSettingsPath)) {
|
|
413
|
+
try {
|
|
414
|
+
const s = JSON.parse(readFileSync(palSettingsPath, "utf-8"));
|
|
415
|
+
const hasIdentity = s?.identity?.principal?.name && s?.identity?.ai?.name;
|
|
416
|
+
hasIdentity
|
|
417
|
+
? ok("Identity configured")
|
|
418
|
+
: warn("Identity — incomplete (run 'pal cli install')");
|
|
419
|
+
} catch {
|
|
420
|
+
warn("Identity — could not read pal-settings.json");
|
|
421
|
+
}
|
|
422
|
+
} else {
|
|
423
|
+
warn("Identity — pal-settings.json missing (run 'pal cli install')");
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// AGENTS.md
|
|
427
|
+
const agentsMdPath = resolve(platform.opencodeDir(), "AGENTS.md");
|
|
428
|
+
existsSync(agentsMdPath)
|
|
429
|
+
? ok("AGENTS.md present")
|
|
430
|
+
: fail("AGENTS.md — missing (run 'pal cli install')");
|
|
431
|
+
|
|
432
|
+
if (claude.available) {
|
|
433
|
+
const claudeMdPath = resolve(platform.claudeDir(), "CLAUDE.md");
|
|
434
|
+
existsSync(claudeMdPath)
|
|
435
|
+
? ok("CLAUDE.md present")
|
|
436
|
+
: fail("CLAUDE.md — missing (run 'pal cli install --claude')");
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// Setup state
|
|
440
|
+
const setupPath = resolve(home, "memory", "state", "setup.json");
|
|
441
|
+
if (existsSync(setupPath)) {
|
|
442
|
+
try {
|
|
443
|
+
const setup = JSON.parse(readFileSync(setupPath, "utf-8"));
|
|
444
|
+
setup?.completed
|
|
445
|
+
? ok("TELOS setup complete")
|
|
446
|
+
: warn("TELOS setup incomplete — run 'pal cli install' or start a session");
|
|
447
|
+
} catch {
|
|
448
|
+
warn("TELOS setup — could not read setup.json");
|
|
449
|
+
}
|
|
450
|
+
} else {
|
|
451
|
+
warn("TELOS setup — setup.json missing (run 'pal cli install')");
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
// Skills (per installed agent)
|
|
455
|
+
const countSkillsIn = (dir: string) =>
|
|
456
|
+
existsSync(dir)
|
|
457
|
+
? readdirSync(dir).filter((f) => existsSync(resolve(dir, f, "SKILL.md"))).length
|
|
458
|
+
: 0;
|
|
459
|
+
if (claude.available) {
|
|
460
|
+
const n = countSkillsIn(resolve(platform.claudeDir(), "skills"));
|
|
461
|
+
n > 0
|
|
462
|
+
? ok(`Claude Code skills: ${n}`)
|
|
463
|
+
: warn("Claude Code skills — none found (run 'pal cli install --claude')");
|
|
464
|
+
}
|
|
465
|
+
if (opencode.available) {
|
|
466
|
+
const n = countSkillsIn(resolve(platform.agentsDir(), "skills"));
|
|
467
|
+
n > 0
|
|
468
|
+
? ok(`opencode skills: ${n}`)
|
|
469
|
+
: warn("opencode skills — none found (run 'pal cli install --opencode')");
|
|
470
|
+
}
|
|
471
|
+
if (cursor.available) {
|
|
472
|
+
const n = countSkillsIn(resolve(platform.cursorDir(), "skills"));
|
|
473
|
+
n > 0
|
|
474
|
+
? ok(`Cursor skills: ${n}`)
|
|
475
|
+
: warn("Cursor skills — none found (run 'pal cli install --cursor')");
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
// Dependencies
|
|
479
|
+
const nodeModulesPath = resolve(palPkg(), "node_modules");
|
|
480
|
+
existsSync(nodeModulesPath)
|
|
481
|
+
? ok("Dependencies installed")
|
|
482
|
+
: fail("Dependencies missing — run 'pal cli install'");
|
|
483
|
+
|
|
484
|
+
// Hook registration (per installed agent)
|
|
485
|
+
if (claude.available) {
|
|
486
|
+
checkClaudeHooksRegistered()
|
|
487
|
+
? ok("Claude Code hooks registered")
|
|
488
|
+
: fail("Claude Code hooks — not registered (run 'pal cli install --claude')");
|
|
489
|
+
}
|
|
490
|
+
if (opencode.available) {
|
|
491
|
+
checkOpencodePluginInstalled()
|
|
492
|
+
? ok("opencode plugin installed")
|
|
493
|
+
: fail("opencode plugin — not installed (run 'pal cli install --opencode')");
|
|
494
|
+
}
|
|
495
|
+
if (cursor.available) {
|
|
496
|
+
checkCursorHooksRegistered()
|
|
497
|
+
? ok("Cursor hooks registered")
|
|
498
|
+
: fail("Cursor hooks — not registered (run 'pal cli install --cursor')");
|
|
499
|
+
}
|
|
500
|
+
|
|
378
501
|
// API key checks
|
|
379
502
|
process.env.PAL_ANTHROPIC_API_KEY
|
|
380
503
|
? ok("PAL_ANTHROPIC_API_KEY is set")
|
|
@@ -382,6 +505,12 @@ function doctor(silent = false): DoctorResult {
|
|
|
382
505
|
process.env.PAL_GEMINI_API_KEY
|
|
383
506
|
? ok("PAL_GEMINI_API_KEY is set")
|
|
384
507
|
: warn("PAL_GEMINI_API_KEY — not set (optional, for YouTube analysis)");
|
|
508
|
+
process.env.PAL_XAI_API_KEY
|
|
509
|
+
? ok("PAL_XAI_API_KEY is set")
|
|
510
|
+
: warn("PAL_XAI_API_KEY — not set (optional, for Grok researcher)");
|
|
511
|
+
process.env.PAL_PERPLEXITY_API_KEY
|
|
512
|
+
? ok("PAL_PERPLEXITY_API_KEY is set")
|
|
513
|
+
: warn("PAL_PERPLEXITY_API_KEY — not set (optional, for Perplexity researcher)");
|
|
385
514
|
|
|
386
515
|
// Hook health from debug.log
|
|
387
516
|
const hookHealth = checkHookHealth(home);
|