@duckmind/dm-darwin-x64 0.36.0 → 0.36.4
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/dm +0 -0
- package/extensions/dm-cua/README.md +9 -2
- package/extensions/dm-cua/bin/browser-cua.mjs +6 -4
- package/extensions/dm-cua/package.json +2 -1
- package/extensions/dm-cua/skills/browser-cua/skill.md +2 -1
- package/extensions/dm-cua/src/browser-cua-lib.mjs +65 -3
- package/extensions/dm-cua/test/browser-cua.test.js +16 -0
- package/extensions/dm-ultradex/package-lock.json +3 -3
- package/extensions/greedysearch-dm/bin/launch.mjs +10 -9
- package/package.json +1 -1
- package/theme/duckmind-harpy.json +0 -84
package/dm
CHANGED
|
Binary file
|
|
@@ -4,14 +4,21 @@ Browser-first Computer Use extension for DM.
|
|
|
4
4
|
|
|
5
5
|
What it does:
|
|
6
6
|
|
|
7
|
-
- launches or reuses a dedicated
|
|
7
|
+
- launches or reuses a dedicated browser profile via the bundled `greedysearch-dm` CDP helpers
|
|
8
8
|
- bootstraps a blank tab on fresh empty profiles so browser automation does not fail on the first run
|
|
9
9
|
- exposes one tool, `browser_cua`, for list / navigate / snapshot / screenshot / click / type / evaluate / stop
|
|
10
10
|
- stores browser screenshots under `~/.dm/agent/cua/screenshots/` by default
|
|
11
11
|
|
|
12
|
+
Browser selection:
|
|
13
|
+
|
|
14
|
+
- default: Chrome/Chromium auto-detected by `greedysearch-dm`
|
|
15
|
+
- opt-in CloakBrowser trial: set `DM_CUA_BROWSER=cloak` and one of `DM_CUA_BROWSER_PATH`, `DM_CUA_CLOAK_PATH`, `CLOAKBROWSER_BINARY_PATH`, or `CHROME_PATH` to the CloakBrowser Chromium executable
|
|
16
|
+
- DM does not bundle or auto-download the compiled CloakBrowser binary; install/pre-download it outside DM first because upstream permits use but not redistribution
|
|
17
|
+
- Current `browser_cua` actions still use CDP commands through `greedysearch-dm`; full CloakBrowser stealth parity would require a future Playwright-backed CUA lane.
|
|
18
|
+
|
|
12
19
|
What it does **not** do yet:
|
|
13
20
|
|
|
14
21
|
- it does not replace the macOS `computer-use` Codex plugin lane
|
|
15
22
|
- it does not replace Android `adbridge`
|
|
16
23
|
|
|
17
|
-
Those broader lanes are still tracked separately. This extension closes the most actionable CUA gap from the current DM snapshot: a first-class browser lane that works from a fresh dedicated
|
|
24
|
+
Those broader lanes are still tracked separately. This extension closes the most actionable CUA gap from the current DM snapshot: a first-class browser lane that works from a fresh dedicated browser profile instead of overloading `coding_task`.
|
|
@@ -16,10 +16,12 @@ Usage:
|
|
|
16
16
|
node browser-cua.mjs evaluate --expression <js> [--tab <prefix>] [--json]
|
|
17
17
|
node browser-cua.mjs stop [--json]
|
|
18
18
|
|
|
19
|
-
Notes:
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
Notes:
|
|
20
|
+
- This helper reuses DM's bundled greedysearch-dm CDP sidecar.
|
|
21
|
+
- Fresh dedicated browser profiles auto-bootstrap a blank tab.
|
|
22
|
+
- Default browser is Chrome/Chromium. To try CloakBrowser, set DM_CUA_BROWSER=cloak
|
|
23
|
+
and point DM_CUA_BROWSER_PATH or CLOAKBROWSER_BINARY_PATH at its Chromium binary.
|
|
24
|
+
- screenshot defaults to ~/.dm/agent/cua/screenshots when --output is omitted.`);
|
|
23
25
|
}
|
|
24
26
|
|
|
25
27
|
function parseArgs(argv) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dm-cua",
|
|
3
3
|
"version": "0.1.0",
|
|
4
|
-
"description": "First-class browser CUA extension for DM using a dedicated Chrome
|
|
4
|
+
"description": "First-class browser CUA extension for DM using a dedicated Chrome/CDP-compatible profile",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
7
7
|
"index.js",
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
"browser",
|
|
25
25
|
"cua",
|
|
26
26
|
"chrome",
|
|
27
|
+
"cloakbrowser",
|
|
27
28
|
"automation"
|
|
28
29
|
],
|
|
29
30
|
"peerDependencies": {
|
|
@@ -15,4 +15,5 @@ Rules:
|
|
|
15
15
|
- Start with an inspect action before click/type on unfamiliar pages.
|
|
16
16
|
- Prefer `navigate` for deterministic URLs, including search URLs.
|
|
17
17
|
- Use `screenshot` before complex click loops or when spatial layout matters.
|
|
18
|
-
- Fresh
|
|
18
|
+
- Fresh dedicated browser profiles auto-bootstrap a blank tab, so the first browser action should not fail just because the page list is empty.
|
|
19
|
+
- Default browser is the bundled Chrome/Chromium-compatible CDP lane. To evaluate CloakBrowser, install/pre-download CloakBrowser outside DM, then run with `DM_CUA_BROWSER=cloak` and `DM_CUA_BROWSER_PATH` or `CLOAKBROWSER_BINARY_PATH` pointing at its Chromium executable. DM must not bundle the compiled CloakBrowser binary because upstream permits use but not redistribution.
|
|
@@ -12,6 +12,10 @@ const DEFAULT_CUA_PORT_BASE = 9322;
|
|
|
12
12
|
const DEFAULT_CUA_PORT_RANGE = 400;
|
|
13
13
|
const DEFAULT_TIMEOUT_MS = 60000;
|
|
14
14
|
const URLISH_PATTERN = /^(about:|https?:\/\/|file:|chrome-error:\/\/)/i;
|
|
15
|
+
const BROWSER_DISPLAY_NAMES = {
|
|
16
|
+
chrome: "Chrome",
|
|
17
|
+
cloak: "CloakBrowser",
|
|
18
|
+
};
|
|
15
19
|
|
|
16
20
|
function parsePort(value) {
|
|
17
21
|
const port = Number.parseInt(String(value ?? ""), 10);
|
|
@@ -22,18 +26,40 @@ function hashScope(value) {
|
|
|
22
26
|
return createHash("sha256").update(String(value || "default")).digest("hex");
|
|
23
27
|
}
|
|
24
28
|
|
|
29
|
+
function normalizeBrowserKind(value) {
|
|
30
|
+
const raw = String(value || "chrome").trim().toLowerCase();
|
|
31
|
+
if (raw === "cloakbrowser" || raw === "cloak-browser") return "cloak";
|
|
32
|
+
if (raw === "chromium" || raw === "google-chrome" || raw === "chrome") return "chrome";
|
|
33
|
+
return raw.replace(/[^a-z0-9_.-]/g, "-") || "chrome";
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function resolveBrowserExecutablePath(env, browserKind) {
|
|
37
|
+
const explicit =
|
|
38
|
+
env.DM_CUA_BROWSER_PATH
|
|
39
|
+
|| (browserKind === "cloak" ? env.DM_CUA_CLOAK_PATH || env.CLOAKBROWSER_BINARY_PATH : undefined)
|
|
40
|
+
|| env.CHROME_PATH;
|
|
41
|
+
return explicit ? resolve(String(explicit)) : undefined;
|
|
42
|
+
}
|
|
43
|
+
|
|
25
44
|
export function resolveBrowserRuntimeConfig(env = process.env, scope = process.cwd()) {
|
|
26
45
|
const rawScope = env.DM_CUA_SCOPE || env.DM_CODING_AGENT_DIR || env.PI_CODING_AGENT_DIR || scope;
|
|
27
46
|
const scopeHash = hashScope(resolve(String(rawScope || ".")));
|
|
28
47
|
const instanceId = String(env.DM_CUA_INSTANCE_ID || scopeHash.slice(0, 12)).replace(/[^a-zA-Z0-9_.-]/g, "-");
|
|
48
|
+
const browserKind = normalizeBrowserKind(env.DM_CUA_BROWSER || env.DM_BROWSER_CUA_BROWSER || env.DM_CUA_BROWSER_KIND);
|
|
49
|
+
const browserDisplayName = env.DM_CUA_BROWSER_DISPLAY_NAME || BROWSER_DISPLAY_NAMES[browserKind] || browserKind;
|
|
50
|
+
const browserExecutablePath = resolveBrowserExecutablePath(env, browserKind);
|
|
29
51
|
const port =
|
|
30
52
|
parsePort(env.DM_CUA_PORT)
|
|
31
53
|
?? parsePort(env.GREEDY_SEARCH_PORT)
|
|
32
54
|
?? DEFAULT_CUA_PORT_BASE + (Number.parseInt(scopeHash.slice(0, 8), 16) % DEFAULT_CUA_PORT_RANGE);
|
|
33
|
-
const
|
|
55
|
+
const profileSuffix = browserKind === "chrome" ? "chrome" : browserKind;
|
|
56
|
+
const profileDir = resolve(env.DM_CUA_PROFILE_DIR || join(tmpdir(), `dm-cua-${profileSuffix}-profile-${instanceId}`));
|
|
34
57
|
const socketBaseDir = platform() === "win32" ? tmpdir() : "/tmp";
|
|
35
58
|
return {
|
|
36
59
|
instanceId,
|
|
60
|
+
browserKind,
|
|
61
|
+
browserDisplayName,
|
|
62
|
+
browserExecutablePath,
|
|
37
63
|
port,
|
|
38
64
|
profileDir,
|
|
39
65
|
pidFile: join(profileDir, "chrome.pid"),
|
|
@@ -48,6 +74,31 @@ const CHROME_PORT = BROWSER_CONFIG.port;
|
|
|
48
74
|
|
|
49
75
|
export const BROWSER_PROFILE_DIR = BROWSER_CONFIG.profileDir;
|
|
50
76
|
|
|
77
|
+
function browserSummary() {
|
|
78
|
+
return {
|
|
79
|
+
kind: BROWSER_CONFIG.browserKind,
|
|
80
|
+
displayName: BROWSER_CONFIG.browserDisplayName,
|
|
81
|
+
executablePath: BROWSER_CONFIG.browserExecutablePath,
|
|
82
|
+
profileDir: BROWSER_CONFIG.profileDir,
|
|
83
|
+
port: BROWSER_CONFIG.port,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function ensureBrowserSelectionUsable() {
|
|
88
|
+
if (BROWSER_CONFIG.browserKind === "cloak" && !BROWSER_CONFIG.browserExecutablePath) {
|
|
89
|
+
throw new Error(
|
|
90
|
+
[
|
|
91
|
+
"CloakBrowser selected for browser CUA, but no executable path was provided.",
|
|
92
|
+
"Install/pre-download CloakBrowser yourself, then set DM_CUA_BROWSER_PATH, DM_CUA_CLOAK_PATH, CLOAKBROWSER_BINARY_PATH, or CHROME_PATH.",
|
|
93
|
+
"DM does not bundle the compiled CloakBrowser binary because its upstream license allows use but not redistribution.",
|
|
94
|
+
].join(" "),
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
if (BROWSER_CONFIG.browserExecutablePath && !existsSync(BROWSER_CONFIG.browserExecutablePath)) {
|
|
98
|
+
throw new Error(`${BROWSER_CONFIG.browserDisplayName} executable not found: ${BROWSER_CONFIG.browserExecutablePath}`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
51
102
|
export function resolveBrowserHelperPaths() {
|
|
52
103
|
return {
|
|
53
104
|
launchScript: fileURLToPath(new URL("../../greedysearch-dm/bin/launch.mjs", import.meta.url)),
|
|
@@ -63,9 +114,11 @@ function browserEnv() {
|
|
|
63
114
|
"1";
|
|
64
115
|
return {
|
|
65
116
|
...process.env,
|
|
117
|
+
...(BROWSER_CONFIG.browserExecutablePath ? { CHROME_PATH: BROWSER_CONFIG.browserExecutablePath } : {}),
|
|
66
118
|
CDP_PROFILE_DIR: BROWSER_CONFIG.profileDir.replace(/\\/g, "/"),
|
|
67
119
|
CDP_PAGES_CACHE: BROWSER_CONFIG.pagesCache.replace(/\\/g, "/"),
|
|
68
120
|
CDP_SOCKET_DIR: BROWSER_CONFIG.socketDir.replace(/\\/g, "/"),
|
|
121
|
+
GREEDY_SEARCH_BROWSER_LABEL: BROWSER_CONFIG.browserDisplayName,
|
|
69
122
|
GREEDY_SEARCH_PORT: String(BROWSER_CONFIG.port),
|
|
70
123
|
GREEDY_SEARCH_PROFILE_DIR: BROWSER_CONFIG.profileDir.replace(/\\/g, "/"),
|
|
71
124
|
GREEDY_SEARCH_PID_FILE: BROWSER_CONFIG.pidFile.replace(/\\/g, "/"),
|
|
@@ -171,7 +224,7 @@ function requestJson(method, requestPath) {
|
|
|
171
224
|
});
|
|
172
225
|
response.on("end", () => {
|
|
173
226
|
if ((response.statusCode ?? 500) >= 400) {
|
|
174
|
-
rejectPromise(new Error(`
|
|
227
|
+
rejectPromise(new Error(`Browser CDP HTTP ${response.statusCode}: ${body.trim()}`));
|
|
175
228
|
return;
|
|
176
229
|
}
|
|
177
230
|
try {
|
|
@@ -216,6 +269,7 @@ async function ensureBrowserHelpersExist() {
|
|
|
216
269
|
}
|
|
217
270
|
|
|
218
271
|
export async function ensureBrowserReady() {
|
|
272
|
+
ensureBrowserSelectionUsable();
|
|
219
273
|
const { launchScript } = await ensureBrowserHelpersExist();
|
|
220
274
|
await runNodeScript(launchScript, [], { env: browserEnv(), timeoutMs: DEFAULT_TIMEOUT_MS });
|
|
221
275
|
let pages = await listPages();
|
|
@@ -252,7 +306,7 @@ export async function runBrowserAction({
|
|
|
252
306
|
switch (action) {
|
|
253
307
|
case "list": {
|
|
254
308
|
const pages = await ensureBrowserReady();
|
|
255
|
-
return { status: "ok", action, pages };
|
|
309
|
+
return { status: "ok", action, browser: browserSummary(), pages };
|
|
256
310
|
}
|
|
257
311
|
case "navigate": {
|
|
258
312
|
if (!url) throw new Error("url is required for action=navigate");
|
|
@@ -263,6 +317,7 @@ export async function runBrowserAction({
|
|
|
263
317
|
return {
|
|
264
318
|
status: "ok",
|
|
265
319
|
action,
|
|
320
|
+
browser: browserSummary(),
|
|
266
321
|
tab: context.tab,
|
|
267
322
|
url: page?.url || url,
|
|
268
323
|
title: page?.title || "",
|
|
@@ -276,6 +331,7 @@ export async function runBrowserAction({
|
|
|
276
331
|
return {
|
|
277
332
|
status: "ok",
|
|
278
333
|
action,
|
|
334
|
+
browser: browserSummary(),
|
|
279
335
|
tab: context.tab,
|
|
280
336
|
title: context.page?.title || "",
|
|
281
337
|
url: context.page?.url || "",
|
|
@@ -291,6 +347,7 @@ export async function runBrowserAction({
|
|
|
291
347
|
return {
|
|
292
348
|
status: "ok",
|
|
293
349
|
action,
|
|
350
|
+
browser: browserSummary(),
|
|
294
351
|
tab: context.tab,
|
|
295
352
|
title: context.page?.title || "",
|
|
296
353
|
url: context.page?.url || "",
|
|
@@ -307,6 +364,7 @@ export async function runBrowserAction({
|
|
|
307
364
|
return {
|
|
308
365
|
status: "ok",
|
|
309
366
|
action,
|
|
367
|
+
browser: browserSummary(),
|
|
310
368
|
tab: context.tab,
|
|
311
369
|
selector,
|
|
312
370
|
message: result.stdout.trim(),
|
|
@@ -321,6 +379,7 @@ export async function runBrowserAction({
|
|
|
321
379
|
return {
|
|
322
380
|
status: "ok",
|
|
323
381
|
action,
|
|
382
|
+
browser: browserSummary(),
|
|
324
383
|
tab: context.tab,
|
|
325
384
|
x,
|
|
326
385
|
y,
|
|
@@ -334,6 +393,7 @@ export async function runBrowserAction({
|
|
|
334
393
|
return {
|
|
335
394
|
status: "ok",
|
|
336
395
|
action,
|
|
396
|
+
browser: browserSummary(),
|
|
337
397
|
tab: context.tab,
|
|
338
398
|
textLength: text.length,
|
|
339
399
|
message: result.stdout.trim(),
|
|
@@ -346,6 +406,7 @@ export async function runBrowserAction({
|
|
|
346
406
|
return {
|
|
347
407
|
status: "ok",
|
|
348
408
|
action,
|
|
409
|
+
browser: browserSummary(),
|
|
349
410
|
tab: context.tab,
|
|
350
411
|
value: result.stdout.trim(),
|
|
351
412
|
};
|
|
@@ -361,6 +422,7 @@ export async function runBrowserAction({
|
|
|
361
422
|
return {
|
|
362
423
|
status: "ok",
|
|
363
424
|
action,
|
|
425
|
+
browser: browserSummary(),
|
|
364
426
|
message: (result.stdout || "Stopped browser CUA lane.").trim(),
|
|
365
427
|
};
|
|
366
428
|
}
|
|
@@ -63,4 +63,20 @@ test("resolveBrowserRuntimeConfig accepts explicit safe overrides", () => {
|
|
|
63
63
|
assert.equal(config.port, 9456);
|
|
64
64
|
assert.equal(config.instanceId, "session-one");
|
|
65
65
|
assert.equal(config.profileDir, "/tmp/custom-dm-cua-profile");
|
|
66
|
+
assert.equal(config.browserKind, "chrome");
|
|
67
|
+
assert.equal(config.browserDisplayName, "Chrome");
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
test("resolveBrowserRuntimeConfig supports opt-in CloakBrowser executable path", () => {
|
|
71
|
+
const config = resolveBrowserRuntimeConfig(
|
|
72
|
+
{
|
|
73
|
+
DM_CUA_BROWSER: "cloakbrowser",
|
|
74
|
+
CLOAKBROWSER_BINARY_PATH: "/opt/cloak/Chromium.app/Contents/MacOS/Chromium",
|
|
75
|
+
},
|
|
76
|
+
"/tmp/dm-cua-project-c",
|
|
77
|
+
);
|
|
78
|
+
assert.equal(config.browserKind, "cloak");
|
|
79
|
+
assert.equal(config.browserDisplayName, "CloakBrowser");
|
|
80
|
+
assert.equal(config.browserExecutablePath, "/opt/cloak/Chromium.app/Contents/MacOS/Chromium");
|
|
81
|
+
assert.match(config.profileDir, /dm-cua-cloak-profile-[a-f0-9]{12}$/);
|
|
66
82
|
});
|
|
@@ -7448,9 +7448,9 @@
|
|
|
7448
7448
|
}
|
|
7449
7449
|
},
|
|
7450
7450
|
"node_modules/semver": {
|
|
7451
|
-
"version": "7.8.
|
|
7452
|
-
"resolved": "https://registry.npmjs.org/semver/-/semver-7.8.
|
|
7453
|
-
"integrity": "sha512-
|
|
7451
|
+
"version": "7.8.3",
|
|
7452
|
+
"resolved": "https://registry.npmjs.org/semver/-/semver-7.8.3.tgz",
|
|
7453
|
+
"integrity": "sha512-wnilbGyMxzbY7dNOl7jpKbLSjcfeweJWU5j4+u5qW+6/wuGD9KzIGOyZnQVSBM9E7DtWaaH3CyHkppYrKYoxwg==",
|
|
7454
7454
|
"dev": true,
|
|
7455
7455
|
"license": "ISC",
|
|
7456
7456
|
"bin": {
|
|
@@ -42,6 +42,7 @@ const ACTIVE_PORT = join(PROFILE_DIR, "DevToolsActivePort");
|
|
|
42
42
|
const PID_FILE = process.env.GREEDY_SEARCH_PID_FILE || join(tmpdir(), "greedysearch-chrome.pid");
|
|
43
43
|
const MODE_FILE = process.env.GREEDY_SEARCH_MODE_FILE || join(tmpdir(), "greedysearch-chrome-mode");
|
|
44
44
|
const ALLOW_PORT_CLEANUP = /^(1|true|yes|on)$/i.test(process.env.GREEDY_SEARCH_ALLOW_PORT_CLEANUP ?? "1");
|
|
45
|
+
const BROWSER_LABEL = process.env.GREEDY_SEARCH_BROWSER_LABEL || "Chrome";
|
|
45
46
|
|
|
46
47
|
function findChrome() {
|
|
47
48
|
const os = platform();
|
|
@@ -283,11 +284,11 @@ function cleanupGhostChrome() {
|
|
|
283
284
|
|
|
284
285
|
if (!ALLOW_PORT_CLEANUP) {
|
|
285
286
|
console.error(
|
|
286
|
-
|
|
287
|
+
`${BROWSER_LABEL}/CDP port ${PORT} is already owned by untracked pid ${portPid}; refusing to kill it. Set GREEDY_SEARCH_PORT or DM_CUA_PORT to a free port.`,
|
|
287
288
|
);
|
|
288
289
|
process.exit(1);
|
|
289
290
|
}
|
|
290
|
-
console.log(`Ghost
|
|
291
|
+
console.log(`Ghost ${BROWSER_LABEL} on port ${PORT} (pid ${portPid}) — cleaning up...`);
|
|
291
292
|
killProcess(portPid);
|
|
292
293
|
try {
|
|
293
294
|
unlinkSync(PID_FILE);
|
|
@@ -351,10 +352,10 @@ async function main() {
|
|
|
351
352
|
if (pid) {
|
|
352
353
|
const ok = killProcess(pid);
|
|
353
354
|
console.log(
|
|
354
|
-
ok ? `Stopped
|
|
355
|
+
ok ? `Stopped ${BROWSER_LABEL} (pid ${pid}).` : `Failed to stop pid ${pid}.`,
|
|
355
356
|
);
|
|
356
357
|
} else {
|
|
357
|
-
console.log(
|
|
358
|
+
console.log(`GreedySearch ${BROWSER_LABEL} is not running.`);
|
|
358
359
|
}
|
|
359
360
|
try {
|
|
360
361
|
unlinkSync(PID_FILE);
|
|
@@ -386,7 +387,7 @@ async function main() {
|
|
|
386
387
|
!process.argv.includes("--headless");
|
|
387
388
|
if (isWantingVisible && isModeFileHeadless()) {
|
|
388
389
|
console.log(
|
|
389
|
-
`Headless
|
|
390
|
+
`Headless ${BROWSER_LABEL} running (pid ${existing}) but visible requested — killing...`,
|
|
390
391
|
);
|
|
391
392
|
killProcess(existing);
|
|
392
393
|
try {
|
|
@@ -399,7 +400,7 @@ async function main() {
|
|
|
399
400
|
} else {
|
|
400
401
|
const ready = await writePortFile(5000);
|
|
401
402
|
if (ready) {
|
|
402
|
-
console.log(`GreedySearch
|
|
403
|
+
console.log(`GreedySearch ${BROWSER_LABEL} already running (pid ${existing}).`);
|
|
403
404
|
return;
|
|
404
405
|
}
|
|
405
406
|
console.log(`Stale PID ${existing} — launching fresh.`);
|
|
@@ -411,13 +412,13 @@ async function main() {
|
|
|
411
412
|
|
|
412
413
|
const CHROME_EXE = process.env.CHROME_PATH || findChrome();
|
|
413
414
|
if (!CHROME_EXE) {
|
|
414
|
-
console.error(
|
|
415
|
+
console.error(`${BROWSER_LABEL} not found. Set CHROME_PATH env var.`);
|
|
415
416
|
process.exit(1);
|
|
416
417
|
}
|
|
417
418
|
|
|
418
419
|
mkdirSync(PROFILE_DIR, { recursive: true });
|
|
419
420
|
|
|
420
|
-
console.log(`Launching GreedySearch
|
|
421
|
+
console.log(`Launching GreedySearch ${BROWSER_LABEL} on port ${PORT}...`);
|
|
421
422
|
if (isHeadless()) {
|
|
422
423
|
console.log("Headless mode — no window will be shown");
|
|
423
424
|
} else if (!isVisible()) {
|
|
@@ -435,7 +436,7 @@ async function main() {
|
|
|
435
436
|
|
|
436
437
|
const portFileReady = await writePortFile();
|
|
437
438
|
if (!portFileReady) {
|
|
438
|
-
console.error(
|
|
439
|
+
console.error(`${BROWSER_LABEL} did not become ready within 15s.`);
|
|
439
440
|
process.exit(1);
|
|
440
441
|
}
|
|
441
442
|
|
package/package.json
CHANGED
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "https://duckmind.ai/theme-schema.json",
|
|
3
|
-
"name": "duckmind-harpy",
|
|
4
|
-
"vars": {
|
|
5
|
-
"background": "#121212",
|
|
6
|
-
"surface": "#171B22",
|
|
7
|
-
"surfaceAlt": "#1F2430",
|
|
8
|
-
"surfaceSuccess": "#18211B",
|
|
9
|
-
"surfaceError": "#21181D",
|
|
10
|
-
"selection": "#2D3748",
|
|
11
|
-
"foreground": "#F8F8F2",
|
|
12
|
-
"foregroundSoft": "#B8BCC6",
|
|
13
|
-
"comment": "#7F869E",
|
|
14
|
-
"dimText": "#5C6378",
|
|
15
|
-
"harpyPink": "#F04282",
|
|
16
|
-
"harpyBlue": "#5FA0DE",
|
|
17
|
-
"harpyTeal": "#4ED4E8",
|
|
18
|
-
"green": "#A6E22E",
|
|
19
|
-
"orange": "#FD971F",
|
|
20
|
-
"amber": "#D19A66",
|
|
21
|
-
"harpyViolet": "#9B8BF4",
|
|
22
|
-
"red": "#E06C75",
|
|
23
|
-
"alarm": "#FF0055",
|
|
24
|
-
"criticalRed": "#FF0040"
|
|
25
|
-
},
|
|
26
|
-
"colors": {
|
|
27
|
-
"accent": "harpyViolet",
|
|
28
|
-
"border": "comment",
|
|
29
|
-
"borderAccent": "harpyTeal",
|
|
30
|
-
"borderMuted": "surfaceAlt",
|
|
31
|
-
"success": "green",
|
|
32
|
-
"error": "red",
|
|
33
|
-
"warning": "orange",
|
|
34
|
-
"muted": "comment",
|
|
35
|
-
"dim": "dimText",
|
|
36
|
-
"text": "#F8F8F2",
|
|
37
|
-
"thinkingText": "comment",
|
|
38
|
-
"selectedBg": "selection",
|
|
39
|
-
"userMessageBg": "surfaceAlt",
|
|
40
|
-
"userMessageText": "foreground",
|
|
41
|
-
"customMessageBg": "surface",
|
|
42
|
-
"customMessageText": "foreground",
|
|
43
|
-
"customMessageLabel": "harpyPink",
|
|
44
|
-
"toolPendingBg": "surface",
|
|
45
|
-
"toolSuccessBg": "surfaceSuccess",
|
|
46
|
-
"toolErrorBg": "surfaceError",
|
|
47
|
-
"toolTitle": "harpyTeal",
|
|
48
|
-
"toolOutput": "foregroundSoft",
|
|
49
|
-
"mdHeading": "harpyViolet",
|
|
50
|
-
"mdLink": "harpyBlue",
|
|
51
|
-
"mdLinkUrl": "comment",
|
|
52
|
-
"mdCode": "amber",
|
|
53
|
-
"mdCodeBlock": "foregroundSoft",
|
|
54
|
-
"mdCodeBlockBorder": "comment",
|
|
55
|
-
"mdQuote": "foregroundSoft",
|
|
56
|
-
"mdQuoteBorder": "comment",
|
|
57
|
-
"mdHr": "dimText",
|
|
58
|
-
"mdListBullet": "harpyTeal",
|
|
59
|
-
"toolDiffAdded": "green",
|
|
60
|
-
"toolDiffRemoved": "red",
|
|
61
|
-
"toolDiffContext": "comment",
|
|
62
|
-
"syntaxComment": "comment",
|
|
63
|
-
"syntaxKeyword": "harpyPink",
|
|
64
|
-
"syntaxFunction": "#5C9CE6",
|
|
65
|
-
"syntaxVariable": "amber",
|
|
66
|
-
"syntaxString": "green",
|
|
67
|
-
"syntaxNumber": "orange",
|
|
68
|
-
"syntaxType": "harpyTeal",
|
|
69
|
-
"syntaxOperator": "harpyPink",
|
|
70
|
-
"syntaxPunctuation": "foregroundSoft",
|
|
71
|
-
"thinkingOff": "surface",
|
|
72
|
-
"thinkingMinimal": "comment",
|
|
73
|
-
"thinkingLow": "amber",
|
|
74
|
-
"thinkingMedium": "orange",
|
|
75
|
-
"thinkingHigh": "alarm",
|
|
76
|
-
"thinkingXhigh": "criticalRed",
|
|
77
|
-
"bashMode": "orange"
|
|
78
|
-
},
|
|
79
|
-
"export": {
|
|
80
|
-
"pageBg": "#121212",
|
|
81
|
-
"cardBg": "#171B22",
|
|
82
|
-
"infoBg": "#4B3F63"
|
|
83
|
-
}
|
|
84
|
-
}
|