wdyt 0.1.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 +83 -0
- package/package.json +52 -0
- package/src/cli.ts +267 -0
- package/src/commands/builder.ts +85 -0
- package/src/commands/chat.ts +306 -0
- package/src/commands/init.ts +222 -0
- package/src/commands/prompt.ts +188 -0
- package/src/commands/select.ts +180 -0
- package/src/commands/windows.ts +54 -0
- package/src/state.test.ts +184 -0
- package/src/state.ts +282 -0
- package/src/types.ts +69 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 user
|
|
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,83 @@
|
|
|
1
|
+
# wdyt
|
|
2
|
+
|
|
3
|
+
Code review context builder for LLMs - get a second opinion on your code.
|
|
4
|
+
|
|
5
|
+
A CLI tool that exports code context for AI review, compatible with flowctl/flow-next.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# Run directly with bunx (recommended)
|
|
11
|
+
bunx wdyt init
|
|
12
|
+
|
|
13
|
+
# Or install globally
|
|
14
|
+
bun add -g wdyt
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Quick Start
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
# Interactive setup - creates data directory and optionally adds rp-cli alias
|
|
21
|
+
bunx wdyt init
|
|
22
|
+
|
|
23
|
+
# List windows
|
|
24
|
+
wdyt -e 'windows'
|
|
25
|
+
|
|
26
|
+
# Create a new tab in window 1
|
|
27
|
+
wdyt -w 1 -e 'builder {}'
|
|
28
|
+
|
|
29
|
+
# Add files to selection
|
|
30
|
+
wdyt -w 1 -t <tab-id> -e 'select add src/cli.ts'
|
|
31
|
+
|
|
32
|
+
# Export context for review
|
|
33
|
+
wdyt -w 1 -t <tab-id> -e 'call chat_send {"mode":"review"}'
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Commands
|
|
37
|
+
|
|
38
|
+
### Setup
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
wdyt init # Interactive setup
|
|
42
|
+
wdyt init --global # Install binary globally
|
|
43
|
+
wdyt init --rp-alias # Create rp-cli alias (for flowctl)
|
|
44
|
+
wdyt init --no-alias # Skip rp-cli alias prompt
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Expressions
|
|
48
|
+
|
|
49
|
+
| Expression | Description |
|
|
50
|
+
|------------|-------------|
|
|
51
|
+
| `windows` | List all windows |
|
|
52
|
+
| `builder {"summary":"..."}` | Create a new tab |
|
|
53
|
+
| `prompt get` | Get current prompt |
|
|
54
|
+
| `prompt export <file>` | Export prompt to file |
|
|
55
|
+
| `select get` | Get selected files |
|
|
56
|
+
| `select add "path"` | Add file to selection |
|
|
57
|
+
| `call chat_send {...}` | Export context for review |
|
|
58
|
+
|
|
59
|
+
### Flags
|
|
60
|
+
|
|
61
|
+
| Flag | Description |
|
|
62
|
+
|------|-------------|
|
|
63
|
+
| `--raw-json` | Output raw JSON |
|
|
64
|
+
| `-w <id>` | Window ID |
|
|
65
|
+
| `-t <id>` | Tab ID |
|
|
66
|
+
| `-e <expr>` | Expression to execute |
|
|
67
|
+
|
|
68
|
+
## flowctl Compatibility
|
|
69
|
+
|
|
70
|
+
This tool is compatible with [flow-next](https://github.com/gmickel/claude-marketplace) and provides the `rp-cli` interface expected by flowctl.
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
# Create the rp-cli alias during init
|
|
74
|
+
bunx wdyt init --rp-alias
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Requirements
|
|
78
|
+
|
|
79
|
+
- [Bun](https://bun.sh) runtime
|
|
80
|
+
|
|
81
|
+
## License
|
|
82
|
+
|
|
83
|
+
MIT
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "wdyt",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Code review context builder for LLMs - what do you think?",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "bewinxed",
|
|
8
|
+
"main": "src/cli.ts",
|
|
9
|
+
"bin": {
|
|
10
|
+
"wdyt": "./src/cli.ts"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"src/**/*.ts",
|
|
14
|
+
"README.md",
|
|
15
|
+
"LICENSE"
|
|
16
|
+
],
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/Bewinxed/reepoproompt.git"
|
|
20
|
+
},
|
|
21
|
+
"bugs": {
|
|
22
|
+
"url": "https://github.com/Bewinxed/reepoproompt/issues"
|
|
23
|
+
},
|
|
24
|
+
"homepage": "https://github.com/Bewinxed/reepoproompt#readme",
|
|
25
|
+
"keywords": [
|
|
26
|
+
"code-review",
|
|
27
|
+
"llm",
|
|
28
|
+
"context",
|
|
29
|
+
"ai",
|
|
30
|
+
"claude",
|
|
31
|
+
"cli",
|
|
32
|
+
"bun"
|
|
33
|
+
],
|
|
34
|
+
"engines": {
|
|
35
|
+
"node": ">=18.0.0"
|
|
36
|
+
},
|
|
37
|
+
"publishConfig": {
|
|
38
|
+
"access": "public"
|
|
39
|
+
},
|
|
40
|
+
"scripts": {
|
|
41
|
+
"dev": "bun run src/cli.ts",
|
|
42
|
+
"build": "bun build ./src/cli.ts --compile --outfile wdyt",
|
|
43
|
+
"test": "bun test",
|
|
44
|
+
"prepublishOnly": "bun test"
|
|
45
|
+
},
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"citty": "^0.1.6"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@types/bun": "^1.1.0"
|
|
51
|
+
}
|
|
52
|
+
}
|
package/src/cli.ts
ADDED
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* wdyt - Code review context builder for LLMs
|
|
4
|
+
*
|
|
5
|
+
* Get a second opinion on your code by building context for AI review.
|
|
6
|
+
* Compatible with flowctl.py (rp-cli interface).
|
|
7
|
+
*
|
|
8
|
+
* Commands:
|
|
9
|
+
* - windows: list windows
|
|
10
|
+
* - builder: create tabs
|
|
11
|
+
* - prompt get/set/export: manage prompts
|
|
12
|
+
* - select get/add: track file selection
|
|
13
|
+
* - chat_send: export context for review
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { defineCommand, runMain } from "citty";
|
|
17
|
+
import type { CLIFlags } from "./types";
|
|
18
|
+
import { windowsCommand } from "./commands/windows";
|
|
19
|
+
import { builderCommand } from "./commands/builder";
|
|
20
|
+
import {
|
|
21
|
+
promptGetCommand,
|
|
22
|
+
promptSetCommand,
|
|
23
|
+
promptExportCommand,
|
|
24
|
+
} from "./commands/prompt";
|
|
25
|
+
import { selectGetCommand, selectAddCommand } from "./commands/select";
|
|
26
|
+
import { chatSendCommand } from "./commands/chat";
|
|
27
|
+
import { initCommand, parseInitArgs } from "./commands/init";
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Parse and execute an expression
|
|
31
|
+
*/
|
|
32
|
+
async function executeExpression(
|
|
33
|
+
expression: string,
|
|
34
|
+
flags: CLIFlags
|
|
35
|
+
): Promise<{ success: boolean; data?: unknown; output?: string; error?: string }> {
|
|
36
|
+
const expr = expression.trim();
|
|
37
|
+
|
|
38
|
+
// Parse command and arguments
|
|
39
|
+
// Expressions can be: "windows", "builder {json}", "prompt get", etc.
|
|
40
|
+
const match = expr.match(/^(\w+)(?:\s+(.*))?$/);
|
|
41
|
+
if (!match) {
|
|
42
|
+
return { success: false, error: `Invalid expression: ${expression}` };
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const [, command, args] = match;
|
|
46
|
+
|
|
47
|
+
switch (command) {
|
|
48
|
+
case "windows":
|
|
49
|
+
return await windowsCommand();
|
|
50
|
+
|
|
51
|
+
case "builder":
|
|
52
|
+
if (!flags.window) {
|
|
53
|
+
return { success: false, error: "builder requires -w <window>" };
|
|
54
|
+
}
|
|
55
|
+
return await builderCommand(flags.window, args);
|
|
56
|
+
|
|
57
|
+
case "prompt": {
|
|
58
|
+
if (!flags.window || !flags.tab) {
|
|
59
|
+
return {
|
|
60
|
+
success: false,
|
|
61
|
+
error: "prompt commands require -w <window> -t <tab>",
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Parse subcommand: "get", "export <file>"
|
|
66
|
+
const promptArgs = args?.trim();
|
|
67
|
+
if (!promptArgs || promptArgs === "get") {
|
|
68
|
+
return await promptGetCommand(flags.window, flags.tab);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (promptArgs.startsWith("export ")) {
|
|
72
|
+
// Extract file path - may be quoted with shlex.quote
|
|
73
|
+
const filePath = promptArgs.slice(7).trim().replace(/^'|'$/g, "");
|
|
74
|
+
return await promptExportCommand(flags.window, flags.tab, filePath);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return { success: false, error: `Unknown prompt subcommand: ${promptArgs}` };
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
case "select": {
|
|
81
|
+
if (!flags.window || !flags.tab) {
|
|
82
|
+
return {
|
|
83
|
+
success: false,
|
|
84
|
+
error: "select commands require -w <window> -t <tab>",
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Parse subcommand: "get", "add <paths>"
|
|
89
|
+
const selectArgs = args?.trim();
|
|
90
|
+
if (!selectArgs || selectArgs === "get") {
|
|
91
|
+
return await selectGetCommand(flags.window, flags.tab);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (selectArgs.startsWith("add ")) {
|
|
95
|
+
const pathsArg = selectArgs.slice(4).trim();
|
|
96
|
+
return await selectAddCommand(flags.window, flags.tab, pathsArg);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return { success: false, error: `Unknown select subcommand: ${selectArgs}` };
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
case "call": {
|
|
103
|
+
// Handle "call prompt {json}" and "call chat_send {json}"
|
|
104
|
+
if (args?.startsWith("prompt ")) {
|
|
105
|
+
if (!flags.window || !flags.tab) {
|
|
106
|
+
return {
|
|
107
|
+
success: false,
|
|
108
|
+
error: "prompt requires -w <window> -t <tab>",
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
const payload = args.slice(7).trim();
|
|
112
|
+
return await promptSetCommand(flags.window, flags.tab, payload);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (args?.startsWith("chat_send")) {
|
|
116
|
+
if (!flags.window || !flags.tab) {
|
|
117
|
+
return {
|
|
118
|
+
success: false,
|
|
119
|
+
error: "chat_send requires -w <window> -t <tab>",
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
// Extract payload - "chat_send {json}" or "chat_send"
|
|
123
|
+
const payload = args.slice(9).trim() || "{}";
|
|
124
|
+
return await chatSendCommand(flags.window, flags.tab, payload);
|
|
125
|
+
}
|
|
126
|
+
return { success: false, error: `Unknown call: ${args}` };
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
default:
|
|
130
|
+
return { success: false, error: `Unknown command: ${command}` };
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Format output based on --raw-json flag
|
|
136
|
+
*/
|
|
137
|
+
function formatOutput(
|
|
138
|
+
result: { success: boolean; data?: unknown; output?: string; error?: string },
|
|
139
|
+
rawJson: boolean
|
|
140
|
+
): string {
|
|
141
|
+
if (rawJson) {
|
|
142
|
+
if (result.success) {
|
|
143
|
+
return JSON.stringify(result.data);
|
|
144
|
+
}
|
|
145
|
+
return JSON.stringify({ error: result.error });
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// For non-raw-json mode, prefer the output field if present
|
|
149
|
+
// This allows commands like builder to return "Tab: <uuid>" format
|
|
150
|
+
if (result.success) {
|
|
151
|
+
// Check if output is defined (not undefined), allowing empty strings
|
|
152
|
+
if (result.output !== undefined) {
|
|
153
|
+
return result.output;
|
|
154
|
+
}
|
|
155
|
+
if (typeof result.data === "object") {
|
|
156
|
+
return JSON.stringify(result.data, null, 2);
|
|
157
|
+
}
|
|
158
|
+
return String(result.data);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return `Error: ${result.error}`;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Check if init command and handle it before citty
|
|
165
|
+
const args = process.argv.slice(2);
|
|
166
|
+
if (args[0] === "init") {
|
|
167
|
+
const options = parseInitArgs(args.slice(1));
|
|
168
|
+
initCommand(options).then((result) => {
|
|
169
|
+
if (result.success) {
|
|
170
|
+
console.log(result.output);
|
|
171
|
+
process.exit(0);
|
|
172
|
+
} else {
|
|
173
|
+
console.error(result.error);
|
|
174
|
+
process.exit(1);
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
} else {
|
|
178
|
+
// Only run citty for non-init commands
|
|
179
|
+
const main = defineCommand({
|
|
180
|
+
meta: {
|
|
181
|
+
name: "wdyt",
|
|
182
|
+
version: "0.1.0",
|
|
183
|
+
description: "Code review context builder for LLMs",
|
|
184
|
+
},
|
|
185
|
+
args: {
|
|
186
|
+
"raw-json": {
|
|
187
|
+
type: "boolean",
|
|
188
|
+
description: "Output raw JSON (no formatting)",
|
|
189
|
+
default: false,
|
|
190
|
+
},
|
|
191
|
+
w: {
|
|
192
|
+
type: "string",
|
|
193
|
+
description: "Window ID",
|
|
194
|
+
},
|
|
195
|
+
t: {
|
|
196
|
+
type: "string",
|
|
197
|
+
description: "Tab ID",
|
|
198
|
+
},
|
|
199
|
+
e: {
|
|
200
|
+
type: "string",
|
|
201
|
+
description: "Expression to execute",
|
|
202
|
+
},
|
|
203
|
+
},
|
|
204
|
+
async run({ args }) {
|
|
205
|
+
// Parse and validate window ID
|
|
206
|
+
let windowId: number | undefined;
|
|
207
|
+
if (args.w) {
|
|
208
|
+
windowId = parseInt(args.w, 10);
|
|
209
|
+
if (isNaN(windowId) || windowId < 1) {
|
|
210
|
+
console.error(`Error: Invalid window ID "${args.w}". Must be a positive integer.`);
|
|
211
|
+
process.exit(1);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const flags: CLIFlags = {
|
|
216
|
+
rawJson: args["raw-json"],
|
|
217
|
+
window: windowId,
|
|
218
|
+
tab: args.t,
|
|
219
|
+
expression: args.e,
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
// If no expression, show help message
|
|
223
|
+
if (!flags.expression) {
|
|
224
|
+
console.log("wdyt - Code review context builder for LLMs");
|
|
225
|
+
console.log("");
|
|
226
|
+
console.log("Setup:");
|
|
227
|
+
console.log(" wdyt init # Interactive setup (prompts for options)");
|
|
228
|
+
console.log(" wdyt init --global # Install binary globally");
|
|
229
|
+
console.log(" wdyt init --rp-alias # Create rp-cli alias (for flowctl)");
|
|
230
|
+
console.log(" wdyt init --no-alias # Skip rp-cli alias prompt");
|
|
231
|
+
console.log("");
|
|
232
|
+
console.log("Usage:");
|
|
233
|
+
console.log(" wdyt --raw-json -e <expression>");
|
|
234
|
+
console.log(" wdyt -w <window> -e <expression>");
|
|
235
|
+
console.log(" wdyt -w <window> -t <tab> -e <expression>");
|
|
236
|
+
console.log("");
|
|
237
|
+
console.log("Expressions:");
|
|
238
|
+
console.log(" windows List all windows");
|
|
239
|
+
console.log(' builder {"summary":"..."} Create a new tab');
|
|
240
|
+
console.log(" prompt get Get current prompt");
|
|
241
|
+
console.log(" prompt export <file> Export prompt to file");
|
|
242
|
+
console.log(" select get Get selected files");
|
|
243
|
+
console.log(' select add "path" Add file to selection');
|
|
244
|
+
console.log(" call chat_send {...} Export context for review");
|
|
245
|
+
console.log("");
|
|
246
|
+
console.log("Flags:");
|
|
247
|
+
console.log(" --raw-json Output raw JSON");
|
|
248
|
+
console.log(" -w <id> Window ID");
|
|
249
|
+
console.log(" -t <id> Tab ID");
|
|
250
|
+
console.log(" -e <expr> Expression to execute");
|
|
251
|
+
process.exit(0);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// Execute expression
|
|
255
|
+
const result = await executeExpression(flags.expression, flags);
|
|
256
|
+
const output = formatOutput(result, flags.rawJson);
|
|
257
|
+
console.log(output);
|
|
258
|
+
|
|
259
|
+
// Exit with code 1 on error
|
|
260
|
+
if (!result.success) {
|
|
261
|
+
process.exit(1);
|
|
262
|
+
}
|
|
263
|
+
},
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
runMain(main);
|
|
267
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builder command - create a new tab
|
|
3
|
+
*
|
|
4
|
+
* Parses JSON arg: {summary: string}
|
|
5
|
+
* Returns: Tab: <uuid>
|
|
6
|
+
* Compatible with flowctl.py parsing at line 255-259:
|
|
7
|
+
* match = re.search(r"Tab:\s*([A-Za-z0-9-]+)", output)
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { createTab, getWindow } from "../state";
|
|
11
|
+
import type { BuilderConfig } from "../types";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Builder command response
|
|
15
|
+
*/
|
|
16
|
+
export interface BuilderResponse {
|
|
17
|
+
tabId: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Parse builder JSON argument
|
|
22
|
+
* @param args - JSON string like {"summary": "test"}
|
|
23
|
+
* @returns Parsed BuilderConfig or null if invalid
|
|
24
|
+
*/
|
|
25
|
+
function parseBuilderArgs(args?: string): BuilderConfig | null {
|
|
26
|
+
if (!args) {
|
|
27
|
+
// Empty config is valid - just creates a blank tab
|
|
28
|
+
return {};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
try {
|
|
32
|
+
const config = JSON.parse(args.trim()) as BuilderConfig;
|
|
33
|
+
return config;
|
|
34
|
+
} catch {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Execute the builder command
|
|
41
|
+
* Creates a new tab in the specified window
|
|
42
|
+
*
|
|
43
|
+
* @param windowId - The window ID to create the tab in
|
|
44
|
+
* @param args - JSON string with optional summary, path, name
|
|
45
|
+
* @returns Tab: <uuid> on success
|
|
46
|
+
*/
|
|
47
|
+
export async function builderCommand(
|
|
48
|
+
windowId: number,
|
|
49
|
+
args?: string
|
|
50
|
+
): Promise<{
|
|
51
|
+
success: boolean;
|
|
52
|
+
data?: BuilderResponse;
|
|
53
|
+
output?: string;
|
|
54
|
+
error?: string;
|
|
55
|
+
}> {
|
|
56
|
+
try {
|
|
57
|
+
// Verify window exists
|
|
58
|
+
await getWindow(windowId);
|
|
59
|
+
|
|
60
|
+
// Parse builder config (optional)
|
|
61
|
+
const config = parseBuilderArgs(args);
|
|
62
|
+
if (config === null) {
|
|
63
|
+
return {
|
|
64
|
+
success: false,
|
|
65
|
+
error: `Invalid builder config JSON: ${args}`,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Create the tab
|
|
70
|
+
const tab = await createTab(windowId);
|
|
71
|
+
|
|
72
|
+
// Return in the format flowctl.py expects: Tab: <uuid>
|
|
73
|
+
return {
|
|
74
|
+
success: true,
|
|
75
|
+
data: { tabId: tab.id },
|
|
76
|
+
output: `Tab: ${tab.id}`,
|
|
77
|
+
};
|
|
78
|
+
} catch (error) {
|
|
79
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
80
|
+
return {
|
|
81
|
+
success: false,
|
|
82
|
+
error: `Failed to create tab: ${message}`,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
}
|