looply-cli 0.5.3 → 0.5.5
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/dist/.src-hash +1 -1
- package/dist/agent-exec.d.ts +10 -5
- package/dist/agent-exec.d.ts.map +1 -1
- package/dist/agent-exec.js.map +1 -1
- package/dist/autonomy-controller.d.ts +14 -1
- package/dist/autonomy-controller.d.ts.map +1 -1
- package/dist/autonomy-controller.js +55 -2
- package/dist/autonomy-controller.js.map +1 -1
- package/dist/autonomy-store.d.ts +35 -2
- package/dist/autonomy-store.d.ts.map +1 -1
- package/dist/autonomy-store.js +27 -2
- package/dist/autonomy-store.js.map +1 -1
- package/dist/autonomy-tick.d.ts +25 -2
- package/dist/autonomy-tick.d.ts.map +1 -1
- package/dist/autonomy-tick.js +145 -4
- package/dist/autonomy-tick.js.map +1 -1
- package/dist/bin.d.ts.map +1 -1
- package/dist/bin.js +112 -82
- package/dist/bin.js.map +1 -1
- package/dist/checkout-carry.d.ts.map +1 -1
- package/dist/checkout-carry.js +12 -0
- package/dist/checkout-carry.js.map +1 -1
- package/dist/config.d.ts +41 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +64 -8
- package/dist/config.js.map +1 -1
- package/dist/coordinator-state.d.ts +14 -0
- package/dist/coordinator-state.d.ts.map +1 -1
- package/dist/coordinator-state.js +29 -0
- package/dist/coordinator-state.js.map +1 -1
- package/dist/daemon-cmd.d.ts +1 -1
- package/dist/daemon-cmd.d.ts.map +1 -1
- package/dist/daemon-cmd.js +69 -33
- package/dist/daemon-cmd.js.map +1 -1
- package/dist/daemon.d.ts +15 -1
- package/dist/daemon.d.ts.map +1 -1
- package/dist/daemon.js +21 -3
- package/dist/daemon.js.map +1 -1
- package/dist/git-driver.d.ts +6 -0
- package/dist/git-driver.d.ts.map +1 -1
- package/dist/git-driver.js +12 -0
- package/dist/git-driver.js.map +1 -1
- package/dist/index-for-head.js +1 -1
- package/dist/index-for-head.js.map +1 -1
- package/dist/init-detect.d.ts.map +1 -1
- package/dist/init-detect.js +1 -1
- package/dist/init-detect.js.map +1 -1
- package/dist/machine-run-slots.d.ts +59 -0
- package/dist/machine-run-slots.d.ts.map +1 -0
- package/dist/machine-run-slots.js +140 -0
- package/dist/machine-run-slots.js.map +1 -0
- package/dist/model-routing.d.ts +52 -7
- package/dist/model-routing.d.ts.map +1 -1
- package/dist/model-routing.js +84 -14
- package/dist/model-routing.js.map +1 -1
- package/dist/model-settings.d.ts +67 -0
- package/dist/model-settings.d.ts.map +1 -0
- package/dist/model-settings.js +177 -0
- package/dist/model-settings.js.map +1 -0
- package/dist/model-transport.d.ts +8 -0
- package/dist/model-transport.d.ts.map +1 -1
- package/dist/model-transport.js +6 -3
- package/dist/model-transport.js.map +1 -1
- package/dist/programme-mode.d.ts +6 -0
- package/dist/programme-mode.d.ts.map +1 -1
- package/dist/programme-mode.js +23 -0
- package/dist/programme-mode.js.map +1 -1
- package/dist/project-index-store.d.ts +19 -1
- package/dist/project-index-store.d.ts.map +1 -1
- package/dist/project-index-store.js +40 -5
- package/dist/project-index-store.js.map +1 -1
- package/dist/project-terminal.d.ts +25 -0
- package/dist/project-terminal.d.ts.map +1 -0
- package/dist/project-terminal.js +46 -0
- package/dist/project-terminal.js.map +1 -0
- package/dist/provider-cmd.d.ts +13 -4
- package/dist/provider-cmd.d.ts.map +1 -1
- package/dist/provider-cmd.js +111 -11
- package/dist/provider-cmd.js.map +1 -1
- package/dist/provider-ready.d.ts +15 -2
- package/dist/provider-ready.d.ts.map +1 -1
- package/dist/provider-ready.js +46 -2
- package/dist/provider-ready.js.map +1 -1
- package/dist/providers.d.ts.map +1 -1
- package/dist/providers.js +4 -0
- package/dist/providers.js.map +1 -1
- package/dist/pursuit-ending.d.ts +57 -0
- package/dist/pursuit-ending.d.ts.map +1 -0
- package/dist/pursuit-ending.js +128 -0
- package/dist/pursuit-ending.js.map +1 -0
- package/dist/run-base.d.ts +84 -0
- package/dist/run-base.d.ts.map +1 -0
- package/dist/run-base.js +142 -0
- package/dist/run-base.js.map +1 -0
- package/dist/run-cmd.d.ts.map +1 -1
- package/dist/run-cmd.js +46 -5
- package/dist/run-cmd.js.map +1 -1
- package/dist/run-ended.d.ts +16 -0
- package/dist/run-ended.d.ts.map +1 -1
- package/dist/run-ended.js +30 -0
- package/dist/run-ended.js.map +1 -1
- package/dist/run-ending-locator.d.ts +10 -0
- package/dist/run-ending-locator.d.ts.map +1 -1
- package/dist/run-ending-locator.js +45 -0
- package/dist/run-ending-locator.js.map +1 -1
- package/dist/run-launcher.d.ts +30 -1
- package/dist/run-launcher.d.ts.map +1 -1
- package/dist/run-launcher.js +60 -2
- package/dist/run-launcher.js.map +1 -1
- package/dist/server-client.d.ts +16 -2
- package/dist/server-client.d.ts.map +1 -1
- package/dist/server-client.js +9 -0
- package/dist/server-client.js.map +1 -1
- package/dist/setup.d.ts.map +1 -1
- package/dist/setup.js +17 -0
- package/dist/setup.js.map +1 -1
- package/dist/workspace-provisioner.d.ts +2 -0
- package/dist/workspace-provisioner.d.ts.map +1 -1
- package/dist/workspace-provisioner.js +27 -1
- package/dist/workspace-provisioner.js.map +1 -1
- package/package.json +54 -54
- package/win/HandleProbe.cs +116 -116
package/package.json
CHANGED
|
@@ -1,54 +1,54 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "looply-cli",
|
|
3
|
-
"version": "0.5.
|
|
4
|
-
"description": "Leave your coding agent running. looply picks the work, holds the rails, and proves every change before it is kept.",
|
|
5
|
-
"license": "MIT",
|
|
6
|
-
"bin": {
|
|
7
|
-
"looply": "dist/bin.js"
|
|
8
|
-
},
|
|
9
|
-
"main": "dist/index.js",
|
|
10
|
-
"types": "dist/index.d.ts",
|
|
11
|
-
"files": [
|
|
12
|
-
"dist",
|
|
13
|
-
"win",
|
|
14
|
-
"README.md",
|
|
15
|
-
"LICENSE"
|
|
16
|
-
],
|
|
17
|
-
"keywords": [
|
|
18
|
-
"claude",
|
|
19
|
-
"claude-code",
|
|
20
|
-
"coding-agent",
|
|
21
|
-
"agent",
|
|
22
|
-
"autonomous",
|
|
23
|
-
"loop",
|
|
24
|
-
"ci",
|
|
25
|
-
"codegen",
|
|
26
|
-
"automation"
|
|
27
|
-
],
|
|
28
|
-
"scripts": {
|
|
29
|
-
"build": "tsc -b",
|
|
30
|
-
"clean": "tsc -b --clean",
|
|
31
|
-
"prepack": "npm run build",
|
|
32
|
-
"prepublishOnly": "npm run build"
|
|
33
|
-
},
|
|
34
|
-
"dependencies": {
|
|
35
|
-
"@looply/core": "0.5.
|
|
36
|
-
"pdfjs-dist": "5.6.205",
|
|
37
|
-
"qrcode-terminal": "^0.12.0",
|
|
38
|
-
"yaml": "^2.5.1"
|
|
39
|
-
},
|
|
40
|
-
"repository": {
|
|
41
|
-
"type": "git",
|
|
42
|
-
"url": "git+https://github.com/georgeemichel/looply.git"
|
|
43
|
-
},
|
|
44
|
-
"homepage": "https://looply-agent-app.web.app",
|
|
45
|
-
"bugs": {
|
|
46
|
-
"url": "https://github.com/georgeemichel/looply/issues"
|
|
47
|
-
},
|
|
48
|
-
"engines": {
|
|
49
|
-
"node": ">=20"
|
|
50
|
-
},
|
|
51
|
-
"publishConfig": {
|
|
52
|
-
"access": "public"
|
|
53
|
-
}
|
|
54
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "looply-cli",
|
|
3
|
+
"version": "0.5.5",
|
|
4
|
+
"description": "Leave your coding agent running. looply picks the work, holds the rails, and proves every change before it is kept.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"bin": {
|
|
7
|
+
"looply": "dist/bin.js"
|
|
8
|
+
},
|
|
9
|
+
"main": "dist/index.js",
|
|
10
|
+
"types": "dist/index.d.ts",
|
|
11
|
+
"files": [
|
|
12
|
+
"dist",
|
|
13
|
+
"win",
|
|
14
|
+
"README.md",
|
|
15
|
+
"LICENSE"
|
|
16
|
+
],
|
|
17
|
+
"keywords": [
|
|
18
|
+
"claude",
|
|
19
|
+
"claude-code",
|
|
20
|
+
"coding-agent",
|
|
21
|
+
"agent",
|
|
22
|
+
"autonomous",
|
|
23
|
+
"loop",
|
|
24
|
+
"ci",
|
|
25
|
+
"codegen",
|
|
26
|
+
"automation"
|
|
27
|
+
],
|
|
28
|
+
"scripts": {
|
|
29
|
+
"build": "tsc -b",
|
|
30
|
+
"clean": "tsc -b --clean",
|
|
31
|
+
"prepack": "npm run build",
|
|
32
|
+
"prepublishOnly": "npm run build"
|
|
33
|
+
},
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"@looply/core": "0.5.5",
|
|
36
|
+
"pdfjs-dist": "5.6.205",
|
|
37
|
+
"qrcode-terminal": "^0.12.0",
|
|
38
|
+
"yaml": "^2.5.1"
|
|
39
|
+
},
|
|
40
|
+
"repository": {
|
|
41
|
+
"type": "git",
|
|
42
|
+
"url": "git+https://github.com/georgeemichel/looply.git"
|
|
43
|
+
},
|
|
44
|
+
"homepage": "https://looply-agent-app.web.app",
|
|
45
|
+
"bugs": {
|
|
46
|
+
"url": "https://github.com/georgeemichel/looply/issues"
|
|
47
|
+
},
|
|
48
|
+
"engines": {
|
|
49
|
+
"node": ">=20"
|
|
50
|
+
},
|
|
51
|
+
"publishConfig": {
|
|
52
|
+
"access": "public"
|
|
53
|
+
}
|
|
54
|
+
}
|
package/win/HandleProbe.cs
CHANGED
|
@@ -1,116 +1,116 @@
|
|
|
1
|
-
using System;
|
|
2
|
-
using System.Runtime.InteropServices;
|
|
3
|
-
|
|
4
|
-
/*
|
|
5
|
-
* WHAT DID THIS PROCESS INHERIT THAT NOBODY MEANT TO GIVE IT?
|
|
6
|
-
*
|
|
7
|
-
* Compiled from source at test time, never checked in as a binary — the same
|
|
8
|
-
* rule CredProbe.cs and TokenProbe.cs follow.
|
|
9
|
-
*
|
|
10
|
-
* The launcher opens three FILE handles for the contained child's stdio and
|
|
11
|
-
* passes them deliberately. Anything else inheritable in the launching process
|
|
12
|
-
* used to ride along, because CreateProcess was called with bInheritHandles =
|
|
13
|
-
* true and an attribute list naming only SECURITY_CAPABILITIES. The launching
|
|
14
|
-
* process is powershell.exe, spawned by Node with three PIPE handles — so the
|
|
15
|
-
* question is not "how many handles do I hold" but "do I hold any PIPE
|
|
16
|
-
* handles", since the three intended ones are all FILE_TYPE_DISK.
|
|
17
|
-
*
|
|
18
|
-
* 🔴 IT DOES NOT GUESS HANDLE VALUES. Walking 4, 8, 12… and calling GetFileType
|
|
19
|
-
* kills the process outright inside an AppContainer: strict handle checking
|
|
20
|
-
* turns the first invalid reference into STATUS_INVALID_HANDLE (0xC0000008) and
|
|
21
|
-
* the container reports a launch that never produced output. Measured, not
|
|
22
|
-
* assumed — the count-only mode below runs fine while the scan died.
|
|
23
|
-
*
|
|
24
|
-
* So the handle table is asked for ITS OWN CONTENTS, via
|
|
25
|
-
* NtQueryInformationProcess(ProcessHandleInformation). Every value that comes
|
|
26
|
-
* back is real, so GetFileType is safe on all of them, and the table also
|
|
27
|
-
* carries HandleAttributes — OBJ_INHERIT tells us which ones would be passed on
|
|
28
|
-
* again.
|
|
29
|
-
*
|
|
30
|
-
* ⚠️ AND IT WRITES TO NOTHING. Proving a handle is there does not require
|
|
31
|
-
* crossing the boundary, and writing to an inherited pipe would corrupt the
|
|
32
|
-
* very channel the launcher parses its reply from.
|
|
33
|
-
*/
|
|
34
|
-
static class HandleProbe {
|
|
35
|
-
[DllImport("kernel32.dll", SetLastError = true)]
|
|
36
|
-
static extern uint GetFileType(IntPtr hFile);
|
|
37
|
-
[DllImport("kernel32.dll", SetLastError = true)]
|
|
38
|
-
static extern bool GetProcessHandleCount(IntPtr hProcess, out uint pdwHandleCount);
|
|
39
|
-
[DllImport("kernel32.dll")]
|
|
40
|
-
static extern IntPtr GetCurrentProcess();
|
|
41
|
-
[DllImport("ntdll.dll")]
|
|
42
|
-
static extern int NtQueryInformationProcess(IntPtr h, int cls, IntPtr info, int len, out int ret);
|
|
43
|
-
|
|
44
|
-
const uint FILE_TYPE_DISK = 0x0001;
|
|
45
|
-
const uint FILE_TYPE_CHAR = 0x0002;
|
|
46
|
-
const uint FILE_TYPE_PIPE = 0x0003;
|
|
47
|
-
|
|
48
|
-
/** ProcessHandleInformation — the process's own handle table, Win8.1+. */
|
|
49
|
-
const int ProcessHandleInformation = 51;
|
|
50
|
-
const uint OBJ_INHERIT = 0x00000002;
|
|
51
|
-
|
|
52
|
-
[StructLayout(LayoutKind.Sequential)]
|
|
53
|
-
struct PROCESS_HANDLE_TABLE_ENTRY_INFO {
|
|
54
|
-
public IntPtr HandleValue;
|
|
55
|
-
public IntPtr HandleCount;
|
|
56
|
-
public IntPtr PointerCount;
|
|
57
|
-
public uint GrantedAccess;
|
|
58
|
-
public uint ObjectTypeIndex;
|
|
59
|
-
public uint HandleAttributes;
|
|
60
|
-
public uint Reserved;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
static int Main(string[] args) {
|
|
64
|
-
uint total = 0;
|
|
65
|
-
GetProcessHandleCount(GetCurrentProcess(), out total);
|
|
66
|
-
if (args.Length > 0 && args[0] == "count") {
|
|
67
|
-
Console.WriteLine("LOOPLY-COUNT total=" + total);
|
|
68
|
-
return 0;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
int pipes = 0, disks = 0, chars = 0, inheritablePipes = 0, listed = 0;
|
|
72
|
-
|
|
73
|
-
// Grow until it fits: the table can change size between the sizing call and
|
|
74
|
-
// the real one, so this asks with a generous buffer and retries.
|
|
75
|
-
int len = 64 * 1024;
|
|
76
|
-
for (int attempt = 0; attempt < 4; attempt++) {
|
|
77
|
-
IntPtr buf = Marshal.AllocHGlobal(len);
|
|
78
|
-
try {
|
|
79
|
-
int needed;
|
|
80
|
-
int status = NtQueryInformationProcess(GetCurrentProcess(), ProcessHandleInformation, buf, len, out needed);
|
|
81
|
-
if (status != 0) {
|
|
82
|
-
if (needed > len) { len = needed + 8192; continue; }
|
|
83
|
-
Console.WriteLine("LOOPLY-HANDLES unavailable status=0x" + status.ToString("X8") + " total=" + total);
|
|
84
|
-
return 0;
|
|
85
|
-
}
|
|
86
|
-
// PROCESS_HANDLE_SNAPSHOT_INFORMATION: NumberOfHandles, Reserved, then
|
|
87
|
-
// the entries.
|
|
88
|
-
IntPtr count = Marshal.ReadIntPtr(buf, 0);
|
|
89
|
-
int n = (int)count.ToInt64();
|
|
90
|
-
int header = IntPtr.Size * 2;
|
|
91
|
-
int stride = Marshal.SizeOf(typeof(PROCESS_HANDLE_TABLE_ENTRY_INFO));
|
|
92
|
-
for (int i = 0; i < n; i++) {
|
|
93
|
-
IntPtr at = new IntPtr(buf.ToInt64() + header + ((long)i * stride));
|
|
94
|
-
PROCESS_HANDLE_TABLE_ENTRY_INFO e =
|
|
95
|
-
(PROCESS_HANDLE_TABLE_ENTRY_INFO)Marshal.PtrToStructure(at, typeof(PROCESS_HANDLE_TABLE_ENTRY_INFO));
|
|
96
|
-
listed++;
|
|
97
|
-
uint t = GetFileType(e.HandleValue);
|
|
98
|
-
if (t == FILE_TYPE_PIPE) {
|
|
99
|
-
pipes++;
|
|
100
|
-
if ((e.HandleAttributes & OBJ_INHERIT) != 0) inheritablePipes++;
|
|
101
|
-
} else if (t == FILE_TYPE_DISK) disks++;
|
|
102
|
-
else if (t == FILE_TYPE_CHAR) chars++;
|
|
103
|
-
}
|
|
104
|
-
break;
|
|
105
|
-
} finally {
|
|
106
|
-
Marshal.FreeHGlobal(buf);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// One line, parsed by the test. stdout here is one of the intended handles,
|
|
111
|
-
// so this line arriving at all is itself part of the evidence.
|
|
112
|
-
Console.WriteLine("LOOPLY-HANDLES pipes=" + pipes + " disks=" + disks + " chars=" + chars
|
|
113
|
-
+ " inheritablePipes=" + inheritablePipes + " listed=" + listed + " total=" + total);
|
|
114
|
-
return 0;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
1
|
+
using System;
|
|
2
|
+
using System.Runtime.InteropServices;
|
|
3
|
+
|
|
4
|
+
/*
|
|
5
|
+
* WHAT DID THIS PROCESS INHERIT THAT NOBODY MEANT TO GIVE IT?
|
|
6
|
+
*
|
|
7
|
+
* Compiled from source at test time, never checked in as a binary — the same
|
|
8
|
+
* rule CredProbe.cs and TokenProbe.cs follow.
|
|
9
|
+
*
|
|
10
|
+
* The launcher opens three FILE handles for the contained child's stdio and
|
|
11
|
+
* passes them deliberately. Anything else inheritable in the launching process
|
|
12
|
+
* used to ride along, because CreateProcess was called with bInheritHandles =
|
|
13
|
+
* true and an attribute list naming only SECURITY_CAPABILITIES. The launching
|
|
14
|
+
* process is powershell.exe, spawned by Node with three PIPE handles — so the
|
|
15
|
+
* question is not "how many handles do I hold" but "do I hold any PIPE
|
|
16
|
+
* handles", since the three intended ones are all FILE_TYPE_DISK.
|
|
17
|
+
*
|
|
18
|
+
* 🔴 IT DOES NOT GUESS HANDLE VALUES. Walking 4, 8, 12… and calling GetFileType
|
|
19
|
+
* kills the process outright inside an AppContainer: strict handle checking
|
|
20
|
+
* turns the first invalid reference into STATUS_INVALID_HANDLE (0xC0000008) and
|
|
21
|
+
* the container reports a launch that never produced output. Measured, not
|
|
22
|
+
* assumed — the count-only mode below runs fine while the scan died.
|
|
23
|
+
*
|
|
24
|
+
* So the handle table is asked for ITS OWN CONTENTS, via
|
|
25
|
+
* NtQueryInformationProcess(ProcessHandleInformation). Every value that comes
|
|
26
|
+
* back is real, so GetFileType is safe on all of them, and the table also
|
|
27
|
+
* carries HandleAttributes — OBJ_INHERIT tells us which ones would be passed on
|
|
28
|
+
* again.
|
|
29
|
+
*
|
|
30
|
+
* ⚠️ AND IT WRITES TO NOTHING. Proving a handle is there does not require
|
|
31
|
+
* crossing the boundary, and writing to an inherited pipe would corrupt the
|
|
32
|
+
* very channel the launcher parses its reply from.
|
|
33
|
+
*/
|
|
34
|
+
static class HandleProbe {
|
|
35
|
+
[DllImport("kernel32.dll", SetLastError = true)]
|
|
36
|
+
static extern uint GetFileType(IntPtr hFile);
|
|
37
|
+
[DllImport("kernel32.dll", SetLastError = true)]
|
|
38
|
+
static extern bool GetProcessHandleCount(IntPtr hProcess, out uint pdwHandleCount);
|
|
39
|
+
[DllImport("kernel32.dll")]
|
|
40
|
+
static extern IntPtr GetCurrentProcess();
|
|
41
|
+
[DllImport("ntdll.dll")]
|
|
42
|
+
static extern int NtQueryInformationProcess(IntPtr h, int cls, IntPtr info, int len, out int ret);
|
|
43
|
+
|
|
44
|
+
const uint FILE_TYPE_DISK = 0x0001;
|
|
45
|
+
const uint FILE_TYPE_CHAR = 0x0002;
|
|
46
|
+
const uint FILE_TYPE_PIPE = 0x0003;
|
|
47
|
+
|
|
48
|
+
/** ProcessHandleInformation — the process's own handle table, Win8.1+. */
|
|
49
|
+
const int ProcessHandleInformation = 51;
|
|
50
|
+
const uint OBJ_INHERIT = 0x00000002;
|
|
51
|
+
|
|
52
|
+
[StructLayout(LayoutKind.Sequential)]
|
|
53
|
+
struct PROCESS_HANDLE_TABLE_ENTRY_INFO {
|
|
54
|
+
public IntPtr HandleValue;
|
|
55
|
+
public IntPtr HandleCount;
|
|
56
|
+
public IntPtr PointerCount;
|
|
57
|
+
public uint GrantedAccess;
|
|
58
|
+
public uint ObjectTypeIndex;
|
|
59
|
+
public uint HandleAttributes;
|
|
60
|
+
public uint Reserved;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
static int Main(string[] args) {
|
|
64
|
+
uint total = 0;
|
|
65
|
+
GetProcessHandleCount(GetCurrentProcess(), out total);
|
|
66
|
+
if (args.Length > 0 && args[0] == "count") {
|
|
67
|
+
Console.WriteLine("LOOPLY-COUNT total=" + total);
|
|
68
|
+
return 0;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
int pipes = 0, disks = 0, chars = 0, inheritablePipes = 0, listed = 0;
|
|
72
|
+
|
|
73
|
+
// Grow until it fits: the table can change size between the sizing call and
|
|
74
|
+
// the real one, so this asks with a generous buffer and retries.
|
|
75
|
+
int len = 64 * 1024;
|
|
76
|
+
for (int attempt = 0; attempt < 4; attempt++) {
|
|
77
|
+
IntPtr buf = Marshal.AllocHGlobal(len);
|
|
78
|
+
try {
|
|
79
|
+
int needed;
|
|
80
|
+
int status = NtQueryInformationProcess(GetCurrentProcess(), ProcessHandleInformation, buf, len, out needed);
|
|
81
|
+
if (status != 0) {
|
|
82
|
+
if (needed > len) { len = needed + 8192; continue; }
|
|
83
|
+
Console.WriteLine("LOOPLY-HANDLES unavailable status=0x" + status.ToString("X8") + " total=" + total);
|
|
84
|
+
return 0;
|
|
85
|
+
}
|
|
86
|
+
// PROCESS_HANDLE_SNAPSHOT_INFORMATION: NumberOfHandles, Reserved, then
|
|
87
|
+
// the entries.
|
|
88
|
+
IntPtr count = Marshal.ReadIntPtr(buf, 0);
|
|
89
|
+
int n = (int)count.ToInt64();
|
|
90
|
+
int header = IntPtr.Size * 2;
|
|
91
|
+
int stride = Marshal.SizeOf(typeof(PROCESS_HANDLE_TABLE_ENTRY_INFO));
|
|
92
|
+
for (int i = 0; i < n; i++) {
|
|
93
|
+
IntPtr at = new IntPtr(buf.ToInt64() + header + ((long)i * stride));
|
|
94
|
+
PROCESS_HANDLE_TABLE_ENTRY_INFO e =
|
|
95
|
+
(PROCESS_HANDLE_TABLE_ENTRY_INFO)Marshal.PtrToStructure(at, typeof(PROCESS_HANDLE_TABLE_ENTRY_INFO));
|
|
96
|
+
listed++;
|
|
97
|
+
uint t = GetFileType(e.HandleValue);
|
|
98
|
+
if (t == FILE_TYPE_PIPE) {
|
|
99
|
+
pipes++;
|
|
100
|
+
if ((e.HandleAttributes & OBJ_INHERIT) != 0) inheritablePipes++;
|
|
101
|
+
} else if (t == FILE_TYPE_DISK) disks++;
|
|
102
|
+
else if (t == FILE_TYPE_CHAR) chars++;
|
|
103
|
+
}
|
|
104
|
+
break;
|
|
105
|
+
} finally {
|
|
106
|
+
Marshal.FreeHGlobal(buf);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// One line, parsed by the test. stdout here is one of the intended handles,
|
|
111
|
+
// so this line arriving at all is itself part of the evidence.
|
|
112
|
+
Console.WriteLine("LOOPLY-HANDLES pipes=" + pipes + " disks=" + disks + " chars=" + chars
|
|
113
|
+
+ " inheritablePipes=" + inheritablePipes + " listed=" + listed + " total=" + total);
|
|
114
|
+
return 0;
|
|
115
|
+
}
|
|
116
|
+
}
|