@ghl-ai/aw 0.1.37-beta.69 → 0.1.37-beta.70

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 (2) hide show
  1. package/integrate.mjs +75 -10
  2. package/package.json +1 -1
package/integrate.mjs CHANGED
@@ -630,7 +630,7 @@ export function installIdeHooks() {
630
630
 
631
631
  writeFileSync(claudeSettingsPath, JSON.stringify(claudeSettings, null, 2) + '\n');
632
632
 
633
- // ── Step 3: Cursor — wire stop only (no session lifecycle hooks) ───
633
+ // ── Step 3: Cursor — wire 4 events (sessionStart, stop, preCompact, sessionEnd) ──
634
634
  const cursorDir = join(home, '.cursor');
635
635
  mkdirSync(cursorDir, { recursive: true });
636
636
  const cursorHooksPath = join(cursorDir, 'hooks.json');
@@ -641,15 +641,26 @@ export function installIdeHooks() {
641
641
  }
642
642
  if (!cursorHooks.hooks) cursorHooks.hooks = {};
643
643
 
644
- // Replace old telemetry-stop.js with new stop.mjs dispatcher
645
- const stopCmd = dispatchers.Stop.cmd;
646
- if (!cursorHooks.hooks.stop) cursorHooks.hooks.stop = [];
644
+ // Cursor uses camelCase event names
645
+ const cursorEventMap = {
646
+ SessionStart: 'sessionStart',
647
+ Stop: 'stop',
648
+ PreCompact: 'preCompact',
649
+ SessionEnd: 'sessionEnd',
650
+ };
651
+
652
+ for (const [event, { cmd, timeout }] of Object.entries(dispatchers)) {
653
+ const cursorEvent = cursorEventMap[event];
654
+ if (!cursorEvent) continue;
647
655
 
648
- // Remove old aw entries
649
- cursorHooks.hooks.stop = cursorHooks.hooks.stop.filter(h =>
650
- !h.command?.includes('.aw/hooks/') && !h.command?.includes('telemetry-stop.js')
651
- );
652
- cursorHooks.hooks.stop.push({ command: stopCmd, timeout: dispatchers.Stop.timeout });
656
+ if (!cursorHooks.hooks[cursorEvent]) cursorHooks.hooks[cursorEvent] = [];
657
+
658
+ // Remove old aw entries
659
+ cursorHooks.hooks[cursorEvent] = cursorHooks.hooks[cursorEvent].filter(h =>
660
+ !h.command?.includes('.aw/hooks/') && !h.command?.includes('telemetry-stop.js')
661
+ );
662
+ cursorHooks.hooks[cursorEvent].push({ command: cmd, timeout });
663
+ }
653
664
 
654
665
  // Remove old postToolUse entry from aw
655
666
  if (cursorHooks.hooks.postToolUse) {
@@ -663,7 +674,61 @@ export function installIdeHooks() {
663
674
 
664
675
  writeFileSync(cursorHooksPath, JSON.stringify(cursorHooks, null, 2) + '\n');
665
676
 
666
- fmt.logSuccess('IDE hooks installed 4 events (Claude) + 1 event (Cursor) ~/.aw/hooks/');
677
+ // ── Step 4: Codex wire SessionStart + Stop via ~/.codex/hooks.json ──
678
+ // Codex hooks use PascalCase event names and require [features] codex_hooks = true in config.toml
679
+ const codexDir = join(home, '.codex');
680
+ mkdirSync(codexDir, { recursive: true });
681
+ const codexHooksPath = join(codexDir, 'hooks.json');
682
+
683
+ let codexHooks = {};
684
+ if (existsSync(codexHooksPath)) {
685
+ try { codexHooks = JSON.parse(readFileSync(codexHooksPath, 'utf8')); } catch { codexHooks = {}; }
686
+ }
687
+
688
+ // Codex supports: SessionStart, Stop, PreToolUse, PostToolUse, UserPromptSubmit
689
+ const codexEvents = { SessionStart: dispatchers.SessionStart, Stop: dispatchers.Stop };
690
+ for (const [event, { cmd, timeout }] of Object.entries(codexEvents)) {
691
+ if (!codexHooks[event]) codexHooks[event] = [];
692
+
693
+ // Each entry is a matcher group: { matcher: "*", hooks: [...] }
694
+ // Find existing aw matcher group or create one
695
+ let awGroup = codexHooks[event].find(g =>
696
+ g.hooks?.some(h => h.command?.includes('.aw/hooks/'))
697
+ );
698
+ if (!awGroup) {
699
+ awGroup = { hooks: [] };
700
+ codexHooks[event].push(awGroup);
701
+ }
702
+ // Replace aw hooks in the group
703
+ awGroup.hooks = awGroup.hooks.filter(h => !h.command?.includes('.aw/hooks/'));
704
+ awGroup.hooks.push({
705
+ type: 'command',
706
+ command: cmd,
707
+ timeoutSec: timeout,
708
+ statusMessage: `AW telemetry (${event})`,
709
+ });
710
+ }
711
+
712
+ writeFileSync(codexHooksPath, JSON.stringify(codexHooks, null, 2) + '\n');
713
+
714
+ // Enable codex_hooks feature if not already set
715
+ const codexConfigPath = join(codexDir, 'config.toml');
716
+ if (existsSync(codexConfigPath)) {
717
+ try {
718
+ let toml = readFileSync(codexConfigPath, 'utf8');
719
+ if (!toml.includes('codex_hooks')) {
720
+ // Append under [features] if it exists, or add it
721
+ if (toml.includes('[features]')) {
722
+ toml = toml.replace('[features]', '[features]\ncodex_hooks = true');
723
+ } else {
724
+ toml += '\n[features]\ncodex_hooks = true\n';
725
+ }
726
+ writeFileSync(codexConfigPath, toml);
727
+ }
728
+ } catch { /* best effort */ }
729
+ }
730
+
731
+ fmt.logSuccess('IDE hooks installed — 4 events (Claude + Cursor) + 2 events (Codex) → ~/.aw/hooks/');
667
732
  }
668
733
 
669
734
  /** Legacy hook wiring — used as fallback when new dispatchers aren't available */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ghl-ai/aw",
3
- "version": "0.1.37-beta.69",
3
+ "version": "0.1.37-beta.70",
4
4
  "description": "Agentic Workspace CLI — pull, push & manage agents, skills and commands from the registry",
5
5
  "type": "module",
6
6
  "bin": "bin.js",