@phnx-labs/agents-cli 1.15.0 → 1.17.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/CHANGELOG.md +143 -39
- package/README.md +6 -6
- package/dist/commands/alias.js +2 -2
- package/dist/commands/browser-picker.d.ts +21 -0
- package/dist/commands/browser-picker.js +114 -0
- package/dist/commands/browser.js +793 -83
- package/dist/commands/cloud.js +8 -0
- package/dist/commands/commands.js +72 -22
- package/dist/commands/daemon.js +2 -2
- package/dist/commands/exec.js +70 -1
- package/dist/commands/hooks.js +71 -26
- package/dist/commands/mcp.js +81 -39
- package/dist/commands/plugins.js +224 -17
- package/dist/commands/prune.js +29 -1
- package/dist/commands/pull.js +3 -3
- package/dist/commands/repo.js +1 -1
- package/dist/commands/routines.js +2 -2
- package/dist/commands/secrets.js +154 -20
- package/dist/commands/sessions.js +62 -19
- package/dist/commands/{init.d.ts → setup.d.ts} +7 -6
- package/dist/commands/{init.js → setup.js} +22 -21
- package/dist/commands/skills.js +60 -19
- package/dist/commands/subagents.js +41 -13
- package/dist/commands/utils.d.ts +16 -0
- package/dist/commands/utils.js +32 -0
- package/dist/commands/view.js +78 -20
- package/dist/commands/workflows.d.ts +10 -0
- package/dist/commands/workflows.js +457 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +48 -36
- package/dist/lib/agents.js +2 -2
- package/dist/lib/auto-pull-worker.js +2 -3
- package/dist/lib/auto-pull.js +2 -2
- package/dist/lib/browser/cdp.d.ts +7 -1
- package/dist/lib/browser/cdp.js +32 -1
- package/dist/lib/browser/chrome.d.ts +10 -0
- package/dist/lib/browser/chrome.js +41 -3
- package/dist/lib/browser/devices.d.ts +4 -0
- package/dist/lib/browser/devices.js +27 -0
- package/dist/lib/browser/drivers/local.js +22 -6
- package/dist/lib/browser/drivers/ssh.js +9 -2
- package/dist/lib/browser/input.d.ts +1 -0
- package/dist/lib/browser/input.js +3 -0
- package/dist/lib/browser/ipc.js +158 -23
- package/dist/lib/browser/profiles.d.ts +10 -2
- package/dist/lib/browser/profiles.js +122 -37
- package/dist/lib/browser/service.d.ts +91 -13
- package/dist/lib/browser/service.js +767 -132
- package/dist/lib/browser/types.d.ts +91 -3
- package/dist/lib/browser/types.js +16 -0
- package/dist/lib/cloud/rush.d.ts +28 -1
- package/dist/lib/cloud/rush.js +69 -14
- package/dist/lib/cloud/store.js +2 -2
- package/dist/lib/commands.d.ts +1 -15
- package/dist/lib/commands.js +11 -7
- package/dist/lib/daemon.js +2 -3
- package/dist/lib/doctor-diff.js +4 -4
- package/dist/lib/events.js +2 -2
- package/dist/lib/hooks.d.ts +11 -7
- package/dist/lib/hooks.js +138 -49
- package/dist/lib/migrate.d.ts +1 -1
- package/dist/lib/migrate.js +1237 -22
- package/dist/lib/models.js +2 -2
- package/dist/lib/permissions.d.ts +8 -66
- package/dist/lib/permissions.js +18 -18
- package/dist/lib/plugins.d.ts +94 -24
- package/dist/lib/plugins.js +702 -123
- package/dist/lib/pty-server.js +9 -10
- package/dist/lib/resource-patterns.d.ts +41 -0
- package/dist/lib/resource-patterns.js +82 -0
- package/dist/lib/resources/hooks.d.ts +5 -1
- package/dist/lib/resources/hooks.js +21 -4
- package/dist/lib/resources/index.d.ts +17 -0
- package/dist/lib/resources/index.js +7 -0
- package/dist/lib/resources/types.d.ts +1 -1
- package/dist/lib/resources/workflows.d.ts +24 -0
- package/dist/lib/resources/workflows.js +110 -0
- package/dist/lib/resources.d.ts +6 -1
- package/dist/lib/resources.js +12 -2
- package/dist/lib/rotate.js +3 -4
- package/dist/lib/session/active.d.ts +3 -0
- package/dist/lib/session/active.js +92 -6
- package/dist/lib/session/cloud.js +2 -2
- package/dist/lib/session/db.d.ts +18 -0
- package/dist/lib/session/db.js +109 -5
- package/dist/lib/session/discover.d.ts +6 -0
- package/dist/lib/session/discover.js +55 -29
- package/dist/lib/session/team-filter.js +2 -2
- package/dist/lib/shims.d.ts +4 -52
- package/dist/lib/shims.js +23 -15
- package/dist/lib/skills.js +6 -2
- package/dist/lib/sqlite.js +10 -4
- package/dist/lib/state.d.ts +101 -16
- package/dist/lib/state.js +179 -31
- package/dist/lib/subagents.d.ts +28 -0
- package/dist/lib/subagents.js +98 -1
- package/dist/lib/sync-manifest.d.ts +1 -1
- package/dist/lib/sync-manifest.js +3 -3
- package/dist/lib/teams/persistence.js +15 -5
- package/dist/lib/teams/registry.js +2 -2
- package/dist/lib/types.d.ts +75 -17
- package/dist/lib/types.js +3 -3
- package/dist/lib/usage.js +2 -2
- package/dist/lib/versions.d.ts +3 -0
- package/dist/lib/versions.js +158 -47
- package/dist/lib/workflows.d.ts +79 -0
- package/dist/lib/workflows.js +233 -0
- package/package.json +1 -5
- package/scripts/postinstall.js +60 -59
- package/dist/commands/fork.d.ts +0 -10
- package/dist/commands/fork.js +0 -146
package/dist/lib/hooks.js
CHANGED
|
@@ -14,8 +14,42 @@ import * as TOML from 'smol-toml';
|
|
|
14
14
|
import { AGENTS, HOOKS_CAPABLE_AGENTS } from './agents.js';
|
|
15
15
|
import { supports, explainSkip } from './capabilities.js';
|
|
16
16
|
import { setGeminiAutoUpdateDisabled, updateGeminiSettings } from './gemini-settings.js';
|
|
17
|
-
import {
|
|
17
|
+
import { getHooksDir as getSystemHooksDir, getUserHooksDir, getUserAgentsDir, getSystemAgentsDir, getProjectAgentsDir, getTrashHooksDir, getEnabledExtraRepos } from './state.js';
|
|
18
18
|
function getCentralHooksDir() { return getUserHooksDir(); }
|
|
19
|
+
/**
|
|
20
|
+
* Resolve a hook script's absolute path. Checks user dir first, then enabled
|
|
21
|
+
* extra repos in insertion order, then system dir. Returns null if not found.
|
|
22
|
+
*/
|
|
23
|
+
function resolveHookScriptPath(script) {
|
|
24
|
+
const extraDirs = getEnabledExtraRepos().map(e => e.dir);
|
|
25
|
+
for (const root of [getUserAgentsDir(), ...extraDirs, getSystemAgentsDir()]) {
|
|
26
|
+
const candidate = path.join(root, 'hooks', script);
|
|
27
|
+
if (fs.existsSync(candidate))
|
|
28
|
+
return candidate;
|
|
29
|
+
}
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Prefixes used for stale-entry cleanup in agent settings files. A registered
|
|
34
|
+
* hook command is considered "managed" if it lives under any known hooks dir
|
|
35
|
+
* (user, extra repos, or system). Entries from removed extra repos are also
|
|
36
|
+
* garbage-collected because they won't appear in this list any more.
|
|
37
|
+
*/
|
|
38
|
+
function getManagedHookPrefixes() {
|
|
39
|
+
const extraDirs = getEnabledExtraRepos().map(e => e.dir);
|
|
40
|
+
return [
|
|
41
|
+
path.join(getUserAgentsDir(), 'hooks') + path.sep,
|
|
42
|
+
...extraDirs.map(d => path.join(d, 'hooks') + path.sep),
|
|
43
|
+
path.join(getSystemAgentsDir(), 'hooks') + path.sep,
|
|
44
|
+
];
|
|
45
|
+
}
|
|
46
|
+
function isManagedHookCommand(command, prefixes) {
|
|
47
|
+
for (const prefix of prefixes) {
|
|
48
|
+
if (command.startsWith(prefix))
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
19
53
|
import { getEffectiveHome, getVersionHomePath, listInstalledVersions } from './versions.js';
|
|
20
54
|
const SCRIPT_EXTENSIONS = new Set([
|
|
21
55
|
'.sh',
|
|
@@ -366,10 +400,32 @@ export function installHookToVersion(agent, version, hookName) {
|
|
|
366
400
|
}
|
|
367
401
|
/**
|
|
368
402
|
* Remove a single hook (script + data file) from a specific version home.
|
|
403
|
+
* Soft-deletes to ~/.agents/.trash/hooks/.
|
|
369
404
|
*/
|
|
370
405
|
export function removeHookFromVersion(agent, version, hookName) {
|
|
371
406
|
try {
|
|
372
|
-
|
|
407
|
+
const hooksDir = getVersionHooksDir(agent, version);
|
|
408
|
+
if (!fs.existsSync(hooksDir))
|
|
409
|
+
return { success: true };
|
|
410
|
+
const stamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
411
|
+
const trashDir = path.join(getTrashHooksDir(), agent, version, hookName, stamp);
|
|
412
|
+
let moved = false;
|
|
413
|
+
const files = fs.readdirSync(hooksDir);
|
|
414
|
+
for (const file of files) {
|
|
415
|
+
const ext = path.extname(file);
|
|
416
|
+
const base = path.basename(file, ext);
|
|
417
|
+
if (base === hookName) {
|
|
418
|
+
const fullPath = path.join(hooksDir, file);
|
|
419
|
+
const stat = fs.statSync(fullPath);
|
|
420
|
+
if (stat.isFile()) {
|
|
421
|
+
if (!moved) {
|
|
422
|
+
fs.mkdirSync(trashDir, { recursive: true, mode: 0o700 });
|
|
423
|
+
moved = true;
|
|
424
|
+
}
|
|
425
|
+
fs.renameSync(fullPath, path.join(trashDir, file));
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
}
|
|
373
429
|
}
|
|
374
430
|
catch (err) {
|
|
375
431
|
return { success: false, error: err.message };
|
|
@@ -502,32 +558,37 @@ export function listCentralHooks() {
|
|
|
502
558
|
return results;
|
|
503
559
|
}
|
|
504
560
|
/**
|
|
505
|
-
* Parse
|
|
506
|
-
* and user
|
|
507
|
-
*
|
|
508
|
-
*
|
|
561
|
+
* Parse hook manifests. Reads system hooks from ~/.agents-system/hooks.yaml
|
|
562
|
+
* (npm-shipped defaults) and user hooks from the `hooks:` section of
|
|
563
|
+
* ~/.agents/agents.yaml. Merges with user-wins-on-key-collision precedence.
|
|
564
|
+
* A user entry with `enabled: false` disables the system-shipped hook of
|
|
565
|
+
* the same name without forking the system file.
|
|
509
566
|
*
|
|
510
567
|
* Hooks marked `enabled: false` are dropped from the returned map.
|
|
511
568
|
*/
|
|
512
569
|
export function parseHookManifest() {
|
|
513
570
|
const merged = {};
|
|
514
|
-
// System
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
if (!fs.existsSync(manifestPath))
|
|
518
|
-
continue;
|
|
571
|
+
// System layer: hooks: section of agents.yaml (npm-shipped, separate repo).
|
|
572
|
+
const systemPath = path.join(getSystemAgentsDir(), 'agents.yaml');
|
|
573
|
+
if (fs.existsSync(systemPath)) {
|
|
519
574
|
try {
|
|
520
|
-
const
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
for (const [name, def] of Object.entries(parsed)) {
|
|
525
|
-
merged[name] = def;
|
|
526
|
-
}
|
|
575
|
+
const meta = yaml.parse(fs.readFileSync(systemPath, 'utf-8'));
|
|
576
|
+
if (meta?.hooks)
|
|
577
|
+
for (const [name, def] of Object.entries(meta.hooks))
|
|
578
|
+
merged[name] = def;
|
|
527
579
|
}
|
|
528
|
-
catch {
|
|
529
|
-
|
|
580
|
+
catch { /* skip unreadable manifest */ }
|
|
581
|
+
}
|
|
582
|
+
// User layer: hooks: section of agents.yaml.
|
|
583
|
+
const userMetaPath = path.join(getUserAgentsDir(), 'agents.yaml');
|
|
584
|
+
if (fs.existsSync(userMetaPath)) {
|
|
585
|
+
try {
|
|
586
|
+
const meta = yaml.parse(fs.readFileSync(userMetaPath, 'utf-8'));
|
|
587
|
+
if (meta?.hooks)
|
|
588
|
+
for (const [name, def] of Object.entries(meta.hooks))
|
|
589
|
+
merged[name] = def;
|
|
530
590
|
}
|
|
591
|
+
catch { /* skip unreadable meta */ }
|
|
531
592
|
}
|
|
532
593
|
// Strip disabled hooks so they never reach the registrar.
|
|
533
594
|
for (const [name, def] of Object.entries(merged)) {
|
|
@@ -542,25 +603,50 @@ const CODEX_MATCHER_EVENTS = new Set(['PreToolUse', 'PostToolUse', 'SessionStart
|
|
|
542
603
|
/**
|
|
543
604
|
* Register hooks as lifecycle events in an agent's config.
|
|
544
605
|
* Reads hooks.yaml manifest, merges into the agent's config file(s).
|
|
545
|
-
* Only manages hooks whose command paths are under ~/.agents/hooks
|
|
546
|
-
* Does not remove user-added hooks.
|
|
606
|
+
* Only manages hooks whose command paths are under ~/.agents/hooks/ or
|
|
607
|
+
* ~/.agents-system/hooks/. Does not remove user-added hooks.
|
|
547
608
|
*
|
|
548
|
-
* @param agentsDirOverride -
|
|
609
|
+
* @param agentsDirOverride - When provided, treats this single dir as the
|
|
610
|
+
* only managed hook root. Used by tests to inject a temp path. In normal
|
|
611
|
+
* operation, both user and system roots are consulted with user precedence.
|
|
549
612
|
*/
|
|
550
613
|
export function registerHooksToSettings(agentId, versionHome, hookManifest, agentsDirOverride) {
|
|
551
614
|
const manifest = hookManifest || parseHookManifest();
|
|
552
615
|
if (Object.keys(manifest).length === 0) {
|
|
553
616
|
return { registered: [], errors: [] };
|
|
554
617
|
}
|
|
555
|
-
const
|
|
618
|
+
const overrideRoots = agentsDirOverride ? [agentsDirOverride] : null;
|
|
619
|
+
// Scripts are copied into the version home during sync — prefer that stable
|
|
620
|
+
// local path so registered commands don't break when source dirs change.
|
|
621
|
+
const localHooksDir = !overrideRoots
|
|
622
|
+
? path.join(versionHome, `.${agentId}`, AGENTS[agentId].hooksDir)
|
|
623
|
+
: null;
|
|
624
|
+
const resolveScript = (script) => {
|
|
625
|
+
if (overrideRoots) {
|
|
626
|
+
const candidate = path.join(overrideRoots[0], 'hooks', script);
|
|
627
|
+
return fs.existsSync(candidate) ? candidate : null;
|
|
628
|
+
}
|
|
629
|
+
if (localHooksDir) {
|
|
630
|
+
const local = path.join(localHooksDir, script);
|
|
631
|
+
if (fs.existsSync(local))
|
|
632
|
+
return local;
|
|
633
|
+
}
|
|
634
|
+
return resolveHookScriptPath(script);
|
|
635
|
+
};
|
|
636
|
+
const managedPrefixes = overrideRoots
|
|
637
|
+
? [path.join(overrideRoots[0], 'hooks') + path.sep]
|
|
638
|
+
: [
|
|
639
|
+
...getManagedHookPrefixes(),
|
|
640
|
+
...(localHooksDir ? [localHooksDir + path.sep] : []),
|
|
641
|
+
];
|
|
556
642
|
if (agentId === 'claude') {
|
|
557
|
-
return registerHooksForClaude(versionHome, manifest,
|
|
643
|
+
return registerHooksForClaude(versionHome, manifest, resolveScript, managedPrefixes);
|
|
558
644
|
}
|
|
559
645
|
if (agentId === 'codex') {
|
|
560
|
-
return registerHooksForCodex(versionHome, manifest,
|
|
646
|
+
return registerHooksForCodex(versionHome, manifest, resolveScript, managedPrefixes);
|
|
561
647
|
}
|
|
562
648
|
if (agentId === 'gemini') {
|
|
563
|
-
return registerHooksForGemini(versionHome, manifest,
|
|
649
|
+
return registerHooksForGemini(versionHome, manifest, resolveScript, managedPrefixes);
|
|
564
650
|
}
|
|
565
651
|
return { registered: [], errors: [] };
|
|
566
652
|
}
|
|
@@ -574,7 +660,7 @@ export function registerHooksToSettings(agentId, versionHome, hookManifest, agen
|
|
|
574
660
|
const GEMINI_EVENT_MAP = {
|
|
575
661
|
UserPromptSubmit: 'BeforeAgent',
|
|
576
662
|
};
|
|
577
|
-
function registerHooksForClaude(versionHome, manifest,
|
|
663
|
+
function registerHooksForClaude(versionHome, manifest, resolveScript, managedPrefixes) {
|
|
578
664
|
const registered = [];
|
|
579
665
|
const errors = [];
|
|
580
666
|
const configDir = path.join(versionHome, '.claude');
|
|
@@ -595,14 +681,15 @@ function registerHooksForClaude(versionHome, manifest, agentsDir) {
|
|
|
595
681
|
const hooks = config.hooks;
|
|
596
682
|
// Build set of all command paths the current manifest will register.
|
|
597
683
|
// Used to garbage-collect stale entries left behind after hook renames.
|
|
598
|
-
const managedHooksPrefix = path.join(agentsDir, 'hooks') + path.sep;
|
|
599
684
|
const currentManifestPaths = new Set();
|
|
600
685
|
for (const hookDef of Object.values(manifest)) {
|
|
601
686
|
if (!hookDef.events || hookDef.events.length === 0)
|
|
602
687
|
continue;
|
|
603
|
-
|
|
688
|
+
const resolved = resolveScript(hookDef.script);
|
|
689
|
+
if (resolved)
|
|
690
|
+
currentManifestPaths.add(resolved);
|
|
604
691
|
}
|
|
605
|
-
// Remove stale entries: any hook command under
|
|
692
|
+
// Remove stale entries: any hook command under a managed root that isn't
|
|
606
693
|
// in the current manifest is a leftover from a renamed/deleted hook script.
|
|
607
694
|
for (const eventEntries of Object.values(hooks)) {
|
|
608
695
|
if (!Array.isArray(eventEntries))
|
|
@@ -610,7 +697,7 @@ function registerHooksForClaude(versionHome, manifest, agentsDir) {
|
|
|
610
697
|
for (const group of eventEntries) {
|
|
611
698
|
if (!group.hooks)
|
|
612
699
|
continue;
|
|
613
|
-
group.hooks = group.hooks.filter((h) => !h.command
|
|
700
|
+
group.hooks = group.hooks.filter((h) => !isManagedHookCommand(h.command, managedPrefixes) || currentManifestPaths.has(h.command));
|
|
614
701
|
}
|
|
615
702
|
}
|
|
616
703
|
// Remove empty matcher groups left after cleanup
|
|
@@ -622,9 +709,9 @@ function registerHooksForClaude(versionHome, manifest, agentsDir) {
|
|
|
622
709
|
for (const [name, hookDef] of Object.entries(manifest)) {
|
|
623
710
|
if (!hookDef.events || hookDef.events.length === 0)
|
|
624
711
|
continue;
|
|
625
|
-
const commandPath =
|
|
626
|
-
if (!
|
|
627
|
-
errors.push(`${name}: script not found
|
|
712
|
+
const commandPath = resolveScript(hookDef.script);
|
|
713
|
+
if (!commandPath) {
|
|
714
|
+
errors.push(`${name}: script not found in user or system hooks dir`);
|
|
628
715
|
continue;
|
|
629
716
|
}
|
|
630
717
|
for (const event of hookDef.events) {
|
|
@@ -662,7 +749,7 @@ function registerHooksForClaude(versionHome, manifest, agentsDir) {
|
|
|
662
749
|
}
|
|
663
750
|
return { registered, errors };
|
|
664
751
|
}
|
|
665
|
-
function registerHooksForCodex(versionHome, manifest,
|
|
752
|
+
function registerHooksForCodex(versionHome, manifest, resolveScript, managedPrefixes) {
|
|
666
753
|
const registered = [];
|
|
667
754
|
const errors = [];
|
|
668
755
|
const configDir = path.join(versionHome, '.codex');
|
|
@@ -687,19 +774,20 @@ function registerHooksForCodex(versionHome, manifest, agentsDir) {
|
|
|
687
774
|
}
|
|
688
775
|
}
|
|
689
776
|
// Build set of current manifest command paths for codex to GC stale entries
|
|
690
|
-
const managedHooksPrefix = path.join(agentsDir, 'hooks') + path.sep;
|
|
691
777
|
const currentManifestPaths = new Set();
|
|
692
778
|
for (const hookDef of Object.values(manifest)) {
|
|
693
779
|
if (!hookDef.events || hookDef.events.length === 0)
|
|
694
780
|
continue;
|
|
695
|
-
|
|
781
|
+
const resolved = resolveScript(hookDef.script);
|
|
782
|
+
if (resolved)
|
|
783
|
+
currentManifestPaths.add(resolved);
|
|
696
784
|
}
|
|
697
785
|
// Remove stale entries from all event groups
|
|
698
786
|
for (const eventGroups of Object.values(hooksFile.hooks)) {
|
|
699
787
|
for (const group of eventGroups) {
|
|
700
788
|
if (!group.hooks)
|
|
701
789
|
continue;
|
|
702
|
-
group.hooks = group.hooks.filter((h) => !h.command
|
|
790
|
+
group.hooks = group.hooks.filter((h) => !isManagedHookCommand(h.command, managedPrefixes) || currentManifestPaths.has(h.command));
|
|
703
791
|
}
|
|
704
792
|
}
|
|
705
793
|
for (const [event, eventGroups] of Object.entries(hooksFile.hooks)) {
|
|
@@ -708,9 +796,9 @@ function registerHooksForCodex(versionHome, manifest, agentsDir) {
|
|
|
708
796
|
for (const [name, hookDef] of Object.entries(manifest)) {
|
|
709
797
|
if (!hookDef.events || hookDef.events.length === 0)
|
|
710
798
|
continue;
|
|
711
|
-
const commandPath =
|
|
712
|
-
if (!
|
|
713
|
-
errors.push(`${name}: script not found
|
|
799
|
+
const commandPath = resolveScript(hookDef.script);
|
|
800
|
+
if (!commandPath) {
|
|
801
|
+
errors.push(`${name}: script not found in user or system hooks dir`);
|
|
714
802
|
continue;
|
|
715
803
|
}
|
|
716
804
|
const timeout = hookDef.timeout || 600;
|
|
@@ -784,7 +872,7 @@ function registerHooksForCodex(versionHome, manifest, agentsDir) {
|
|
|
784
872
|
}
|
|
785
873
|
return { registered, errors };
|
|
786
874
|
}
|
|
787
|
-
function registerHooksForGemini(versionHome, manifest,
|
|
875
|
+
function registerHooksForGemini(versionHome, manifest, resolveScript, managedPrefixes) {
|
|
788
876
|
const registered = [];
|
|
789
877
|
const errors = [];
|
|
790
878
|
const settingsPath = path.join(versionHome, '.gemini', 'settings.json');
|
|
@@ -795,12 +883,13 @@ function registerHooksForGemini(versionHome, manifest, agentsDir) {
|
|
|
795
883
|
config.hooks = {};
|
|
796
884
|
}
|
|
797
885
|
const hooks = config.hooks;
|
|
798
|
-
const managedHooksPrefix = path.join(agentsDir, 'hooks') + path.sep;
|
|
799
886
|
const currentManifestPaths = new Set();
|
|
800
887
|
for (const hookDef of Object.values(manifest)) {
|
|
801
888
|
if (!hookDef.events || hookDef.events.length === 0)
|
|
802
889
|
continue;
|
|
803
|
-
|
|
890
|
+
const resolved = resolveScript(hookDef.script);
|
|
891
|
+
if (resolved)
|
|
892
|
+
currentManifestPaths.add(resolved);
|
|
804
893
|
}
|
|
805
894
|
for (const eventEntries of Object.values(hooks)) {
|
|
806
895
|
if (!Array.isArray(eventEntries))
|
|
@@ -808,7 +897,7 @@ function registerHooksForGemini(versionHome, manifest, agentsDir) {
|
|
|
808
897
|
for (const group of eventEntries) {
|
|
809
898
|
if (!group.hooks)
|
|
810
899
|
continue;
|
|
811
|
-
group.hooks = group.hooks.filter((h) => !h.command
|
|
900
|
+
group.hooks = group.hooks.filter((h) => !isManagedHookCommand(h.command, managedPrefixes) || currentManifestPaths.has(h.command));
|
|
812
901
|
}
|
|
813
902
|
}
|
|
814
903
|
for (const [event, eventEntries] of Object.entries(hooks)) {
|
|
@@ -819,9 +908,9 @@ function registerHooksForGemini(versionHome, manifest, agentsDir) {
|
|
|
819
908
|
for (const [name, hookDef] of Object.entries(manifest)) {
|
|
820
909
|
if (!hookDef.events || hookDef.events.length === 0)
|
|
821
910
|
continue;
|
|
822
|
-
const commandPath =
|
|
823
|
-
if (!
|
|
824
|
-
errors.push(`${name}: script not found
|
|
911
|
+
const commandPath = resolveScript(hookDef.script);
|
|
912
|
+
if (!commandPath) {
|
|
913
|
+
errors.push(`${name}: script not found in user or system hooks dir`);
|
|
825
914
|
continue;
|
|
826
915
|
}
|
|
827
916
|
const timeoutMs = (hookDef.timeout || 600) * 1000;
|
package/dist/lib/migrate.d.ts
CHANGED