dev3000 0.0.153 → 0.0.155

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.
Files changed (166) hide show
  1. package/README.md +121 -103
  2. package/dist/cdp-monitor.d.ts.map +1 -1
  3. package/dist/cdp-monitor.js +2 -3
  4. package/dist/cdp-monitor.js.map +1 -1
  5. package/dist/cli.js +301 -75
  6. package/dist/cli.js.map +1 -1
  7. package/dist/commands/cloud-check-pr.d.ts +1 -0
  8. package/dist/commands/cloud-check-pr.d.ts.map +1 -1
  9. package/dist/commands/cloud-check-pr.js +18 -6
  10. package/dist/commands/cloud-check-pr.js.map +1 -1
  11. package/dist/commands/crawl.d.ts +12 -0
  12. package/dist/commands/crawl.d.ts.map +1 -0
  13. package/dist/commands/crawl.js +140 -0
  14. package/dist/commands/crawl.js.map +1 -0
  15. package/dist/commands/errors.d.ts +14 -0
  16. package/dist/commands/errors.d.ts.map +1 -0
  17. package/dist/commands/errors.js +295 -0
  18. package/dist/commands/errors.js.map +1 -0
  19. package/dist/commands/find-component.d.ts +8 -0
  20. package/dist/commands/find-component.d.ts.map +1 -0
  21. package/dist/commands/find-component.js +182 -0
  22. package/dist/commands/find-component.js.map +1 -0
  23. package/dist/commands/fix.d.ts +13 -0
  24. package/dist/commands/fix.d.ts.map +1 -0
  25. package/dist/commands/fix.js +288 -0
  26. package/dist/commands/fix.js.map +1 -0
  27. package/dist/commands/logs.d.ts +13 -0
  28. package/dist/commands/logs.d.ts.map +1 -0
  29. package/dist/commands/logs.js +195 -0
  30. package/dist/commands/logs.js.map +1 -0
  31. package/dist/commands/restart.d.ts +8 -0
  32. package/dist/commands/restart.d.ts.map +1 -0
  33. package/dist/commands/restart.js +92 -0
  34. package/dist/commands/restart.js.map +1 -0
  35. package/dist/components/PackageSelector.d.ts +12 -0
  36. package/dist/components/PackageSelector.d.ts.map +1 -0
  37. package/dist/components/PackageSelector.js +74 -0
  38. package/dist/components/PackageSelector.js.map +1 -0
  39. package/dist/dev-environment.d.ts +0 -7
  40. package/dist/dev-environment.d.ts.map +1 -1
  41. package/dist/dev-environment.js +108 -674
  42. package/dist/dev-environment.js.map +1 -1
  43. package/dist/screencast-manager.d.ts.map +1 -1
  44. package/dist/screencast-manager.js +7 -8
  45. package/dist/screencast-manager.js.map +1 -1
  46. package/dist/skills/d3k/SKILL.md +38 -27
  47. package/dist/skills/index.d.ts +10 -14
  48. package/dist/skills/index.d.ts.map +1 -1
  49. package/dist/skills/index.js +56 -75
  50. package/dist/skills/index.js.map +1 -1
  51. package/dist/skills/index.test.ts +13 -55
  52. package/dist/skills/index.ts +59 -80
  53. package/dist/src/tui-interface-impl.tsx +6 -15
  54. package/dist/tui-interface-impl.d.ts.map +1 -1
  55. package/dist/tui-interface-impl.js +4 -4
  56. package/dist/tui-interface-impl.js.map +1 -1
  57. package/dist/tui-interface-opentui.d.ts.map +1 -1
  58. package/dist/tui-interface-opentui.js +211 -80
  59. package/dist/tui-interface-opentui.js.map +1 -1
  60. package/dist/utils/agent-browser.d.ts +2 -0
  61. package/dist/utils/agent-browser.d.ts.map +1 -1
  62. package/dist/utils/agent-browser.js +46 -8
  63. package/dist/utils/agent-browser.js.map +1 -1
  64. package/dist/utils/agent-selection.d.ts.map +1 -1
  65. package/dist/utils/agent-selection.js +9 -2
  66. package/dist/utils/agent-selection.js.map +1 -1
  67. package/dist/utils/skill-installer.d.ts +55 -29
  68. package/dist/utils/skill-installer.d.ts.map +1 -1
  69. package/dist/utils/skill-installer.js +118 -229
  70. package/dist/utils/skill-installer.js.map +1 -1
  71. package/dist/utils/tmux-helpers.d.ts +1 -2
  72. package/dist/utils/tmux-helpers.d.ts.map +1 -1
  73. package/dist/utils/tmux-helpers.js +17 -18
  74. package/dist/utils/tmux-helpers.js.map +1 -1
  75. package/dist/utils/version-check.d.ts +2 -1
  76. package/dist/utils/version-check.d.ts.map +1 -1
  77. package/dist/utils/version-check.js +9 -0
  78. package/dist/utils/version-check.js.map +1 -1
  79. package/mcp-server/.next/BUILD_ID +1 -1
  80. package/mcp-server/.next/build-manifest.json +2 -2
  81. package/mcp-server/.next/fallback-build-manifest.json +2 -2
  82. package/mcp-server/.next/prerender-manifest.json +3 -3
  83. package/mcp-server/.next/server/app/_global-error/page.js +1 -1
  84. package/mcp-server/.next/server/app/_global-error/page.js.nft.json +1 -1
  85. package/mcp-server/.next/server/app/_global-error.html +2 -2
  86. package/mcp-server/.next/server/app/_global-error.rsc +1 -1
  87. package/mcp-server/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  88. package/mcp-server/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  89. package/mcp-server/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  90. package/mcp-server/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  91. package/mcp-server/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  92. package/mcp-server/.next/server/app/_not-found/page.js +1 -1
  93. package/mcp-server/.next/server/app/_not-found/page.js.nft.json +1 -1
  94. package/mcp-server/.next/server/app/_not-found.html +1 -1
  95. package/mcp-server/.next/server/app/_not-found.rsc +1 -1
  96. package/mcp-server/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  97. package/mcp-server/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  98. package/mcp-server/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  99. package/mcp-server/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  100. package/mcp-server/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  101. package/mcp-server/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  102. package/mcp-server/.next/server/app/api/screenshots/capture/route.js +2 -2
  103. package/mcp-server/.next/server/app/api/screenshots/capture/route.js.nft.json +1 -1
  104. package/mcp-server/.next/server/app/index.html +1 -1
  105. package/mcp-server/.next/server/app/index.rsc +2 -2
  106. package/mcp-server/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  107. package/mcp-server/.next/server/app/index.segments/_full.segment.rsc +2 -2
  108. package/mcp-server/.next/server/app/index.segments/_head.segment.rsc +1 -1
  109. package/mcp-server/.next/server/app/index.segments/_index.segment.rsc +1 -1
  110. package/mcp-server/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  111. package/mcp-server/.next/server/app/logs/page.js +1 -1
  112. package/mcp-server/.next/server/app/logs/page.js.nft.json +1 -1
  113. package/mcp-server/.next/server/app/mcp/route.js +4 -4
  114. package/mcp-server/.next/server/app/mcp/route.js.nft.json +1 -1
  115. package/mcp-server/.next/server/app/page.js +1 -1
  116. package/mcp-server/.next/server/app/page.js.nft.json +1 -1
  117. package/mcp-server/.next/server/app/page_client-reference-manifest.js +1 -1
  118. package/mcp-server/.next/server/app/video/[session]/page.js +1 -1
  119. package/mcp-server/.next/server/app/video/[session]/page.js.nft.json +1 -1
  120. package/mcp-server/.next/server/chunks/[root-of-the-server]__2f95edf0._.js +3 -3
  121. package/mcp-server/.next/server/chunks/[root-of-the-server]__2f95edf0._.js.map +1 -1
  122. package/mcp-server/.next/server/chunks/[root-of-the-server]__69e6dfb7._.js +3 -0
  123. package/mcp-server/.next/server/chunks/{[root-of-the-server]__444592aa._.js.map → [root-of-the-server]__69e6dfb7._.js.map} +1 -1
  124. package/mcp-server/.next/server/chunks/[root-of-the-server]__6baff21e._.js +4 -0
  125. package/mcp-server/.next/server/chunks/{[root-of-the-server]__130a5f58._.js.map → [root-of-the-server]__6baff21e._.js.map} +1 -1
  126. package/mcp-server/.next/server/chunks/[root-of-the-server]__6f790e1f._.js +1 -1
  127. package/mcp-server/.next/server/chunks/[root-of-the-server]__6f790e1f._.js.map +1 -1
  128. package/mcp-server/.next/server/chunks/[root-of-the-server]__c8cf5b23._.js +3 -0
  129. package/mcp-server/.next/server/chunks/[root-of-the-server]__e6a83e60._.js +4 -0
  130. package/mcp-server/.next/server/chunks/{[root-of-the-server]__b71c83ed._.js.map → [root-of-the-server]__e6a83e60._.js.map} +1 -1
  131. package/mcp-server/.next/server/chunks/mcp-server_app_mcp_tools_ts_faf6d7df._.js +32 -66
  132. package/mcp-server/.next/server/chunks/mcp-server_app_mcp_tools_ts_faf6d7df._.js.map +1 -1
  133. package/mcp-server/.next/server/chunks/src_utils_agent-browser_ts_cc00e0d8._.js +1 -1
  134. package/mcp-server/.next/server/chunks/src_utils_agent-browser_ts_cc00e0d8._.js.map +1 -1
  135. package/mcp-server/.next/server/chunks/src_utils_project-name_ts_1fab1dd5._.js +3 -0
  136. package/mcp-server/.next/server/chunks/src_utils_project-name_ts_1fab1dd5._.js.map +1 -0
  137. package/mcp-server/.next/server/chunks/ssr/{[root-of-the-server]__f66148e5._.js → [root-of-the-server]__b17d4048._.js} +2 -2
  138. package/mcp-server/.next/server/chunks/ssr/{[root-of-the-server]__50eb2eba._.js → [root-of-the-server]__dcf84f77._.js} +2 -2
  139. package/mcp-server/.next/server/chunks/ssr/mcp-server_app_page_tsx_9fc46577._.js +1 -1
  140. package/mcp-server/.next/server/chunks/ssr/mcp-server_app_page_tsx_9fc46577._.js.map +1 -1
  141. package/mcp-server/.next/server/pages/404.html +1 -1
  142. package/mcp-server/.next/server/pages/500.html +2 -2
  143. package/mcp-server/.next/server/server-reference-manifest.js +1 -1
  144. package/mcp-server/.next/server/server-reference-manifest.json +1 -1
  145. package/mcp-server/.next/static/chunks/{2422ea9ed874427b.js → 3f3f8e7d16ba3bf4.js} +1 -1
  146. package/mcp-server/app/api/tools/route.ts +5 -4
  147. package/mcp-server/app/mcp/route.ts +8 -63
  148. package/mcp-server/app/mcp/tools.ts +71 -445
  149. package/mcp-server/app/page.tsx +1 -1
  150. package/mcp-server/package.json +1 -0
  151. package/package.json +6 -6
  152. package/src/tui-interface-impl.tsx +6 -15
  153. package/dist/components/SkillSelector.d.ts +0 -10
  154. package/dist/components/SkillSelector.d.ts.map +0 -1
  155. package/dist/components/SkillSelector.js +0 -87
  156. package/dist/components/SkillSelector.js.map +0 -1
  157. package/mcp-server/.next/server/chunks/[root-of-the-server]__130a5f58._.js +0 -4
  158. package/mcp-server/.next/server/chunks/[root-of-the-server]__444592aa._.js +0 -3
  159. package/mcp-server/.next/server/chunks/[root-of-the-server]__8f84b4cc._.js +0 -3
  160. package/mcp-server/.next/server/chunks/[root-of-the-server]__b71c83ed._.js +0 -4
  161. /package/mcp-server/.next/server/chunks/{[root-of-the-server]__8f84b4cc._.js.map → [root-of-the-server]__c8cf5b23._.js.map} +0 -0
  162. /package/mcp-server/.next/server/chunks/ssr/{[root-of-the-server]__f66148e5._.js.map → [root-of-the-server]__b17d4048._.js.map} +0 -0
  163. /package/mcp-server/.next/server/chunks/ssr/{[root-of-the-server]__50eb2eba._.js.map → [root-of-the-server]__dcf84f77._.js.map} +0 -0
  164. /package/mcp-server/.next/static/{Mseg7iY2pocGklcPCObqM → uxzBYIUkyXehXbe9VuXKp}/_buildManifest.js +0 -0
  165. /package/mcp-server/.next/static/{Mseg7iY2pocGklcPCObqM → uxzBYIUkyXehXbe9VuXKp}/_clientMiddlewareManifest.json +0 -0
  166. /package/mcp-server/.next/static/{Mseg7iY2pocGklcPCObqM → uxzBYIUkyXehXbe9VuXKp}/_ssgManifest.js +0 -0
