dev3000 0.0.171 → 0.0.174

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -1,118 +1,196 @@
1
1
  #!/usr/bin/env bun
2
- // Intercept agent-browser command early, before Commander parses args.
3
- // This allows passing all args directly to agent-browser without Commander interference.
4
- const agentBrowserIndex = process.argv.indexOf("agent-browser");
5
- if (agentBrowserIndex >= 0 && (process.argv[1]?.includes("d3k") || process.argv[1]?.includes("dev3000"))) {
6
- const args = process.argv.slice(agentBrowserIndex + 1);
7
- // Intercept "errors" and "console" subcommands - redirect to d3k's superior commands
8
- // These d3k commands show BOTH browser AND server logs, unlike agent-browser which only shows browser
9
- const subcommandIndex = args.findIndex((arg) => !arg.startsWith("-") && !arg.startsWith("@") && arg !== "9222");
10
- const subcommand = subcommandIndex >= 0 ? args[subcommandIndex] : null;
11
- if (subcommand === "errors") {
12
- console.log("\x1b[33mšŸ’” Tip: Using `d3k errors` instead (shows browser + server errors)\x1b[0m\n");
13
- const d3kBin = process.argv[1];
14
- const result = spawnSync(d3kBin, ["errors"], { stdio: "inherit", shell: false });
15
- process.exit(result.status ?? 0);
16
- }
17
- if (subcommand === "console") {
18
- console.log("\x1b[33mšŸ’” Tip: Using `d3k logs` instead (shows browser + server logs)\x1b[0m\n");
19
- const d3kBin = process.argv[1];
20
- const result = spawnSync(d3kBin, ["logs", "--type", "browser"], { stdio: "inherit", shell: false });
21
- process.exit(result.status ?? 0);
22
- }
23
- // Find agent-browser native binary directly (avoids shell wrapper that needs node)
24
- function findAgentBrowser() {
25
- const os = process.platform === "darwin" ? "darwin" : process.platform === "win32" ? "win32" : "linux";
26
- const arch = process.arch === "arm64" ? "arm64" : "x64";
27
- const nativeName = `agent-browser-${os}-${arch}`;
28
- const platformPkg = `${os}-${arch}`;
29
- const cwd = process.cwd();
30
- const home = homedir();
31
- const getRunnablePath = (searchPath) => {
32
- if (!existsSync(searchPath)) {
33
- return null;
34
- }
35
- if (process.platform === "win32") {
36
- return searchPath;
37
- }
38
- try {
39
- accessSync(searchPath, constants.X_OK);
40
- return searchPath;
41
- }
42
- catch {
43
- try {
44
- chmodSync(searchPath, 0o755);
45
- accessSync(searchPath, constants.X_OK);
46
- return searchPath;
47
- }
48
- catch {
49
- return null;
50
- }
51
- }
52
- };
53
- // Prefer native binary to avoid shell wrapper needing node in PATH
54
- const searchPaths = [
55
- // Bun global install paths (native binary) - use homedir since compiled binary has virtual path
56
- join(home, ".bun", "install", "global", "node_modules", "@d3k", platformPkg, "node_modules", ".bin", nativeName),
57
- join(home, ".bun", "install", "global", "node_modules", "agent-browser", "bin", nativeName),
58
- // Bun global dev3000 dependency path
59
- join(home, ".bun", "install", "global", "node_modules", "dev3000", "node_modules", ".bin", nativeName),
60
- // Local development paths (native binary)
61
- join(cwd, "node_modules", ".bin", nativeName),
62
- join(cwd, "node_modules", "agent-browser", "bin", nativeName),
63
- // Fallback to wrapper script (needs node in PATH)
64
- join(home, ".bun", "install", "global", "node_modules", "@d3k", platformPkg, "node_modules", ".bin", "agent-browser"),
65
- join(home, ".bun", "install", "global", "node_modules", "dev3000", "node_modules", ".bin", "agent-browser"),
66
- join(home, ".bun", "install", "global", "node_modules", ".bin", "agent-browser"),
67
- join(home, ".bun", "install", "global", "node_modules", "agent-browser", "bin", "agent-browser.js"),
68
- join(cwd, "node_modules", ".bin", "agent-browser"),
69
- join(cwd, "node_modules", "agent-browser", "bin", "agent-browser.js")
70
- ];
71
- // npm/pnpm/yarn global install locations (best-effort)
72
- const globalNodeModules = [
73
- join("/usr", "local", "lib", "node_modules"),
74
- join("/opt", "homebrew", "lib", "node_modules")
75
- ];
76
- for (const root of globalNodeModules) {
77
- searchPaths.push(join(root, "dev3000", "node_modules", ".bin", nativeName));
78
- searchPaths.push(join(root, "dev3000", "node_modules", ".bin", "agent-browser"));
79
- searchPaths.push(join(root, "agent-browser", "bin", nativeName));
80
- searchPaths.push(join(root, "agent-browser", "bin", "agent-browser.js"));
2
+ function getRunnablePath(searchPath) {
3
+ if (!existsSync(searchPath)) {
4
+ return null;
5
+ }
6
+ if (process.platform === "win32") {
7
+ return searchPath;
8
+ }
9
+ try {
10
+ accessSync(searchPath, constants.X_OK);
11
+ return searchPath;
12
+ }
13
+ catch {
14
+ try {
15
+ chmodSync(searchPath, 0o755);
16
+ accessSync(searchPath, constants.X_OK);
17
+ return searchPath;
81
18
  }
82
- for (const p of searchPaths) {
83
- const runnablePath = getRunnablePath(p);
84
- if (runnablePath)
85
- return runnablePath;
19
+ catch {
20
+ return null;
86
21
  }
87
- return "agent-browser"; // fallback to PATH
88
22
  }
89
- const binaryPath = findAgentBrowser();
90
- // Ensure PATH is set for child process (Claude Code can have empty PATH)
91
- const env = { ...process.env };
23
+ }
24
+ function ensureCommandPath(env) {
92
25
  if (!env.PATH || env.PATH === "") {
93
26
  env.PATH = "/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin";
94
27
  }
95
- // Capture output so we can show errors if command fails
96
- const result = spawnSync(binaryPath, args, {
28
+ }
29
+ function findAgentBrowser() {
30
+ const os = process.platform === "darwin" ? "darwin" : process.platform === "win32" ? "win32" : "linux";
31
+ const arch = process.arch === "arm64" ? "arm64" : "x64";
32
+ const nativeName = `agent-browser-${os}-${arch}`;
33
+ const platformPkg = `${os}-${arch}`;
34
+ const cwd = process.cwd();
35
+ const home = homedir();
36
+ const searchPaths = [
37
+ join(home, ".bun", "install", "global", "node_modules", "@d3k", platformPkg, "node_modules", ".bin", nativeName),
38
+ join(home, ".bun", "install", "global", "node_modules", "agent-browser", "bin", nativeName),
39
+ join(home, ".bun", "install", "global", "node_modules", "dev3000", "node_modules", ".bin", nativeName),
40
+ join(cwd, "node_modules", ".bin", nativeName),
41
+ join(cwd, "node_modules", "agent-browser", "bin", nativeName),
42
+ join(home, ".bun", "install", "global", "node_modules", "@d3k", platformPkg, "node_modules", ".bin", "agent-browser"),
43
+ join(home, ".bun", "install", "global", "node_modules", "dev3000", "node_modules", ".bin", "agent-browser"),
44
+ join(home, ".bun", "install", "global", "node_modules", ".bin", "agent-browser"),
45
+ join(home, ".bun", "install", "global", "node_modules", "agent-browser", "bin", "agent-browser.js"),
46
+ join(cwd, "node_modules", ".bin", "agent-browser"),
47
+ join(cwd, "node_modules", "agent-browser", "bin", "agent-browser.js")
48
+ ];
49
+ const globalNodeModules = [
50
+ join("/usr", "local", "lib", "node_modules"),
51
+ join("/opt", "homebrew", "lib", "node_modules")
52
+ ];
53
+ for (const root of globalNodeModules) {
54
+ searchPaths.push(join(root, "dev3000", "node_modules", ".bin", nativeName));
55
+ searchPaths.push(join(root, "dev3000", "node_modules", ".bin", "agent-browser"));
56
+ searchPaths.push(join(root, "agent-browser", "bin", nativeName));
57
+ searchPaths.push(join(root, "agent-browser", "bin", "agent-browser.js"));
58
+ }
59
+ for (const p of searchPaths) {
60
+ const runnablePath = getRunnablePath(p);
61
+ if (runnablePath)
62
+ return runnablePath;
63
+ }
64
+ return "agent-browser";
65
+ }
66
+ function findNextBrowserCli() {
67
+ if (process.env.NEXT_BROWSER_PATH) {
68
+ const runnablePath = getRunnablePath(process.env.NEXT_BROWSER_PATH);
69
+ if (runnablePath) {
70
+ return runnablePath;
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
+ }
93
+ }
94
+ return null;
95
+ }
96
+ function getProjectBrowserToolPreference() {
97
+ try {
98
+ const sessionFile = join(getProjectDir(), "session.json");
99
+ if (!existsSync(sessionFile)) {
100
+ return "agent-browser";
101
+ }
102
+ const sessionInfo = JSON.parse(readFileSync(sessionFile, "utf8"));
103
+ return sessionInfo.preferredBrowserTool === "next-browser" ? "next-browser" : "agent-browser";
104
+ }
105
+ catch {
106
+ return "agent-browser";
107
+ }
108
+ }
109
+ function runLocalBrowserTool(browserTool, args) {
110
+ const env = { ...process.env };
111
+ ensureCommandPath(env);
112
+ if (browserTool === "agent-browser") {
113
+ const subcommandIndex = args.findIndex((arg) => !arg.startsWith("-") && !arg.startsWith("@") && arg !== "9222");
114
+ const subcommand = subcommandIndex >= 0 ? args[subcommandIndex] : null;
115
+ if (subcommand === "errors") {
116
+ console.log("\x1b[33mšŸ’” Tip: Using `d3k errors` instead (shows browser + server errors)\x1b[0m\n");
117
+ const d3kBin = process.argv[1];
118
+ const result = spawnSync(d3kBin, ["errors"], { stdio: "inherit", shell: false });
119
+ process.exit(result.status ?? 0);
120
+ }
121
+ if (subcommand === "console") {
122
+ console.log("\x1b[33mšŸ’” Tip: Using `d3k logs` instead (shows browser + server logs)\x1b[0m\n");
123
+ const d3kBin = process.argv[1];
124
+ const result = spawnSync(d3kBin, ["logs", "--type", "browser"], { stdio: "inherit", shell: false });
125
+ process.exit(result.status ?? 0);
126
+ }
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
+ }
146
+ const nodeVersionCheck = spawnSync("node", ["-e", "process.stdout.write(process.versions.node)"], {
147
+ encoding: "utf-8",
148
+ env,
149
+ shell: false
150
+ });
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, {
97
164
  stdio: "pipe",
98
165
  shell: false,
99
166
  env
100
167
  });
101
- // Show output
102
168
  if (result.stdout?.length > 0) {
103
169
  process.stdout.write(result.stdout);
104
170
  }
105
171
  if (result.stderr?.length > 0) {
106
172
  process.stderr.write(result.stderr);
107
173
  }
108
- // If spawn failed (e.g., binary not found), show the error
109
174
  if (result.error) {
110
- console.error(`\nError spawning agent-browser: ${result.error.message}`);
111
- console.error(`Binary path: ${binaryPath}`);
175
+ console.error(`\nError spawning next-browser: ${result.error.message}`);
176
+ if (cliPath) {
177
+ console.error(`CLI path: ${cliPath}`);
178
+ }
112
179
  process.exit(1);
113
180
  }
114
181
  process.exit(result.status ?? 1);
115
182
  }
183
+ import { getBrowserCommandInvocation } from "./utils/browser-command-argv.js";
184
+ const browserCommandInvocation = getBrowserCommandInvocation(process.argv.slice(2));
185
+ if (browserCommandInvocation && (process.argv[1]?.includes("d3k") || process.argv[1]?.includes("dev3000"))) {
186
+ const { browserCommand, args } = browserCommandInvocation;
187
+ const browserTool = browserCommand === "browser"
188
+ ? getProjectBrowserToolPreference()
189
+ : browserCommand === "next-browser"
190
+ ? "next-browser"
191
+ : "agent-browser";
192
+ runLocalBrowserTool(browserTool, args);
193
+ }
116
194
  import chalk from "chalk";
117
195
  import { execSync, spawnSync } from "child_process";
118
196
  import { Command } from "commander";
@@ -128,6 +206,7 @@ import { getBundledSkillsPath, getSkill, getSkillsInfo, listAvailableSkills } fr
128
206
  import { detectAIAgent } from "./utils/agent-detection.js";
129
207
  import { getAvailableAgents, getSkillsAgentId } from "./utils/agent-selection.js";
130
208
  import { ensureD3kHomeDir } from "./utils/d3k-dir.js";
209
+ import { readProjectAgentName } from "./utils/project-metadata.js";
131
210
  import { getProjectDir, getProjectDisplayName } from "./utils/project-name.js";
132
211
  import { checkForSkillUpdates, getApplicablePackages, getSkillsPathForLocation, installSkillPackage, isPackageInstalled, updateSkills } from "./utils/skill-installer.js";
133
212
  import { DEFAULT_TMUX_CONFIG, generateSessionName, generateTmuxCommands, getTmuxInstallInstructions, isTmuxInstalled } from "./utils/tmux-helpers.js";
@@ -205,8 +284,13 @@ function buildD3kCommandWithOptions(options) {
205
284
  args.push(`--command "${options.command.replace(/"/g, '\\"')}"`);
206
285
  if (options.startupTimeout)
207
286
  args.push(`--startup-timeout ${options.startupTimeout}`);
287
+ if (options.browserNavigationTimeout) {
288
+ args.push(`--browser-navigation-timeout ${options.browserNavigationTimeout}`);
289
+ }
208
290
  if (options.profileDir)
209
291
  args.push(`--profile-dir "${options.profileDir}"`);
292
+ if (options.browserTool)
293
+ args.push(`--browser-tool ${options.browserTool}`);
210
294
  if (options.browser)
211
295
  args.push(`--browser "${options.browser}"`);
212
296
  if (options.serversOnly)
@@ -692,7 +776,9 @@ program
692
776
  .option("-s, --script <script>", "Script to run (e.g. dev, main.py) - auto-detected by project type")
693
777
  .option("-c, --command <command>", "Custom command to run (overrides auto-detection and --script)")
694
778
  .option("--startup-timeout <seconds>", "Seconds to wait for your app server to become reachable", "30")
779
+ .option("--browser-navigation-timeout <seconds>", "Seconds to wait for browser-initiated page navigation commands", "60")
695
780
  .option("--profile-dir <dir>", "Chrome profile directory")
781
+ .option("--browser-tool <tool>", "Preferred local browser CLI: 'agent-browser' (default) or 'next-browser'", "agent-browser")
696
782
  .option("--browser <path>", "Full path to browser executable (e.g. for Arc: '/Applications/Arc.app/Contents/MacOS/Arc')")
697
783
  .option("--servers-only", "Run servers only, skip browser launch")
698
784
  .option("--debug", "Enable debug logging to console (automatically disables TUI)")
@@ -721,7 +807,9 @@ program
721
807
  script: options.script,
722
808
  command: options.command,
723
809
  startupTimeout: options.startupTimeout,
810
+ browserNavigationTimeout: options.browserNavigationTimeout,
724
811
  profileDir: options.profileDir,
812
+ browserTool: options.browserTool,
725
813
  browser: browserOption,
726
814
  serversOnly: options.serversOnly,
727
815
  headless: options.headless,
@@ -749,7 +837,8 @@ program
749
837
  }
750
838
  else {
751
839
  // Always show prompt, pre-selecting the last-used option
752
- selectedAgent = await promptAgentSelection(userConfig.defaultAgent?.name);
840
+ const preferredAgentName = readProjectAgentName() || userConfig.defaultAgent?.name;
841
+ selectedAgent = await promptAgentSelection(preferredAgentName);
753
842
  didPromptAgentSelection = true;
754
843
  if (selectedAgent) {
755
844
  if (selectedAgent.name === "debug") {
@@ -880,11 +969,13 @@ program
880
969
  command: options.command,
881
970
  startupTimeout: options.startupTimeout,
882
971
  profileDir: options.profileDir,
972
+ browserTool: options.browserTool,
883
973
  browser: browserOption,
884
974
  serversOnly: options.serversOnly,
885
975
  headless: options.headless,
886
976
  dateTime: options.dateTime,
887
- pluginReactScan: options.pluginReactScan
977
+ pluginReactScan: options.pluginReactScan,
978
+ agentName: selectedAgent.name
888
979
  });
889
980
  return;
890
981
  }
@@ -922,10 +1013,16 @@ program
922
1013
  const script = options.script || projectConfig.defaultScript;
923
1014
  const userSetPort = options.port !== undefined;
924
1015
  const startupTimeoutSeconds = Number.parseInt(options.startupTimeout, 10);
1016
+ const browserNavigationTimeoutSeconds = Number.parseInt(options.browserNavigationTimeout, 10);
1017
+ const browserTool = options.browserTool === "next-browser" ? "next-browser" : "agent-browser";
925
1018
  if (Number.isNaN(startupTimeoutSeconds) || startupTimeoutSeconds <= 0) {
926
1019
  console.error(chalk.red("\nāŒ --startup-timeout must be a positive integer (seconds).\n"));
927
1020
  process.exit(1);
928
1021
  }
1022
+ if (Number.isNaN(browserNavigationTimeoutSeconds) || browserNavigationTimeoutSeconds <= 0) {
1023
+ console.error(chalk.red("\nāŒ --browser-navigation-timeout must be a positive integer (seconds).\n"));
1024
+ process.exit(1);
1025
+ }
929
1026
  // Generate server command based on custom command or project type
930
1027
  let serverCommand;
931
1028
  if (options.command) {
@@ -1007,6 +1104,7 @@ program
1007
1104
  await startDevEnvironment({
1008
1105
  ...options,
1009
1106
  browser: browserOption,
1107
+ browserTool,
1010
1108
  port,
1011
1109
  debugPort: Number.parseInt(debugPort, 10),
1012
1110
  defaultPort: projectConfig.defaultPort,
@@ -1019,11 +1117,13 @@ program
1019
1117
  serversOnly: options.serversOnly,
1020
1118
  commandName,
1021
1119
  startupTimeoutSeconds,
1120
+ browserNavigationTimeoutSeconds,
1022
1121
  tail: options.tail,
1023
1122
  tui: options.tui && !options.debug, // TUI is default unless --no-tui or --debug is specified
1024
1123
  portless: options.portless === true,
1025
1124
  dateTimeFormat: options.dateTime || "local",
1026
1125
  pluginReactScan: options.pluginReactScan || false,
1126
+ agentName: options.agentName || undefined,
1027
1127
  skillsAgentId: skillsAgentId || undefined,
1028
1128
  autoSkills: options.skills !== false ? options.autoSkills || false : false,
1029
1129
  installSkills: options.skills !== false
@@ -1114,6 +1214,14 @@ program
1114
1214
  .command("agent-browser [args...]")
1115
1215
  .description("Run the bundled agent-browser CLI (e.g., d3k agent-browser screenshot /tmp/foo.png)")
1116
1216
  .allowUnknownOption(true);
1217
+ program
1218
+ .command("next-browser [args...]")
1219
+ .description("Run the bundled next-browser CLI (e.g., d3k next-browser open http://localhost:3000)")
1220
+ .allowUnknownOption(true);
1221
+ program
1222
+ .command("browser [args...]")
1223
+ .description("Run the preferred local browser CLI for this session")
1224
+ .allowUnknownOption(true);
1117
1225
  // Skill command - get skill content for use in prompts/workflows
1118
1226
  program
1119
1227
  .command("skill [name]")
@@ -1221,6 +1329,13 @@ program
1221
1329
  const { findComponent } = await import("./commands/find-component.js");
1222
1330
  await findComponent(selector);
1223
1331
  });
1332
+ program
1333
+ .command("resume")
1334
+ .description("Resume the last supported AI agent session for this project")
1335
+ .action(async () => {
1336
+ const { resumeLastAgent } = await import("./commands/resume.js");
1337
+ await resumeLastAgent();
1338
+ });
1224
1339
  // CDP port command - get the CDP port from the session file
1225
1340
  program
1226
1341
  .command("cdp-port")