@@ -13,6 +13,15 @@ import { EventEmitter } from 'node:events';
1313import { RelayClient } from './client.js' ;
1414import type { ParsedCommand } from './parser.js' ;
1515import type { SendPayload , SpeakOnTrigger } from '../protocol/types.js' ;
16+ import { getProjectPaths } from '../utils/project-namespace.js' ;
17+ import {
18+ TrajectoryIntegration ,
19+ getTrajectoryIntegration ,
20+ getTrailEnvVars ,
21+ getCompactTrailInstructions ,
22+ detectPhaseFromContent ,
23+ type PDEROPhase ,
24+ } from '../trajectory/integration.js' ;
1625
1726/** Maximum lines to keep in output buffer */
1827const MAX_BUFFER_LINES = 10000 ;
@@ -42,6 +51,8 @@ export interface PtyWrapperConfig {
4251 shadowSpeakOn ?: SpeakOnTrigger [ ] ;
4352 /** Stream output to daemon for dashboard log viewing (default: true) */
4453 streamLogs ?: boolean ;
54+ /** Task/role description for trajectory tracking */
55+ task ?: string ;
4556}
4657
4758export interface PtyWrapperEvents {
@@ -67,6 +78,8 @@ export class PtyWrapper extends EventEmitter {
6778 private logFilePath ?: string ;
6879 private logStream ?: fs . WriteStream ;
6980 private hasAcceptedPrompt = false ;
81+ private trajectory ?: TrajectoryIntegration ; // Trajectory tracking via trail
82+ private lastDetectedPhase ?: PDEROPhase ;
7083
7184 constructor ( config : PtyWrapperConfig ) {
7285 super ( ) ;
@@ -81,6 +94,10 @@ export class PtyWrapper extends EventEmitter {
8194 quiet : true ,
8295 } ) ;
8396
97+ // Initialize trajectory tracking
98+ const projectPaths = getProjectPaths ( ) ;
99+ this . trajectory = getTrajectoryIntegration ( projectPaths . projectId , config . name ) ;
100+
84101 // Handle incoming messages
85102 this . client . onMessage = ( from : string , payload : SendPayload , messageId : string ) => {
86103 this . handleIncomingMessage ( from , payload , messageId ) ;
@@ -131,6 +148,10 @@ export class PtyWrapper extends EventEmitter {
131148 console . log ( `[pty:${ this . config . name } ] Spawning: ${ this . config . command } ${ args . join ( ' ' ) } ` ) ;
132149 console . log ( `[pty:${ this . config . name } ] CWD: ${ cwd } ` ) ;
133150
151+ // Get trail environment variables
152+ const projectPaths = getProjectPaths ( ) ;
153+ const trailEnvVars = getTrailEnvVars ( projectPaths . projectId , this . config . name , projectPaths . dataDir ) ;
154+
134155 // Spawn the process with error handling
135156 try {
136157 this . ptyProcess = pty . spawn ( this . config . command , args , {
@@ -141,6 +162,7 @@ export class PtyWrapper extends EventEmitter {
141162 env : {
142163 ...process . env ,
143164 ...this . config . env ,
165+ ...trailEnvVars ,
144166 AGENT_RELAY_NAME : this . config . name ,
145167 TERM : 'xterm-256color' ,
146168 } ,
@@ -152,6 +174,15 @@ export class PtyWrapper extends EventEmitter {
152174 throw spawnError ;
153175 }
154176
177+ // Initialize trajectory (auto-start if task provided)
178+ if ( this . config . task ) {
179+ this . trajectory ?. initialize ( this . config . task ) . then ( success => {
180+ if ( success ) {
181+ console . log ( `[pty:${ this . config . name } ] Trajectory started for task: ${ this . config . task } ` ) ;
182+ }
183+ } ) ;
184+ }
185+
155186 this . running = true ;
156187
157188 // Capture output
@@ -215,6 +246,24 @@ export class PtyWrapper extends EventEmitter {
215246
216247 // Parse for relay commands
217248 this . parseRelayCommands ( ) ;
249+
250+ // Auto-detect phase transitions from output
251+ this . detectAndTransitionPhase ( data ) ;
252+ }
253+
254+ /**
255+ * Detect PDERO phase from output and transition if needed
256+ */
257+ private detectAndTransitionPhase ( data : string ) : void {
258+ if ( ! this . trajectory ) return ;
259+
260+ const cleanData = this . stripAnsi ( data ) ;
261+ const detectedPhase = detectPhaseFromContent ( cleanData ) ;
262+
263+ if ( detectedPhase && detectedPhase !== this . lastDetectedPhase ) {
264+ this . lastDetectedPhase = detectedPhase ;
265+ this . trajectory . transition ( detectedPhase , 'Auto-detected from output' ) ;
266+ }
218267 }
219268
220269 /**
@@ -386,6 +435,9 @@ export class PtyWrapper extends EventEmitter {
386435 const success = this . client . sendMessage ( cmd . to , cmd . body , cmd . kind , cmd . data , cmd . thread ) ;
387436 if ( success ) {
388437 this . sentMessageHashes . add ( msgHash ) ;
438+
439+ // Record outgoing message in trajectory
440+ this . trajectory ?. message ( 'sent' , this . config . name , cmd . to , cmd . body ) ;
389441 }
390442 }
391443
@@ -514,6 +566,9 @@ export class PtyWrapper extends EventEmitter {
514566 private handleIncomingMessage ( from : string , payload : SendPayload , messageId : string ) : void {
515567 this . messageQueue . push ( { from, body : payload . body , messageId } ) ;
516568 this . processMessageQueue ( ) ;
569+
570+ // Record incoming message in trajectory
571+ this . trajectory ?. message ( 'received' , from , this . config . name , payload . body ) ;
517572 }
518573
519574 /**
@@ -562,7 +617,14 @@ export class PtyWrapper extends EventEmitter {
562617 if ( ! this . running || ! this . ptyProcess ) return ;
563618
564619 const escapedPrefix = '\\' + this . relayPrefix ;
565- const instructions = `[Agent Relay] You are "${ this . config . name } " - connected for real-time messaging. SEND: ${ escapedPrefix } AgentName message` ;
620+ const relayInstruction = `[Agent Relay] You are "${ this . config . name } " - connected for real-time messaging. SEND: ${ escapedPrefix } AgentName message` ;
621+
622+ // Include trail instructions if available
623+ const trailInstruction = this . trajectory ?. isTrailInstalledSync ( )
624+ ? ` ${ getCompactTrailInstructions ( ) } `
625+ : '' ;
626+
627+ const instructions = relayInstruction + trailInstruction ;
566628
567629 try {
568630 this . ptyProcess . write ( instructions + '\r' ) ;
@@ -604,6 +666,11 @@ export class PtyWrapper extends EventEmitter {
604666 if ( ! this . running ) return ;
605667 this . running = false ;
606668
669+ // Complete trajectory with summary
670+ this . trajectory ?. complete ( {
671+ summary : `Agent ${ this . config . name } stopped gracefully` ,
672+ } ) ;
673+
607674 if ( this . ptyProcess ) {
608675 // Try graceful termination first
609676 this . ptyProcess . write ( '\x03' ) ; // Ctrl+C
@@ -623,6 +690,10 @@ export class PtyWrapper extends EventEmitter {
623690 */
624691 kill ( ) : void {
625692 this . running = false ;
693+
694+ // Abandon trajectory (forced termination)
695+ this . trajectory ?. abandon ( `Agent ${ this . config . name } killed` ) ;
696+
626697 if ( this . ptyProcess ) {
627698 this . ptyProcess . kill ( ) ;
628699 }
0 commit comments