package/dist/cli.js CHANGED
@@ -1,7 +1,85 @@
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
+ // Use require for synchronous execution before other imports
7
+ const { spawnSync } = require("child_process");
8
+ const { existsSync } = require("fs");
9
+ const { join } = require("path");
10
+ const args = process.argv.slice(agentBrowserIndex + 1);
11
+ // Intercept "errors" and "console" subcommands - redirect to d3k's superior commands
12
+ // These d3k commands show BOTH browser AND server logs, unlike agent-browser which only shows browser
13
+ const subcommandIndex = args.findIndex((arg) => !arg.startsWith("-") && !arg.startsWith("@") && arg !== "9222");
14
+ const subcommand = subcommandIndex >= 0 ? args[subcommandIndex] : null;
15
+ if (subcommand === "errors") {
16
+ console.log("\x1b[33m💡 Tip: Using `d3k errors` instead (shows browser + server errors)\x1b[0m\n");
17
+ const d3kBin = process.argv[1];
18
+ const result = spawnSync(d3kBin, ["errors"], { stdio: "inherit", shell: false });
19
+ process.exit(result.status ?? 0);
20
+ }
21
+ if (subcommand === "console") {
22
+ console.log("\x1b[33m💡 Tip: Using `d3k logs` instead (shows browser + server logs)\x1b[0m\n");
23
+ const d3kBin = process.argv[1];
24
+ const result = spawnSync(d3kBin, ["logs", "--type", "browser"], { stdio: "inherit", shell: false });
25
+ process.exit(result.status ?? 0);
26
+ }
27
+ // Find agent-browser native binary directly (avoids shell wrapper that needs node)
28
+ function findAgentBrowser() {
29
+ const os = process.platform === "darwin" ? "darwin" : process.platform === "win32" ? "win32" : "linux";
30
+ const arch = process.arch === "arm64" ? "arm64" : "x64";
31
+ const nativeName = `agent-browser-${os}-${arch}`;
32
+ const platformPkg = `${os}-${arch}`;
33
+ const cwd = process.cwd();
34
+ const home = require("os").homedir();
35
+ // Prefer native binary to avoid shell wrapper needing node in PATH
36
+ const searchPaths = [
37
+ // Bun global install paths (native binary) - use homedir since compiled binary has virtual path
38
+ join(home, ".bun", "install", "global", "node_modules", "@d3k", platformPkg, "mcp-server", "node_modules", ".bin", nativeName),
39
+ // Local development paths (native binary)
40
+ join(cwd, "mcp-server", "node_modules", ".bin", nativeName),
41
+ join(cwd, "node_modules", ".bin", nativeName),
42
+ // Fallback to wrapper script (needs node in PATH)
43
+ join(home, ".bun", "install", "global", "node_modules", "@d3k", platformPkg, "mcp-server", "node_modules", ".bin", "agent-browser"),
44
+ join(cwd, "mcp-server", "node_modules", ".bin", "agent-browser"),
45
+ join(cwd, "node_modules", ".bin", "agent-browser")
46
+ ];
47
+ for (const p of searchPaths) {
48
+ if (existsSync(p))
49
+ return p;
50
+ }
51
+ return "agent-browser"; // fallback to PATH
52
+ }
53
+ const binaryPath = findAgentBrowser();
54
+ // Ensure PATH is set for child process (Claude Code can have empty PATH)
55
+ const env = { ...process.env };
56
+ if (!env.PATH || env.PATH === "") {
57
+ env.PATH = "/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin";
58
+ }
59
+ // Capture output so we can show errors if command fails
60
+ const result = spawnSync(binaryPath, args, {
61
+ stdio: "pipe",
62
+ shell: false,
63
+ env
64
+ });
65
+ // Show output
66
+ if (result.stdout?.length > 0) {
67
+ process.stdout.write(result.stdout);
68
+ }
69
+ if (result.stderr?.length > 0) {
70
+ process.stderr.write(result.stderr);
71
+ }
72
+ // If spawn failed (e.g., binary not found), show the error
73
+ if (result.error) {
74
+ console.error(`\nError spawning agent-browser: ${result.error.message}`);
75
+ console.error(`Binary path: ${binaryPath}`);
76
+ process.exit(1);
77
+ }
78
+ process.exit(result.status ?? 1);
79
+ }
2
80
  import chalk from "chalk";
