@ordis_co_th/execute-powershell 1.0.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/LICENSE +21 -0
- package/README.md +85 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/tools/execute_powershell.d.ts +11 -0
- package/dist/tools/execute_powershell.d.ts.map +1 -0
- package/dist/tools/execute_powershell.js +75 -0
- package/dist/tools/execute_powershell.js.map +1 -0
- package/dist/tools/metadata.d.ts +44 -0
- package/dist/tools/metadata.d.ts.map +1 -0
- package/dist/tools/metadata.js +52 -0
- package/dist/tools/metadata.js.map +1 -0
- package/dist/tools/output.d.ts +15 -0
- package/dist/tools/output.d.ts.map +1 -0
- package/dist/tools/output.js +44 -0
- package/dist/tools/output.js.map +1 -0
- package/dist/tools/permissions.d.ts +18 -0
- package/dist/tools/permissions.d.ts.map +1 -0
- package/dist/tools/permissions.js +39 -0
- package/dist/tools/permissions.js.map +1 -0
- package/dist/tools/powershell_exe.d.ts +6 -0
- package/dist/tools/powershell_exe.d.ts.map +1 -0
- package/dist/tools/powershell_exe.js +12 -0
- package/dist/tools/powershell_exe.js.map +1 -0
- package/dist/tools/process.d.ts +71 -0
- package/dist/tools/process.d.ts.map +1 -0
- package/dist/tools/process.js +124 -0
- package/dist/tools/process.js.map +1 -0
- package/dist/tools/workdir.d.ts +52 -0
- package/dist/tools/workdir.d.ts.map +1 -0
- package/dist/tools/workdir.js +97 -0
- package/dist/tools/workdir.js.map +1 -0
- package/package.json +34 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 OpenCode
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# Execute PowerShell Plugin
|
|
2
|
+
|
|
3
|
+
An OpenCode plugin that provides PowerShell script execution capabilities with built-in safety controls and permission management.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
bun install @ordis_co_th/execute-powershell
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
### Register in `opencode.json`
|
|
14
|
+
|
|
15
|
+
Add the plugin to your OpenCode configuration:
|
|
16
|
+
|
|
17
|
+
```json
|
|
18
|
+
{
|
|
19
|
+
"plugins": [
|
|
20
|
+
"@ordis_co_th/execute-powershell"
|
|
21
|
+
]
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Or with explicit import path:
|
|
26
|
+
|
|
27
|
+
```json
|
|
28
|
+
{
|
|
29
|
+
"plugins": [
|
|
30
|
+
{
|
|
31
|
+
"import": "@ordis_co_th/execute-powershell",
|
|
32
|
+
"config": {}
|
|
33
|
+
}
|
|
34
|
+
]
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Available Tools
|
|
39
|
+
|
|
40
|
+
Once registered, the plugin provides the `execute_powershell` tool with the following features:
|
|
41
|
+
|
|
42
|
+
- **Command Execution**: Execute PowerShell scripts with proper output capture
|
|
43
|
+
- **Permission Controls**: Built-in safety mechanisms for command validation
|
|
44
|
+
- **Working Directory**: Configurable working directory for script execution
|
|
45
|
+
- **Timeout Support**: Configurable execution timeouts
|
|
46
|
+
- **Output Streaming**: Real-time stdout/stderr capture
|
|
47
|
+
|
|
48
|
+
### Example Tool Call
|
|
49
|
+
|
|
50
|
+
```json
|
|
51
|
+
{
|
|
52
|
+
"tool": "execute_powershell",
|
|
53
|
+
"params": {
|
|
54
|
+
"command": "Get-Process",
|
|
55
|
+
"workdir": "/path/to/workdir",
|
|
56
|
+
"timeout_ms": 30000
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Development
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
# Install dependencies
|
|
65
|
+
bun install
|
|
66
|
+
|
|
67
|
+
# Build the project
|
|
68
|
+
bun run build
|
|
69
|
+
|
|
70
|
+
# Run tests
|
|
71
|
+
bun test
|
|
72
|
+
|
|
73
|
+
# Check package contents
|
|
74
|
+
bun run package:check
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Package Structure
|
|
78
|
+
|
|
79
|
+
- **Entry Point**: `./dist/index.js`
|
|
80
|
+
- **Type Definitions**: `./dist/index.d.ts`
|
|
81
|
+
- **Export**: `ExecutePowerShellPlugin` - Main plugin function
|
|
82
|
+
|
|
83
|
+
## License
|
|
84
|
+
|
|
85
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAGlD,eAAO,MAAM,uBAAuB,EAAE,MAMrC,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAEnE,MAAM,CAAC,MAAM,uBAAuB,GAAW,KAAK,IAAI,EAAE;IACxD,OAAO;QACL,IAAI,EAAE;YACJ,kBAAkB;SACnB;KACF,CAAC;AACJ,CAAC,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type ToolDefinition } from "@opencode-ai/plugin/tool";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
declare const argsSchema: {
|
|
4
|
+
readonly command: z.ZodString;
|
|
5
|
+
readonly description: z.ZodString;
|
|
6
|
+
readonly timeout_ms: z.ZodDefault<z.ZodNumber>;
|
|
7
|
+
readonly workdir: z.ZodOptional<z.ZodString>;
|
|
8
|
+
};
|
|
9
|
+
export declare const execute_powershell: ToolDefinition;
|
|
10
|
+
export { argsSchema };
|
|
11
|
+
//# sourceMappingURL=execute_powershell.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"execute_powershell.d.ts","sourceRoot":"","sources":["../../src/tools/execute_powershell.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0B,KAAK,cAAc,EAAE,MAAM,0BAA0B,CAAC;AACvF,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAQxB,QAAA,MAAM,UAAU;;;;;CAKN,CAAC;AASX,eAAO,MAAM,kBAAkB,EAAE,cAiE/B,CAAC;AAEH,OAAO,EAAE,UAAU,EAAE,CAAC"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { tool } from "@opencode-ai/plugin/tool";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { askExecutePowerShellPermission } from "./permissions.js";
|
|
4
|
+
import { askExternalDirectoryIfRequired, resolveWorkdir } from "./workdir.js";
|
|
5
|
+
import { formatMetadataFooter } from "./metadata.js";
|
|
6
|
+
import { resolvePowerShellExecutable } from "./powershell_exe.js";
|
|
7
|
+
import { spawnPowerShell, createTerminationSignal, terminateProcessTree } from "./process.js";
|
|
8
|
+
import { collectCombinedOutput } from "./output.js";
|
|
9
|
+
const argsSchema = {
|
|
10
|
+
command: z.string(),
|
|
11
|
+
description: z.string(),
|
|
12
|
+
timeout_ms: z.number().int().min(0).default(120000),
|
|
13
|
+
workdir: z.string().optional(),
|
|
14
|
+
};
|
|
15
|
+
export const execute_powershell = tool({
|
|
16
|
+
description: "Execute PowerShell commands on Windows",
|
|
17
|
+
args: argsSchema,
|
|
18
|
+
async execute(args, context) {
|
|
19
|
+
await askExecutePowerShellPermission(context, args.command);
|
|
20
|
+
const resolvedWorkdir = resolveWorkdir(context.directory, args.workdir);
|
|
21
|
+
await askExternalDirectoryIfRequired(context, resolvedWorkdir);
|
|
22
|
+
const timeoutMs = args.timeout_ms ?? 120000;
|
|
23
|
+
const { signal, getEndedBy } = createTerminationSignal(context.abort, timeoutMs);
|
|
24
|
+
const startTime = Date.now();
|
|
25
|
+
let exitCode = 0;
|
|
26
|
+
let shell = "unknown";
|
|
27
|
+
let proc;
|
|
28
|
+
try {
|
|
29
|
+
const exe = resolvePowerShellExecutable();
|
|
30
|
+
shell = exe.kind;
|
|
31
|
+
proc = spawnPowerShell({
|
|
32
|
+
exePath: exe.path,
|
|
33
|
+
command: args.command,
|
|
34
|
+
cwd: resolvedWorkdir,
|
|
35
|
+
signal,
|
|
36
|
+
});
|
|
37
|
+
const output = await collectCombinedOutput(proc);
|
|
38
|
+
exitCode = await proc.exited;
|
|
39
|
+
const durationMs = Date.now() - startTime;
|
|
40
|
+
const endedBy = getEndedBy();
|
|
41
|
+
const metadata = {
|
|
42
|
+
exitCode,
|
|
43
|
+
endedBy,
|
|
44
|
+
shell,
|
|
45
|
+
resolvedWorkdir,
|
|
46
|
+
timeoutMs,
|
|
47
|
+
durationMs,
|
|
48
|
+
};
|
|
49
|
+
return output + formatMetadataFooter(metadata);
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
const durationMs = Date.now() - startTime;
|
|
53
|
+
const endedBy = getEndedBy();
|
|
54
|
+
exitCode = endedBy === "timeout" ? 1 : -1;
|
|
55
|
+
const metadata = {
|
|
56
|
+
exitCode,
|
|
57
|
+
endedBy,
|
|
58
|
+
shell,
|
|
59
|
+
resolvedWorkdir,
|
|
60
|
+
timeoutMs,
|
|
61
|
+
durationMs,
|
|
62
|
+
};
|
|
63
|
+
const errorOutput = error instanceof Error ? error.message : String(error);
|
|
64
|
+
return errorOutput + formatMetadataFooter(metadata);
|
|
65
|
+
}
|
|
66
|
+
finally {
|
|
67
|
+
const endedBy = getEndedBy();
|
|
68
|
+
if ((endedBy === "timeout" || endedBy === "abort") && proc?.pid) {
|
|
69
|
+
await terminateProcessTree(proc.pid);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
export { argsSchema };
|
|
75
|
+
//# sourceMappingURL=execute_powershell.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"execute_powershell.js","sourceRoot":"","sources":["../../src/tools/execute_powershell.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAyC,MAAM,0BAA0B,CAAC;AACvF,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,8BAA8B,EAAE,MAAM,kBAAkB,CAAC;AAClE,OAAO,EAAE,8BAA8B,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9E,OAAO,EAAE,oBAAoB,EAA2B,MAAM,eAAe,CAAC;AAC9E,OAAO,EAAE,2BAA2B,EAAE,MAAM,qBAAqB,CAAC;AAClE,OAAO,EAAE,eAAe,EAAE,uBAAuB,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAC9F,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAEpD,MAAM,UAAU,GAAG;IACjB,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;IACnB,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;IACvB,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;IACnD,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CACtB,CAAC;AASX,MAAM,CAAC,MAAM,kBAAkB,GAAmB,IAAI,CAAC;IACrD,WAAW,EAAE,wCAAwC;IACrD,IAAI,EAAE,UAAiB;IACvB,KAAK,CAAC,OAAO,CAAC,IAAc,EAAE,OAAoB;QAChD,MAAM,8BAA8B,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QAC5D,MAAM,eAAe,GAAG,cAAc,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QACxE,MAAM,8BAA8B,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;QAC/D,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,IAAI,MAAM,CAAC;QAC5C,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,uBAAuB,CACpD,OAAO,CAAC,KAAK,EACb,SAAS,CACV,CAAC;QACF,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC7B,IAAI,QAAQ,GAAG,CAAC,CAAC;QACjB,IAAI,KAAK,GAAG,SAAS,CAAC;QACtB,IAAI,IAAoD,CAAC;QAEzD,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,2BAA2B,EAAE,CAAC;YAC1C,KAAK,GAAG,GAAG,CAAC,IAAI,CAAC;YAEjB,IAAI,GAAG,eAAe,CAAC;gBACrB,OAAO,EAAE,GAAG,CAAC,IAAI;gBACjB,OAAO,EAAE,IAAI,CAAC,OAAO;gBACrB,GAAG,EAAE,eAAe;gBACpB,MAAM;aACP,CAAC,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,qBAAqB,CAAC,IAAI,CAAC,CAAC;YACjD,QAAQ,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC;YAC7B,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;YAC1C,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;YAE7B,MAAM,QAAQ,GAAuB;gBACnC,QAAQ;gBACR,OAAO;gBACP,KAAK;gBACL,eAAe;gBACf,SAAS;gBACT,UAAU;aACX,CAAC;YAEF,OAAO,MAAM,GAAG,oBAAoB,CAAC,QAAQ,CAAC,CAAC;QACjD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;YAC1C,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;YAC7B,QAAQ,GAAG,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAE1C,MAAM,QAAQ,GAAuB;gBACnC,QAAQ;gBACR,OAAO;gBACP,KAAK;gBACL,eAAe;gBACf,SAAS;gBACT,UAAU;aACX,CAAC;YAEF,MAAM,WAAW,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAC3E,OAAO,WAAW,GAAG,oBAAoB,CAAC,QAAQ,CAAC,CAAC;QACtD,CAAC;gBAAS,CAAC;YACT,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;YAC7B,IAAI,CAAC,OAAO,KAAK,SAAS,IAAI,OAAO,KAAK,OAAO,CAAC,IAAI,IAAI,EAAE,GAAG,EAAE,CAAC;gBAChE,MAAM,oBAAoB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACvC,CAAC;QACH,CAAC;IACH,CAAC;CACF,CAAC,CAAC;AAEH,OAAO,EAAE,UAAU,EAAE,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Metadata footer for PowerShell execution outcomes.
|
|
3
|
+
*
|
|
4
|
+
* This module provides functions to format and parse metadata footers
|
|
5
|
+
* that are appended to PowerShell command output. The footer uses a
|
|
6
|
+
* tagged JSON format that can be easily extracted and parsed.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Metadata about a PowerShell execution outcome.
|
|
10
|
+
*/
|
|
11
|
+
export interface PowerShellMetadata {
|
|
12
|
+
/** Exit code from the PowerShell process */
|
|
13
|
+
exitCode: number;
|
|
14
|
+
/** How the execution ended: "exit" (normal), "timeout", or "abort" */
|
|
15
|
+
endedBy: "exit" | "timeout" | "abort";
|
|
16
|
+
/** Shell identifier (e.g., "powershell", "pwsh") */
|
|
17
|
+
shell: string;
|
|
18
|
+
/** Resolved absolute path of the working directory */
|
|
19
|
+
resolvedWorkdir: string;
|
|
20
|
+
/** Timeout in milliseconds */
|
|
21
|
+
timeoutMs: number;
|
|
22
|
+
/** Duration of execution in milliseconds */
|
|
23
|
+
durationMs: number;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Format metadata as a tagged JSON footer.
|
|
27
|
+
*
|
|
28
|
+
* The footer format is: <powershell_metadata>{"exitCode": ..., ...}</powershell_metadata>
|
|
29
|
+
*
|
|
30
|
+
* @param meta - The metadata to format
|
|
31
|
+
* @returns The formatted metadata footer string
|
|
32
|
+
*/
|
|
33
|
+
export declare function formatMetadataFooter(meta: PowerShellMetadata): string;
|
|
34
|
+
/**
|
|
35
|
+
* Parse a metadata footer from text.
|
|
36
|
+
*
|
|
37
|
+
* Extracts and parses the tagged JSON metadata from the end of text.
|
|
38
|
+
* Returns null if no valid metadata footer is found.
|
|
39
|
+
*
|
|
40
|
+
* @param text - The text to parse
|
|
41
|
+
* @returns The parsed metadata, or null if not found
|
|
42
|
+
*/
|
|
43
|
+
export declare function parseMetadataFooter(text: string): PowerShellMetadata | null;
|
|
44
|
+
//# sourceMappingURL=metadata.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metadata.d.ts","sourceRoot":"","sources":["../../src/tools/metadata.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,4CAA4C;IAC5C,QAAQ,EAAE,MAAM,CAAC;IACjB,sEAAsE;IACtE,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC;IACtC,oDAAoD;IACpD,KAAK,EAAE,MAAM,CAAC;IACd,sDAAsD;IACtD,eAAe,EAAE,MAAM,CAAC;IACxB,8BAA8B;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,4CAA4C;IAC5C,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,kBAAkB,GAAG,MAAM,CAErE;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,kBAAkB,GAAG,IAAI,CAwB3E"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Metadata footer for PowerShell execution outcomes.
|
|
3
|
+
*
|
|
4
|
+
* This module provides functions to format and parse metadata footers
|
|
5
|
+
* that are appended to PowerShell command output. The footer uses a
|
|
6
|
+
* tagged JSON format that can be easily extracted and parsed.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Format metadata as a tagged JSON footer.
|
|
10
|
+
*
|
|
11
|
+
* The footer format is: <powershell_metadata>{"exitCode": ..., ...}</powershell_metadata>
|
|
12
|
+
*
|
|
13
|
+
* @param meta - The metadata to format
|
|
14
|
+
* @returns The formatted metadata footer string
|
|
15
|
+
*/
|
|
16
|
+
export function formatMetadataFooter(meta) {
|
|
17
|
+
return `<powershell_metadata>${JSON.stringify(meta)}</powershell_metadata>`;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Parse a metadata footer from text.
|
|
21
|
+
*
|
|
22
|
+
* Extracts and parses the tagged JSON metadata from the end of text.
|
|
23
|
+
* Returns null if no valid metadata footer is found.
|
|
24
|
+
*
|
|
25
|
+
* @param text - The text to parse
|
|
26
|
+
* @returns The parsed metadata, or null if not found
|
|
27
|
+
*/
|
|
28
|
+
export function parseMetadataFooter(text) {
|
|
29
|
+
// Find ALL matches and take the LAST one (the actual footer, not any
|
|
30
|
+
// metadata-like text that might appear in command output)
|
|
31
|
+
const matches = [...text.matchAll(/<powershell_metadata>(.+?)<\/powershell_metadata>/gs)];
|
|
32
|
+
if (matches.length === 0)
|
|
33
|
+
return null;
|
|
34
|
+
const lastMatch = matches[matches.length - 1];
|
|
35
|
+
try {
|
|
36
|
+
const parsed = JSON.parse(lastMatch[1]);
|
|
37
|
+
// Validate all required fields
|
|
38
|
+
if (typeof parsed.exitCode !== "number" ||
|
|
39
|
+
!["exit", "timeout", "abort"].includes(parsed.endedBy) ||
|
|
40
|
+
typeof parsed.shell !== "string" ||
|
|
41
|
+
typeof parsed.resolvedWorkdir !== "string" ||
|
|
42
|
+
typeof parsed.timeoutMs !== "number" ||
|
|
43
|
+
typeof parsed.durationMs !== "number") {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
return parsed;
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=metadata.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metadata.js","sourceRoot":"","sources":["../../src/tools/metadata.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAoBH;;;;;;;GAOG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAAwB;IAC3D,OAAO,wBAAwB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,wBAAwB,CAAC;AAC9E,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAY;IAC9C,qEAAqE;IACrE,0DAA0D;IAC1D,MAAM,OAAO,GAAG,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,qDAAqD,CAAC,CAAC,CAAC;IAC1F,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAEtC,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC9C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;QACxC,+BAA+B;QAC/B,IACE,OAAO,MAAM,CAAC,QAAQ,KAAK,QAAQ;YACnC,CAAC,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC;YACtD,OAAO,MAAM,CAAC,KAAK,KAAK,QAAQ;YAChC,OAAO,MAAM,CAAC,eAAe,KAAK,QAAQ;YAC1C,OAAO,MAAM,CAAC,SAAS,KAAK,QAAQ;YACpC,OAAO,MAAM,CAAC,UAAU,KAAK,QAAQ,EACrC,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,MAA4B,CAAC;IACtC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Collect combined stdout and stderr output from a process.
|
|
3
|
+
*
|
|
4
|
+
* Reads both streams concurrently and appends chunks in observed arrival order,
|
|
5
|
+
* preserving the interleaving of output as it occurred. Uses separate TextDecoder
|
|
6
|
+
* instances per stream to prevent UTF-8 corruption when chunks interleave.
|
|
7
|
+
*
|
|
8
|
+
* @param proc - Object with stdout and stderr ReadableStreams
|
|
9
|
+
* @returns Promise resolving to combined output string
|
|
10
|
+
*/
|
|
11
|
+
export declare function collectCombinedOutput(proc: {
|
|
12
|
+
stdout: ReadableStream<Uint8Array>;
|
|
13
|
+
stderr: ReadableStream<Uint8Array>;
|
|
14
|
+
}): Promise<string>;
|
|
15
|
+
//# sourceMappingURL=output.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../../src/tools/output.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,wBAAsB,qBAAqB,CACzC,IAAI,EAAE;IAAE,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC;IAAC,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,CAAA;CAAE,GAC/E,OAAO,CAAC,MAAM,CAAC,CAwCjB"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Collect combined stdout and stderr output from a process.
|
|
3
|
+
*
|
|
4
|
+
* Reads both streams concurrently and appends chunks in observed arrival order,
|
|
5
|
+
* preserving the interleaving of output as it occurred. Uses separate TextDecoder
|
|
6
|
+
* instances per stream to prevent UTF-8 corruption when chunks interleave.
|
|
7
|
+
*
|
|
8
|
+
* @param proc - Object with stdout and stderr ReadableStreams
|
|
9
|
+
* @returns Promise resolving to combined output string
|
|
10
|
+
*/
|
|
11
|
+
export async function collectCombinedOutput(proc) {
|
|
12
|
+
const chunks = [];
|
|
13
|
+
let order = 0;
|
|
14
|
+
const readStream = async (stream, decoder) => {
|
|
15
|
+
const reader = stream.getReader();
|
|
16
|
+
try {
|
|
17
|
+
while (true) {
|
|
18
|
+
const { done, value } = await reader.read();
|
|
19
|
+
if (done)
|
|
20
|
+
break;
|
|
21
|
+
const text = decoder.decode(value, { stream: true });
|
|
22
|
+
chunks.push({ text, order: order++ });
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
finally {
|
|
26
|
+
reader.releaseLock();
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
// Use separate decoders for each stream to prevent UTF-8 corruption
|
|
30
|
+
const stdoutDecoder = new TextDecoder("utf-8");
|
|
31
|
+
const stderrDecoder = new TextDecoder("utf-8");
|
|
32
|
+
// Read both streams concurrently
|
|
33
|
+
await Promise.all([
|
|
34
|
+
readStream(proc.stdout, stdoutDecoder),
|
|
35
|
+
readStream(proc.stderr, stderrDecoder),
|
|
36
|
+
]);
|
|
37
|
+
// Sort by arrival order
|
|
38
|
+
chunks.sort((a, b) => a.order - b.order);
|
|
39
|
+
// Join chunks and flush any remaining bytes from both decoders
|
|
40
|
+
return (chunks.map((c) => c.text).join("") +
|
|
41
|
+
stdoutDecoder.decode() +
|
|
42
|
+
stderrDecoder.decode());
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=output.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output.js","sourceRoot":"","sources":["../../src/tools/output.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,IAAgF;IAEhF,MAAM,MAAM,GAA2C,EAAE,CAAC;IAC1D,IAAI,KAAK,GAAG,CAAC,CAAC;IAEd,MAAM,UAAU,GAAG,KAAK,EACtB,MAAkC,EAClC,OAAoB,EACpB,EAAE;QACF,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,EAAE,CAAC;QAClC,IAAI,CAAC;YACH,OAAO,IAAI,EAAE,CAAC;gBACZ,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;gBAC5C,IAAI,IAAI;oBAAE,MAAM;gBAChB,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;gBACrD,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;YACxC,CAAC;QACH,CAAC;gBAAS,CAAC;YACT,MAAM,CAAC,WAAW,EAAE,CAAC;QACvB,CAAC;IACH,CAAC,CAAC;IAEF,oEAAoE;IACpE,MAAM,aAAa,GAAG,IAAI,WAAW,CAAC,OAAO,CAAC,CAAC;IAC/C,MAAM,aAAa,GAAG,IAAI,WAAW,CAAC,OAAO,CAAC,CAAC;IAE/C,iCAAiC;IACjC,MAAM,OAAO,CAAC,GAAG,CAAC;QAChB,UAAU,CAAC,IAAI,CAAC,MAAM,EAAE,aAAa,CAAC;QACtC,UAAU,CAAC,IAAI,CAAC,MAAM,EAAE,aAAa,CAAC;KACvC,CAAC,CAAC;IAEH,wBAAwB;IACxB,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;IAEzC,+DAA+D;IAC/D,OAAO,CACL,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;QAClC,aAAa,CAAC,MAAM,EAAE;QACtB,aAAa,CAAC,MAAM,EAAE,CACvB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ToolContext } from "@opencode-ai/plugin/tool";
|
|
2
|
+
/**
|
|
3
|
+
* Asks for permission to execute a PowerShell command.
|
|
4
|
+
*
|
|
5
|
+
* @param context - The tool execution context
|
|
6
|
+
* @param command - The PowerShell command to execute
|
|
7
|
+
*/
|
|
8
|
+
export declare function askExecutePowerShellPermission(context: ToolContext, command: string): Promise<void>;
|
|
9
|
+
/**
|
|
10
|
+
* Derives the always permission pattern from a PowerShell command.
|
|
11
|
+
*
|
|
12
|
+
* Rules:
|
|
13
|
+
* 1. Tokenize by whitespace
|
|
14
|
+
* 2. Skip leading tokens that equal '&' or '.'
|
|
15
|
+
* 3. Return '<prefix> *' from the first remaining token
|
|
16
|
+
*/
|
|
17
|
+
export declare function deriveAlwaysPattern(command: string): string;
|
|
18
|
+
//# sourceMappingURL=permissions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permissions.d.ts","sourceRoot":"","sources":["../../src/tools/permissions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAE5D;;;;;GAKG;AACH,wBAAsB,8BAA8B,CAClD,OAAO,EAAE,WAAW,EACpB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,IAAI,CAAC,CAOf;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAiB3D"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Asks for permission to execute a PowerShell command.
|
|
3
|
+
*
|
|
4
|
+
* @param context - The tool execution context
|
|
5
|
+
* @param command - The PowerShell command to execute
|
|
6
|
+
*/
|
|
7
|
+
export async function askExecutePowerShellPermission(context, command) {
|
|
8
|
+
await context.ask({
|
|
9
|
+
permission: "execute_powershell",
|
|
10
|
+
patterns: [command],
|
|
11
|
+
always: [deriveAlwaysPattern(command)],
|
|
12
|
+
metadata: {},
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Derives the always permission pattern from a PowerShell command.
|
|
17
|
+
*
|
|
18
|
+
* Rules:
|
|
19
|
+
* 1. Tokenize by whitespace
|
|
20
|
+
* 2. Skip leading tokens that equal '&' or '.'
|
|
21
|
+
* 3. Return '<prefix> *' from the first remaining token
|
|
22
|
+
*/
|
|
23
|
+
export function deriveAlwaysPattern(command) {
|
|
24
|
+
// Trim whitespace and split by whitespace
|
|
25
|
+
const tokens = command.trim().split(/\s+/).filter(token => token.length > 0);
|
|
26
|
+
// Find the first non-skippable token
|
|
27
|
+
for (const token of tokens) {
|
|
28
|
+
// Skip leading tokens that equal '&' or '.'
|
|
29
|
+
if (token === '&' || token === '.') {
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
// Return pattern with wildcard
|
|
33
|
+
return `${token} *`;
|
|
34
|
+
}
|
|
35
|
+
// Fallback: if no valid token found, throw error (fail-closed security)
|
|
36
|
+
// This prevents over-broad permission patterns from being generated
|
|
37
|
+
throw new Error("Cannot derive permission pattern: no valid command token found");
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=permissions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permissions.js","sourceRoot":"","sources":["../../src/tools/permissions.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,8BAA8B,CAClD,OAAoB,EACpB,OAAe;IAEf,MAAM,OAAO,CAAC,GAAG,CAAC;QAChB,UAAU,EAAE,oBAAoB;QAChC,QAAQ,EAAE,CAAC,OAAO,CAAC;QACnB,MAAM,EAAE,CAAC,mBAAmB,CAAC,OAAO,CAAC,CAAC;QACtC,QAAQ,EAAE,EAAE;KACb,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,mBAAmB,CAAC,OAAe;IACjD,0CAA0C;IAC1C,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAE7E,qCAAqC;IACrC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,4CAA4C;QAC5C,IAAI,KAAK,KAAK,GAAG,IAAI,KAAK,KAAK,GAAG,EAAE,CAAC;YACnC,SAAS;QACX,CAAC;QACD,+BAA+B;QAC/B,OAAO,GAAG,KAAK,IAAI,CAAC;IACtB,CAAC;IAED,wEAAwE;IACxE,oEAAoE;IACpE,MAAM,IAAI,KAAK,CAAC,gEAAgE,CAAC,CAAC;AACpF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"powershell_exe.d.ts","sourceRoot":"","sources":["../../src/tools/powershell_exe.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,GAAG,YAAY,CAAC;IAC5B,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,2BAA2B,IAAI,oBAAoB,CAclE"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export function resolvePowerShellExecutable() {
|
|
2
|
+
const pwshPath = Bun.which("pwsh");
|
|
3
|
+
if (pwshPath) {
|
|
4
|
+
return { kind: "pwsh", path: pwshPath };
|
|
5
|
+
}
|
|
6
|
+
const winPwshPath = Bun.which("powershell.exe");
|
|
7
|
+
if (winPwshPath) {
|
|
8
|
+
return { kind: "powershell", path: winPwshPath };
|
|
9
|
+
}
|
|
10
|
+
throw new Error("PowerShell not found. Please install PowerShell (pwsh) or Windows PowerShell (powershell.exe).");
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=powershell_exe.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"powershell_exe.js","sourceRoot":"","sources":["../../src/tools/powershell_exe.ts"],"names":[],"mappings":"AAKA,MAAM,UAAU,2BAA2B;IACzC,MAAM,QAAQ,GAAG,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACnC,IAAI,QAAQ,EAAE,CAAC;QACb,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;IAC1C,CAAC;IAED,MAAM,WAAW,GAAG,GAAG,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;IAChD,IAAI,WAAW,EAAE,CAAC;QAChB,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;IACnD,CAAC;IAED,MAAM,IAAI,KAAK,CACb,gGAAgG,CACjG,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build PowerShell command argv array with security invariants.
|
|
3
|
+
*
|
|
4
|
+
* SECURITY: This function must NEVER accept or include user-supplied script text
|
|
5
|
+
* in the returned argv array. Script text must be passed via stdin to prevent
|
|
6
|
+
* command-line injection attacks.
|
|
7
|
+
*
|
|
8
|
+
* @param exePath - Path to the PowerShell executable
|
|
9
|
+
* @returns Array of command-line arguments for spawning PowerShell
|
|
10
|
+
*/
|
|
11
|
+
export declare function buildPowerShellCommand(exePath: string): string[];
|
|
12
|
+
/**
|
|
13
|
+
* Termination signal interface for coordinating timeout and abort.
|
|
14
|
+
*/
|
|
15
|
+
export interface TerminationSignal {
|
|
16
|
+
/** AbortSignal that is triggered on timeout or abort */
|
|
17
|
+
signal: AbortSignal;
|
|
18
|
+
/** Returns how the execution ended: "exit", "timeout", or "abort" */
|
|
19
|
+
getEndedBy: () => "exit" | "timeout" | "abort";
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Creates a termination signal coordinator that merges context abort and timeout.
|
|
23
|
+
*
|
|
24
|
+
* This function creates an AbortController and wires up:
|
|
25
|
+
* - Context abort listener: triggers abort when the parent context is cancelled
|
|
26
|
+
* - Timeout logic: triggers abort after timeoutMs milliseconds (disabled if 0)
|
|
27
|
+
*
|
|
28
|
+
* The `getEndedBy()` function reports how the execution ended:
|
|
29
|
+
* - "exit": Process completed normally (signal not triggered by timeout/abort)
|
|
30
|
+
* - "timeout": Timeout duration was exceeded
|
|
31
|
+
* - "abort": Explicitly cancelled via context.abort
|
|
32
|
+
*
|
|
33
|
+
* @param contextAbort - Optional AbortSignal from parent context
|
|
34
|
+
* @param timeoutMs - Timeout in milliseconds (0 disables timeout)
|
|
35
|
+
* @returns TerminationSignal with signal and endedBy tracker
|
|
36
|
+
*/
|
|
37
|
+
export declare function createTerminationSignal(contextAbort: AbortSignal | undefined, timeoutMs: number): TerminationSignal;
|
|
38
|
+
/**
|
|
39
|
+
* Options for spawning a PowerShell process with stdin transport.
|
|
40
|
+
*/
|
|
41
|
+
export interface SpawnPowerShellOptions {
|
|
42
|
+
/** Path to the PowerShell executable */
|
|
43
|
+
exePath: string;
|
|
44
|
+
/** PowerShell script text (goes to stdin, NOT argv) */
|
|
45
|
+
command: string;
|
|
46
|
+
/** Working directory for the spawned process */
|
|
47
|
+
cwd: string;
|
|
48
|
+
/** Optional AbortSignal for cancellation */
|
|
49
|
+
signal?: AbortSignal;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Spawn a PowerShell process with script text passed via stdin.
|
|
53
|
+
*
|
|
54
|
+
* SECURITY: The command text is NEVER included in argv - it is always
|
|
55
|
+
* passed via stdin to prevent command-line injection attacks.
|
|
56
|
+
*
|
|
57
|
+
* @param options - Spawn options including exePath, command, cwd, and signal
|
|
58
|
+
* @returns Subprocess handle with piped stdout/stderr
|
|
59
|
+
*/
|
|
60
|
+
export declare function spawnPowerShell(options: SpawnPowerShellOptions): Bun.Subprocess<NodeJS.NonSharedUint8Array, "pipe", "pipe">;
|
|
61
|
+
/**
|
|
62
|
+
* Terminate a process and its entire process tree.
|
|
63
|
+
*
|
|
64
|
+
* On Windows, uses `taskkill /T` to terminate the process tree.
|
|
65
|
+
* On Unix-like systems, uses `kill -9 -pid` (negative PID kills process group).
|
|
66
|
+
*
|
|
67
|
+
* @param pid - Process ID to terminate
|
|
68
|
+
* @returns Promise that resolves when the termination command completes
|
|
69
|
+
*/
|
|
70
|
+
export declare function terminateProcessTree(pid: number): Promise<void>;
|
|
71
|
+
//# sourceMappingURL=process.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"process.d.ts","sourceRoot":"","sources":["../../src/tools/process.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAEhE;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,wDAAwD;IACxD,MAAM,EAAE,WAAW,CAAC;IACpB,qEAAqE;IACrE,UAAU,EAAE,MAAM,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC;CAChD;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,uBAAuB,CACrC,YAAY,EAAE,WAAW,GAAG,SAAS,EACrC,SAAS,EAAE,MAAM,GAChB,iBAAiB,CA4CnB;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,wCAAwC;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,uDAAuD;IACvD,OAAO,EAAE,MAAM,CAAC;IAChB,gDAAgD;IAChD,GAAG,EAAE,MAAM,CAAC;IACZ,4CAA4C;IAC5C,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,sBAAsB,8DAa9D;AAED;;;;;;;;GAQG;AACH,wBAAsB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAmBrE"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build PowerShell command argv array with security invariants.
|
|
3
|
+
*
|
|
4
|
+
* SECURITY: This function must NEVER accept or include user-supplied script text
|
|
5
|
+
* in the returned argv array. Script text must be passed via stdin to prevent
|
|
6
|
+
* command-line injection attacks.
|
|
7
|
+
*
|
|
8
|
+
* @param exePath - Path to the PowerShell executable
|
|
9
|
+
* @returns Array of command-line arguments for spawning PowerShell
|
|
10
|
+
*/
|
|
11
|
+
export function buildPowerShellCommand(exePath) {
|
|
12
|
+
return [exePath, "-NoProfile", "-NonInteractive", "-Command", "-"];
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Creates a termination signal coordinator that merges context abort and timeout.
|
|
16
|
+
*
|
|
17
|
+
* This function creates an AbortController and wires up:
|
|
18
|
+
* - Context abort listener: triggers abort when the parent context is cancelled
|
|
19
|
+
* - Timeout logic: triggers abort after timeoutMs milliseconds (disabled if 0)
|
|
20
|
+
*
|
|
21
|
+
* The `getEndedBy()` function reports how the execution ended:
|
|
22
|
+
* - "exit": Process completed normally (signal not triggered by timeout/abort)
|
|
23
|
+
* - "timeout": Timeout duration was exceeded
|
|
24
|
+
* - "abort": Explicitly cancelled via context.abort
|
|
25
|
+
*
|
|
26
|
+
* @param contextAbort - Optional AbortSignal from parent context
|
|
27
|
+
* @param timeoutMs - Timeout in milliseconds (0 disables timeout)
|
|
28
|
+
* @returns TerminationSignal with signal and endedBy tracker
|
|
29
|
+
*/
|
|
30
|
+
export function createTerminationSignal(contextAbort, timeoutMs) {
|
|
31
|
+
// Check if already aborted - if so, return immediately with abort status
|
|
32
|
+
if (contextAbort?.aborted) {
|
|
33
|
+
return {
|
|
34
|
+
signal: contextAbort,
|
|
35
|
+
getEndedBy: () => "abort",
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
const controller = new AbortController();
|
|
39
|
+
let endedBy = "exit";
|
|
40
|
+
// Handle context abort - triggered immediately when parent context cancels
|
|
41
|
+
if (contextAbort) {
|
|
42
|
+
contextAbort.addEventListener("abort", () => {
|
|
43
|
+
// Only set if not already decided (first-cause wins)
|
|
44
|
+
if (endedBy === "exit") {
|
|
45
|
+
endedBy = "abort";
|
|
46
|
+
controller.abort();
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
// Handle timeout - only set up if timeoutMs > 0
|
|
51
|
+
let timeoutId;
|
|
52
|
+
if (timeoutMs > 0) {
|
|
53
|
+
timeoutId = setTimeout(() => {
|
|
54
|
+
// Only set if not already decided (first-cause wins)
|
|
55
|
+
if (endedBy === "exit") {
|
|
56
|
+
endedBy = "timeout";
|
|
57
|
+
controller.abort();
|
|
58
|
+
}
|
|
59
|
+
}, timeoutMs);
|
|
60
|
+
}
|
|
61
|
+
// Clean up timeout when signal is aborted (prevents memory leaks)
|
|
62
|
+
controller.signal.addEventListener("abort", () => {
|
|
63
|
+
if (timeoutId)
|
|
64
|
+
clearTimeout(timeoutId);
|
|
65
|
+
});
|
|
66
|
+
return {
|
|
67
|
+
signal: controller.signal,
|
|
68
|
+
getEndedBy: () => endedBy,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Spawn a PowerShell process with script text passed via stdin.
|
|
73
|
+
*
|
|
74
|
+
* SECURITY: The command text is NEVER included in argv - it is always
|
|
75
|
+
* passed via stdin to prevent command-line injection attacks.
|
|
76
|
+
*
|
|
77
|
+
* @param options - Spawn options including exePath, command, cwd, and signal
|
|
78
|
+
* @returns Subprocess handle with piped stdout/stderr
|
|
79
|
+
*/
|
|
80
|
+
export function spawnPowerShell(options) {
|
|
81
|
+
const cmd = buildPowerShellCommand(options.exePath);
|
|
82
|
+
const stdin = new TextEncoder().encode(options.command);
|
|
83
|
+
return Bun.spawn({
|
|
84
|
+
cmd,
|
|
85
|
+
stdin,
|
|
86
|
+
cwd: options.cwd,
|
|
87
|
+
stdout: "pipe",
|
|
88
|
+
stderr: "pipe",
|
|
89
|
+
signal: options.signal,
|
|
90
|
+
windowsHide: true,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Terminate a process and its entire process tree.
|
|
95
|
+
*
|
|
96
|
+
* On Windows, uses `taskkill /T` to terminate the process tree.
|
|
97
|
+
* On Unix-like systems, uses `kill -9 -pid` (negative PID kills process group).
|
|
98
|
+
*
|
|
99
|
+
* @param pid - Process ID to terminate
|
|
100
|
+
* @returns Promise that resolves when the termination command completes
|
|
101
|
+
*/
|
|
102
|
+
export async function terminateProcessTree(pid) {
|
|
103
|
+
if (process.platform === "win32") {
|
|
104
|
+
// Windows: taskkill /T kills the process tree
|
|
105
|
+
const proc = Bun.spawn([
|
|
106
|
+
"taskkill",
|
|
107
|
+
"/PID",
|
|
108
|
+
String(pid),
|
|
109
|
+
"/T", // Terminate process tree
|
|
110
|
+
"/F", // Force
|
|
111
|
+
]);
|
|
112
|
+
await proc.exited;
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
// Unix: kill negative PID kills process group
|
|
116
|
+
try {
|
|
117
|
+
process.kill(-pid, "SIGKILL");
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
// Process may already be dead
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=process.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"process.js","sourceRoot":"","sources":["../../src/tools/process.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,UAAU,sBAAsB,CAAC,OAAe;IACpD,OAAO,CAAC,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,UAAU,EAAE,GAAG,CAAC,CAAC;AACrE,CAAC;AAYD;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,uBAAuB,CACrC,YAAqC,EACrC,SAAiB;IAEjB,yEAAyE;IACzE,IAAI,YAAY,EAAE,OAAO,EAAE,CAAC;QAC1B,OAAO;YACL,MAAM,EAAE,YAAY;YACpB,UAAU,EAAE,GAAG,EAAE,CAAC,OAAO;SAC1B,CAAC;IACJ,CAAC;IAED,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,IAAI,OAAO,GAAiC,MAAM,CAAC;IAEnD,2EAA2E;IAC3E,IAAI,YAAY,EAAE,CAAC;QACjB,YAAY,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE;YAC1C,qDAAqD;YACrD,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;gBACvB,OAAO,GAAG,OAAO,CAAC;gBAClB,UAAU,CAAC,KAAK,EAAE,CAAC;YACrB,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED,gDAAgD;IAChD,IAAI,SAA4B,CAAC;IACjC,IAAI,SAAS,GAAG,CAAC,EAAE,CAAC;QAClB,SAAS,GAAG,UAAU,CAAC,GAAG,EAAE;YAC1B,qDAAqD;YACrD,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;gBACvB,OAAO,GAAG,SAAS,CAAC;gBACpB,UAAU,CAAC,KAAK,EAAE,CAAC;YACrB,CAAC;QACH,CAAC,EAAE,SAAS,CAAC,CAAC;IAChB,CAAC;IAED,kEAAkE;IAClE,UAAU,CAAC,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE;QAC/C,IAAI,SAAS;YAAE,YAAY,CAAC,SAAS,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;IAEH,OAAO;QACL,MAAM,EAAE,UAAU,CAAC,MAAM;QACzB,UAAU,EAAE,GAAG,EAAE,CAAC,OAAO;KAC1B,CAAC;AACJ,CAAC;AAgBD;;;;;;;;GAQG;AACH,MAAM,UAAU,eAAe,CAAC,OAA+B;IAC7D,MAAM,GAAG,GAAG,sBAAsB,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACpD,MAAM,KAAK,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAExD,OAAO,GAAG,CAAC,KAAK,CAAC;QACf,GAAG;QACH,KAAK;QACL,GAAG,EAAE,OAAO,CAAC,GAAG;QAChB,MAAM,EAAE,MAAM;QACd,MAAM,EAAE,MAAM;QACd,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,WAAW,EAAE,IAAI;KAClB,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,GAAW;IACpD,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACjC,8CAA8C;QAC9C,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC;YACrB,UAAU;YACV,MAAM;YACN,MAAM,CAAC,GAAG,CAAC;YACX,IAAI,EAAG,yBAAyB;YAChC,IAAI,EAAG,QAAQ;SAChB,CAAC,CAAC;QACH,MAAM,IAAI,CAAC,MAAM,CAAC;IACpB,CAAC;SAAM,CAAC;QACN,8CAA8C;QAC9C,IAAI,CAAC;YACH,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;QAChC,CAAC;QAAC,MAAM,CAAC;YACP,8BAA8B;QAChC,CAAC;IACH,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { ToolContext } from "@opencode-ai/plugin/tool";
|
|
2
|
+
/**
|
|
3
|
+
* Asks for external_directory permission if the resolved workdir is outside the allowed boundary.
|
|
4
|
+
*
|
|
5
|
+
* Rules:
|
|
6
|
+
* 1. Build allowed roots from context
|
|
7
|
+
* 2. Check if resolvedWorkdir is within boundary
|
|
8
|
+
* 3. If outside: call context.ask() with permission "external_directory" and glob pattern
|
|
9
|
+
* 4. If inside: return without asking (no-op)
|
|
10
|
+
*
|
|
11
|
+
* @param context - The tool execution context
|
|
12
|
+
* @param resolvedWorkdir - The absolute, normalized workdir path
|
|
13
|
+
*/
|
|
14
|
+
export declare function askExternalDirectoryIfRequired(context: ToolContext, resolvedWorkdir: string): Promise<void>;
|
|
15
|
+
/**
|
|
16
|
+
* Resolves a workdir argument to an absolute path.
|
|
17
|
+
*
|
|
18
|
+
* Rules:
|
|
19
|
+
* 1. If workdirArg is omitted, uses '.' semantics (resolves to contextDirectory)
|
|
20
|
+
* 2. If workdirArg is absolute, returns it normalized
|
|
21
|
+
* 3. If workdirArg is relative, resolves it against contextDirectory
|
|
22
|
+
*
|
|
23
|
+
* @param contextDirectory - The base directory from context
|
|
24
|
+
* @param workdirArg - Optional workdir argument (can be relative, absolute, or omitted)
|
|
25
|
+
* @returns The absolute, normalized path
|
|
26
|
+
*/
|
|
27
|
+
export declare function resolveWorkdir(contextDirectory: string, workdirArg?: string): string;
|
|
28
|
+
/**
|
|
29
|
+
* Checks if a resolved path is within the allowed boundary roots.
|
|
30
|
+
*
|
|
31
|
+
* A path is considered "within boundary" if:
|
|
32
|
+
* - It exactly matches an allowed root
|
|
33
|
+
* - It starts with an allowed root path + path separator
|
|
34
|
+
* - The root is "/" (Unix root allows all paths)
|
|
35
|
+
*
|
|
36
|
+
* @param resolvedPath - The absolute, normalized path to check
|
|
37
|
+
* @param allowedRoots - Array of allowed root paths (should be absolute and normalized)
|
|
38
|
+
* @returns true if the path is within any of the allowed roots
|
|
39
|
+
*/
|
|
40
|
+
export declare function isWithinBoundary(resolvedPath: string, allowedRoots: string[]): boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Builds the list of allowed boundary roots from the tool context.
|
|
43
|
+
*
|
|
44
|
+
* Rules:
|
|
45
|
+
* 1. Always include context.directory
|
|
46
|
+
* 2. Include context.worktree only if it's not "/"
|
|
47
|
+
*
|
|
48
|
+
* @param context - The tool context containing directory and worktree information
|
|
49
|
+
* @returns Array of allowed root paths
|
|
50
|
+
*/
|
|
51
|
+
export declare function buildAllowedRoots(context: ToolContext): string[];
|
|
52
|
+
//# sourceMappingURL=workdir.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workdir.d.ts","sourceRoot":"","sources":["../../src/tools/workdir.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAE5D;;;;;;;;;;;GAWG;AACH,wBAAsB,8BAA8B,CAClD,OAAO,EAAE,WAAW,EACpB,eAAe,EAAE,MAAM,GACtB,OAAO,CAAC,IAAI,CAAC,CAkBf;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAC5B,gBAAgB,EAAE,MAAM,EACxB,UAAU,CAAC,EAAE,MAAM,GAClB,MAAM,CAMR;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAC9B,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,MAAM,EAAE,GACrB,OAAO,CAsBT;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,EAAE,CAMhE"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
/**
|
|
3
|
+
* Asks for external_directory permission if the resolved workdir is outside the allowed boundary.
|
|
4
|
+
*
|
|
5
|
+
* Rules:
|
|
6
|
+
* 1. Build allowed roots from context
|
|
7
|
+
* 2. Check if resolvedWorkdir is within boundary
|
|
8
|
+
* 3. If outside: call context.ask() with permission "external_directory" and glob pattern
|
|
9
|
+
* 4. If inside: return without asking (no-op)
|
|
10
|
+
*
|
|
11
|
+
* @param context - The tool execution context
|
|
12
|
+
* @param resolvedWorkdir - The absolute, normalized workdir path
|
|
13
|
+
*/
|
|
14
|
+
export async function askExternalDirectoryIfRequired(context, resolvedWorkdir) {
|
|
15
|
+
const allowedRoots = buildAllowedRoots(context);
|
|
16
|
+
if (isWithinBoundary(resolvedWorkdir, allowedRoots)) {
|
|
17
|
+
// Path is within boundary, no permission needed
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
// Path is outside boundary, ask for external_directory permission
|
|
21
|
+
// Convert Windows backslashes to forward slashes for glob pattern
|
|
22
|
+
const globPattern = resolvedWorkdir.replace(/\\/g, "/") + "/**";
|
|
23
|
+
await context.ask({
|
|
24
|
+
permission: "external_directory",
|
|
25
|
+
patterns: [globPattern],
|
|
26
|
+
always: [globPattern],
|
|
27
|
+
metadata: {},
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Resolves a workdir argument to an absolute path.
|
|
32
|
+
*
|
|
33
|
+
* Rules:
|
|
34
|
+
* 1. If workdirArg is omitted, uses '.' semantics (resolves to contextDirectory)
|
|
35
|
+
* 2. If workdirArg is absolute, returns it normalized
|
|
36
|
+
* 3. If workdirArg is relative, resolves it against contextDirectory
|
|
37
|
+
*
|
|
38
|
+
* @param contextDirectory - The base directory from context
|
|
39
|
+
* @param workdirArg - Optional workdir argument (can be relative, absolute, or omitted)
|
|
40
|
+
* @returns The absolute, normalized path
|
|
41
|
+
*/
|
|
42
|
+
export function resolveWorkdir(contextDirectory, workdirArg) {
|
|
43
|
+
const rawWorkdir = workdirArg ?? ".";
|
|
44
|
+
if (path.isAbsolute(rawWorkdir)) {
|
|
45
|
+
return path.normalize(rawWorkdir);
|
|
46
|
+
}
|
|
47
|
+
return path.resolve(contextDirectory, rawWorkdir);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Checks if a resolved path is within the allowed boundary roots.
|
|
51
|
+
*
|
|
52
|
+
* A path is considered "within boundary" if:
|
|
53
|
+
* - It exactly matches an allowed root
|
|
54
|
+
* - It starts with an allowed root path + path separator
|
|
55
|
+
* - The root is "/" (Unix root allows all paths)
|
|
56
|
+
*
|
|
57
|
+
* @param resolvedPath - The absolute, normalized path to check
|
|
58
|
+
* @param allowedRoots - Array of allowed root paths (should be absolute and normalized)
|
|
59
|
+
* @returns true if the path is within any of the allowed roots
|
|
60
|
+
*/
|
|
61
|
+
export function isWithinBoundary(resolvedPath, allowedRoots) {
|
|
62
|
+
const normalizedPath = path.normalize(resolvedPath);
|
|
63
|
+
return allowedRoots.some((root) => {
|
|
64
|
+
const normalizedRoot = path.normalize(root);
|
|
65
|
+
// Exact match
|
|
66
|
+
if (normalizedPath === normalizedRoot) {
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
// Root "/" allows everything on Unix
|
|
70
|
+
if (normalizedRoot === "/") {
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
// Ensure root has trailing separator for proper prefix check
|
|
74
|
+
const rootWithSep = normalizedRoot.endsWith(path.sep)
|
|
75
|
+
? normalizedRoot
|
|
76
|
+
: normalizedRoot + path.sep;
|
|
77
|
+
return normalizedPath.startsWith(rootWithSep);
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Builds the list of allowed boundary roots from the tool context.
|
|
82
|
+
*
|
|
83
|
+
* Rules:
|
|
84
|
+
* 1. Always include context.directory
|
|
85
|
+
* 2. Include context.worktree only if it's not "/"
|
|
86
|
+
*
|
|
87
|
+
* @param context - The tool context containing directory and worktree information
|
|
88
|
+
* @returns Array of allowed root paths
|
|
89
|
+
*/
|
|
90
|
+
export function buildAllowedRoots(context) {
|
|
91
|
+
const roots = [context.directory];
|
|
92
|
+
if (context.worktree && context.worktree !== "/") {
|
|
93
|
+
roots.push(context.worktree);
|
|
94
|
+
}
|
|
95
|
+
return roots;
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=workdir.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workdir.js","sourceRoot":"","sources":["../../src/tools/workdir.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AAGxB;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,8BAA8B,CAClD,OAAoB,EACpB,eAAuB;IAEvB,MAAM,YAAY,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;IAEhD,IAAI,gBAAgB,CAAC,eAAe,EAAE,YAAY,CAAC,EAAE,CAAC;QACpD,gDAAgD;QAChD,OAAO;IACT,CAAC;IAED,kEAAkE;IAClE,kEAAkE;IAClE,MAAM,WAAW,GAAG,eAAe,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,GAAG,KAAK,CAAC;IAEhE,MAAM,OAAO,CAAC,GAAG,CAAC;QAChB,UAAU,EAAE,oBAAoB;QAChC,QAAQ,EAAE,CAAC,WAAW,CAAC;QACvB,MAAM,EAAE,CAAC,WAAW,CAAC;QACrB,QAAQ,EAAE,EAAE;KACb,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,cAAc,CAC5B,gBAAwB,EACxB,UAAmB;IAEnB,MAAM,UAAU,GAAG,UAAU,IAAI,GAAG,CAAC;IACrC,IAAI,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAChC,OAAO,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;IACpC,CAAC;IACD,OAAO,IAAI,CAAC,OAAO,CAAC,gBAAgB,EAAE,UAAU,CAAC,CAAC;AACpD,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,gBAAgB,CAC9B,YAAoB,EACpB,YAAsB;IAEtB,MAAM,cAAc,GAAG,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;IACpD,OAAO,YAAY,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE;QAChC,MAAM,cAAc,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAE5C,cAAc;QACd,IAAI,cAAc,KAAK,cAAc,EAAE,CAAC;YACtC,OAAO,IAAI,CAAC;QACd,CAAC;QAED,qCAAqC;QACrC,IAAI,cAAc,KAAK,GAAG,EAAE,CAAC;YAC3B,OAAO,IAAI,CAAC;QACd,CAAC;QAED,6DAA6D;QAC7D,MAAM,WAAW,GAAG,cAAc,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC;YACnD,CAAC,CAAC,cAAc;YAChB,CAAC,CAAC,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC;QAE9B,OAAO,cAAc,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAAoB;IACpD,MAAM,KAAK,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAClC,IAAI,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,QAAQ,KAAK,GAAG,EAAE,CAAC;QACjD,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC/B,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ordis_co_th/execute-powershell",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"packageManager": "bun@1.3.9",
|
|
6
|
+
"files": [
|
|
7
|
+
"dist/",
|
|
8
|
+
"README.md",
|
|
9
|
+
"LICENSE"
|
|
10
|
+
],
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"import": "./dist/index.js",
|
|
14
|
+
"types": "./dist/index.d.ts"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@opencode-ai/plugin": "1.2.10",
|
|
19
|
+
"zod": "4.3.6"
|
|
20
|
+
},
|
|
21
|
+
"overrides": {
|
|
22
|
+
"zod": "4.3.6"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@types/bun": "1.3.9",
|
|
26
|
+
"js-yaml": "^4.1.0",
|
|
27
|
+
"typescript": "5.9.3"
|
|
28
|
+
},
|
|
29
|
+
"scripts": {
|
|
30
|
+
"test": "bun test",
|
|
31
|
+
"build": "tsc",
|
|
32
|
+
"package:check": "bun run bin/package-check.ts"
|
|
33
|
+
}
|
|
34
|
+
}
|