@ai-devkit/agent-manager 0.6.0 → 0.6.1

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.
@@ -1 +1 @@
1
- {"version":3,"file":"TtyWriter.d.ts","sourceRoot":"","sources":["../../src/terminal/TtyWriter.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAa/D,qBAAa,SAAS;IAClB;;;;;;;;;;;;;;OAcG;WACU,IAAI,CAAC,QAAQ,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;mBAgBxD,WAAW;mBAIX,aAAa;mBAuBb,kBAAkB;CAqC1C"}
1
+ {"version":3,"file":"TtyWriter.d.ts","sourceRoot":"","sources":["../../src/terminal/TtyWriter.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAa/D,qBAAa,SAAS;IAClB;;;;;;;;;;;;;;OAcG;WACU,IAAI,CAAC,QAAQ,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;mBAgBxD,WAAW;mBAWX,aAAa;mBAsCb,kBAAkB;CA6C1C"}
@@ -42,24 +42,46 @@ class TtyWriter {
42
42
  }
43
43
  }
44
44
  static async sendViaTmux(identifier, message) {
45
- await execFileAsync('tmux', ['send-keys', '-t', identifier, message, 'Enter']);
45
+ // Send text and Enter as two separate calls so that Enter arrives
46
+ // outside of bracketed paste mode. When the inner application (e.g.
47
+ // Claude Code) has bracketed paste enabled, tmux wraps the send-keys
48
+ // payload in paste brackets — if Enter is included, it gets swallowed
49
+ // as part of the paste instead of acting as a submit action.
50
+ await execFileAsync('tmux', ['send-keys', '-t', identifier, '-l', message]);
51
+ await new Promise((resolve) => setTimeout(resolve, 150));
52
+ await execFileAsync('tmux', ['send-keys', '-t', identifier, 'Enter']);
46
53
  }
47
54
  static async sendViaITerm2(tty, message) {
48
55
  const escaped = escapeAppleScript(message);
56
+ // Send text WITHOUT a trailing newline to avoid the newline being swallowed
57
+ // by bracketed paste mode. Then simulate pressing Return separately so that
58
+ // Claude Code (and other interactive TUIs) treat it as a real submit action.
49
59
  const script = `
50
60
  tell application "iTerm"
61
+ set targetSession to missing value
51
62
  repeat with w in windows
52
63
  repeat with t in tabs of w
53
64
  repeat with s in sessions of t
54
65
  if tty of s is "${tty}" then
55
- tell s to write text "${escaped}"
56
- return "ok"
66
+ set targetSession to s
67
+ exit repeat
57
68
  end if
58
69
  end repeat
70
+ if targetSession is not missing value then exit repeat
59
71
  end repeat
72
+ if targetSession is not missing value then exit repeat
60
73
  end repeat
74
+ if targetSession is missing value then return "not_found"
75
+ tell targetSession to write text "${escaped}" newline no
61
76
  end tell
62
- return "not_found"`;
77
+ tell application "iTerm" to activate
78
+ delay 0.15
79
+ tell application "System Events"
80
+ tell process "iTerm2"
81
+ key code 36
82
+ end tell
83
+ end tell
84
+ return "ok"`;
63
85
  const { stdout } = await execFileAsync('osascript', ['-e', script]);
64
86
  if (stdout.trim() !== 'ok') {
65
87
  throw new Error(`iTerm2 session not found for TTY ${tty}`);
@@ -70,6 +92,9 @@ return "not_found"`;
70
92
  // Use System Events keystroke to type into the foreground process,
71
93
  // NOT Terminal.app's "do script" which runs a new shell command.
72
94
  // First activate Terminal and select the correct tab, then type via System Events.
95
+ // Send the text first, then wait for the paste/input to complete before pressing
96
+ // Return separately — this ensures interactive TUIs (like Claude Code) see the
97
+ // Return as a real submit action, not part of a bracketed paste.
73
98
  const script = `
74
99
  tell application "Terminal"
75
100
  set targetFound to false
@@ -92,6 +117,11 @@ delay 0.1
92
117
  tell application "System Events"
93
118
  tell process "Terminal"
94
119
  keystroke "${escaped}"
120
+ end tell
121
+ end tell
122
+ delay 0.15
123
+ tell application "System Events"
124
+ tell process "Terminal"
95
125
  key code 36
96
126
  end tell
97
127
  end tell
@@ -1 +1 @@
1
- {"version":3,"file":"TtyWriter.js","sourceRoot":"","sources":["../../src/terminal/TtyWriter.ts"],"names":[],"mappings":";;;AAAA,iDAAyC;AACzC,+BAAiC;AAEjC,iEAAsD;AAEtD,MAAM,aAAa,GAAG,IAAA,gBAAS,EAAC,wBAAQ,CAAC,CAAC;AAE1C;;;GAGG;AACH,SAAS,iBAAiB,CAAC,IAAY;IACnC,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;AAC5D,CAAC;AAED,MAAa,SAAS;IAClB;;;;;;;;;;;;;;OAcG;IACH,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,QAA0B,EAAE,OAAe;QACzD,QAAQ,QAAQ,CAAC,IAAI,EAAE,CAAC;YACpB,KAAK,mCAAY,CAAC,IAAI;gBAClB,OAAO,SAAS,CAAC,WAAW,CAAC,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;YAC/D,KAAK,mCAAY,CAAC,MAAM;gBACpB,OAAO,SAAS,CAAC,aAAa,CAAC,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;YAC1D,KAAK,mCAAY,CAAC,YAAY;gBAC1B,OAAO,SAAS,CAAC,kBAAkB,CAAC,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;YAC/D;gBACI,MAAM,IAAI,KAAK,CACX,iDAAiD,QAAQ,CAAC,IAAI,KAAK;oBACnE,wCAAwC,CAC3C,CAAC;QACV,CAAC;IACL,CAAC;IAEO,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,UAAkB,EAAE,OAAe;QAChE,MAAM,aAAa,CAAC,MAAM,EAAE,CAAC,WAAW,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;IACnF,CAAC;IAEO,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,GAAW,EAAE,OAAe;QAC3D,MAAM,OAAO,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;QAC3C,MAAM,MAAM,GAAG;;;;;0BAKG,GAAG;kCACK,OAAO;;;;;;;mBAOtB,CAAC;QAEZ,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,aAAa,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;QACpE,IAAI,MAAM,CAAC,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,oCAAoC,GAAG,EAAE,CAAC,CAAC;QAC/D,CAAC;IACL,CAAC;IAEO,MAAM,CAAC,KAAK,CAAC,kBAAkB,CAAC,GAAW,EAAE,OAAe;QAChE,MAAM,OAAO,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;QAC3C,mEAAmE;QACnE,iEAAiE;QACjE,mFAAmF;QACnF,MAAM,MAAM,GAAG;;;;;;wBAMC,GAAG;;;;;;;;;;;;;;;iBAeV,OAAO;;;;YAIZ,CAAC;QAEL,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,aAAa,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;QACpE,IAAI,MAAM,CAAC,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,sCAAsC,GAAG,EAAE,CAAC,CAAC;QACjE,CAAC;IACL,CAAC;CACJ;AAhGD,8BAgGC"}
1
+ {"version":3,"file":"TtyWriter.js","sourceRoot":"","sources":["../../src/terminal/TtyWriter.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-devkit/agent-manager",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
4
4
  "description": "Standalone agent detection and management utilities for AI DevKit",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -40,16 +40,22 @@ describe('TtyWriter', () => {
40
40
  tty: '/dev/ttys030',
41
41
  };
42
42
 
43
- it('sends message via tmux send-keys', async () => {
43
+ it('sends message and Enter as separate tmux send-keys calls', async () => {
44
44
  mockExecFileSuccess();
45
45
 
46
46
  await TtyWriter.send(location, 'continue');
47
47
 
48
48
  expect(mockedExecFile).toHaveBeenCalledWith(
49
49
  'tmux',
50
- ['send-keys', '-t', 'main:0.1', 'continue', 'Enter'],
50
+ ['send-keys', '-t', 'main:0.1', '-l', 'continue'],
51
51
  expect.any(Function),
52
52
  );
53
+ expect(mockedExecFile).toHaveBeenCalledWith(
54
+ 'tmux',
55
+ ['send-keys', '-t', 'main:0.1', 'Enter'],
56
+ expect.any(Function),
57
+ );
58
+ expect(mockedExecFile).toHaveBeenCalledTimes(2);
53
59
  });
54
60
 
55
61
  it('throws on tmux failure', async () => {
@@ -74,9 +80,12 @@ describe('TtyWriter', () => {
74
80
 
75
81
  expect(mockedExecFile).toHaveBeenCalledWith(
76
82
  'osascript',
77
- ['-e', expect.stringContaining('write text "hello"')],
83
+ ['-e', expect.stringContaining('write text "hello" newline no')],
78
84
  expect.any(Function),
79
85
  );
86
+ const scriptArg = (mockedExecFile.mock.calls[0] as unknown[])[1] as string[];
87
+ const script = scriptArg[1];
88
+ expect(script).toContain('key code 36');
80
89
  });
81
90
 
82
91
  it('escapes special characters in message', async () => {
@@ -86,7 +95,7 @@ describe('TtyWriter', () => {
86
95
 
87
96
  expect(mockedExecFile).toHaveBeenCalledWith(
88
97
  'osascript',
89
- ['-e', expect.stringContaining('write text "say \\"hi\\" \\\\ there"')],
98
+ ['-e', expect.stringContaining('write text "say \\"hi\\" \\\\ there" newline no')],
90
99
  expect.any(Function),
91
100
  );
92
101
  });
@@ -113,24 +122,11 @@ describe('TtyWriter', () => {
113
122
 
114
123
  const scriptArg = (mockedExecFile.mock.calls[0] as unknown[])[1] as string[];
115
124
  const script = scriptArg[1];
116
- // Must use keystroke, NOT do script
117
125
  expect(script).toContain('keystroke "hello"');
118
126
  expect(script).toContain('key code 36');
119
127
  expect(script).not.toContain('do script');
120
128
  });
121
129
 
122
- it('uses execFile to avoid shell injection', async () => {
123
- mockExecFileSuccess('ok');
124
-
125
- await TtyWriter.send(location, "don't stop");
126
-
127
- expect(mockedExecFile).toHaveBeenCalledWith(
128
- 'osascript',
129
- ['-e', expect.any(String)],
130
- expect.any(Function),
131
- );
132
- });
133
-
134
130
  it('throws when tab not found', async () => {
135
131
  mockExecFileSuccess('not_found');
136
132
 
@@ -46,25 +46,47 @@ export class TtyWriter {
46
46
  }
47
47
 
48
48
  private static async sendViaTmux(identifier: string, message: string): Promise<void> {
49
- await execFileAsync('tmux', ['send-keys', '-t', identifier, message, 'Enter']);
49
+ // Send text and Enter as two separate calls so that Enter arrives
50
+ // outside of bracketed paste mode. When the inner application (e.g.
51
+ // Claude Code) has bracketed paste enabled, tmux wraps the send-keys
52
+ // payload in paste brackets — if Enter is included, it gets swallowed
53
+ // as part of the paste instead of acting as a submit action.
54
+ await execFileAsync('tmux', ['send-keys', '-t', identifier, '-l', message]);
55
+ await new Promise((resolve) => setTimeout(resolve, 150));
56
+ await execFileAsync('tmux', ['send-keys', '-t', identifier, 'Enter']);
50
57
  }
51
58
 
52
59
  private static async sendViaITerm2(tty: string, message: string): Promise<void> {
53
60
  const escaped = escapeAppleScript(message);
61
+ // Send text WITHOUT a trailing newline to avoid the newline being swallowed
62
+ // by bracketed paste mode. Then simulate pressing Return separately so that
63
+ // Claude Code (and other interactive TUIs) treat it as a real submit action.
54
64
  const script = `
55
65
  tell application "iTerm"
66
+ set targetSession to missing value
56
67
  repeat with w in windows
57
68
  repeat with t in tabs of w
58
69
  repeat with s in sessions of t
59
70
  if tty of s is "${tty}" then
60
- tell s to write text "${escaped}"
61
- return "ok"
71
+ set targetSession to s
72
+ exit repeat
62
73
  end if
63
74
  end repeat
75
+ if targetSession is not missing value then exit repeat
64
76
  end repeat
77
+ if targetSession is not missing value then exit repeat
65
78
  end repeat
79
+ if targetSession is missing value then return "not_found"
80
+ tell targetSession to write text "${escaped}" newline no
66
81
  end tell
67
- return "not_found"`;
82
+ tell application "iTerm" to activate
83
+ delay 0.15
84
+ tell application "System Events"
85
+ tell process "iTerm2"
86
+ key code 36
87
+ end tell
88
+ end tell
89
+ return "ok"`;
68
90
 
69
91
  const { stdout } = await execFileAsync('osascript', ['-e', script]);
70
92
  if (stdout.trim() !== 'ok') {
@@ -77,6 +99,9 @@ return "not_found"`;
77
99
  // Use System Events keystroke to type into the foreground process,
78
100
  // NOT Terminal.app's "do script" which runs a new shell command.
79
101
  // First activate Terminal and select the correct tab, then type via System Events.
102
+ // Send the text first, then wait for the paste/input to complete before pressing
103
+ // Return separately — this ensures interactive TUIs (like Claude Code) see the
104
+ // Return as a real submit action, not part of a bracketed paste.
80
105
  const script = `
81
106
  tell application "Terminal"
82
107
  set targetFound to false
@@ -99,6 +124,11 @@ delay 0.1
99
124
  tell application "System Events"
100
125
  tell process "Terminal"
101
126
  keystroke "${escaped}"
127
+ end tell
128
+ end tell
129
+ delay 0.15
130
+ tell application "System Events"
131
+ tell process "Terminal"
102
132
  key code 36
103
133
  end tell
104
134
  end tell