3
81
  import { Command } from "commander";
4
- import { existsSync, readFileSync } from "fs";
82
+ import { appendFileSync, existsSync, mkdirSync, readFileSync } from "fs";
5
83
  import { homedir, tmpdir } from "os";
6
84
  import { detect } from "package-manager-detector";
7
85
  import { dirname, join } from "path";
@@ -14,10 +92,38 @@ import { detectAIAgent } from "./utils/agent-detection.js";
14
92
  import { getAvailableAgents } from "./utils/agent-selection.js";
15
93
  import { formatMcpConfigTargets, parseDisabledMcpConfigs } from "./utils/mcp-configs.js";
16
94
  import { getProjectDir } from "./utils/project-name.js";
17
- import { checkForNewSkills, detectsReact, installSelectedSkills, markSkillsAsSeen } from "./utils/skill-installer.js";
95
+ import { checkForSkillUpdates, getApplicablePackages, installSkillPackage, isPackageInstalled, updateSkills } from "./utils/skill-installer.js";
18
96
  import { DEFAULT_TMUX_CONFIG, generateSessionName, generateTmuxCommands, getTmuxInstallInstructions, isTmuxInstalled } from "./utils/tmux-helpers.js";
19
97
  import { loadUserConfig, saveUserConfig } from "./utils/user-config.js";
