axmap-cli 1.9.0 → 1.11.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.
- package/README.ko.md +33 -0
- package/README.md +33 -0
- package/mcp/server.mjs +17 -3
- package/package.json +1 -1
- package/src/app-session.mjs +324 -0
- package/src/app-session.mts +294 -0
- package/src/bridge.mjs +167 -12
- package/src/bridge.mts +117 -11
- package/src/external-console.mjs +45 -12
- package/src/external-console.mts +44 -14
- package/src/managed-session.mjs +101 -12
- package/src/managed-session.mts +80 -15
- package/src/monitor.mjs +3 -3
- package/src/monitor.mts +3 -3
- package/src/pipeline-mcp.mjs +7 -4
- package/src/pipeline-mcp.mts +6 -4
- package/src/session-dialogue.mjs +21 -5
- package/src/session-dialogue.mts +22 -5
- package/src/session-status.mjs +10 -1
- package/src/session-status.mts +10 -1
- package/src/session-types.mts +20 -7
- package/src/session-usage.mjs +16 -0
- package/src/session-usage.mts +17 -1
- package/src/terminal-bridge.mjs +19 -9
- package/src/terminal-bridge.mts +19 -10
- package/tools/bridge.mjs +33 -9
- package/tools/console-queue.mjs +3 -0
- package/tools/run.mjs +17 -5
- package/tools/setup.mjs +1 -1
- package/tools/windows-console.cs +24 -8
- package/tools/windows-console.ps1 +14 -5
package/tools/windows-console.cs
CHANGED
|
@@ -25,6 +25,7 @@ public static class AxConsole {
|
|
|
25
25
|
[DllImport("kernel32.dll", CharSet=CharSet.Unicode, SetLastError=true)] static extern IntPtr CreateFile(string name,uint access,uint share,IntPtr sec,uint mode,uint flags,IntPtr template);
|
|
26
26
|
[DllImport("kernel32.dll", SetLastError=true)] static extern bool GetConsoleScreenBufferInfo(IntPtr h,out Info info);
|
|
27
27
|
[DllImport("kernel32.dll", CharSet=CharSet.Unicode, SetLastError=true)] static extern bool ReadConsoleOutputCharacter(IntPtr h,[Out] char[] text,uint count,Coord at,out uint read);
|
|
28
|
+
[DllImport("kernel32.dll", SetLastError=true)] static extern bool ReadConsoleOutputAttribute(IntPtr h,[Out] ushort[] attrs,uint count,Coord at,out uint read);
|
|
28
29
|
[DllImport("kernel32.dll", CharSet=CharSet.Unicode, SetLastError=true)] static extern bool WriteConsoleInput(IntPtr h,Record[] input,uint count,out uint written);
|
|
29
30
|
[DllImport("kernel32.dll")] static extern bool CloseHandle(IntPtr h);
|
|
30
31
|
static void Check(bool ok) { if(!ok) throw new Win32Exception(Marshal.GetLastWin32Error()); }
|
|
@@ -61,18 +62,19 @@ public static class AxConsole {
|
|
|
61
62
|
}
|
|
62
63
|
static Dictionary<string,object> Identity(int pid) {
|
|
63
64
|
using(var proc=Process.GetProcessById(pid)) {
|
|
64
|
-
if(proc.ProcessName!="agy") throw new Exception("Target is not agy.exe");
|
|
65
|
-
return new Dictionary<string,object> { {"pid",pid}, {"startedAt",proc.StartTime.ToUniversalTime().ToString("o")} };
|
|
65
|
+
if(proc.ProcessName!="agy" && proc.ProcessName!="claude") throw new Exception("Target is not agy.exe or claude.exe");
|
|
66
|
+
return new Dictionary<string,object> { {"provider",proc.ProcessName}, {"pid",pid}, {"startedAt",proc.StartTime.ToUniversalTime().ToString("o")} };
|
|
66
67
|
}
|
|
67
68
|
}
|
|
68
69
|
static bool Headless(string commandLine) {
|
|
69
|
-
return Regex.IsMatch(commandLine ?? "", @"--input-format|--print(?:\s|=|$)|(?:^|\s)-p(?:\s
|
|
70
|
+
return Regex.IsMatch(commandLine ?? "", @"--input-format|--print(?:\s|=|$)|(?:^|\s)-p(?:\s|=|$)");
|
|
70
71
|
}
|
|
71
72
|
public static int Main(string[] args) {
|
|
72
73
|
Console.InputEncoding=new UTF8Encoding(false); Console.OutputEncoding=new UTF8Encoding(false);
|
|
73
74
|
// AttachConsole replaces standard handles. Preserve the caller's pipe first.
|
|
74
75
|
var reply=Console.Out;
|
|
75
76
|
var json=new JavaScriptSerializer { MaxJsonLength=1024*1024 };
|
|
77
|
+
bool sending=false;
|
|
76
78
|
try {
|
|
77
79
|
int pid=int.Parse(args[0]); var action=args[1];
|
|
78
80
|
if(pid<=0) throw new Exception("A positive PID is required");
|
|
@@ -82,35 +84,49 @@ public static class AxConsole {
|
|
|
82
84
|
for(int i=0;i<12 && pid>0;i++) {
|
|
83
85
|
using(var entry=new ManagementObject("Win32_Process.Handle='"+pid+"'")) {
|
|
84
86
|
entry.Get();
|
|
85
|
-
if((string)entry["Name"]=="agy.exe") {
|
|
87
|
+
if((string)entry["Name"]=="agy.exe" || (string)entry["Name"]=="claude.exe") {
|
|
86
88
|
var result=Headless((string)entry["CommandLine"]) ? new Dictionary<string,object> {{"ignored",true}} : Identity(pid);
|
|
87
89
|
reply.WriteLine(json.Serialize(result)); return 0;
|
|
88
90
|
}
|
|
89
91
|
pid=Convert.ToInt32(entry["ParentProcessId"]);
|
|
90
92
|
}
|
|
91
93
|
}
|
|
92
|
-
throw new Exception("No interactive
|
|
94
|
+
throw new Exception("No interactive AI ancestor found");
|
|
93
95
|
}
|
|
94
96
|
var identity=Identity(pid);
|
|
95
97
|
using(var entry=new ManagementObject("Win32_Process.Handle='"+pid+"'")) {
|
|
96
98
|
entry.Get();
|
|
97
|
-
if(Headless((string)entry["CommandLine"])) throw new Exception("Target is not an interactive
|
|
99
|
+
if(Headless((string)entry["CommandLine"])) throw new Exception("Target is not an interactive AI console");
|
|
98
100
|
}
|
|
99
101
|
if(Get(payload,"startedAt")!=null && Get(payload,"startedAt")!=(string)identity["startedAt"]) throw new Exception("Process identity changed");
|
|
100
102
|
FreeConsole(); Check(AttachConsole((uint)pid));
|
|
101
103
|
var screen=Snapshot();
|
|
102
104
|
if(action=="send") {
|
|
103
105
|
if(Get(payload,"expectedScreen")!=screen) throw new Exception("Console changed before delivery; input was not sent");
|
|
106
|
+
var cursorHandle=Open("CONOUT$");
|
|
107
|
+
try {
|
|
108
|
+
Info current; Check(GetConsoleScreenBufferInfo(cursorHandle,out current));
|
|
109
|
+
object x,y;
|
|
110
|
+
if(payload.TryGetValue("expectedCursorX",out x) && x!=null && Convert.ToInt32(x)!=current.Cursor.X) throw new Exception("Console cursor changed before delivery");
|
|
111
|
+
if(payload.TryGetValue("expectedCursorRow",out y) && y!=null && Convert.ToInt32(y)!=current.Cursor.Y-current.Window.Top) throw new Exception("Console cursor changed before delivery");
|
|
112
|
+
} finally { CloseHandle(cursorHandle); }
|
|
104
113
|
var text=Get(payload,"text");
|
|
105
114
|
if(text==null || text.Length>65536) throw new Exception("Invalid console input");
|
|
106
115
|
// Recheck identity immediately before mutating the console input queue.
|
|
107
116
|
if((string)Identity(pid)["startedAt"]!=(string)identity["startedAt"]) throw new Exception("Process identity changed");
|
|
108
|
-
Send(text);
|
|
117
|
+
sending=true; Send(text);
|
|
109
118
|
}
|
|
119
|
+
var output=Open("CONOUT$");
|
|
120
|
+
try {
|
|
121
|
+
Info info; Check(GetConsoleScreenBufferInfo(output,out info));
|
|
122
|
+
uint read; var attrs=new ushort[info.Size.X];
|
|
123
|
+
Check(ReadConsoleOutputAttribute(output,attrs,(uint)attrs.Length,new Coord { X=0,Y=info.Cursor.Y },out read));
|
|
124
|
+
identity["cursorX"]=info.Cursor.X; identity["cursorRow"]=info.Cursor.Y-info.Window.Top; identity["cursorAttributes"]=attrs;
|
|
125
|
+
} finally { CloseHandle(output); }
|
|
110
126
|
FreeConsole(); identity["screen"]=screen;
|
|
111
127
|
reply.WriteLine(json.Serialize(identity)); return 0;
|
|
112
128
|
} catch(Exception e) {
|
|
113
|
-
FreeConsole(); reply.WriteLine(json.Serialize(new Dictionary<string,object> {{"error",e.Message}})); return 1;
|
|
129
|
+
FreeConsole(); reply.WriteLine(json.Serialize(new Dictionary<string,object> {{"error",e.Message},{"notDelivered",!sending}})); return 1;
|
|
114
130
|
}
|
|
115
131
|
}
|
|
116
132
|
}
|
|
@@ -10,10 +10,10 @@ if ($Action -eq 'ancestor') {
|
|
|
10
10
|
for ($i = 0; $i -lt 12 -and $TargetPid -gt 0; $i++) {
|
|
11
11
|
$entry = Get-CimInstance Win32_Process -Filter "ProcessId=$TargetPid"
|
|
12
12
|
if (!$entry) { break }
|
|
13
|
-
if ($entry.Name -
|
|
13
|
+
if ($entry.Name -in @('agy.exe','claude.exe')) {
|
|
14
14
|
if ($entry.CommandLine -match '--input-format|--print(?:\s|=|$)|(?:^|\s)-p(?:\s|$)') { $reply.WriteLine('{"ignored":true}'); exit 0 }
|
|
15
15
|
$proc = Get-Process -Id $TargetPid
|
|
16
|
-
$reply.WriteLine((@{ pid=$TargetPid; startedAt=$proc.StartTime.ToUniversalTime().ToString('o') } | ConvertTo-Json -Compress))
|
|
16
|
+
$reply.WriteLine((@{ provider=($entry.Name -replace '\.exe$',''); pid=$TargetPid; startedAt=$proc.StartTime.ToUniversalTime().ToString('o') } | ConvertTo-Json -Compress))
|
|
17
17
|
exit 0
|
|
18
18
|
}
|
|
19
19
|
$TargetPid = $entry.ParentProcessId
|
|
@@ -56,6 +56,9 @@ public static class AxConsole {
|
|
|
56
56
|
return text.ToString();
|
|
57
57
|
} finally { CloseHandle(h); }
|
|
58
58
|
}
|
|
59
|
+
public static int[] Cursor() {
|
|
60
|
+
var h=Open("CONOUT$"); try { Info info; Check(GetConsoleScreenBufferInfo(h,out info)); return new int[] {info.Cursor.X,info.Cursor.Y-info.Window.Top}; } finally { CloseHandle(h); }
|
|
61
|
+
}
|
|
59
62
|
public static void Send(string text) {
|
|
60
63
|
var h=Open("CONIN$"); try {
|
|
61
64
|
var records=new Record[text.Length*2];
|
|
@@ -69,9 +72,10 @@ public static class AxConsole {
|
|
|
69
72
|
}
|
|
70
73
|
}
|
|
71
74
|
'@
|
|
75
|
+
$sending = $false
|
|
72
76
|
try {
|
|
73
77
|
$proc = Get-Process -Id $TargetPid
|
|
74
|
-
if ($proc.ProcessName -
|
|
78
|
+
if ($proc.ProcessName -notin @('agy','claude')) { throw 'Target is not agy.exe or claude.exe' }
|
|
75
79
|
$commandLine = (Get-CimInstance Win32_Process -Filter "ProcessId=$TargetPid").CommandLine
|
|
76
80
|
if ($commandLine -match '--input-format|--print(?:\s|=|$)|(?:^|\s)-p(?:\s|$)') { throw 'Target is not an interactive agy console' }
|
|
77
81
|
if ($payload.startedAt -and $proc.StartTime.ToUniversalTime().ToString('o') -ne $payload.startedAt) { throw 'Process identity changed' }
|
|
@@ -79,13 +83,18 @@ try {
|
|
|
79
83
|
$screen = [AxConsole]::Snapshot()
|
|
80
84
|
if ($Action -eq 'send') {
|
|
81
85
|
if ($payload.expectedScreen -cne $screen) { throw 'Console changed before delivery; input was not sent' }
|
|
86
|
+
$cursor = [AxConsole]::Cursor()
|
|
87
|
+
if ($null -ne $payload.expectedCursorX -and $payload.expectedCursorX -ne $cursor[0]) { throw 'Console cursor changed before delivery' }
|
|
88
|
+
if ($null -ne $payload.expectedCursorRow -and $payload.expectedCursorRow -ne $cursor[1]) { throw 'Console cursor changed before delivery' }
|
|
89
|
+
$sending = $true
|
|
82
90
|
[AxConsole]::Send($payload.text)
|
|
83
91
|
}
|
|
84
|
-
$
|
|
92
|
+
$cursor = [AxConsole]::Cursor()
|
|
93
|
+
$result = @{ provider=$proc.ProcessName; cursorX=$cursor[0]; cursorRow=$cursor[1]; screen = $screen; startedAt = $proc.StartTime.ToUniversalTime().ToString('o'); pid = $TargetPid }
|
|
85
94
|
[AxConsole]::FreeConsole() | Out-Null
|
|
86
95
|
$reply.WriteLine(($result | ConvertTo-Json -Compress))
|
|
87
96
|
} catch {
|
|
88
97
|
[AxConsole]::FreeConsole() | Out-Null
|
|
89
|
-
$reply.WriteLine((@{ error = $_.Exception.Message } | ConvertTo-Json -Compress))
|
|
98
|
+
$reply.WriteLine((@{ error = $_.Exception.Message; notDelivered = !$sending } | ConvertTo-Json -Compress))
|
|
90
99
|
exit 1
|
|
91
100
|
}
|