11/**
22 * Daemon: multiple concurrent sessions.
33 *
4- * Connects to a local daemon, creates two sessions in separate /tmp
5- * directories, and runs them concurrently over a single WebSocket
6- * connection.
4+ * Connects to a local daemon, creates two sessions in separate temporary
5+ * directories, and runs them concurrently over a single WebSocket connection.
76 *
87 * Usage:
98 * npx tsx examples/daemon-multi-session.ts
1312 * example skips itself when the env var is unset.
1413 */
1514
16- import { connectDaemon , DroidMessageType } from '@factory/droid-sdk' ;
15+ import { mkdtemp , mkdir , readFile , rm } from 'node:fs/promises' ;
16+ import { tmpdir } from 'node:os' ;
17+ import { join } from 'node:path' ;
18+
19+ import {
20+ connectDaemon ,
21+ DroidMessageType ,
22+ ToolConfirmationOutcome ,
23+ ToolConfirmationType ,
24+ type ToolConfirmationDetails ,
25+ } from '@factory/droid-sdk' ;
26+
27+ function canWriteFile (
28+ filePath : string ,
29+ details : ToolConfirmationDetails
30+ ) : boolean {
31+ switch ( details . type ) {
32+ case ToolConfirmationType . Create :
33+ case ToolConfirmationType . Edit :
34+ case ToolConfirmationType . ApplyPatch :
35+ return details . filePath === filePath ;
36+ default :
37+ return false ;
38+ }
39+ }
1740
1841async function main ( ) : Promise < void > {
1942 if ( ! process . env . FACTORY_API_KEY ) {
@@ -27,13 +50,36 @@ async function main(): Promise<void> {
2750 console . log ( 'Connecting to local daemon...\n' ) ;
2851 const daemon = await connectDaemon ( { apiKey : process . env . FACTORY_API_KEY } ) ;
2952 console . log ( 'Connected!\n' ) ;
53+ const tempDir = await mkdtemp ( join ( tmpdir ( ) , 'droid-sdk-daemon-' ) ) ;
54+ const frontendDir = join ( tempDir , 'frontend' ) ;
55+ const backendDir = join ( tempDir , 'backend' ) ;
56+ const frontendFile = join ( frontendDir , 'hello.md' ) ;
57+ const backendFile = join ( backendDir , 'notes.md' ) ;
58+ await Promise . all ( [
59+ mkdir ( frontendDir , { recursive : true } ) ,
60+ mkdir ( backendDir , { recursive : true } ) ,
61+ ] ) ;
3062
3163 try {
3264 const frontend = await daemon . createSession ( {
33- cwd : '/tmp/daemon-test-frontend' ,
65+ cwd : frontendDir ,
66+ permissionHandler ( params ) {
67+ return params . toolUses . every ( ( item ) =>
68+ canWriteFile ( frontendFile , item . details )
69+ )
70+ ? ToolConfirmationOutcome . ProceedOnce
71+ : ToolConfirmationOutcome . Cancel ;
72+ } ,
3473 } ) ;
3574 const backend = await daemon . createSession ( {
36- cwd : '/tmp/daemon-test-backend' ,
75+ cwd : backendDir ,
76+ permissionHandler ( params ) {
77+ return params . toolUses . every ( ( item ) =>
78+ canWriteFile ( backendFile , item . details )
79+ )
80+ ? ToolConfirmationOutcome . ProceedOnce
81+ : ToolConfirmationOutcome . Cancel ;
82+ } ,
3783 } ) ;
3884
3985 console . log ( 'Two sessions created. Running concurrently...\n' ) ;
@@ -76,11 +122,17 @@ async function main(): Promise<void> {
76122 ] ) ;
77123 } finally {
78124 await daemon . close ( ) ;
125+ try {
126+ const [ greeting , notes ] = await Promise . all ( [
127+ readFile ( frontendFile , 'utf8' ) ,
128+ readFile ( backendFile , 'utf8' ) ,
129+ ] ) ;
130+ console . log ( `\n=== hello.md ===\n${ greeting . trim ( ) } ` ) ;
131+ console . log ( `\n=== notes.md ===\n${ notes . trim ( ) } ` ) ;
132+ } finally {
133+ await rm ( tempDir , { recursive : true , force : true } ) ;
134+ }
79135 }
80-
81- console . log (
82- '\nDone. Check /tmp/daemon-test-frontend/hello.md and /tmp/daemon-test-backend/notes.md'
83- ) ;
84136}
85137
86138main ( ) . catch ( ( err : unknown ) => {
0 commit comments