20
98
  import { checkForUpdates, getUpgradeCommand, performUpgrade } from "./utils/version-check.js";
99
+ // Global error handlers to log crashes
100
+ const crashLogPath = join(homedir(), ".d3k", "crash.log");
101
+ function logCrash(type, error) {
102
+ try {
103
+ const crashDir = join(homedir(), ".d3k");
104
+ if (!existsSync(crashDir)) {
105
+ mkdirSync(crashDir, { recursive: true });
106
+ }
107
+ const timestamp = new Date().toISOString();
108
+ const errorStr = error instanceof Error ? `${error.message}\n${error.stack}` : String(error);
109
+ const logEntry = `[${timestamp}] ${type}: ${errorStr}\n\n`;
110
+ appendFileSync(crashLogPath, logEntry);
111
+ console.error(chalk.red(`\n💥 d3k crashed: ${error instanceof Error ? error.message : error}`));
112
+ console.error(chalk.gray(` Details logged to: ${crashLogPath}`));
113
+ }
114
+ catch {
115
+ // If we can't log, at least print to stderr
116
+ console.error(`d3k crashed: ${error}`);
117
+ }
118
+ }
119
+ process.on("uncaughtException", (error) => {
120
+ logCrash("Uncaught Exception", error);
121
+ process.exit(1);
122
+ });
123
+ process.on("unhandledRejection", (reason) => {
124
+ logCrash("Unhandled Promise Rejection", reason);
125
+ process.exit(1);
126
+ });
21
127
  /**
22
128
  * Build the d3k command string with forwarded options.
23
129
  */
