dev3000 0.0.173 → 0.0.175
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.md +0 -4
- package/dist/cdp-monitor.d.ts +21 -2
- package/dist/cdp-monitor.d.ts.map +1 -1
- package/dist/cdp-monitor.js +449 -107
- package/dist/cdp-monitor.js.map +1 -1
- package/dist/cli.js +193 -216
- package/dist/cli.js.map +1 -1
- package/dist/commands/crawl.d.ts.map +1 -1
- package/dist/commands/crawl.js +4 -43
- package/dist/commands/crawl.js.map +1 -1
- package/dist/commands/errors.d.ts.map +1 -1
- package/dist/commands/errors.js +4 -53
- package/dist/commands/errors.js.map +1 -1
- package/dist/commands/fix.d.ts.map +1 -1
- package/dist/commands/fix.js +5 -74
- package/dist/commands/fix.js.map +1 -1
- package/dist/commands/logs.d.ts.map +1 -1
- package/dist/commands/logs.js +4 -53
- package/dist/commands/logs.js.map +1 -1
- package/dist/commands/resume.d.ts +11 -0
- package/dist/commands/resume.d.ts.map +1 -0
- package/dist/commands/resume.js +75 -0
- package/dist/commands/resume.js.map +1 -0
- package/dist/commands/skill-runner.d.ts +14 -0
- package/dist/commands/skill-runner.d.ts.map +1 -0
- package/dist/commands/skill-runner.js +494 -0
- package/dist/commands/skill-runner.js.map +1 -0
- package/dist/dev-environment.d.ts +26 -3
- package/dist/dev-environment.d.ts.map +1 -1
- package/dist/dev-environment.js +285 -118
- package/dist/dev-environment.js.map +1 -1
- package/dist/skills/d3k/internal-skill.md +145 -0
- package/dist/skills/index.test.ts +28 -1
- package/dist/skills/index.ts +58 -7
- package/dist/tui-interface-opentui.d.ts +2 -0
- package/dist/tui-interface-opentui.d.ts.map +1 -1
- package/dist/tui-interface-opentui.js +17 -3
- package/dist/tui-interface-opentui.js.map +1 -1
- package/dist/utils/agent-browser.d.ts.map +1 -1
- package/dist/utils/agent-browser.js +6 -3
- package/dist/utils/agent-browser.js.map +1 -1
- package/dist/utils/agent-detection.d.ts +1 -0
- package/dist/utils/agent-detection.d.ts.map +1 -1
- package/dist/utils/agent-detection.js +11 -0
- package/dist/utils/agent-detection.js.map +1 -1
- package/dist/utils/agent-selection.js +4 -4
- package/dist/utils/agent-selection.js.map +1 -1
- package/dist/utils/browser-command-argv.d.ts +1 -1
- package/dist/utils/browser-command-argv.d.ts.map +1 -1
- package/dist/utils/browser-command-argv.js +1 -1
- package/dist/utils/browser-command-argv.js.map +1 -1
- package/dist/utils/project-metadata.d.ts +4 -0
- package/dist/utils/project-metadata.d.ts.map +1 -0
- package/dist/utils/project-metadata.js +48 -0
- package/dist/utils/project-metadata.js.map +1 -0
- package/dist/utils/project-name.d.ts +2 -0
- package/dist/utils/project-name.d.ts.map +1 -1
- package/dist/utils/project-name.js +6 -0
- package/dist/utils/project-name.js.map +1 -1
- package/dist/utils/session.d.ts +14 -0
- package/dist/utils/session.d.ts.map +1 -0
- package/dist/utils/session.js +65 -0
- package/dist/utils/session.js.map +1 -0
- package/dist/utils/version-check.js +2 -2
- package/dist/utils/version-check.js.map +1 -1
- package/package.json +9 -21
- package/dist/commands/cloud-check-pr.d.ts +0 -9
- package/dist/commands/cloud-check-pr.d.ts.map +0 -1
- package/dist/commands/cloud-check-pr.js +0 -243
- package/dist/commands/cloud-check-pr.js.map +0 -1
- package/dist/commands/cloud-fix.d.ts +0 -13
- package/dist/commands/cloud-fix.d.ts.map +0 -1
- package/dist/commands/cloud-fix.js +0 -79
- package/dist/commands/cloud-fix.js.map +0 -1
- package/dist/commands/find-component.d.ts +0 -8
- package/dist/commands/find-component.d.ts.map +0 -1
- package/dist/commands/find-component.js +0 -182
- package/dist/commands/find-component.js.map +0 -1
- package/dist/skills/d3k/SKILL.md +0 -126
- package/dist/skills/index.d.ts +0 -46
- package/dist/skills/index.d.ts.map +0 -1
- package/dist/skills/index.js +0 -174
- package/dist/skills/index.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -63,108 +63,59 @@ function findAgentBrowser() {
|
|
|
63
63
|
}
|
|
64
64
|
return "agent-browser";
|
|
65
65
|
}
|
|
66
|
-
function
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
const cwd = process.cwd();
|
|
74
|
-
const home = homedir();
|
|
75
|
-
const searchPaths = [
|
|
76
|
-
join(home, ".bun", "install", "global", "node_modules", "dev3000", "node_modules", "@vercel", "next-browser", "dist", "cli.js"),
|
|
77
|
-
join(home, ".bun", "install", "global", "node_modules", "@vercel", "next-browser", "dist", "cli.js"),
|
|
78
|
-
join(cwd, "node_modules", "@vercel", "next-browser", "dist", "cli.js"),
|
|
79
|
-
join(cwd, "..", "node_modules", "@vercel", "next-browser", "dist", "cli.js")
|
|
80
|
-
];
|
|
81
|
-
const globalNodeModules = [
|
|
82
|
-
join("/usr", "local", "lib", "node_modules"),
|
|
83
|
-
join("/opt", "homebrew", "lib", "node_modules")
|
|
84
|
-
];
|
|
85
|
-
for (const root of globalNodeModules) {
|
|
86
|
-
searchPaths.push(join(root, "dev3000", "node_modules", "@vercel", "next-browser", "dist", "cli.js"));
|
|
87
|
-
searchPaths.push(join(root, "@vercel", "next-browser", "dist", "cli.js"));
|
|
88
|
-
}
|
|
89
|
-
for (const searchPath of searchPaths) {
|
|
90
|
-
if (existsSync(searchPath)) {
|
|
91
|
-
return searchPath;
|
|
92
|
-
}
|
|
66
|
+
function getSessionCdpPort() {
|
|
67
|
+
const session = findCurrentSession();
|
|
68
|
+
const cdpUrl = session?.cdpUrl;
|
|
69
|
+
if (!cdpUrl) {
|
|
70
|
+
return null;
|
|
93
71
|
}
|
|
94
|
-
return null;
|
|
95
|
-
}
|
|
96
|
-
function getProjectBrowserToolPreference() {
|
|
97
72
|
try {
|
|
98
|
-
const
|
|
99
|
-
if (
|
|
100
|
-
return
|
|
73
|
+
const parsed = new URL(cdpUrl);
|
|
74
|
+
if (/^\d+$/.test(parsed.port)) {
|
|
75
|
+
return parsed.port;
|
|
101
76
|
}
|
|
102
|
-
const sessionInfo = JSON.parse(readFileSync(sessionFile, "utf8"));
|
|
103
|
-
return sessionInfo.preferredBrowserTool === "next-browser" ? "next-browser" : "agent-browser";
|
|
104
77
|
}
|
|
105
78
|
catch {
|
|
106
|
-
|
|
79
|
+
const match = cdpUrl.match(/:(\d+)/);
|
|
80
|
+
if (match) {
|
|
81
|
+
return match[1];
|
|
82
|
+
}
|
|
107
83
|
}
|
|
84
|
+
return null;
|
|
108
85
|
}
|
|
109
|
-
function runLocalBrowserTool(
|
|
86
|
+
function runLocalBrowserTool(args) {
|
|
110
87
|
const env = { ...process.env };
|
|
111
88
|
ensureCommandPath(env);
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
89
|
+
const subcommandIndex = args.findIndex((arg) => !arg.startsWith("-") && !arg.startsWith("@") && arg !== "9222");
|
|
90
|
+
const subcommand = subcommandIndex >= 0 ? args[subcommandIndex] : null;
|
|
91
|
+
if (subcommand === "errors") {
|
|
92
|
+
console.log("\x1b[33m💡 Tip: Using `d3k errors` instead (shows browser + server errors)\x1b[0m\n");
|
|
93
|
+
const d3kBin = process.argv[1];
|
|
94
|
+
const result = spawnSync(d3kBin, ["errors"], { stdio: "inherit", shell: false });
|
|
95
|
+
process.exit(result.status ?? 0);
|
|
96
|
+
}
|
|
97
|
+
if (subcommand === "console") {
|
|
98
|
+
console.log("\x1b[33m💡 Tip: Using `d3k logs` instead (shows browser + server logs)\x1b[0m\n");
|
|
99
|
+
const d3kBin = process.argv[1];
|
|
100
|
+
const result = spawnSync(d3kBin, ["logs", "--type", "browser"], { stdio: "inherit", shell: false });
|
|
101
|
+
process.exit(result.status ?? 0);
|
|
102
|
+
}
|
|
103
|
+
const binaryPath = findAgentBrowser();
|
|
104
|
+
if (subcommand !== "connect" &&
|
|
105
|
+
subcommand !== "close" &&
|
|
106
|
+
!args.includes("--cdp") &&
|
|
107
|
+
!args.includes("--profile") &&
|
|
108
|
+
!args.includes("--profile-dir")) {
|
|
109
|
+
const cdpPort = getSessionCdpPort();
|
|
110
|
+
if (cdpPort) {
|
|
111
|
+
spawnSync(binaryPath, ["connect", cdpPort], { stdio: "pipe", env, shell: false });
|
|
126
112
|
}
|
|
127
|
-
const binaryPath = findAgentBrowser();
|
|
128
|
-
const result = spawnSync(binaryPath, args, {
|
|
129
|
-
stdio: "pipe",
|
|
130
|
-
shell: false,
|
|
131
|
-
env
|
|
132
|
-
});
|
|
133
|
-
if (result.stdout?.length > 0) {
|
|
134
|
-
process.stdout.write(result.stdout);
|
|
135
|
-
}
|
|
136
|
-
if (result.stderr?.length > 0) {
|
|
137
|
-
process.stderr.write(result.stderr);
|
|
138
|
-
}
|
|
139
|
-
if (result.error) {
|
|
140
|
-
console.error(`\nError spawning agent-browser: ${result.error.message}`);
|
|
141
|
-
console.error(`Binary path: ${binaryPath}`);
|
|
142
|
-
process.exit(1);
|
|
143
|
-
}
|
|
144
|
-
process.exit(result.status ?? 1);
|
|
145
113
|
}
|
|
146
|
-
const
|
|
147
|
-
|
|
114
|
+
const result = spawnSync(binaryPath, args, {
|
|
115
|
+
stdio: "pipe",
|
|
148
116
|
env,
|
|
149
117
|
shell: false
|
|
150
118
|
});
|
|
151
|
-
const nodeVersion = nodeVersionCheck.stdout?.trim();
|
|
152
|
-
const nodeMajor = nodeVersion ? Number.parseInt(nodeVersion.split(".")[0] || "0", 10) : 0;
|
|
153
|
-
if (nodeVersionCheck.status !== 0 || Number.isNaN(nodeMajor) || nodeMajor < 20) {
|
|
154
|
-
console.error("\nnext-browser requires a system Node.js runtime >= 20.");
|
|
155
|
-
console.error("Install Node 20+ or keep using agent-browser for local d3k sessions.");
|
|
156
|
-
process.exit(1);
|
|
157
|
-
}
|
|
158
|
-
const cliPath = findNextBrowserCli();
|
|
159
|
-
const nextBrowserHome = join(getProjectDir(), "next-browser-home");
|
|
160
|
-
mkdirSync(nextBrowserHome, { recursive: true });
|
|
161
|
-
env.HOME = nextBrowserHome;
|
|
162
|
-
env.USERPROFILE = nextBrowserHome;
|
|
163
|
-
const result = spawnSync(cliPath ? "node" : "next-browser", cliPath ? [cliPath, ...args] : args, {
|
|
164
|
-
stdio: "pipe",
|
|
165
|
-
shell: false,
|
|
166
|
-
env
|
|
167
|
-
});
|
|
168
119
|
if (result.stdout?.length > 0) {
|
|
169
120
|
process.stdout.write(result.stdout);
|
|
170
121
|
}
|
|
@@ -172,10 +123,8 @@ function runLocalBrowserTool(browserTool, args) {
|
|
|
172
123
|
process.stderr.write(result.stderr);
|
|
173
124
|
}
|
|
174
125
|
if (result.error) {
|
|
175
|
-
console.error(`\nError spawning
|
|
176
|
-
|
|
177
|
-
console.error(`CLI path: ${cliPath}`);
|
|
178
|
-
}
|
|
126
|
+
console.error(`\nError spawning agent-browser: ${result.error.message}`);
|
|
127
|
+
console.error(`Binary path: ${binaryPath}`);
|
|
179
128
|
process.exit(1);
|
|
180
129
|
}
|
|
181
130
|
process.exit(result.status ?? 1);
|
|
@@ -183,13 +132,7 @@ function runLocalBrowserTool(browserTool, args) {
|
|
|
183
132
|
import { getBrowserCommandInvocation } from "./utils/browser-command-argv.js";
|
|
184
133
|
const browserCommandInvocation = getBrowserCommandInvocation(process.argv.slice(2));
|
|
185
134
|
if (browserCommandInvocation && (process.argv[1]?.includes("d3k") || process.argv[1]?.includes("dev3000"))) {
|
|
186
|
-
|
|
187
|
-
const browserTool = browserCommand === "browser"
|
|
188
|
-
? getProjectBrowserToolPreference()
|
|
189
|
-
: browserCommand === "next-browser"
|
|
190
|
-
? "next-browser"
|
|
191
|
-
: "agent-browser";
|
|
192
|
-
runLocalBrowserTool(browserTool, args);
|
|
135
|
+
runLocalBrowserTool(browserCommandInvocation.args);
|
|
193
136
|
}
|
|
194
137
|
import chalk from "chalk";
|
|
195
138
|
import { execSync, spawnSync } from "child_process";
|
|
@@ -197,16 +140,17 @@ import { Command } from "commander";
|
|
|
197
140
|
import { accessSync, appendFileSync, chmodSync, constants, copyFileSync, existsSync, mkdirSync, readFileSync } from "fs";
|
|
198
141
|
import { homedir } from "os";
|
|
199
142
|
import { detect } from "package-manager-detector";
|
|
200
|
-
import { dirname, join } from "path";
|
|
143
|
+
import { dirname, join, resolve } from "path";
|
|
201
144
|
import { fileURLToPath } from "url";
|
|
202
|
-
import {
|
|
203
|
-
import { cloudFix } from "./commands/cloud-fix.js";
|
|
145
|
+
import { runRemoteSkillCommand, shouldUseRemoteSkillRunner } from "./commands/skill-runner.js";
|
|
204
146
|
import { createPersistentLogFile, findAvailablePort, startDevEnvironment } from "./dev-environment.js";
|
|
205
|
-
import {
|
|
147
|
+
import { getBundledD3kSkillPath, getSkill, getSkillsInfo, listAvailableSkills } from "./skills/index.js";
|
|
206
148
|
import { detectAIAgent } from "./utils/agent-detection.js";
|
|
207
149
|
import { getAvailableAgents, getSkillsAgentId } from "./utils/agent-selection.js";
|
|
208
150
|
import { ensureD3kHomeDir } from "./utils/d3k-dir.js";
|
|
151
|
+
import { readProjectAgentName } from "./utils/project-metadata.js";
|
|
209
152
|
import { getProjectDir, getProjectDisplayName } from "./utils/project-name.js";
|
|
153
|
+
import { findCurrentSession } from "./utils/session.js";
|
|
210
154
|
import { checkForSkillUpdates, getApplicablePackages, getSkillsPathForLocation, installSkillPackage, isPackageInstalled, updateSkills } from "./utils/skill-installer.js";
|
|
211
155
|
import { DEFAULT_TMUX_CONFIG, generateSessionName, generateTmuxCommands, getTmuxInstallInstructions, isTmuxInstalled } from "./utils/tmux-helpers.js";
|
|
212
156
|
import { loadUserConfig, saveUserConfig } from "./utils/user-config.js";
|
|
@@ -268,46 +212,81 @@ process.on("unhandledRejection", (reason) => {
|
|
|
268
212
|
process.exit(1);
|
|
269
213
|
}
|
|
270
214
|
});
|
|
215
|
+
function shellQuote(value) {
|
|
216
|
+
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
217
|
+
}
|
|
218
|
+
function validatePortOption(port) {
|
|
219
|
+
if (!/^\d+$/.test(port)) {
|
|
220
|
+
throw new Error("--port must be a numeric port number.");
|
|
221
|
+
}
|
|
222
|
+
const parsed = Number.parseInt(port, 10);
|
|
223
|
+
if (!Number.isInteger(parsed) || parsed < 1 || parsed > 65535) {
|
|
224
|
+
throw new Error("--port must be between 1 and 65535.");
|
|
225
|
+
}
|
|
226
|
+
return String(parsed);
|
|
227
|
+
}
|
|
228
|
+
function validatePositiveIntegerOption(name, value) {
|
|
229
|
+
if (!/^\d+$/.test(value)) {
|
|
230
|
+
throw new Error(`${name} must be a positive integer.`);
|
|
231
|
+
}
|
|
232
|
+
const parsed = Number.parseInt(value, 10);
|
|
233
|
+
if (!Number.isInteger(parsed) || parsed <= 0) {
|
|
234
|
+
throw new Error(`${name} must be a positive integer.`);
|
|
235
|
+
}
|
|
236
|
+
return String(parsed);
|
|
237
|
+
}
|
|
238
|
+
function validateScriptOption(script) {
|
|
239
|
+
if (!/^[A-Za-z0-9._:/-]+$/.test(script)) {
|
|
240
|
+
throw new Error("--script may only contain letters, numbers, dots, slashes, colons, underscores, and hyphens.");
|
|
241
|
+
}
|
|
242
|
+
return script;
|
|
243
|
+
}
|
|
244
|
+
function validateDateTimeOption(value) {
|
|
245
|
+
if (value !== "local" && value !== "utc") {
|
|
246
|
+
throw new Error("--date-time must be either 'local' or 'utc'.");
|
|
247
|
+
}
|
|
248
|
+
return value;
|
|
249
|
+
}
|
|
271
250
|
/**
|
|
272
251
|
* Build the d3k command string with forwarded options.
|
|
273
252
|
*/
|
|
274
253
|
function buildD3kCommandWithOptions(options) {
|
|
275
254
|
const d3kBase = process.argv[1].endsWith("d3k") ? "d3k" : "dev3000";
|
|
276
|
-
const args = [d3kBase];
|
|
255
|
+
const args = [shellQuote(d3kBase)];
|
|
277
256
|
// Forward options that were explicitly set
|
|
278
257
|
if (options.port)
|
|
279
|
-
args.push(
|
|
258
|
+
args.push("--port", shellQuote(options.port));
|
|
280
259
|
if (options.script)
|
|
281
|
-
args.push(
|
|
260
|
+
args.push("--script", shellQuote(options.script));
|
|
282
261
|
if (options.command)
|
|
283
|
-
args.push(
|
|
262
|
+
args.push("--command", shellQuote(options.command));
|
|
284
263
|
if (options.startupTimeout)
|
|
285
|
-
args.push(
|
|
264
|
+
args.push("--startup-timeout", shellQuote(options.startupTimeout));
|
|
265
|
+
if (options.browserNavigationTimeout) {
|
|
266
|
+
args.push("--browser-navigation-timeout", shellQuote(options.browserNavigationTimeout));
|
|
267
|
+
}
|
|
286
268
|
if (options.profileDir)
|
|
287
|
-
args.push(
|
|
269
|
+
args.push("--profile-dir", shellQuote(options.profileDir));
|
|
288
270
|
if (options.browserTool)
|
|
289
|
-
args.push(
|
|
271
|
+
args.push("--browser-tool", shellQuote(options.browserTool));
|
|
290
272
|
if (options.browser)
|
|
291
|
-
args.push(
|
|
273
|
+
args.push("--browser", shellQuote(options.browser));
|
|
292
274
|
if (options.serversOnly)
|
|
293
275
|
args.push("--servers-only");
|
|
294
276
|
if (options.headless)
|
|
295
277
|
args.push("--headless");
|
|
296
278
|
if (options.dateTime)
|
|
297
|
-
args.push(
|
|
279
|
+
args.push("--date-time", shellQuote(options.dateTime));
|
|
298
280
|
if (options.pluginReactScan)
|
|
299
281
|
args.push("--plugin-react-scan");
|
|
300
282
|
if (options.agentName)
|
|
301
|
-
args.push(
|
|
283
|
+
args.push("--agent-name", shellQuote(options.agentName));
|
|
302
284
|
return args.join(" ");
|
|
303
285
|
}
|
|
304
286
|
function ensureClaudeD3kSkill() {
|
|
305
287
|
try {
|
|
306
|
-
const
|
|
307
|
-
if (!
|
|
308
|
-
return;
|
|
309
|
-
const bundledSkillPath = join(bundledSkillsDir, "d3k", "SKILL.md");
|
|
310
|
-
if (!existsSync(bundledSkillPath))
|
|
288
|
+
const bundledSkillPath = getBundledD3kSkillPath();
|
|
289
|
+
if (!bundledSkillPath)
|
|
311
290
|
return;
|
|
312
291
|
const skillsRoot = join(process.cwd(), ".claude", "skills");
|
|
313
292
|
const skillDir = join(skillsRoot, "d3k");
|
|
@@ -772,8 +751,12 @@ program
|
|
|
772
751
|
.option("-s, --script <script>", "Script to run (e.g. dev, main.py) - auto-detected by project type")
|
|
773
752
|
.option("-c, --command <command>", "Custom command to run (overrides auto-detection and --script)")
|
|
774
753
|
.option("--startup-timeout <seconds>", "Seconds to wait for your app server to become reachable", "30")
|
|
754
|
+
.option("--browser-navigation-timeout <seconds>", "Seconds to wait for browser-initiated page navigation commands", "60")
|
|
775
755
|
.option("--profile-dir <dir>", "Chrome profile directory")
|
|
776
|
-
.option("--
|
|
756
|
+
.option("--data-dir <dir>", "Override the per-project data directory (default: ~/.d3k/<project>/). Holds session.json, logs, screenshots, and the Chrome profile.")
|
|
757
|
+
.option("--log-file <path>", "Override the consolidated log file path (default: <data-dir>/logs/<timestamp>.log)")
|
|
758
|
+
.option("--screenshots-dir <dir>", "Override the screenshots directory (default: <data-dir>/screenshots)")
|
|
759
|
+
.option("--browser-tool <tool>", "Preferred local browser CLI: 'agent-browser'", "agent-browser")
|
|
777
760
|
.option("--browser <path>", "Full path to browser executable (e.g. for Arc: '/Applications/Arc.app/Contents/MacOS/Arc')")
|
|
778
761
|
.option("--servers-only", "Run servers only, skip browser launch")
|
|
779
762
|
.option("--debug", "Enable debug logging to console (automatically disables TUI)")
|
|
@@ -789,10 +772,34 @@ program
|
|
|
789
772
|
.option("--agent-name <name>", "Selected agent name (internal)")
|
|
790
773
|
.option("--no-agent", "Skip agent selection prompt and run d3k standalone")
|
|
791
774
|
.action(async (options) => {
|
|
775
|
+
if (options.dataDir) {
|
|
776
|
+
process.env.D3K_DATA_DIR = resolve(options.dataDir);
|
|
777
|
+
}
|
|
792
778
|
const projectName = getProjectDisplayName();
|
|
793
779
|
setTerminalTitle(projectName);
|
|
780
|
+
try {
|
|
781
|
+
if (options.port) {
|
|
782
|
+
options.port = validatePortOption(options.port);
|
|
783
|
+
}
|
|
784
|
+
if (options.script) {
|
|
785
|
+
options.script = validateScriptOption(options.script);
|
|
786
|
+
}
|
|
787
|
+
options.startupTimeout = validatePositiveIntegerOption("--startup-timeout", options.startupTimeout);
|
|
788
|
+
options.browserNavigationTimeout = validatePositiveIntegerOption("--browser-navigation-timeout", options.browserNavigationTimeout);
|
|
789
|
+
if (options.browserTool && options.browserTool !== "agent-browser") {
|
|
790
|
+
throw new Error("--browser-tool must be 'agent-browser'.");
|
|
791
|
+
}
|
|
792
|
+
options.browserTool = "agent-browser";
|
|
793
|
+
options.dateTime = validateDateTimeOption(options.dateTime || "local");
|
|
794
|
+
}
|
|
795
|
+
catch (error) {
|
|
796
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
797
|
+
console.error(chalk.red(`\n❌ ${message}\n`));
|
|
798
|
+
process.exit(1);
|
|
799
|
+
}
|
|
794
800
|
// Load user config early so it can be used for --with-agent and agent selection flows
|
|
795
801
|
const userConfig = loadUserConfig();
|
|
802
|
+
const agentDetection = detectAIAgent();
|
|
796
803
|
// Apply browser default from user config if not explicitly provided via CLI
|
|
797
804
|
const browserOption = options.browser || userConfig.browser;
|
|
798
805
|
// Handle --with-agent by spawning tmux with split panes
|
|
@@ -802,6 +809,7 @@ program
|
|
|
802
809
|
script: options.script,
|
|
803
810
|
command: options.command,
|
|
804
811
|
startupTimeout: options.startupTimeout,
|
|
812
|
+
browserNavigationTimeout: options.browserNavigationTimeout,
|
|
805
813
|
profileDir: options.profileDir,
|
|
806
814
|
browserTool: options.browserTool,
|
|
807
815
|
browser: browserOption,
|
|
@@ -818,7 +826,23 @@ program
|
|
|
818
826
|
const insideTmux = !!process.env.TMUX;
|
|
819
827
|
let selectedAgent = null;
|
|
820
828
|
let didPromptAgentSelection = false;
|
|
821
|
-
let skillsAgentId = options.agentName
|
|
829
|
+
let skillsAgentId = options.agentName
|
|
830
|
+
? getSkillsAgentId(options.agentName)
|
|
831
|
+
: agentDetection.agentId || null;
|
|
832
|
+
if (agentDetection.isAgent) {
|
|
833
|
+
if (options.tui !== false) {
|
|
834
|
+
if (options.debug) {
|
|
835
|
+
console.log(`[DEBUG] AI agent detected: ${agentDetection.agentName} (${agentDetection.reason}), auto-disabling TUI`);
|
|
836
|
+
}
|
|
837
|
+
options.tui = false;
|
|
838
|
+
}
|
|
839
|
+
if (agentDetection.agentId && options.skills !== false && !options.autoSkills) {
|
|
840
|
+
if (options.debug) {
|
|
841
|
+
console.log(`[DEBUG] AI agent detected: ${agentDetection.agentName} (${agentDetection.reason}), auto-enabling project skill installs`);
|
|
842
|
+
}
|
|
843
|
+
options.autoSkills = true;
|
|
844
|
+
}
|
|
845
|
+
}
|
|
822
846
|
if (process.stdin.isTTY && options.agent !== false && options.tui !== false && !options.debug && !insideTmux) {
|
|
823
847
|
// Clear the terminal so d3k UI starts at the top of the screen
|
|
824
848
|
process.stdout.write("\x1B[2J\x1B[0f");
|
|
@@ -831,7 +855,8 @@ program
|
|
|
831
855
|
}
|
|
832
856
|
else {
|
|
833
857
|
// Always show prompt, pre-selecting the last-used option
|
|
834
|
-
|
|
858
|
+
const preferredAgentName = readProjectAgentName() || userConfig.defaultAgent?.name;
|
|
859
|
+
selectedAgent = await promptAgentSelection(preferredAgentName);
|
|
835
860
|
didPromptAgentSelection = true;
|
|
836
861
|
if (selectedAgent) {
|
|
837
862
|
if (selectedAgent.name === "debug") {
|
|
@@ -961,19 +986,21 @@ program
|
|
|
961
986
|
script: options.script,
|
|
962
987
|
command: options.command,
|
|
963
988
|
startupTimeout: options.startupTimeout,
|
|
989
|
+
browserNavigationTimeout: options.browserNavigationTimeout,
|
|
964
990
|
profileDir: options.profileDir,
|
|
965
991
|
browserTool: options.browserTool,
|
|
966
992
|
browser: browserOption,
|
|
967
993
|
serversOnly: options.serversOnly,
|
|
968
994
|
headless: options.headless,
|
|
969
995
|
dateTime: options.dateTime,
|
|
970
|
-
pluginReactScan: options.pluginReactScan
|
|
996
|
+
pluginReactScan: options.pluginReactScan,
|
|
997
|
+
agentName: selectedAgent.name
|
|
971
998
|
});
|
|
972
999
|
return;
|
|
973
1000
|
}
|
|
974
1001
|
}
|
|
975
1002
|
if (options.autoSkills && options.skills !== false && !skillsAgentId) {
|
|
976
|
-
skillsAgentId = "codex";
|
|
1003
|
+
skillsAgentId = agentDetection.agentId || "codex";
|
|
977
1004
|
}
|
|
978
1005
|
// Detect project type and configuration
|
|
979
1006
|
const projectConfig = await detectProjectType(options.debug);
|
|
@@ -991,25 +1018,21 @@ program
|
|
|
991
1018
|
console.error(chalk.yellow(` d3k --command "node server.js" -p 3000\n`));
|
|
992
1019
|
process.exit(1);
|
|
993
1020
|
}
|
|
994
|
-
// Detect if running under an AI agent and auto-disable TUI
|
|
995
|
-
const agentDetection = detectAIAgent();
|
|
996
|
-
if (agentDetection.isAgent && options.tui !== false) {
|
|
997
|
-
if (options.debug) {
|
|
998
|
-
console.log(`[DEBUG] AI agent detected: ${agentDetection.agentName} (${agentDetection.reason}), auto-disabling TUI`);
|
|
999
|
-
}
|
|
1000
|
-
// Override TUI setting to false when agent is detected
|
|
1001
|
-
options.tui = false;
|
|
1002
|
-
}
|
|
1003
1021
|
// Use defaults from project detection if not explicitly provided
|
|
1004
1022
|
const port = options.port || projectConfig.defaultPort;
|
|
1005
1023
|
const script = options.script || projectConfig.defaultScript;
|
|
1006
1024
|
const userSetPort = options.port !== undefined;
|
|
1007
1025
|
const startupTimeoutSeconds = Number.parseInt(options.startupTimeout, 10);
|
|
1008
|
-
const
|
|
1026
|
+
const browserNavigationTimeoutSeconds = Number.parseInt(options.browserNavigationTimeout, 10);
|
|
1027
|
+
const browserTool = "agent-browser";
|
|
1009
1028
|
if (Number.isNaN(startupTimeoutSeconds) || startupTimeoutSeconds <= 0) {
|
|
1010
1029
|
console.error(chalk.red("\n❌ --startup-timeout must be a positive integer (seconds).\n"));
|
|
1011
1030
|
process.exit(1);
|
|
1012
1031
|
}
|
|
1032
|
+
if (Number.isNaN(browserNavigationTimeoutSeconds) || browserNavigationTimeoutSeconds <= 0) {
|
|
1033
|
+
console.error(chalk.red("\n❌ --browser-navigation-timeout must be a positive integer (seconds).\n"));
|
|
1034
|
+
process.exit(1);
|
|
1035
|
+
}
|
|
1013
1036
|
// Generate server command based on custom command or project type
|
|
1014
1037
|
let serverCommand;
|
|
1015
1038
|
if (options.command) {
|
|
@@ -1081,7 +1104,7 @@ program
|
|
|
1081
1104
|
const commandName = executablePath.endsWith("/d3k") || executablePath.includes("/d3k") ? "d3k" : "dev3000";
|
|
1082
1105
|
try {
|
|
1083
1106
|
// Create persistent log file
|
|
1084
|
-
const logFile = createPersistentLogFile();
|
|
1107
|
+
const logFile = createPersistentLogFile(options.logFile);
|
|
1085
1108
|
// Use a per-project Chrome profile by default so concurrent d3k sessions
|
|
1086
1109
|
// don't fight over the same browser state. Honor explicit overrides.
|
|
1087
1110
|
const profileDir = options.profileDir || join(getProjectDir(), "chrome-profile");
|
|
@@ -1104,14 +1127,17 @@ program
|
|
|
1104
1127
|
serversOnly: options.serversOnly,
|
|
1105
1128
|
commandName,
|
|
1106
1129
|
startupTimeoutSeconds,
|
|
1130
|
+
browserNavigationTimeoutSeconds,
|
|
1107
1131
|
tail: options.tail,
|
|
1108
1132
|
tui: options.tui && !options.debug, // TUI is default unless --no-tui or --debug is specified
|
|
1109
1133
|
portless: options.portless === true,
|
|
1110
1134
|
dateTimeFormat: options.dateTime || "local",
|
|
1111
1135
|
pluginReactScan: options.pluginReactScan || false,
|
|
1136
|
+
agentName: options.agentName || undefined,
|
|
1112
1137
|
skillsAgentId: skillsAgentId || undefined,
|
|
1113
1138
|
autoSkills: options.skills !== false ? options.autoSkills || false : false,
|
|
1114
|
-
installSkills: options.skills !== false
|
|
1139
|
+
installSkills: options.skills !== false,
|
|
1140
|
+
screenshotsDir: options.screenshotsDir
|
|
1115
1141
|
});
|
|
1116
1142
|
}
|
|
1117
1143
|
catch (error) {
|
|
@@ -1119,41 +1145,6 @@ program
|
|
|
1119
1145
|
process.exit(1);
|
|
1120
1146
|
}
|
|
1121
1147
|
});
|
|
1122
|
-
// Cloud commands
|
|
1123
|
-
const cloud = program.command("cloud").description("Cloud-based tools using Vercel Sandbox");
|
|
1124
|
-
// Cloud fix command
|
|
1125
|
-
cloud
|
|
1126
|
-
.command("fix")
|
|
1127
|
-
.description("Start a cloud fix workflow for the current project")
|
|
1128
|
-
.option("--repo <url>", "Repository URL (e.g. https://github.com/user/repo)")
|
|
1129
|
-
.option("--branch <name>", "Git branch to test")
|
|
1130
|
-
.option("--project-dir <dir>", "Project directory within repo (e.g. 'www')")
|
|
1131
|
-
.option("--debug", "Enable debug logging")
|
|
1132
|
-
.action(async (options) => {
|
|
1133
|
-
try {
|
|
1134
|
-
await cloudFix(options);
|
|
1135
|
-
}
|
|
1136
|
-
catch (error) {
|
|
1137
|
-
console.error(chalk.red("❌ Cloud fix failed:"), error);
|
|
1138
|
-
process.exit(1);
|
|
1139
|
-
}
|
|
1140
|
-
});
|
|
1141
|
-
// Cloud check-pr command
|
|
1142
|
-
cloud
|
|
1143
|
-
.command("check-pr [pr-number]")
|
|
1144
|
-
.description("Verify a PR's changes work as expected using Vercel preview deployment")
|
|
1145
|
-
.option("--repo <url>", "Repository URL (optional, auto-detected from git)")
|
|
1146
|
-
.option("--url <preview-url>", "Preview deployment URL (optional, auto-detected from Vercel)")
|
|
1147
|
-
.option("--debug", "Enable debug logging")
|
|
1148
|
-
.action(async (prNumber, options) => {
|
|
1149
|
-
try {
|
|
1150
|
-
await cloudCheckPR({ ...options, prNumber });
|
|
1151
|
-
}
|
|
1152
|
-
catch (error) {
|
|
1153
|
-
console.error(chalk.red("❌ Cloud check-pr failed:"), error);
|
|
1154
|
-
process.exit(1);
|
|
1155
|
-
}
|
|
1156
|
-
});
|
|
1157
1148
|
// Upgrade command
|
|
1158
1149
|
program
|
|
1159
1150
|
.command("upgrade")
|
|
@@ -1199,21 +1190,37 @@ program
|
|
|
1199
1190
|
.command("agent-browser [args...]")
|
|
1200
1191
|
.description("Run the bundled agent-browser CLI (e.g., d3k agent-browser screenshot /tmp/foo.png)")
|
|
1201
1192
|
.allowUnknownOption(true);
|
|
1202
|
-
program
|
|
1203
|
-
.command("next-browser [args...]")
|
|
1204
|
-
.description("Run the bundled next-browser CLI (e.g., d3k next-browser open http://localhost:3000)")
|
|
1205
|
-
.allowUnknownOption(true);
|
|
1206
|
-
program
|
|
1207
|
-
.command("browser [args...]")
|
|
1208
|
-
.description("Run the preferred local browser CLI for this session")
|
|
1209
|
-
.allowUnknownOption(true);
|
|
1210
1193
|
// Skill command - get skill content for use in prompts/workflows
|
|
1211
1194
|
program
|
|
1212
1195
|
.command("skill [name]")
|
|
1213
1196
|
.description("Get skill content or list available skills")
|
|
1214
1197
|
.option("-l, --list", "List all available skills")
|
|
1215
1198
|
.option("-v, --verbose", "Show detailed skill information")
|
|
1216
|
-
.
|
|
1199
|
+
.option("--team <team>", "Override the inferred Vercel team slug or ID for a hosted skill run")
|
|
1200
|
+
.option("--project <project>", "Override the inferred Vercel project name or ID for a hosted skill run")
|
|
1201
|
+
.option("--branch <branch>", "Git branch or ref to scan")
|
|
1202
|
+
.option("--project-dir <dir>", "Project root directory inside the repository")
|
|
1203
|
+
.option("--base-url <url>", "dev3000 base URL")
|
|
1204
|
+
.option("--wait", "Wait for the run to finish")
|
|
1205
|
+
.option("--json", "Print machine-readable JSON")
|
|
1206
|
+
.option("--no-install", "Do not install or repair the team skill runner project before starting")
|
|
1207
|
+
.action(async (name, options) => {
|
|
1208
|
+
if (shouldUseRemoteSkillRunner(name, options)) {
|
|
1209
|
+
try {
|
|
1210
|
+
await runRemoteSkillCommand(name, options);
|
|
1211
|
+
}
|
|
1212
|
+
catch (error) {
|
|
1213
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1214
|
+
if (options.json) {
|
|
1215
|
+
console.log(JSON.stringify({ success: false, error: message }, null, 2));
|
|
1216
|
+
}
|
|
1217
|
+
else {
|
|
1218
|
+
console.error(chalk.red(`Error: ${message}`));
|
|
1219
|
+
}
|
|
1220
|
+
process.exit(1);
|
|
1221
|
+
}
|
|
1222
|
+
return;
|
|
1223
|
+
}
|
|
1217
1224
|
// List skills if --list flag or no name provided
|
|
1218
1225
|
if (options.list || !name) {
|
|
1219
1226
|
if (options.verbose) {
|
|
@@ -1306,49 +1313,19 @@ program
|
|
|
1306
1313
|
const { crawlApp } = await import("./commands/crawl.js");
|
|
1307
1314
|
await crawlApp(options);
|
|
1308
1315
|
});
|
|
1309
|
-
// Find-component command - map DOM to React source
|
|
1310
1316
|
program
|
|
1311
|
-
.command("
|
|
1312
|
-
.description("
|
|
1313
|
-
.action(async (
|
|
1314
|
-
const {
|
|
1315
|
-
await
|
|
1317
|
+
.command("resume")
|
|
1318
|
+
.description("Resume the last supported AI agent session for this project")
|
|
1319
|
+
.action(async () => {
|
|
1320
|
+
const { resumeLastAgent } = await import("./commands/resume.js");
|
|
1321
|
+
await resumeLastAgent();
|
|
1316
1322
|
});
|
|
1317
1323
|
// CDP port command - get the CDP port from the session file
|
|
1318
1324
|
program
|
|
1319
1325
|
.command("cdp-port")
|
|
1320
1326
|
.description("Output the CDP port for the current d3k session (for use in scripts)")
|
|
1321
|
-
.action(
|
|
1322
|
-
|
|
1323
|
-
const projectDir = getProjectDir();
|
|
1324
|
-
const projectName = projectDir.split("/").pop() || "unknown";
|
|
1325
|
-
// Try to find session.json in ~/.d3k/{project-name}/
|
|
1326
|
-
const entries = existsSync(sessionDir)
|
|
1327
|
-
? await import("fs").then((fs) => fs.readdirSync(sessionDir, { withFileTypes: true }))
|
|
1328
|
-
: [];
|
|
1329
|
-
for (const entry of entries) {
|
|
1330
|
-
if (entry.isDirectory() && entry.name.startsWith(projectName.substring(0, 20))) {
|
|
1331
|
-
const sessionFile = join(sessionDir, entry.name, "session.json");
|
|
1332
|
-
if (existsSync(sessionFile)) {
|
|
1333
|
-
try {
|
|
1334
|
-
const content = JSON.parse(readFileSync(sessionFile, "utf-8"));
|
|
1335
|
-
if (content.cdpUrl) {
|
|
1336
|
-
// Extract port from URL like "ws://localhost:9223/devtools/browser/..."
|
|
1337
|
-
const match = content.cdpUrl.match(/:(\d+)/);
|
|
1338
|
-
if (match) {
|
|
1339
|
-
console.log(match[1]);
|
|
1340
|
-
process.exit(0);
|
|
1341
|
-
}
|
|
1342
|
-
}
|
|
1343
|
-
}
|
|
1344
|
-
catch {
|
|
1345
|
-
// Continue searching
|
|
1346
|
-
}
|
|
1347
|
-
}
|
|
1348
|
-
}
|
|
1349
|
-
}
|
|
1350
|
-
// Default to 9222 if no session found
|
|
1351
|
-
console.log("9222");
|
|
1327
|
+
.action(() => {
|
|
1328
|
+
console.log(getSessionCdpPort() || "9222");
|
|
1352
1329
|
});
|
|
1353
1330
|
program.parse();
|
|
1354
1331
|
//# sourceMappingURL=cli.js.map
|