@ai-devkit/agent-manager 0.20.0 → 0.22.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.
@@ -635,6 +635,169 @@ describe('CodexAdapter', ()=>{
635
635
  });
636
636
  }
637
637
  });
638
+ it('should map a running Codex process from the hook session mapping', async ()=>{
639
+ const originalHome = process.env.HOME;
640
+ const tmpHome = fs.mkdtempSync(path.join(os.tmpdir(), 'codex-mapping-'));
641
+ process.env.HOME = tmpHome;
642
+ try {
643
+ const mappedAdapter = new CodexAdapter(new AgentRegistry(path.join(tmpHome, 'agents.json')));
644
+ const sessionsDir = path.join(tmpHome, '.codex', 'sessions');
645
+ const dateDir = path.join(sessionsDir, '2026', '06', '26');
646
+ const mappingPath = path.join(tmpHome, '.codex', 'ai-devkit', 'sessions.json');
647
+ const sessionFile = path.join(dateDir, 'rollout-2026-06-26T09-56-12-sess-mapped.jsonl');
648
+ const recentTs = new Date().toISOString();
649
+ fs.mkdirSync(dateDir, {
650
+ recursive: true
651
+ });
652
+ fs.mkdirSync(path.dirname(mappingPath), {
653
+ recursive: true
654
+ });
655
+ fs.writeFileSync(sessionFile, [
656
+ JSON.stringify({
657
+ type: 'session_meta',
658
+ payload: {
659
+ id: 'sess-mapped',
660
+ timestamp: recentTs,
661
+ cwd: '/repo-mapped'
662
+ }
663
+ }),
664
+ JSON.stringify({
665
+ type: 'event',
666
+ timestamp: recentTs,
667
+ payload: {
668
+ type: 'agent_message',
669
+ message: 'mapped conversation'
670
+ }
671
+ })
672
+ ].join('\n'));
673
+ fs.writeFileSync(mappingPath, JSON.stringify({
674
+ 5151: sessionFile
675
+ }));
676
+ const processes = [
677
+ {
678
+ pid: 5151,
679
+ command: 'codex',
680
+ cwd: '/repo-mapped',
681
+ tty: 'ttys001',
682
+ startTime: new Date('2026-06-26T09:56:12.000Z')
683
+ }
684
+ ];
685
+ mockedListAgentProcesses.mockReturnValue(processes);
686
+ mockedEnrichProcesses.mockReturnValue(processes);
687
+ const agents = await mappedAdapter.detectAgents();
688
+ expect(agents).toHaveLength(1);
689
+ expect(agents[0]).toMatchObject({
690
+ type: 'codex',
691
+ pid: 5151,
692
+ sessionId: 'sess-mapped',
693
+ projectPath: '/repo-mapped',
694
+ summary: 'mapped conversation',
695
+ sessionFilePath: sessionFile
696
+ });
697
+ expect(mockedBatchGetSessionFileBirthtimes).not.toHaveBeenCalled();
698
+ expect(mockedMatchProcessesToSessions).not.toHaveBeenCalled();
699
+ } finally{
700
+ process.env.HOME = originalHome;
701
+ fs.rmSync(tmpHome, {
702
+ recursive: true,
703
+ force: true
704
+ });
705
+ }
706
+ });
707
+ it('should fall back to legacy matching when mapped session file cannot be parsed', async ()=>{
708
+ const originalHome = process.env.HOME;
709
+ const tmpHome = fs.mkdtempSync(path.join(os.tmpdir(), 'codex-mapping-fallback-'));
710
+ process.env.HOME = tmpHome;
711
+ try {
712
+ const mappedAdapter = new CodexAdapter(new AgentRegistry(path.join(tmpHome, 'agents.json')));
713
+ const sessionsDir = path.join(tmpHome, '.codex', 'sessions');
714
+ const dateDir = path.join(sessionsDir, '2026', '06', '26');
715
+ const mappingPath = path.join(tmpHome, '.codex', 'ai-devkit', 'sessions.json');
716
+ const badSessionFile = path.join(dateDir, 'bad.jsonl');
717
+ const fallbackSessionFile = path.join(dateDir, 'fallback.jsonl');
718
+ const recentTs = new Date().toISOString();
719
+ fs.mkdirSync(dateDir, {
720
+ recursive: true
721
+ });
722
+ fs.mkdirSync(path.dirname(mappingPath), {
723
+ recursive: true
724
+ });
725
+ fs.writeFileSync(badSessionFile, '{not-json');
726
+ fs.writeFileSync(fallbackSessionFile, [
727
+ JSON.stringify({
728
+ type: 'session_meta',
729
+ payload: {
730
+ id: 'sess-fallback',
731
+ timestamp: recentTs,
732
+ cwd: '/repo-fallback'
733
+ }
734
+ }),
735
+ JSON.stringify({
736
+ type: 'event',
737
+ timestamp: recentTs,
738
+ payload: {
739
+ type: 'token_count',
740
+ message: 'fallback conversation'
741
+ }
742
+ })
743
+ ].join('\n'));
744
+ fs.writeFileSync(mappingPath, JSON.stringify({
745
+ 6161: badSessionFile
746
+ }));
747
+ const processes = [
748
+ {
749
+ pid: 6161,
750
+ command: 'codex',
751
+ cwd: '/repo-fallback',
752
+ tty: 'ttys001',
753
+ startTime: new Date('2026-06-26T09:56:12.000Z')
754
+ }
755
+ ];
756
+ const fallbackSession = {
757
+ sessionId: 'sess-fallback',
758
+ filePath: fallbackSessionFile,
759
+ projectDir: dateDir,
760
+ birthtimeMs: new Date('2026-06-26T09:56:15.000Z').getTime(),
761
+ resolvedCwd: ''
762
+ };
763
+ mockedListAgentProcesses.mockReturnValue(processes);
764
+ mockedEnrichProcesses.mockReturnValue(processes);
765
+ mockedBatchGetSessionFileBirthtimes.mockReturnValue([
766
+ fallbackSession
767
+ ]);
768
+ mockedMatchProcessesToSessions.mockReturnValue([
769
+ {
770
+ process: processes[0],
771
+ session: {
772
+ ...fallbackSession,
773
+ resolvedCwd: '/repo-fallback'
774
+ },
775
+ deltaMs: 3000
776
+ }
777
+ ]);
778
+ const agents = await mappedAdapter.detectAgents();
779
+ expect(agents).toHaveLength(1);
780
+ expect(agents[0]).toMatchObject({
781
+ pid: 6161,
782
+ sessionId: 'sess-fallback',
783
+ summary: 'fallback conversation',
784
+ sessionFilePath: fallbackSessionFile
785
+ });
786
+ expect(mockedMatchProcessesToSessions).toHaveBeenCalledWith([
787
+ processes[0]
788
+ ], expect.arrayContaining([
789
+ expect.objectContaining({
790
+ filePath: fallbackSessionFile
791
+ })
792
+ ]));
793
+ } finally{
794
+ process.env.HOME = originalHome;
795
+ fs.rmSync(tmpHome, {
796
+ recursive: true,
797
+ force: true
798
+ });
799
+ }
800
+ });
638
801
  });
639
802
  describe('detectAgents — registry cache short-circuit', ()=>{
640
803
  let tmpDir;