@@ -55,7 +161,7 @@ function buildD3kCommandWithOptions(options) {
55
161
  * Launch d3k with an agent using tmux for proper terminal multiplexing.
56
162
  * This creates a split-screen with the agent on the left and d3k logs on the right.
57
163
  */
58
- async function launchWithTmux(agentCommand, mcpPort = DEFAULT_TMUX_CONFIG.mcpPort, forwardedOptions = {}) {
164
+ async function launchWithTmux(agentCommand, forwardedOptions = {}) {
59
165
  const { execSync } = await import("child_process");
60
166
  const { appendFileSync, writeFileSync } = await import("fs");
61
167
  // Log file for debugging crashes
@@ -94,7 +200,6 @@ async function launchWithTmux(agentCommand, mcpPort = DEFAULT_TMUX_CONFIG.mcpPor
94
200
  sessionName,
95
201
  d3kCommand,
96
202
  agentCommand,
97
- mcpPort,
98
203
  paneWidthPercent: DEFAULT_TMUX_CONFIG.paneWidthPercent
99
204
  });
100
205
  // Create a shell script that sets up tmux and attaches
@@ -198,25 +303,22 @@ async function promptAgentSelection(defaultAgentName) {
198
303
  * Show interactive skill selection prompt using Ink.
199
304
  * Returns the selected skills and install location, or empty array if user skipped.
200
305
  */
201
- async function promptSkillSelection(skills, initiallySelected) {
306
+ async function promptPackageSelection(packages) {
202
307
  const { render } = await import("ink");
203
308
  const React = await import("react");
204
- const { SkillSelector } = await import("./components/SkillSelector.js");
205
- let selectedSkills = [];
309
+ const { PackageSelector } = await import("./components/PackageSelector.js");
310
+ let selectedPackages = [];
206
311
  let installLocation = "project";
207
- let skipped = false;
208
312
  try {
209
- const { unmount, waitUntilExit, clear } = render(React.createElement(SkillSelector, {
210
- skills,
211
- initiallySelected,
313
+ const { unmount, waitUntilExit, clear } = render(React.createElement(PackageSelector, {
314
+ packages,
212
315
  onComplete: (selected, location) => {
213
- selectedSkills = selected;
316
+ selectedPackages = selected;
214
317
  installLocation = location;
215
318
  clear();
216
319
  unmount();
217
320
  },
218
321
  onSkip: () => {
219
- skipped = true;
220
322
  clear();
221
323
  unmount();
222
324
  }
@@ -226,14 +328,10 @@ async function promptSkillSelection(skills, initiallySelected) {
226
328
  process.stdout.write("\x1b[2J\x1b[H\x1b[3J");
227
329
  }
228
330
  catch (error) {
229
- console.error(chalk.red("Error in skill selection:"), error);
230
- return { skills: [], location: "project" };
231
- }
232
- // If user skipped, mark skills as seen so we don't ask again
233
- if (skipped) {
234
- markSkillsAsSeen(skills);
331
+ console.error(chalk.red("Error in package selection:"), error);
332
+ return { packages: [], location: "project" };
235
333
  }
236
- return { skills: selectedSkills, location: installLocation };
334
+ return { packages: selectedPackages, location: installLocation };
237
335
  }
238
336
  function detectPythonCommand(debug = false) {
239
337
  // Check if we're in a virtual environment
@@ -466,7 +564,6 @@ program
466
564
  program
467
565
  .description("AI-powered development tools with browser monitoring and MCP server")
468
566
  .option("-p, --port <port>", "Development server port (auto-detected by project type)")
469
- .option("-m, --port-mcp <port>", "MCP server port", "3684")
470
567
  .option("-s, --script <script>", "Script to run (e.g. dev, main.py) - auto-detected by project type")
471
568
  .option("-c, --command <command>", "Custom command to run (overrides auto-detection and --script)")
472
569
  .option("--profile-dir <dir>", "Chrome profile directory", join(tmpdir(), "dev3000-chrome-profile"))
@@ -480,7 +577,6 @@ program
480
577
  .option("--disable-mcp-configs <targets>", "Comma or space separated list of MCP config files to skip (.mcp.json, .cursor/mcp.json, opencode.json). Use 'all' to disable all.")
481
578
  .option("--no-chrome-devtools-mcp", "Disable chrome-devtools MCP integration (enabled by default)")
482
579
  .option("--headless", "Run Chrome in headless mode (for serverless/CI environments)")
483
- .option("--kill-mcp", "Kill the MCP server on port 3684 and exit")
484
580
  .option("--with-agent <command>", 'Run an agent (e.g. claude) in split-screen mode using tmux. Example: --with-agent "claude"')
485
581
  .option("--no-agent", "Skip agent selection prompt and run d3k standalone")
486
582
  .action(async (options) => {
@@ -490,7 +586,7 @@ program
490
586
  const browserOption = options.browser || userConfig.browser;
491
587
  // Handle --with-agent by spawning tmux with split panes
492
588
  if (options.withAgent) {
493
- await launchWithTmux(options.withAgent, parseInt(options.portMcp, 10), {
589
+ await launchWithTmux(options.withAgent, {
494
590
  port: options.port,
495
591
  portMcp: options.portMcp,
496
592
  script: options.script,
@@ -506,70 +602,97 @@ program
506
602
  });
507
603
  return;
508
604
  }
509
- // Handle --kill-mcp option
510
- if (options.killMcp) {
511
- console.log(chalk.yellow("🛑 Killing MCP server on port 3684..."));
512
- try {
513
- const { spawn } = require("child_process");
514
- await new Promise((resolve) => {
515
- const killProcess = spawn("sh", ["-c", "lsof -ti:3684 | xargs kill -9"], { stdio: "inherit" });
516
- killProcess.on("exit", () => resolve());
517
- });
518
- console.log(chalk.green("✅ MCP server killed"));
519
- }
520
- catch (_error) {
521
- console.log(chalk.gray("⚠️ No MCP server found on port 3684"));
522
- }
523
- process.exit(0);
524
- }
525
605
  // Handle agent selection for split-screen mode (default behavior in TTY)
526
606
  // Skip if --no-agent, --no-tui, --debug flags are used, or if already inside tmux (to avoid nested prompts)
527
607
  const insideTmux = !!process.env.TMUX;
528
608
  if (process.stdin.isTTY && options.agent !== false && options.tui !== false && !options.debug && !insideTmux) {
529
609
  // Clear the terminal so d3k UI starts at the top of the screen
530
610
  process.stdout.write("\x1B[2J\x1B[0f");
531
- // Show loading message while checking for skills
532
- process.stdout.write(chalk.gray(" Checking for skill updates...\r"));
533
- // Check for new/updated skills from vercel-labs/agent-skills
611
+ // Check for skill updates and offer new packages
534
612
  try {
535
- const newSkills = await checkForNewSkills();
536
- // Clear the loading message
537
- process.stdout.write("\x1B[2J\x1B[0f");
538
- if (newSkills.length > 0) {
539
- // Determine initial selections: all remote skills, plus react-performance for React projects
540
- const isReactProject = detectsReact();
541
- const initialSelections = newSkills
542
- .filter((skill) => {
543
- // Always pre-select remote skills (from agent-skills repo)
544
- if (skill.sha !== "bundled")
545
- return true;
546
- // For bundled skills, only pre-select react-performance if it's a React project
547
- if (skill.name === "react-performance")
548
- return isReactProject;
549
- // Don't pre-select other bundled skills by default
550
- return false;
551
- })
552
- .map((s) => s.name);
553
- const { skills: selected, location } = await promptSkillSelection(newSkills, initialSelections);
554
- if (selected.length > 0) {
555
- const locationLabel = location === "global" ? "globally" : "to project";
556
- console.log(chalk.cyan(`Installing ${selected.length} skill(s) ${locationLabel}...`));
557
- const result = await installSelectedSkills(selected, location, (skill, index, total) => {
558
- console.log(chalk.gray(` [${index + 1}/${total}] ${skill.name}...`));
559
- });
560
- if (result.success.length > 0) {
561
- console.log(chalk.green(`✓ Installed: ${result.success.join(", ")}`));
613
+ // Show loading message
614
+ process.stdout.write(chalk.gray(" Checking for skills...\r"));
615
+ // 1. Check for updates to existing skills
616
+ const { hasUpdates } = await checkForSkillUpdates();
617
+ // Clear the loading message line
618
+ process.stdout.write("\x1B[2K\r");
619
+ if (hasUpdates) {
620
+ // Show which packages have updates (use applicable packages since lock file may not exist)
621
+ const applicablePackages = getApplicablePackages();
622
+ console.log(chalk.cyan("📦 Skill updates available"));
623
+ for (const pkg of applicablePackages) {
624
+ console.log(chalk.gray(` • ${pkg.repo}`));
625
+ }
626
+ const { default: readline } = await import("readline");
627
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
628
+ const answer = await new Promise((resolve) => {
629
+ rl.question(chalk.white(" Update now? (Y/n) "), resolve);
630
+ });
631
+ rl.close();
632
+ if (answer.toLowerCase() !== "n") {
633
+ console.log(chalk.gray(" Updating skills..."));
634
+ const updateResult = await updateSkills();
635
+ if (updateResult.success) {
636
+ console.log(chalk.green(" ✓ Skills updated"));
637
+ }
638
+ else {
639
+ console.log(chalk.yellow(" ⚠ Some skills failed to update"));
562
640
  }
563
- if (result.failed.length > 0) {
564
- console.log(chalk.yellow(`⚠ Failed: ${result.failed.join(", ")}`));
641
+ }
642
+ console.log("");
643
+ }
644
+ // 2. Show all applicable packages with install status
645
+ // Skip if we just handled updates
646
+ if (!hasUpdates) {
647
+ const applicablePackages = getApplicablePackages();
648
+ const packagesWithStatus = applicablePackages.map((pkg) => ({
649
+ ...pkg,
650
+ installed: isPackageInstalled(pkg)
651
+ }));
652
+ const hasUninstalled = packagesWithStatus.some((p) => !p.installed);
653
+ // Only show package selector if there are packages to install
654
+ if (packagesWithStatus.length > 0 && hasUninstalled) {
655
+ const { packages: selectedPackages, location } = await promptPackageSelection(packagesWithStatus);
656
+ if (selectedPackages.length > 0) {
657
+ const locationLabel = location === "global" ? "globally" : "to project";
658
+ console.log(chalk.cyan(`Installing ${selectedPackages.length} skill package(s) ${locationLabel}...`));
659
+ const results = { success: [], failed: [] };
660
+ for (let i = 0; i < selectedPackages.length; i++) {
661
+ const pkg = selectedPackages[i];
662
+ console.log(chalk.gray(` [${i + 1}/${selectedPackages.length}] ${pkg.displayName}...`));
663
+ const result = await installSkillPackage(pkg, location);
664
+ if (result.success) {
665
+ results.success.push(pkg.displayName);
666
+ }
667
+ else {
668
+ results.failed.push(pkg.displayName);
669
+ }
670
+ }
671
+ if (results.success.length > 0) {
672
+ console.log(chalk.green(`✓ Installed: ${results.success.join(", ")}`));
673
+ }
674
+ if (results.failed.length > 0) {
675
+ console.log(chalk.yellow(`⚠ Failed: ${results.failed.join(", ")}`));
676
+ }
677
+ console.log("");
565
678
  }
679
+ else {
680
+ // User skipped package installation, show skills are up to date
681
+ console.log(chalk.green("✓ Skills up to date"));
682
+ console.log("");
683
+ }
684
+ }
685
+ else {
686
+ // No updates and no new packages - show success
687
+ console.log(chalk.green("✓ Skills up to date"));
566
688
  console.log("");
567
689
  }
568
690
  }
569
691
  }
570
692
  catch {
571
- // Clear and continue silently on errors (network issues, etc.)
572
- process.stdout.write("\x1B[2J\x1B[0f");
693
+ // Show error briefly, then continue
694
+ console.log(chalk.yellow("⚠ Could not check for skill updates"));
695
+ console.log("");
573
696
  }
574
697
  // Check if tmux is available before showing prompt
575
698
  if (!(await isTmuxInstalled())) {
@@ -592,7 +715,7 @@ program
592
715
  }
593
716
  // Clear screen and scrollback before launching tmux so when tmux exits, terminal is clean
594
717
  process.stdout.write("\x1b[2J\x1b[H\x1b[3J");
595
- await launchWithTmux(selectedAgent.command, parseInt(options.portMcp, 10), {
718
+ await launchWithTmux(selectedAgent.command, {
596
719
  port: options.port,
597
720
  portMcp: options.portMcp,
598
721
  script: options.script,
@@ -779,6 +902,7 @@ cloud
779
902
  .command("check-pr [pr-number]")
780
903
  .description("Verify a PR's changes work as expected using Vercel preview deployment")
781
904
  .option("--repo <url>", "Repository URL (optional, auto-detected from git)")
905
+ .option("--url <preview-url>", "Preview deployment URL (optional, auto-detected from Vercel)")
782
906
  .option("--debug", "Enable debug logging")
783
907
  .action(async (prNumber, options) => {
784
908
  try {
@@ -828,6 +952,12 @@ program
828
952
  process.exit(1);
829
953
  }
830
954
  });
955
+ // Agent-browser command - registered for --help display only
956
+ // Actual handling happens at the top of the file before Commander runs
957
+ program
958
+ .command("agent-browser [args...]")
959
+ .description("Run the bundled agent-browser CLI (e.g., d3k agent-browser screenshot /tmp/foo.png)")
960
+ .allowUnknownOption(true);
831
961
  // Skill command - get skill content for use in prompts/workflows
832
962
  program
833
963
  .command("skill [name]")
@@ -842,7 +972,7 @@ program
842
972
  if (skills.length === 0) {
843
973
  console.log(chalk.yellow("No skills found."));
844
974
  console.log(chalk.gray("\nSkills are loaded from:"));
845
- console.log(chalk.gray(" • .claude/skills/ (project-local)"));
975
+ console.log(chalk.gray(" • .agents/skills/ (project-local)"));
846
976
  console.log(chalk.gray(" • d3k built-in skills"));
847
977
  process.exit(0);
848
978
  }
@@ -883,5 +1013,101 @@ program
883
1013
  // Output skill content to stdout (no formatting, for piping/parsing)
884
1014
  console.log(result.content);
885
1015
  });
1016
+ // Errors command - quick view of recent errors
1017
+ program
1018
+ .command("errors")
1019
+ .description("Show recent errors from d3k logs (browser + server)")
1020
+ .option("-n, --count <count>", "Number of errors to show", "10")
1021
+ .option("-a, --all", "Show all errors, not just recent")
1022
+ .option("-c, --context", "Show interactions before each error (for replay)")
1023
+ .option("--json", "Output as JSON for parsing")
1024
+ .action(async (options) => {
1025
+ const { showErrors } = await import("./commands/errors.js");
1026
+ await showErrors(options);
1027
+ });
1028
+ // Logs command - view recent logs
1029
+ program
1030
+ .command("logs")
1031
+ .description("Show recent logs from d3k (browser + server)")
1032
+ .option("-n, --count <count>", "Number of lines to show", "50")
1033
+ .option("-t, --type <type>", "Filter by type: browser, server, network, all", "all")
1034
+ .option("--json", "Output as JSON for parsing")
1035
+ .action(async (options) => {
1036
+ const { showLogs } = await import("./commands/logs.js");
1037
+ await showLogs(options);
1038
+ });
1039
+ // Fix command - diagnose application errors from logs
1040
+ program
1041
+ .command("fix")
1042
+ .description("Diagnose application errors from d3k logs")
1043
+ .option("-f, --focus <area>", "Focus area: build, runtime, network, ui, all", "all")
1044
+ .option("-t, --time <minutes>", "Minutes to analyze back", "10")
1045
+ .option("--json", "Output as JSON for parsing")
1046
+ .action(async (options) => {
1047
+ const { fixMyApp } = await import("./commands/fix.js");
1048
+ await fixMyApp(options);
1049
+ });
1050
+ // Crawl command - discover app URLs
1051
+ program
1052
+ .command("crawl")
1053
+ .description("Discover URLs by crawling the app")
1054
+ .option("-d, --depth <depth>", "Crawl depth (1, 2, 3, or 'all')", "1")
1055
+ .option("-l, --limit <limit>", "Max links per page to follow", "3")
1056
+ .action(async (options) => {
1057
+ const { crawlApp } = await import("./commands/crawl.js");
1058
+ await crawlApp(options);
1059
+ });
1060
+ // Find-component command - map DOM to React source
1061
+ program
1062
+ .command("find-component <selector>")
1063
+ .description("Find React component source for a DOM selector")
1064
+ .action(async (selector) => {
1065
+ const { findComponent } = await import("./commands/find-component.js");
1066
+ await findComponent(selector);
1067
+ });
1068
+ // Restart command - restart the dev server
1069
+ program
1070
+ .command("restart")
1071
+ .description("Restart the development server (rarely needed - HMR handles most changes)")
1072
+ .action(async () => {
1073
+ const { restartServer } = await import("./commands/restart.js");
1074
+ await restartServer();
1075
+ });
1076
+ // CDP port command - get the CDP port from the session file
1077
+ program
1078
+ .command("cdp-port")
1079
+ .description("Output the CDP port for the current d3k session (for use in scripts)")
1080
+ .action(async () => {
1081
+ const sessionDir = join(homedir(), ".d3k");
1082
+ const projectDir = getProjectDir();
1083
+ const projectName = projectDir.split("/").pop() || "unknown";
1084
+ // Try to find session.json in ~/.d3k/{project-name}/
1085
+ const entries = existsSync(sessionDir)
1086
+ ? await import("fs").then((fs) => fs.readdirSync(sessionDir, { withFileTypes: true }))
1087
+ : [];
1088
+ for (const entry of entries) {
1089
+ if (entry.isDirectory() && entry.name.startsWith(projectName.substring(0, 20))) {
1090
+ const sessionFile = join(sessionDir, entry.name, "session.json");
1091
+ if (existsSync(sessionFile)) {
1092
+ try {
1093
+ const content = JSON.parse(readFileSync(sessionFile, "utf-8"));
1094
+ if (content.cdpUrl) {
1095
+ // Extract port from URL like "ws://localhost:9223/devtools/browser/..."
1096
+ const match = content.cdpUrl.match(/:(\d+)/);
1097
+ if (match) {
1098
+ console.log(match[1]);
1099
+ process.exit(0);
1100
+ }
1101
+ }
1102
+ }
1103
+ catch {
1104
+ // Continue searching
1105
+ }
1106
+ }
1107
+ }
1108
+ }
1109
+ // Default to 9222 if no session found
1110
+ console.log("9222");
1111
+ });
886
1112
  program.parse();
887
1113
  //# sourceMappingURL=cli.js.map