@trydecember/cli 0.4.4 → 0.4.5
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/december.js +1935 -276
- package/package.json +1 -1
package/dist/december.js
CHANGED
|
@@ -65,7 +65,7 @@ var package_default;
|
|
|
65
65
|
var init_package = __esm(() => {
|
|
66
66
|
package_default = {
|
|
67
67
|
name: "@trydecember/cli",
|
|
68
|
-
version: "0.4.
|
|
68
|
+
version: "0.4.5",
|
|
69
69
|
description: "a coding agent for terminal and cloud.",
|
|
70
70
|
homepage: "https://trydecember.com",
|
|
71
71
|
repository: {
|
|
@@ -84297,7 +84297,7 @@ var require_websocket = __commonJS(function(exports, module) {
|
|
|
84297
84297
|
var readyStates = ["CONNECTING", "OPEN", "CLOSING", "CLOSED"];
|
|
84298
84298
|
var subprotocolRegex = /^[!#$%&'*+\-.0-9A-Z^_`|a-z~]+$/;
|
|
84299
84299
|
|
|
84300
|
-
class
|
|
84300
|
+
class WebSocket2 extends EventEmitter {
|
|
84301
84301
|
constructor(address, protocols, options) {
|
|
84302
84302
|
super();
|
|
84303
84303
|
this._binaryType = BINARY_TYPES[0];
|
|
@@ -84310,7 +84310,7 @@ var require_websocket = __commonJS(function(exports, module) {
|
|
|
84310
84310
|
this._extensions = {};
|
|
84311
84311
|
this._paused = false;
|
|
84312
84312
|
this._protocol = "";
|
|
84313
|
-
this._readyState =
|
|
84313
|
+
this._readyState = WebSocket2.CONNECTING;
|
|
84314
84314
|
this._receiver = null;
|
|
84315
84315
|
this._sender = null;
|
|
84316
84316
|
this._socket = null;
|
|
@@ -84412,12 +84412,12 @@ var require_websocket = __commonJS(function(exports, module) {
|
|
|
84412
84412
|
socket.on("data", socketOnData);
|
|
84413
84413
|
socket.on("end", socketOnEnd);
|
|
84414
84414
|
socket.on("error", socketOnError);
|
|
84415
|
-
this._readyState =
|
|
84415
|
+
this._readyState = WebSocket2.OPEN;
|
|
84416
84416
|
this.emit("open");
|
|
84417
84417
|
}
|
|
84418
84418
|
emitClose() {
|
|
84419
84419
|
if (!this._socket) {
|
|
84420
|
-
this._readyState =
|
|
84420
|
+
this._readyState = WebSocket2.CLOSED;
|
|
84421
84421
|
this.emit("close", this._closeCode, this._closeMessage);
|
|
84422
84422
|
return;
|
|
84423
84423
|
}
|
|
@@ -84425,24 +84425,24 @@ var require_websocket = __commonJS(function(exports, module) {
|
|
|
84425
84425
|
this._extensions[PerMessageDeflate.extensionName].cleanup();
|
|
84426
84426
|
}
|
|
84427
84427
|
this._receiver.removeAllListeners();
|
|
84428
|
-
this._readyState =
|
|
84428
|
+
this._readyState = WebSocket2.CLOSED;
|
|
84429
84429
|
this.emit("close", this._closeCode, this._closeMessage);
|
|
84430
84430
|
}
|
|
84431
84431
|
close(code, data) {
|
|
84432
|
-
if (this.readyState ===
|
|
84432
|
+
if (this.readyState === WebSocket2.CLOSED)
|
|
84433
84433
|
return;
|
|
84434
|
-
if (this.readyState ===
|
|
84434
|
+
if (this.readyState === WebSocket2.CONNECTING) {
|
|
84435
84435
|
const msg = "WebSocket was closed before the connection was established";
|
|
84436
84436
|
abortHandshake(this, this._req, msg);
|
|
84437
84437
|
return;
|
|
84438
84438
|
}
|
|
84439
|
-
if (this.readyState ===
|
|
84439
|
+
if (this.readyState === WebSocket2.CLOSING) {
|
|
84440
84440
|
if (this._closeFrameSent && (this._closeFrameReceived || this._receiver._writableState.errorEmitted)) {
|
|
84441
84441
|
this._socket.end();
|
|
84442
84442
|
}
|
|
84443
84443
|
return;
|
|
84444
84444
|
}
|
|
84445
|
-
this._readyState =
|
|
84445
|
+
this._readyState = WebSocket2.CLOSING;
|
|
84446
84446
|
this._sender.close(code, data, !this._isServer, (err) => {
|
|
84447
84447
|
if (err)
|
|
84448
84448
|
return;
|
|
@@ -84454,14 +84454,14 @@ var require_websocket = __commonJS(function(exports, module) {
|
|
|
84454
84454
|
setCloseTimer(this);
|
|
84455
84455
|
}
|
|
84456
84456
|
pause() {
|
|
84457
|
-
if (this.readyState ===
|
|
84457
|
+
if (this.readyState === WebSocket2.CONNECTING || this.readyState === WebSocket2.CLOSED) {
|
|
84458
84458
|
return;
|
|
84459
84459
|
}
|
|
84460
84460
|
this._paused = true;
|
|
84461
84461
|
this._socket.pause();
|
|
84462
84462
|
}
|
|
84463
84463
|
ping(data, mask, cb) {
|
|
84464
|
-
if (this.readyState ===
|
|
84464
|
+
if (this.readyState === WebSocket2.CONNECTING) {
|
|
84465
84465
|
throw new Error("WebSocket is not open: readyState 0 (CONNECTING)");
|
|
84466
84466
|
}
|
|
84467
84467
|
if (typeof data === "function") {
|
|
@@ -84473,7 +84473,7 @@ var require_websocket = __commonJS(function(exports, module) {
|
|
|
84473
84473
|
}
|
|
84474
84474
|
if (typeof data === "number")
|
|
84475
84475
|
data = data.toString();
|
|
84476
|
-
if (this.readyState !==
|
|
84476
|
+
if (this.readyState !== WebSocket2.OPEN) {
|
|
84477
84477
|
sendAfterClose(this, data, cb);
|
|
84478
84478
|
return;
|
|
84479
84479
|
}
|
|
@@ -84482,7 +84482,7 @@ var require_websocket = __commonJS(function(exports, module) {
|
|
|
84482
84482
|
this._sender.ping(data || EMPTY_BUFFER, mask, cb);
|
|
84483
84483
|
}
|
|
84484
84484
|
pong(data, mask, cb) {
|
|
84485
|
-
if (this.readyState ===
|
|
84485
|
+
if (this.readyState === WebSocket2.CONNECTING) {
|
|
84486
84486
|
throw new Error("WebSocket is not open: readyState 0 (CONNECTING)");
|
|
84487
84487
|
}
|
|
84488
84488
|
if (typeof data === "function") {
|
|
@@ -84494,7 +84494,7 @@ var require_websocket = __commonJS(function(exports, module) {
|
|
|
84494
84494
|
}
|
|
84495
84495
|
if (typeof data === "number")
|
|
84496
84496
|
data = data.toString();
|
|
84497
|
-
if (this.readyState !==
|
|
84497
|
+
if (this.readyState !== WebSocket2.OPEN) {
|
|
84498
84498
|
sendAfterClose(this, data, cb);
|
|
84499
84499
|
return;
|
|
84500
84500
|
}
|
|
@@ -84503,7 +84503,7 @@ var require_websocket = __commonJS(function(exports, module) {
|
|
|
84503
84503
|
this._sender.pong(data || EMPTY_BUFFER, mask, cb);
|
|
84504
84504
|
}
|
|
84505
84505
|
resume() {
|
|
84506
|
-
if (this.readyState ===
|
|
84506
|
+
if (this.readyState === WebSocket2.CONNECTING || this.readyState === WebSocket2.CLOSED) {
|
|
84507
84507
|
return;
|
|
84508
84508
|
}
|
|
84509
84509
|
this._paused = false;
|
|
@@ -84511,7 +84511,7 @@ var require_websocket = __commonJS(function(exports, module) {
|
|
|
84511
84511
|
this._socket.resume();
|
|
84512
84512
|
}
|
|
84513
84513
|
send(data, options, cb) {
|
|
84514
|
-
if (this.readyState ===
|
|
84514
|
+
if (this.readyState === WebSocket2.CONNECTING) {
|
|
84515
84515
|
throw new Error("WebSocket is not open: readyState 0 (CONNECTING)");
|
|
84516
84516
|
}
|
|
84517
84517
|
if (typeof options === "function") {
|
|
@@ -84520,7 +84520,7 @@ var require_websocket = __commonJS(function(exports, module) {
|
|
|
84520
84520
|
}
|
|
84521
84521
|
if (typeof data === "number")
|
|
84522
84522
|
data = data.toString();
|
|
84523
|
-
if (this.readyState !==
|
|
84523
|
+
if (this.readyState !== WebSocket2.OPEN) {
|
|
84524
84524
|
sendAfterClose(this, data, cb);
|
|
84525
84525
|
return;
|
|
84526
84526
|
}
|
|
@@ -84537,48 +84537,48 @@ var require_websocket = __commonJS(function(exports, module) {
|
|
|
84537
84537
|
this._sender.send(data || EMPTY_BUFFER, opts, cb);
|
|
84538
84538
|
}
|
|
84539
84539
|
terminate() {
|
|
84540
|
-
if (this.readyState ===
|
|
84540
|
+
if (this.readyState === WebSocket2.CLOSED)
|
|
84541
84541
|
return;
|
|
84542
|
-
if (this.readyState ===
|
|
84542
|
+
if (this.readyState === WebSocket2.CONNECTING) {
|
|
84543
84543
|
const msg = "WebSocket was closed before the connection was established";
|
|
84544
84544
|
abortHandshake(this, this._req, msg);
|
|
84545
84545
|
return;
|
|
84546
84546
|
}
|
|
84547
84547
|
if (this._socket) {
|
|
84548
|
-
this._readyState =
|
|
84548
|
+
this._readyState = WebSocket2.CLOSING;
|
|
84549
84549
|
this._socket.destroy();
|
|
84550
84550
|
}
|
|
84551
84551
|
}
|
|
84552
84552
|
}
|
|
84553
|
-
Object.defineProperty(
|
|
84553
|
+
Object.defineProperty(WebSocket2, "CONNECTING", {
|
|
84554
84554
|
enumerable: true,
|
|
84555
84555
|
value: readyStates.indexOf("CONNECTING")
|
|
84556
84556
|
});
|
|
84557
|
-
Object.defineProperty(
|
|
84557
|
+
Object.defineProperty(WebSocket2.prototype, "CONNECTING", {
|
|
84558
84558
|
enumerable: true,
|
|
84559
84559
|
value: readyStates.indexOf("CONNECTING")
|
|
84560
84560
|
});
|
|
84561
|
-
Object.defineProperty(
|
|
84561
|
+
Object.defineProperty(WebSocket2, "OPEN", {
|
|
84562
84562
|
enumerable: true,
|
|
84563
84563
|
value: readyStates.indexOf("OPEN")
|
|
84564
84564
|
});
|
|
84565
|
-
Object.defineProperty(
|
|
84565
|
+
Object.defineProperty(WebSocket2.prototype, "OPEN", {
|
|
84566
84566
|
enumerable: true,
|
|
84567
84567
|
value: readyStates.indexOf("OPEN")
|
|
84568
84568
|
});
|
|
84569
|
-
Object.defineProperty(
|
|
84569
|
+
Object.defineProperty(WebSocket2, "CLOSING", {
|
|
84570
84570
|
enumerable: true,
|
|
84571
84571
|
value: readyStates.indexOf("CLOSING")
|
|
84572
84572
|
});
|
|
84573
|
-
Object.defineProperty(
|
|
84573
|
+
Object.defineProperty(WebSocket2.prototype, "CLOSING", {
|
|
84574
84574
|
enumerable: true,
|
|
84575
84575
|
value: readyStates.indexOf("CLOSING")
|
|
84576
84576
|
});
|
|
84577
|
-
Object.defineProperty(
|
|
84577
|
+
Object.defineProperty(WebSocket2, "CLOSED", {
|
|
84578
84578
|
enumerable: true,
|
|
84579
84579
|
value: readyStates.indexOf("CLOSED")
|
|
84580
84580
|
});
|
|
84581
|
-
Object.defineProperty(
|
|
84581
|
+
Object.defineProperty(WebSocket2.prototype, "CLOSED", {
|
|
84582
84582
|
enumerable: true,
|
|
84583
84583
|
value: readyStates.indexOf("CLOSED")
|
|
84584
84584
|
});
|
|
@@ -84591,10 +84591,10 @@ var require_websocket = __commonJS(function(exports, module) {
|
|
|
84591
84591
|
"readyState",
|
|
84592
84592
|
"url"
|
|
84593
84593
|
].forEach((property) => {
|
|
84594
|
-
Object.defineProperty(
|
|
84594
|
+
Object.defineProperty(WebSocket2.prototype, property, { enumerable: true });
|
|
84595
84595
|
});
|
|
84596
84596
|
["open", "error", "close", "message"].forEach((method) => {
|
|
84597
|
-
Object.defineProperty(
|
|
84597
|
+
Object.defineProperty(WebSocket2.prototype, `on${method}`, {
|
|
84598
84598
|
enumerable: true,
|
|
84599
84599
|
get() {
|
|
84600
84600
|
for (const listener of this.listeners(method)) {
|
|
@@ -84618,9 +84618,9 @@ var require_websocket = __commonJS(function(exports, module) {
|
|
|
84618
84618
|
}
|
|
84619
84619
|
});
|
|
84620
84620
|
});
|
|
84621
|
-
|
|
84622
|
-
|
|
84623
|
-
module.exports =
|
|
84621
|
+
WebSocket2.prototype.addEventListener = addEventListener;
|
|
84622
|
+
WebSocket2.prototype.removeEventListener = removeEventListener;
|
|
84623
|
+
module.exports = WebSocket2;
|
|
84624
84624
|
function initAsClient(websocket, address, protocols, options) {
|
|
84625
84625
|
const opts = {
|
|
84626
84626
|
allowSynchronousEvents: true,
|
|
@@ -84804,7 +84804,7 @@ var require_websocket = __commonJS(function(exports, module) {
|
|
|
84804
84804
|
});
|
|
84805
84805
|
req.on("upgrade", (res, socket, head) => {
|
|
84806
84806
|
websocket.emit("upgrade", res);
|
|
84807
|
-
if (websocket.readyState !==
|
|
84807
|
+
if (websocket.readyState !== WebSocket2.CONNECTING)
|
|
84808
84808
|
return;
|
|
84809
84809
|
req = websocket._req = null;
|
|
84810
84810
|
const upgrade = res.headers.upgrade;
|
|
@@ -84880,7 +84880,7 @@ var require_websocket = __commonJS(function(exports, module) {
|
|
|
84880
84880
|
}
|
|
84881
84881
|
}
|
|
84882
84882
|
function emitErrorAndClose(websocket, err) {
|
|
84883
|
-
websocket._readyState =
|
|
84883
|
+
websocket._readyState = WebSocket2.CLOSING;
|
|
84884
84884
|
websocket._errorEmitted = true;
|
|
84885
84885
|
websocket.emit("error", err);
|
|
84886
84886
|
websocket.emitClose();
|
|
@@ -84897,7 +84897,7 @@ var require_websocket = __commonJS(function(exports, module) {
|
|
|
84897
84897
|
return tls.connect(options);
|
|
84898
84898
|
}
|
|
84899
84899
|
function abortHandshake(websocket, stream, message) {
|
|
84900
|
-
websocket._readyState =
|
|
84900
|
+
websocket._readyState = WebSocket2.CLOSING;
|
|
84901
84901
|
const err = new Error(message);
|
|
84902
84902
|
Error.captureStackTrace(err, abortHandshake);
|
|
84903
84903
|
if (stream.setHeader) {
|
|
@@ -84977,10 +84977,10 @@ var require_websocket = __commonJS(function(exports, module) {
|
|
|
84977
84977
|
}
|
|
84978
84978
|
function senderOnError(err) {
|
|
84979
84979
|
const websocket = this[kWebSocket];
|
|
84980
|
-
if (websocket.readyState ===
|
|
84980
|
+
if (websocket.readyState === WebSocket2.CLOSED)
|
|
84981
84981
|
return;
|
|
84982
|
-
if (websocket.readyState ===
|
|
84983
|
-
websocket._readyState =
|
|
84982
|
+
if (websocket.readyState === WebSocket2.OPEN) {
|
|
84983
|
+
websocket._readyState = WebSocket2.CLOSING;
|
|
84984
84984
|
setCloseTimer(websocket);
|
|
84985
84985
|
}
|
|
84986
84986
|
this._socket.end();
|
|
@@ -84997,7 +84997,7 @@ var require_websocket = __commonJS(function(exports, module) {
|
|
|
84997
84997
|
this.removeListener("close", socketOnClose);
|
|
84998
84998
|
this.removeListener("data", socketOnData);
|
|
84999
84999
|
this.removeListener("end", socketOnEnd);
|
|
85000
|
-
websocket._readyState =
|
|
85000
|
+
websocket._readyState = WebSocket2.CLOSING;
|
|
85001
85001
|
if (!this._readableState.endEmitted && !websocket._closeFrameReceived && !websocket._receiver._writableState.errorEmitted && this._readableState.length !== 0) {
|
|
85002
85002
|
const chunk = this.read(this._readableState.length);
|
|
85003
85003
|
websocket._receiver.write(chunk);
|
|
@@ -85019,7 +85019,7 @@ var require_websocket = __commonJS(function(exports, module) {
|
|
|
85019
85019
|
}
|
|
85020
85020
|
function socketOnEnd() {
|
|
85021
85021
|
const websocket = this[kWebSocket];
|
|
85022
|
-
websocket._readyState =
|
|
85022
|
+
websocket._readyState = WebSocket2.CLOSING;
|
|
85023
85023
|
websocket._receiver.end();
|
|
85024
85024
|
this.end();
|
|
85025
85025
|
}
|
|
@@ -85028,7 +85028,7 @@ var require_websocket = __commonJS(function(exports, module) {
|
|
|
85028
85028
|
this.removeListener("error", socketOnError);
|
|
85029
85029
|
this.on("error", NOOP);
|
|
85030
85030
|
if (websocket) {
|
|
85031
|
-
websocket._readyState =
|
|
85031
|
+
websocket._readyState = WebSocket2.CLOSING;
|
|
85032
85032
|
this.destroy();
|
|
85033
85033
|
}
|
|
85034
85034
|
}
|
|
@@ -85036,7 +85036,7 @@ var require_websocket = __commonJS(function(exports, module) {
|
|
|
85036
85036
|
|
|
85037
85037
|
// ../../node_modules/.bun/ws@8.21.0/node_modules/ws/lib/stream.js
|
|
85038
85038
|
var require_stream = __commonJS(function(exports, module) {
|
|
85039
|
-
var
|
|
85039
|
+
var WebSocket2 = require_websocket();
|
|
85040
85040
|
var { Duplex } = __require("stream");
|
|
85041
85041
|
function emitClose(stream) {
|
|
85042
85042
|
stream.emit("close");
|
|
@@ -85191,7 +85191,7 @@ var require_websocket_server = __commonJS(function(exports, module) {
|
|
|
85191
85191
|
var extension = require_extension();
|
|
85192
85192
|
var PerMessageDeflate = require_permessage_deflate();
|
|
85193
85193
|
var subprotocol = require_subprotocol();
|
|
85194
|
-
var
|
|
85194
|
+
var WebSocket2 = require_websocket();
|
|
85195
85195
|
var { CLOSE_TIMEOUT, GUID, kWebSocket } = require_constants2();
|
|
85196
85196
|
var keyRegex = /^[+/0-9A-Za-z]{22}==$/;
|
|
85197
85197
|
var RUNNING = 0;
|
|
@@ -85219,7 +85219,7 @@ var require_websocket_server = __commonJS(function(exports, module) {
|
|
|
85219
85219
|
host: null,
|
|
85220
85220
|
path: null,
|
|
85221
85221
|
port: null,
|
|
85222
|
-
WebSocket,
|
|
85222
|
+
WebSocket: WebSocket2,
|
|
85223
85223
|
...options
|
|
85224
85224
|
};
|
|
85225
85225
|
if (options.port == null && !options.server && !options.noServer || options.port != null && (options.server || options.noServer) || options.server && options.noServer) {
|
|
@@ -115360,20 +115360,28 @@ Examples:`);
|
|
|
115360
115360
|
console.log("No API key provided. Operation cancelled.");
|
|
115361
115361
|
return;
|
|
115362
115362
|
}
|
|
115363
|
-
|
|
115364
|
-
const defaultModel = getDefaultModelForProvider(provider);
|
|
115363
|
+
const isSTTProvider = provider.toLowerCase() === "deepgram";
|
|
115365
115364
|
const config = await loadConfig();
|
|
115366
115365
|
config.providers = config.providers || {};
|
|
115367
115366
|
config.providers[provider] = finalKey;
|
|
115368
|
-
|
|
115369
|
-
|
|
115370
|
-
|
|
115371
|
-
|
|
115372
|
-
|
|
115373
|
-
|
|
115374
|
-
|
|
115367
|
+
if (!isSTTProvider) {
|
|
115368
|
+
await Promise.resolve().then(() => init_models5());
|
|
115369
|
+
const defaultModel = getDefaultModelForProvider(provider);
|
|
115370
|
+
config.activeProvider = provider;
|
|
115371
|
+
config.activeModel = defaultModel;
|
|
115372
|
+
config.authPriority = "byok";
|
|
115373
|
+
await saveConfig(config);
|
|
115374
|
+
await Promise.resolve().then(() => init_models5());
|
|
115375
|
+
fetchLiveProviderModels(provider, finalKey).catch(() => {});
|
|
115376
|
+
console.log(`
|
|
115375
115377
|
${GREEN}Successfully saved API key for ${provider.toUpperCase()} (Model: ${defaultModel})!${RESET}
|
|
115376
115378
|
`);
|
|
115379
|
+
} else {
|
|
115380
|
+
await saveConfig(config);
|
|
115381
|
+
console.log(`
|
|
115382
|
+
${GREEN}Successfully saved API key for DEEPGRAM (Live Voice Dictation)!${RESET}
|
|
115383
|
+
`);
|
|
115384
|
+
}
|
|
115377
115385
|
}
|
|
115378
115386
|
async function handleLoginCommand(options) {
|
|
115379
115387
|
const targetProvider = (options?.provider || "december").toLowerCase().trim();
|
|
@@ -119419,7 +119427,7 @@ var init_browser = __esm(() => {
|
|
|
119419
119427
|
});
|
|
119420
119428
|
BrowserTool = {
|
|
119421
119429
|
name: "browser",
|
|
119422
|
-
description: "Use
|
|
119430
|
+
description: "Use an interactive browser engine to navigate to a URL, execute client-side JavaScript, extract rendered page content, and capture console or network errors.",
|
|
119423
119431
|
inputSchema: browserSchema,
|
|
119424
119432
|
execute: async ({ url }, context) => {
|
|
119425
119433
|
try {
|
|
@@ -119431,6 +119439,20 @@ var init_browser = __esm(() => {
|
|
|
119431
119439
|
return `Failed to fetch URL: ${result.error}`;
|
|
119432
119440
|
}
|
|
119433
119441
|
let output = truncateOutput(result.text, 25000, 100).text;
|
|
119442
|
+
if (result.consoleErrors && result.consoleErrors.length > 0) {
|
|
119443
|
+
output += `
|
|
119444
|
+
|
|
119445
|
+
[CONSOLE ERRORS]
|
|
119446
|
+
` + result.consoleErrors.map((err) => `- ${err}`).join(`
|
|
119447
|
+
`);
|
|
119448
|
+
}
|
|
119449
|
+
if (result.networkErrors && result.networkErrors.length > 0) {
|
|
119450
|
+
output += `
|
|
119451
|
+
|
|
119452
|
+
[FAILED NETWORK REQUESTS]
|
|
119453
|
+
` + result.networkErrors.map((err) => `- ${err}`).join(`
|
|
119454
|
+
`);
|
|
119455
|
+
}
|
|
119434
119456
|
if (result.vncUrl) {
|
|
119435
119457
|
output += `
|
|
119436
119458
|
|
|
@@ -119444,6 +119466,89 @@ var init_browser = __esm(() => {
|
|
|
119444
119466
|
};
|
|
119445
119467
|
});
|
|
119446
119468
|
|
|
119469
|
+
// ../../packages/tools/src/browser_action.ts
|
|
119470
|
+
var browserActionSchema, BrowserActionTool;
|
|
119471
|
+
var init_browser_action = __esm(() => {
|
|
119472
|
+
init_src();
|
|
119473
|
+
init_esm2();
|
|
119474
|
+
browserActionSchema = Type2.Object({
|
|
119475
|
+
action: Type2.Union([
|
|
119476
|
+
Type2.Literal("navigate"),
|
|
119477
|
+
Type2.Literal("click"),
|
|
119478
|
+
Type2.Literal("type"),
|
|
119479
|
+
Type2.Literal("screenshot"),
|
|
119480
|
+
Type2.Literal("get_console_errors")
|
|
119481
|
+
], { description: "The interactive browser action to execute" }),
|
|
119482
|
+
url: Type2.Optional(Type2.String({ description: 'URL to navigate to (required for action: "navigate")' })),
|
|
119483
|
+
selector: Type2.Optional(Type2.String({ description: 'CSS selector or text target (for action: "click" or "type")' })),
|
|
119484
|
+
text: Type2.Optional(Type2.String({ description: 'Text to input (required for action: "type")' })),
|
|
119485
|
+
fullPage: Type2.Optional(Type2.Boolean({ description: 'Capture full scrollable page (for action: "screenshot")' }))
|
|
119486
|
+
});
|
|
119487
|
+
BrowserActionTool = {
|
|
119488
|
+
name: "browser_action",
|
|
119489
|
+
description: "Interact with a headless browser session. Supports navigating to URLs, clicking elements, typing into inputs, capturing screenshots, and inspecting console or network errors on localhost web apps.",
|
|
119490
|
+
inputSchema: browserActionSchema,
|
|
119491
|
+
execute: async (input, context) => {
|
|
119492
|
+
try {
|
|
119493
|
+
if (!context.operations.browser) {
|
|
119494
|
+
return `Failed to execute browser action: Browser operations are not supported in this environment.`;
|
|
119495
|
+
}
|
|
119496
|
+
if (!context.operations.browser.action) {
|
|
119497
|
+
if (input.action === "navigate" && input.url) {
|
|
119498
|
+
const navResult = await context.operations.browser.navigate(input.url);
|
|
119499
|
+
if (navResult.error) {
|
|
119500
|
+
return `Failed to navigate: ${navResult.error}`;
|
|
119501
|
+
}
|
|
119502
|
+
let out = truncateOutput(navResult.text, 25000, 100).text;
|
|
119503
|
+
if (navResult.consoleErrors && navResult.consoleErrors.length > 0) {
|
|
119504
|
+
out += `
|
|
119505
|
+
|
|
119506
|
+
[CONSOLE ERRORS]
|
|
119507
|
+
` + navResult.consoleErrors.map((err) => `- ${err}`).join(`
|
|
119508
|
+
`);
|
|
119509
|
+
}
|
|
119510
|
+
if (navResult.networkErrors && navResult.networkErrors.length > 0) {
|
|
119511
|
+
out += `
|
|
119512
|
+
|
|
119513
|
+
[FAILED NETWORK REQUESTS]
|
|
119514
|
+
` + navResult.networkErrors.map((err) => `- ${err}`).join(`
|
|
119515
|
+
`);
|
|
119516
|
+
}
|
|
119517
|
+
return out;
|
|
119518
|
+
}
|
|
119519
|
+
return `Browser interactive actions ('click', 'type', 'screenshot') require Chrome or Chromium to be installed.`;
|
|
119520
|
+
}
|
|
119521
|
+
const result = await context.operations.browser.action(input);
|
|
119522
|
+
if (result.error) {
|
|
119523
|
+
return `Failed to execute action "${input.action}": ${result.error}`;
|
|
119524
|
+
}
|
|
119525
|
+
let response = result.output || result.text || `Browser action "${input.action}" completed successfully.`;
|
|
119526
|
+
if (result.screenshotPath) {
|
|
119527
|
+
response += `
|
|
119528
|
+
[Screenshot saved: ${result.screenshotPath}]`;
|
|
119529
|
+
}
|
|
119530
|
+
if (result.consoleErrors && result.consoleErrors.length > 0) {
|
|
119531
|
+
response += `
|
|
119532
|
+
|
|
119533
|
+
[CONSOLE ERRORS]
|
|
119534
|
+
` + result.consoleErrors.map((err) => `- ${err}`).join(`
|
|
119535
|
+
`);
|
|
119536
|
+
}
|
|
119537
|
+
if (result.networkErrors && result.networkErrors.length > 0) {
|
|
119538
|
+
response += `
|
|
119539
|
+
|
|
119540
|
+
[FAILED NETWORK REQUESTS]
|
|
119541
|
+
` + result.networkErrors.map((err) => `- ${err}`).join(`
|
|
119542
|
+
`);
|
|
119543
|
+
}
|
|
119544
|
+
return response;
|
|
119545
|
+
} catch (error) {
|
|
119546
|
+
return `Failed to execute browser action: ${error.message}`;
|
|
119547
|
+
}
|
|
119548
|
+
}
|
|
119549
|
+
};
|
|
119550
|
+
});
|
|
119551
|
+
|
|
119447
119552
|
// ../../packages/tools/src/code_intelligence.ts
|
|
119448
119553
|
function formatDiagnostics(diags, path) {
|
|
119449
119554
|
const target = path ? ` for ${path}` : "";
|
|
@@ -160892,7 +160997,7 @@ var require_websocket2 = __commonJS(function(exports, module) {
|
|
|
160892
160997
|
return null;
|
|
160893
160998
|
}
|
|
160894
160999
|
|
|
160895
|
-
class
|
|
161000
|
+
class WebSocket2 extends EventTarget {
|
|
160896
161001
|
#events = {
|
|
160897
161002
|
open: null,
|
|
160898
161003
|
error: null,
|
|
@@ -160968,11 +161073,11 @@ var require_websocket2 = __commonJS(function(exports, module) {
|
|
|
160968
161073
|
this.#url = new URL(urlRecord.href);
|
|
160969
161074
|
const client = environmentSettingsObject.settingsObject;
|
|
160970
161075
|
this.#handler.controller = establishWebSocketConnection(urlRecord, protocols, client, this.#handler, options);
|
|
160971
|
-
this.#handler.readyState =
|
|
161076
|
+
this.#handler.readyState = WebSocket2.CONNECTING;
|
|
160972
161077
|
this.#binaryType = "blob";
|
|
160973
161078
|
}
|
|
160974
161079
|
close(code = undefined, reason = undefined) {
|
|
160975
|
-
webidl.brandCheck(this,
|
|
161080
|
+
webidl.brandCheck(this, WebSocket2);
|
|
160976
161081
|
const prefix = "WebSocket.close";
|
|
160977
161082
|
if (code !== undefined) {
|
|
160978
161083
|
code = webidl.converters["unsigned short"](code, prefix, "code", webidl.attributes.Clamp);
|
|
@@ -160985,7 +161090,7 @@ var require_websocket2 = __commonJS(function(exports, module) {
|
|
|
160985
161090
|
closeWebSocketConnection(this.#handler, code, reason, true);
|
|
160986
161091
|
}
|
|
160987
161092
|
send(data) {
|
|
160988
|
-
webidl.brandCheck(this,
|
|
161093
|
+
webidl.brandCheck(this, WebSocket2);
|
|
160989
161094
|
const prefix = "WebSocket.send";
|
|
160990
161095
|
webidl.argumentLengthCheck(arguments, 1, prefix);
|
|
160991
161096
|
data = webidl.converters.WebSocketSendData(data, prefix, "data");
|
|
@@ -161019,31 +161124,31 @@ var require_websocket2 = __commonJS(function(exports, module) {
|
|
|
161019
161124
|
}
|
|
161020
161125
|
}
|
|
161021
161126
|
get readyState() {
|
|
161022
|
-
webidl.brandCheck(this,
|
|
161127
|
+
webidl.brandCheck(this, WebSocket2);
|
|
161023
161128
|
return this.#handler.readyState;
|
|
161024
161129
|
}
|
|
161025
161130
|
get bufferedAmount() {
|
|
161026
|
-
webidl.brandCheck(this,
|
|
161131
|
+
webidl.brandCheck(this, WebSocket2);
|
|
161027
161132
|
return this.#bufferedAmount;
|
|
161028
161133
|
}
|
|
161029
161134
|
get url() {
|
|
161030
|
-
webidl.brandCheck(this,
|
|
161135
|
+
webidl.brandCheck(this, WebSocket2);
|
|
161031
161136
|
return URLSerializer(this.#url);
|
|
161032
161137
|
}
|
|
161033
161138
|
get extensions() {
|
|
161034
|
-
webidl.brandCheck(this,
|
|
161139
|
+
webidl.brandCheck(this, WebSocket2);
|
|
161035
161140
|
return this.#extensions;
|
|
161036
161141
|
}
|
|
161037
161142
|
get protocol() {
|
|
161038
|
-
webidl.brandCheck(this,
|
|
161143
|
+
webidl.brandCheck(this, WebSocket2);
|
|
161039
161144
|
return this.#protocol;
|
|
161040
161145
|
}
|
|
161041
161146
|
get onopen() {
|
|
161042
|
-
webidl.brandCheck(this,
|
|
161147
|
+
webidl.brandCheck(this, WebSocket2);
|
|
161043
161148
|
return this.#events.open;
|
|
161044
161149
|
}
|
|
161045
161150
|
set onopen(fn) {
|
|
161046
|
-
webidl.brandCheck(this,
|
|
161151
|
+
webidl.brandCheck(this, WebSocket2);
|
|
161047
161152
|
if (this.#events.open) {
|
|
161048
161153
|
this.removeEventListener("open", this.#events.open);
|
|
161049
161154
|
}
|
|
@@ -161056,11 +161161,11 @@ var require_websocket2 = __commonJS(function(exports, module) {
|
|
|
161056
161161
|
}
|
|
161057
161162
|
}
|
|
161058
161163
|
get onerror() {
|
|
161059
|
-
webidl.brandCheck(this,
|
|
161164
|
+
webidl.brandCheck(this, WebSocket2);
|
|
161060
161165
|
return this.#events.error;
|
|
161061
161166
|
}
|
|
161062
161167
|
set onerror(fn) {
|
|
161063
|
-
webidl.brandCheck(this,
|
|
161168
|
+
webidl.brandCheck(this, WebSocket2);
|
|
161064
161169
|
if (this.#events.error) {
|
|
161065
161170
|
this.removeEventListener("error", this.#events.error);
|
|
161066
161171
|
}
|
|
@@ -161073,11 +161178,11 @@ var require_websocket2 = __commonJS(function(exports, module) {
|
|
|
161073
161178
|
}
|
|
161074
161179
|
}
|
|
161075
161180
|
get onclose() {
|
|
161076
|
-
webidl.brandCheck(this,
|
|
161181
|
+
webidl.brandCheck(this, WebSocket2);
|
|
161077
161182
|
return this.#events.close;
|
|
161078
161183
|
}
|
|
161079
161184
|
set onclose(fn) {
|
|
161080
|
-
webidl.brandCheck(this,
|
|
161185
|
+
webidl.brandCheck(this, WebSocket2);
|
|
161081
161186
|
if (this.#events.close) {
|
|
161082
161187
|
this.removeEventListener("close", this.#events.close);
|
|
161083
161188
|
}
|
|
@@ -161090,11 +161195,11 @@ var require_websocket2 = __commonJS(function(exports, module) {
|
|
|
161090
161195
|
}
|
|
161091
161196
|
}
|
|
161092
161197
|
get onmessage() {
|
|
161093
|
-
webidl.brandCheck(this,
|
|
161198
|
+
webidl.brandCheck(this, WebSocket2);
|
|
161094
161199
|
return this.#events.message;
|
|
161095
161200
|
}
|
|
161096
161201
|
set onmessage(fn) {
|
|
161097
|
-
webidl.brandCheck(this,
|
|
161202
|
+
webidl.brandCheck(this, WebSocket2);
|
|
161098
161203
|
if (this.#events.message) {
|
|
161099
161204
|
this.removeEventListener("message", this.#events.message);
|
|
161100
161205
|
}
|
|
@@ -161107,11 +161212,11 @@ var require_websocket2 = __commonJS(function(exports, module) {
|
|
|
161107
161212
|
}
|
|
161108
161213
|
}
|
|
161109
161214
|
get binaryType() {
|
|
161110
|
-
webidl.brandCheck(this,
|
|
161215
|
+
webidl.brandCheck(this, WebSocket2);
|
|
161111
161216
|
return this.#binaryType;
|
|
161112
161217
|
}
|
|
161113
161218
|
set binaryType(type) {
|
|
161114
|
-
webidl.brandCheck(this,
|
|
161219
|
+
webidl.brandCheck(this, WebSocket2);
|
|
161115
161220
|
if (type !== "blob" && type !== "arraybuffer") {
|
|
161116
161221
|
this.#binaryType = "blob";
|
|
161117
161222
|
} else {
|
|
@@ -161227,13 +161332,13 @@ var require_websocket2 = __commonJS(function(exports, module) {
|
|
|
161227
161332
|
}
|
|
161228
161333
|
}
|
|
161229
161334
|
}
|
|
161230
|
-
var { ping } =
|
|
161231
|
-
Reflect.deleteProperty(
|
|
161232
|
-
|
|
161233
|
-
|
|
161234
|
-
|
|
161235
|
-
|
|
161236
|
-
Object.defineProperties(
|
|
161335
|
+
var { ping } = WebSocket2;
|
|
161336
|
+
Reflect.deleteProperty(WebSocket2, "ping");
|
|
161337
|
+
WebSocket2.CONNECTING = WebSocket2.prototype.CONNECTING = states.CONNECTING;
|
|
161338
|
+
WebSocket2.OPEN = WebSocket2.prototype.OPEN = states.OPEN;
|
|
161339
|
+
WebSocket2.CLOSING = WebSocket2.prototype.CLOSING = states.CLOSING;
|
|
161340
|
+
WebSocket2.CLOSED = WebSocket2.prototype.CLOSED = states.CLOSED;
|
|
161341
|
+
Object.defineProperties(WebSocket2.prototype, {
|
|
161237
161342
|
CONNECTING: staticPropertyDescriptors,
|
|
161238
161343
|
OPEN: staticPropertyDescriptors,
|
|
161239
161344
|
CLOSING: staticPropertyDescriptors,
|
|
@@ -161257,7 +161362,7 @@ var require_websocket2 = __commonJS(function(exports, module) {
|
|
|
161257
161362
|
configurable: true
|
|
161258
161363
|
}
|
|
161259
161364
|
});
|
|
161260
|
-
Object.defineProperties(
|
|
161365
|
+
Object.defineProperties(WebSocket2, {
|
|
161261
161366
|
CONNECTING: staticPropertyDescriptors,
|
|
161262
161367
|
OPEN: staticPropertyDescriptors,
|
|
161263
161368
|
CLOSING: staticPropertyDescriptors,
|
|
@@ -161304,7 +161409,7 @@ var require_websocket2 = __commonJS(function(exports, module) {
|
|
|
161304
161409
|
return webidl.converters.USVString(V);
|
|
161305
161410
|
};
|
|
161306
161411
|
module.exports = {
|
|
161307
|
-
WebSocket,
|
|
161412
|
+
WebSocket: WebSocket2,
|
|
161308
161413
|
ping
|
|
161309
161414
|
};
|
|
161310
161415
|
});
|
|
@@ -162189,7 +162294,7 @@ function makeDispatcher(fn) {
|
|
|
162189
162294
|
}, handler);
|
|
162190
162295
|
};
|
|
162191
162296
|
}
|
|
162192
|
-
var __filename = "/home/runner/work/december/december/node_modules/.bun/undici@7.28.0/node_modules/undici/index.js", Client, Dispatcher, Pool, BalancedPool, RoundRobinPool, Agent, ProxyAgent, Socks5ProxyAgent, EnvHttpProxyAgent, RetryAgent, H2CClient, errors2, util3, InvalidArgumentError, api, buildConnector, MockClient, MockCallHistory, MockCallHistoryLog, MockAgent, MockPool, SnapshotAgent, mockErrors, RetryHandler, getGlobalDispatcher, setGlobalDispatcher, DecoratorHandler, RedirectHandler, $interceptors, $cacheStores, SqliteCacheStore, fetchImpl, $Headers, $Response, $Request, $FormData, setGlobalOrigin, getGlobalOrigin, CacheStorage, kConstruct, $caches, deleteCookie, getCookies, getSetCookies, setCookie, parseCookie, parseMIMEType, serializeAMimeType, CloseEvent, ErrorEvent, MessageEvent,
|
|
162297
|
+
var __filename = "/home/runner/work/december/december/node_modules/.bun/undici@7.28.0/node_modules/undici/index.js", Client, Dispatcher, Pool, BalancedPool, RoundRobinPool, Agent, ProxyAgent, Socks5ProxyAgent, EnvHttpProxyAgent, RetryAgent, H2CClient, errors2, util3, InvalidArgumentError, api, buildConnector, MockClient, MockCallHistory, MockCallHistoryLog, MockAgent, MockPool, SnapshotAgent, mockErrors, RetryHandler, getGlobalDispatcher, setGlobalDispatcher, DecoratorHandler, RedirectHandler, $interceptors, $cacheStores, SqliteCacheStore, fetchImpl, $Headers, $Response, $Request, $FormData, setGlobalOrigin, getGlobalOrigin, CacheStorage, kConstruct, $caches, deleteCookie, getCookies, getSetCookies, setCookie, parseCookie, parseMIMEType, serializeAMimeType, CloseEvent, ErrorEvent, MessageEvent, WebSocket3, ping, $WebSocketStream, $WebSocketError, $request, $stream, $pipeline, $connect, $upgrade, EventSource;
|
|
162193
162298
|
var init_undici = __esm(() => {
|
|
162194
162299
|
Client = require_client();
|
|
162195
162300
|
Dispatcher = require_dispatcher();
|
|
@@ -162245,7 +162350,7 @@ var init_undici = __esm(() => {
|
|
|
162245
162350
|
({ deleteCookie, getCookies, getSetCookies, setCookie, parseCookie } = require_cookies());
|
|
162246
162351
|
({ parseMIMEType, serializeAMimeType } = require_data_url());
|
|
162247
162352
|
({ CloseEvent, ErrorEvent, MessageEvent } = require_events());
|
|
162248
|
-
({ WebSocket:
|
|
162353
|
+
({ WebSocket: WebSocket3, ping } = require_websocket2());
|
|
162249
162354
|
$WebSocketStream = require_websocketstream().WebSocketStream;
|
|
162250
162355
|
$WebSocketError = require_websocketerror().WebSocketError;
|
|
162251
162356
|
$request = makeDispatcher(api.request);
|
|
@@ -162835,6 +162940,7 @@ var init_src4 = __esm(() => {
|
|
|
162835
162940
|
init_ask_question();
|
|
162836
162941
|
init_bash();
|
|
162837
162942
|
init_browser();
|
|
162943
|
+
init_browser_action();
|
|
162838
162944
|
init_code_intelligence();
|
|
162839
162945
|
init_deferred_registry();
|
|
162840
162946
|
init_edit();
|
|
@@ -162862,6 +162968,7 @@ var init_src4 = __esm(() => {
|
|
|
162862
162968
|
init_manage_task();
|
|
162863
162969
|
init_manage_memory();
|
|
162864
162970
|
init_browser();
|
|
162971
|
+
init_browser_action();
|
|
162865
162972
|
init_web_search();
|
|
162866
162973
|
init_diff_preview();
|
|
162867
162974
|
init_deferred_registry();
|
|
@@ -162881,11 +162988,26 @@ var init_src4 = __esm(() => {
|
|
|
162881
162988
|
CodeIntelligenceTool,
|
|
162882
162989
|
ManageMemoryTool
|
|
162883
162990
|
];
|
|
162884
|
-
DEFERRED_TOOLS = [ManageTaskTool, BrowserTool, WebSearchTool];
|
|
162991
|
+
DEFERRED_TOOLS = [ManageTaskTool, BrowserTool, BrowserActionTool, WebSearchTool];
|
|
162885
162992
|
defaultDeferredRegistry.register(BrowserTool, {
|
|
162886
162993
|
category: "web",
|
|
162887
162994
|
keywords: ["browser", "render", "html", "scrape", "page", "url", "browse", "webpage"]
|
|
162888
162995
|
});
|
|
162996
|
+
defaultDeferredRegistry.register(BrowserActionTool, {
|
|
162997
|
+
category: "web",
|
|
162998
|
+
keywords: [
|
|
162999
|
+
"browser_action",
|
|
163000
|
+
"click",
|
|
163001
|
+
"type",
|
|
163002
|
+
"screenshot",
|
|
163003
|
+
"dom",
|
|
163004
|
+
"test",
|
|
163005
|
+
"input",
|
|
163006
|
+
"form",
|
|
163007
|
+
"ui",
|
|
163008
|
+
"localhost"
|
|
163009
|
+
]
|
|
163010
|
+
});
|
|
162889
163011
|
defaultDeferredRegistry.register(WebSearchTool, {
|
|
162890
163012
|
category: "web",
|
|
162891
163013
|
keywords: ["search", "google", "duckduckgo", "tavily", "internet", "docs", "websearch"]
|
|
@@ -169706,13 +169828,210 @@ var init_headless_runner = __esm(() => {
|
|
|
169706
169828
|
};
|
|
169707
169829
|
});
|
|
169708
169830
|
|
|
169831
|
+
// src/utils/workspace-trust.ts
|
|
169832
|
+
import { execSync as execSync2 } from "node:child_process";
|
|
169833
|
+
import fs25 from "node:fs";
|
|
169834
|
+
import os13 from "node:os";
|
|
169835
|
+
import path26 from "node:path";
|
|
169836
|
+
import readline3 from "node:readline";
|
|
169837
|
+
function resolveWorkspaceRoot(targetDir = process.cwd()) {
|
|
169838
|
+
const resolved = path26.resolve(targetDir);
|
|
169839
|
+
try {
|
|
169840
|
+
const stdout = execSync2("git rev-parse --show-toplevel", {
|
|
169841
|
+
cwd: resolved,
|
|
169842
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
169843
|
+
encoding: "utf8"
|
|
169844
|
+
}).trim();
|
|
169845
|
+
if (stdout && fs25.existsSync(stdout)) {
|
|
169846
|
+
return path26.resolve(stdout);
|
|
169847
|
+
}
|
|
169848
|
+
} catch {}
|
|
169849
|
+
let current = resolved;
|
|
169850
|
+
const homeDir = path26.resolve(os13.homedir());
|
|
169851
|
+
while (true) {
|
|
169852
|
+
if (fs25.existsSync(path26.join(current, ".git"))) {
|
|
169853
|
+
return current;
|
|
169854
|
+
}
|
|
169855
|
+
const parent = path26.dirname(current);
|
|
169856
|
+
if (parent === current || current === homeDir) {
|
|
169857
|
+
break;
|
|
169858
|
+
}
|
|
169859
|
+
current = parent;
|
|
169860
|
+
}
|
|
169861
|
+
return resolved;
|
|
169862
|
+
}
|
|
169863
|
+
function isWorkspaceTrusted(workspaceRoot, config) {
|
|
169864
|
+
const canonicalRoot = path26.resolve(workspaceRoot);
|
|
169865
|
+
const homeDir = path26.resolve(os13.homedir());
|
|
169866
|
+
const trustedList = (config.trustedWorkspaces || []).map((p) => path26.resolve(p));
|
|
169867
|
+
for (const trustedPath of trustedList) {
|
|
169868
|
+
if (canonicalRoot === trustedPath) {
|
|
169869
|
+
return true;
|
|
169870
|
+
}
|
|
169871
|
+
if (trustedPath !== "/" && trustedPath !== homeDir) {
|
|
169872
|
+
const rel = path26.relative(trustedPath, canonicalRoot);
|
|
169873
|
+
if (!rel.startsWith("..") && !path26.isAbsolute(rel)) {
|
|
169874
|
+
return true;
|
|
169875
|
+
}
|
|
169876
|
+
}
|
|
169877
|
+
}
|
|
169878
|
+
return false;
|
|
169879
|
+
}
|
|
169880
|
+
async function addTrustedWorkspace(workspaceRoot) {
|
|
169881
|
+
const config = await loadConfig();
|
|
169882
|
+
const canonical = path26.resolve(workspaceRoot);
|
|
169883
|
+
const existing = (config.trustedWorkspaces || []).map((p) => path26.resolve(p));
|
|
169884
|
+
if (!existing.includes(canonical)) {
|
|
169885
|
+
config.trustedWorkspaces = [...existing, canonical];
|
|
169886
|
+
await saveConfig(config);
|
|
169887
|
+
}
|
|
169888
|
+
}
|
|
169889
|
+
async function promptWorkspaceTrust(workspaceRoot) {
|
|
169890
|
+
if (!process.stdin.isTTY) {
|
|
169891
|
+
return false;
|
|
169892
|
+
}
|
|
169893
|
+
const homeDir = path26.resolve(os13.homedir());
|
|
169894
|
+
const isHomeOrRoot = workspaceRoot === homeDir || workspaceRoot === "/";
|
|
169895
|
+
const BRAND = "\x1B[38;2;137;180;248m";
|
|
169896
|
+
const TEXT = "\x1B[38;2;244;244;245m";
|
|
169897
|
+
const MUTED = "\x1B[38;2;170;170;170m";
|
|
169898
|
+
const GRAY = "\x1B[38;2;119;119;119m";
|
|
169899
|
+
const YELLOW = "\x1B[38;2;253;214;99m";
|
|
169900
|
+
const BOLD = "\x1B[1m";
|
|
169901
|
+
const RESET = "\x1B[0m";
|
|
169902
|
+
const options = isHomeOrRoot ? [
|
|
169903
|
+
{ label: "No, exit", value: false },
|
|
169904
|
+
{ label: "Yes, trust folder anyway", value: true }
|
|
169905
|
+
] : [
|
|
169906
|
+
{ label: "Yes, trust folder", value: true },
|
|
169907
|
+
{ label: "No, exit", value: false }
|
|
169908
|
+
];
|
|
169909
|
+
return new Promise((resolve) => {
|
|
169910
|
+
let selectedIndex = 0;
|
|
169911
|
+
let renderedLineCount = 0;
|
|
169912
|
+
const wasRaw = process.stdin.isRaw;
|
|
169913
|
+
if (typeof process.stdin.setRawMode === "function") {
|
|
169914
|
+
process.stdin.setRawMode(true);
|
|
169915
|
+
}
|
|
169916
|
+
process.stdin.resume();
|
|
169917
|
+
readline3.emitKeypressEvents(process.stdin);
|
|
169918
|
+
const cleanup = () => {
|
|
169919
|
+
process.stdin.removeListener("keypress", onKeypress);
|
|
169920
|
+
if (typeof process.stdin.setRawMode === "function" && !wasRaw) {
|
|
169921
|
+
process.stdin.setRawMode(false);
|
|
169922
|
+
}
|
|
169923
|
+
process.stdin.pause();
|
|
169924
|
+
process.stdout.write("\x1B[?25h");
|
|
169925
|
+
};
|
|
169926
|
+
const clearRenderedLines = () => {
|
|
169927
|
+
if (renderedLineCount > 0) {
|
|
169928
|
+
readline3.cursorTo(process.stdout, 0);
|
|
169929
|
+
readline3.moveCursor(process.stdout, 0, -renderedLineCount);
|
|
169930
|
+
readline3.clearScreenDown(process.stdout);
|
|
169931
|
+
}
|
|
169932
|
+
};
|
|
169933
|
+
const render = () => {
|
|
169934
|
+
clearRenderedLines();
|
|
169935
|
+
const lines = [];
|
|
169936
|
+
lines.push("");
|
|
169937
|
+
lines.push(` ${BOLD}${TEXT}Trust workspace?${RESET}`);
|
|
169938
|
+
lines.push("");
|
|
169939
|
+
lines.push(` ${GRAY}Directory${RESET} ${BOLD}${BRAND}${workspaceRoot}${RESET}`);
|
|
169940
|
+
if (isHomeOrRoot) {
|
|
169941
|
+
lines.push(` ${YELLOW}Warning${RESET} ${YELLOW}Home or system root directory. Gives access to all personal files.${RESET}`);
|
|
169942
|
+
} else {
|
|
169943
|
+
lines.push(` ${GRAY}Permission${RESET} ${TEXT}Read, edit, and run commands${RESET}`);
|
|
169944
|
+
}
|
|
169945
|
+
lines.push("");
|
|
169946
|
+
for (let i = 0;i < options.length; i++) {
|
|
169947
|
+
const opt = options[i];
|
|
169948
|
+
if (i === selectedIndex) {
|
|
169949
|
+
lines.push(` ${BRAND}❭${RESET} ${BOLD}${TEXT}${opt.label}${RESET}`);
|
|
169950
|
+
} else {
|
|
169951
|
+
lines.push(` ${MUTED}${opt.label}${RESET}`);
|
|
169952
|
+
}
|
|
169953
|
+
}
|
|
169954
|
+
lines.push("");
|
|
169955
|
+
lines.push(` ${BRAND}Enter${RESET} ${MUTED}confirm${RESET} ${MUTED}·${RESET} ${BRAND}Esc${RESET} ${MUTED}cancel${RESET} ${MUTED}·${RESET} ${BRAND}↑↓${RESET} ${MUTED}navigate${RESET}`);
|
|
169956
|
+
lines.push("");
|
|
169957
|
+
renderedLineCount = lines.length;
|
|
169958
|
+
process.stdout.write(lines.join(`
|
|
169959
|
+
`));
|
|
169960
|
+
};
|
|
169961
|
+
const onKeypress = (str, key) => {
|
|
169962
|
+
if (!key && !str)
|
|
169963
|
+
return;
|
|
169964
|
+
const lowerStr = (str || "").toLowerCase();
|
|
169965
|
+
const keyName = key?.name;
|
|
169966
|
+
if (lowerStr === "y" || keyName === "y") {
|
|
169967
|
+
cleanup();
|
|
169968
|
+
clearRenderedLines();
|
|
169969
|
+
resolve(true);
|
|
169970
|
+
return;
|
|
169971
|
+
}
|
|
169972
|
+
if (lowerStr === "n" || keyName === "n") {
|
|
169973
|
+
cleanup();
|
|
169974
|
+
clearRenderedLines();
|
|
169975
|
+
resolve(false);
|
|
169976
|
+
return;
|
|
169977
|
+
}
|
|
169978
|
+
if (keyName === "up" || keyName === "k") {
|
|
169979
|
+
selectedIndex = Math.max(0, selectedIndex - 1);
|
|
169980
|
+
render();
|
|
169981
|
+
} else if (keyName === "down" || keyName === "j" || keyName === "tab") {
|
|
169982
|
+
selectedIndex = Math.min(options.length - 1, selectedIndex + 1);
|
|
169983
|
+
render();
|
|
169984
|
+
} else if (keyName === "return" || keyName === "enter") {
|
|
169985
|
+
cleanup();
|
|
169986
|
+
clearRenderedLines();
|
|
169987
|
+
resolve(options[selectedIndex].value);
|
|
169988
|
+
} else if (keyName === "escape" || key?.ctrl && keyName === "c") {
|
|
169989
|
+
cleanup();
|
|
169990
|
+
clearRenderedLines();
|
|
169991
|
+
resolve(false);
|
|
169992
|
+
}
|
|
169993
|
+
};
|
|
169994
|
+
process.stdout.write("\x1B[?25l");
|
|
169995
|
+
process.stdin.on("keypress", onKeypress);
|
|
169996
|
+
render();
|
|
169997
|
+
});
|
|
169998
|
+
}
|
|
169999
|
+
async function ensureWorkspaceTrust(options = {}) {
|
|
170000
|
+
const workspaceRoot = resolveWorkspaceRoot(options.targetDir || process.cwd());
|
|
170001
|
+
const config = await loadConfig();
|
|
170002
|
+
if (isWorkspaceTrusted(workspaceRoot, config)) {
|
|
170003
|
+
return;
|
|
170004
|
+
}
|
|
170005
|
+
const isNonInteractive = Boolean(options.isHeadless) || !process.stdin.isTTY || Boolean(process.env.NON_INTERACTIVE) || Boolean(process.env.CI);
|
|
170006
|
+
if (isNonInteractive) {
|
|
170007
|
+
const RED = "\x1B[38;2;252;165;165m";
|
|
170008
|
+
const RESET = "\x1B[0m";
|
|
170009
|
+
console.error(`
|
|
170010
|
+
${RED}Error:${RESET} Workspace "${workspaceRoot}" is not trusted.`);
|
|
170011
|
+
console.error(`Please run "december" interactively first to review and trust this workspace.
|
|
170012
|
+
`);
|
|
170013
|
+
process.exit(1);
|
|
170014
|
+
}
|
|
170015
|
+
const trusted = await promptWorkspaceTrust(workspaceRoot);
|
|
170016
|
+
if (!trusted) {
|
|
170017
|
+
console.log(`
|
|
170018
|
+
Workspace untrusted. Exiting.
|
|
170019
|
+
`);
|
|
170020
|
+
process.exit(0);
|
|
170021
|
+
}
|
|
170022
|
+
await addTrustedWorkspace(workspaceRoot);
|
|
170023
|
+
}
|
|
170024
|
+
var init_workspace_trust = __esm(() => {
|
|
170025
|
+
init_config();
|
|
170026
|
+
});
|
|
170027
|
+
|
|
169709
170028
|
// src/file-session-repository.ts
|
|
169710
170029
|
var exports_file_session_repository = {};
|
|
169711
170030
|
__export(exports_file_session_repository, {
|
|
169712
170031
|
FileSessionRepository: () => FileSessionRepository
|
|
169713
170032
|
});
|
|
169714
|
-
import
|
|
169715
|
-
import
|
|
170033
|
+
import fs26 from "node:fs/promises";
|
|
170034
|
+
import path27 from "node:path";
|
|
169716
170035
|
|
|
169717
170036
|
class FileSessionRepository {
|
|
169718
170037
|
sessionDir;
|
|
@@ -169722,22 +170041,22 @@ class FileSessionRepository {
|
|
|
169722
170041
|
if (sessionDir) {
|
|
169723
170042
|
this.sessionDir = sessionDir;
|
|
169724
170043
|
} else {
|
|
169725
|
-
this.sessionDir =
|
|
169726
|
-
const legacyDir =
|
|
170044
|
+
this.sessionDir = path27.join(getConfigDir(), "sessions");
|
|
170045
|
+
const legacyDir = path27.join(getLegacyConfigDir(), "sessions");
|
|
169727
170046
|
if (legacyDir !== this.sessionDir) {
|
|
169728
170047
|
this.legacySessionDir = legacyDir;
|
|
169729
170048
|
}
|
|
169730
170049
|
}
|
|
169731
170050
|
}
|
|
169732
170051
|
async saveContext(sessionId, messages) {
|
|
169733
|
-
await
|
|
169734
|
-
const historyPath =
|
|
170052
|
+
await fs26.mkdir(this.sessionDir, { recursive: true });
|
|
170053
|
+
const historyPath = path27.join(this.sessionDir, `${sessionId}.jsonl`);
|
|
169735
170054
|
let existing = this.sessionCache[sessionId];
|
|
169736
170055
|
if (!existing) {
|
|
169737
170056
|
existing = {};
|
|
169738
170057
|
this.sessionCache[sessionId] = existing;
|
|
169739
170058
|
try {
|
|
169740
|
-
const data = await
|
|
170059
|
+
const data = await fs26.readFile(historyPath, "utf-8");
|
|
169741
170060
|
const lines = data.split(`
|
|
169742
170061
|
`).filter((l) => l.trim().length > 0);
|
|
169743
170062
|
for (const l of lines) {
|
|
@@ -169761,19 +170080,19 @@ class FileSessionRepository {
|
|
|
169761
170080
|
}
|
|
169762
170081
|
}
|
|
169763
170082
|
if (appendContent) {
|
|
169764
|
-
await
|
|
170083
|
+
await fs26.appendFile(historyPath, appendContent, "utf-8");
|
|
169765
170084
|
}
|
|
169766
170085
|
}
|
|
169767
170086
|
async loadContext(sessionId) {
|
|
169768
|
-
let historyPath =
|
|
170087
|
+
let historyPath = path27.join(this.sessionDir, `${sessionId}.jsonl`);
|
|
169769
170088
|
try {
|
|
169770
170089
|
let data;
|
|
169771
170090
|
try {
|
|
169772
|
-
data = await
|
|
170091
|
+
data = await fs26.readFile(historyPath, "utf-8");
|
|
169773
170092
|
} catch (err) {
|
|
169774
170093
|
if (this.legacySessionDir) {
|
|
169775
|
-
const legacyPath =
|
|
169776
|
-
data = await
|
|
170094
|
+
const legacyPath = path27.join(this.legacySessionDir, `${sessionId}.jsonl`);
|
|
170095
|
+
data = await fs26.readFile(legacyPath, "utf-8");
|
|
169777
170096
|
historyPath = legacyPath;
|
|
169778
170097
|
} else {
|
|
169779
170098
|
throw err;
|
|
@@ -169814,7 +170133,7 @@ class FileSessionRepository {
|
|
|
169814
170133
|
if (msgs.length < lines.length) {
|
|
169815
170134
|
const compacted = msgs.map((m) => JSON.stringify(m)).join(`
|
|
169816
170135
|
`);
|
|
169817
|
-
await
|
|
170136
|
+
await fs26.writeFile(historyPath, compacted, "utf-8").catch(() => {});
|
|
169818
170137
|
}
|
|
169819
170138
|
const cacheObj = {};
|
|
169820
170139
|
for (const msg of msgs) {
|
|
@@ -169828,12 +170147,12 @@ class FileSessionRepository {
|
|
|
169828
170147
|
}
|
|
169829
170148
|
async listSessions() {
|
|
169830
170149
|
try {
|
|
169831
|
-
await
|
|
170150
|
+
await fs26.mkdir(this.sessionDir, { recursive: true });
|
|
169832
170151
|
const sessions = [];
|
|
169833
170152
|
const seenIds = new Set;
|
|
169834
170153
|
const processDirectory = async (dirPath) => {
|
|
169835
170154
|
try {
|
|
169836
|
-
const dirFiles = await
|
|
170155
|
+
const dirFiles = await fs26.readdir(dirPath);
|
|
169837
170156
|
for (const file of dirFiles) {
|
|
169838
170157
|
if (!file.endsWith(".jsonl"))
|
|
169839
170158
|
continue;
|
|
@@ -169841,10 +170160,10 @@ class FileSessionRepository {
|
|
|
169841
170160
|
if (seenIds.has(id))
|
|
169842
170161
|
continue;
|
|
169843
170162
|
seenIds.add(id);
|
|
169844
|
-
const filePath =
|
|
170163
|
+
const filePath = path27.join(dirPath, file);
|
|
169845
170164
|
try {
|
|
169846
|
-
const stat = await
|
|
169847
|
-
const data = await
|
|
170165
|
+
const stat = await fs26.stat(filePath);
|
|
170166
|
+
const data = await fs26.readFile(filePath, "utf-8");
|
|
169848
170167
|
const lines = data.split(`
|
|
169849
170168
|
`).filter((l) => l.trim().length > 0);
|
|
169850
170169
|
let preview = "";
|
|
@@ -169878,20 +170197,20 @@ class FileSessionRepository {
|
|
|
169878
170197
|
}
|
|
169879
170198
|
}
|
|
169880
170199
|
async deleteSession(sessionId) {
|
|
169881
|
-
const historyPath =
|
|
170200
|
+
const historyPath = path27.join(this.sessionDir, `${sessionId}.jsonl`);
|
|
169882
170201
|
try {
|
|
169883
|
-
await
|
|
170202
|
+
await fs26.unlink(historyPath);
|
|
169884
170203
|
} catch (e) {}
|
|
169885
170204
|
if (this.legacySessionDir) {
|
|
169886
170205
|
try {
|
|
169887
|
-
await
|
|
170206
|
+
await fs26.unlink(path27.join(this.legacySessionDir, `${sessionId}.jsonl`));
|
|
169888
170207
|
} catch {}
|
|
169889
170208
|
}
|
|
169890
170209
|
}
|
|
169891
170210
|
async renameSession(oldSessionId, newSessionId) {
|
|
169892
|
-
const oldPath =
|
|
169893
|
-
const newPath =
|
|
169894
|
-
await
|
|
170211
|
+
const oldPath = path27.join(this.sessionDir, `${oldSessionId}.jsonl`);
|
|
170212
|
+
const newPath = path27.join(this.sessionDir, `${newSessionId}.jsonl`);
|
|
170213
|
+
await fs26.rename(oldPath, newPath);
|
|
169895
170214
|
}
|
|
169896
170215
|
}
|
|
169897
170216
|
var init_file_session_repository = __esm(() => {
|
|
@@ -175518,6 +175837,614 @@ var init_task_manager = __esm(() => {
|
|
|
175518
175837
|
}
|
|
175519
175838
|
});
|
|
175520
175839
|
|
|
175840
|
+
// src/utils/browser/detector.ts
|
|
175841
|
+
import { execSync as execSync3 } from "node:child_process";
|
|
175842
|
+
import fs27 from "node:fs/promises";
|
|
175843
|
+
import os14 from "node:os";
|
|
175844
|
+
import path28 from "node:path";
|
|
175845
|
+
async function isExecutable(filePath) {
|
|
175846
|
+
try {
|
|
175847
|
+
await fs27.access(filePath, fs27.constants.X_OK);
|
|
175848
|
+
const stats = await fs27.stat(filePath);
|
|
175849
|
+
return stats.isFile();
|
|
175850
|
+
} catch {
|
|
175851
|
+
return false;
|
|
175852
|
+
}
|
|
175853
|
+
}
|
|
175854
|
+
async function findSystemChrome() {
|
|
175855
|
+
if (cachedChromePath !== undefined) {
|
|
175856
|
+
return cachedChromePath;
|
|
175857
|
+
}
|
|
175858
|
+
const envVars = ["CHROME_PATH", "CHROME_BIN", "CHROMIUM_PATH", "PUPPETEER_EXECUTABLE_PATH"];
|
|
175859
|
+
for (const envVar of envVars) {
|
|
175860
|
+
const val = process.env[envVar];
|
|
175861
|
+
if (val && await isExecutable(val)) {
|
|
175862
|
+
cachedChromePath = val;
|
|
175863
|
+
return val;
|
|
175864
|
+
}
|
|
175865
|
+
}
|
|
175866
|
+
const platform = os14.platform();
|
|
175867
|
+
const candidates = [];
|
|
175868
|
+
if (platform === "linux") {
|
|
175869
|
+
candidates.push("/usr/bin/google-chrome", "/usr/bin/google-chrome-stable", "/usr/bin/chromium", "/usr/bin/chromium-browser", "/snap/bin/chromium", "/usr/bin/brave-browser", "/usr/bin/microsoft-edge", "/usr/bin/microsoft-edge-stable");
|
|
175870
|
+
} else if (platform === "darwin") {
|
|
175871
|
+
const home = os14.homedir();
|
|
175872
|
+
candidates.push("/Applications/Google Chrome.app/Contents/MacOS/Google Chrome", "/Applications/Chromium.app/Contents/MacOS/Chromium", "/Applications/Brave Browser.app/Contents/MacOS/Brave Browser", "/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge", path28.join(home, "Applications/Google Chrome.app/Contents/MacOS/Google Chrome"), path28.join(home, "Applications/Chromium.app/Contents/MacOS/Chromium"));
|
|
175873
|
+
} else if (platform === "win32") {
|
|
175874
|
+
const localAppData = process.env.LOCALAPPDATA || "";
|
|
175875
|
+
const programFiles = process.env.PROGRAMFILES || "C:\\Program Files";
|
|
175876
|
+
const programFilesX86 = process.env["PROGRAMFILES(X86)"] || "C:\\Program Files (x86)";
|
|
175877
|
+
candidates.push(path28.join(programFiles, "Google\\Chrome\\Application\\chrome.exe"), path28.join(programFilesX86, "Google\\Chrome\\Application\\chrome.exe"), path28.join(localAppData, "Google\\Chrome\\Application\\chrome.exe"), path28.join(programFiles, "Microsoft\\Edge\\Application\\msedge.exe"), path28.join(programFilesX86, "Microsoft\\Edge\\Application\\msedge.exe"), path28.join(localAppData, "BraveSoftware\\Brave-Browser\\Application\\brave.exe"));
|
|
175878
|
+
}
|
|
175879
|
+
for (const candidate of candidates) {
|
|
175880
|
+
if (await isExecutable(candidate)) {
|
|
175881
|
+
cachedChromePath = candidate;
|
|
175882
|
+
return candidate;
|
|
175883
|
+
}
|
|
175884
|
+
}
|
|
175885
|
+
const binaryNames = platform === "win32" ? ["chrome.exe", "msedge.exe", "brave.exe"] : [
|
|
175886
|
+
"google-chrome",
|
|
175887
|
+
"google-chrome-stable",
|
|
175888
|
+
"chromium",
|
|
175889
|
+
"chromium-browser",
|
|
175890
|
+
"brave-browser",
|
|
175891
|
+
"microsoft-edge"
|
|
175892
|
+
];
|
|
175893
|
+
const whichCmd = platform === "win32" ? "where" : "which";
|
|
175894
|
+
for (const bin of binaryNames) {
|
|
175895
|
+
try {
|
|
175896
|
+
const out = execSync3(`${whichCmd} ${bin}`, {
|
|
175897
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
175898
|
+
encoding: "utf-8"
|
|
175899
|
+
}).trim();
|
|
175900
|
+
const firstLine = out.split(`
|
|
175901
|
+
`)[0]?.trim();
|
|
175902
|
+
if (firstLine && await isExecutable(firstLine)) {
|
|
175903
|
+
cachedChromePath = firstLine;
|
|
175904
|
+
return firstLine;
|
|
175905
|
+
}
|
|
175906
|
+
} catch {}
|
|
175907
|
+
}
|
|
175908
|
+
cachedChromePath = null;
|
|
175909
|
+
return null;
|
|
175910
|
+
}
|
|
175911
|
+
var cachedChromePath = undefined;
|
|
175912
|
+
var init_detector = () => {};
|
|
175913
|
+
|
|
175914
|
+
// src/utils/browser/cdp-client.ts
|
|
175915
|
+
import { spawn as spawn4 } from "node:child_process";
|
|
175916
|
+
import fs28 from "node:fs/promises";
|
|
175917
|
+
import os15 from "node:os";
|
|
175918
|
+
import path29 from "node:path";
|
|
175919
|
+
|
|
175920
|
+
class CdpBrowserSession {
|
|
175921
|
+
options;
|
|
175922
|
+
chromeProc = null;
|
|
175923
|
+
ws = null;
|
|
175924
|
+
nextId = 1;
|
|
175925
|
+
pendingCommands = new Map;
|
|
175926
|
+
sessionId = null;
|
|
175927
|
+
tmpProfileDir = null;
|
|
175928
|
+
consoleErrors = [];
|
|
175929
|
+
networkErrors = [];
|
|
175930
|
+
isLoaded = false;
|
|
175931
|
+
constructor(options) {
|
|
175932
|
+
this.options = options;
|
|
175933
|
+
}
|
|
175934
|
+
async launch() {
|
|
175935
|
+
this.tmpProfileDir = path29.join(os15.tmpdir(), `december-chrome-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`);
|
|
175936
|
+
await fs28.mkdir(this.tmpProfileDir, { recursive: true });
|
|
175937
|
+
const isHeadless = this.options.headless ?? (process.env.DECEMBER_HEADED !== "1" && process.env.HEADED !== "1");
|
|
175938
|
+
const args = [
|
|
175939
|
+
...isHeadless ? ["--headless=new"] : [],
|
|
175940
|
+
"--disable-gpu",
|
|
175941
|
+
"--no-sandbox",
|
|
175942
|
+
"--disable-dev-shm-usage",
|
|
175943
|
+
"--remote-debugging-port=0",
|
|
175944
|
+
"--hide-scrollbars",
|
|
175945
|
+
"--window-size=1280,800",
|
|
175946
|
+
`--user-data-dir=${this.tmpProfileDir}`,
|
|
175947
|
+
"about:blank"
|
|
175948
|
+
];
|
|
175949
|
+
const proc = spawn4(this.options.chromePath, args, {
|
|
175950
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
175951
|
+
});
|
|
175952
|
+
this.chromeProc = proc;
|
|
175953
|
+
const wsUrl = await new Promise((resolve, reject) => {
|
|
175954
|
+
let buffer = "";
|
|
175955
|
+
const timeout = setTimeout(() => {
|
|
175956
|
+
reject(new Error("Timeout waiting for Chrome DevTools WebSocket URL."));
|
|
175957
|
+
}, this.options.timeoutMs || 15000);
|
|
175958
|
+
const onData = (chunk) => {
|
|
175959
|
+
buffer += chunk.toString();
|
|
175960
|
+
const match = buffer.match(/DevTools listening on (ws:\/\/[^\s]+)/);
|
|
175961
|
+
if (match && match[1]) {
|
|
175962
|
+
clearTimeout(timeout);
|
|
175963
|
+
proc.stderr?.off("data", onData);
|
|
175964
|
+
resolve(match[1]);
|
|
175965
|
+
}
|
|
175966
|
+
};
|
|
175967
|
+
proc.stderr?.on("data", onData);
|
|
175968
|
+
proc.on("error", (err) => {
|
|
175969
|
+
clearTimeout(timeout);
|
|
175970
|
+
reject(err);
|
|
175971
|
+
});
|
|
175972
|
+
proc.on("exit", (code) => {
|
|
175973
|
+
clearTimeout(timeout);
|
|
175974
|
+
reject(new Error(`Chrome exited prematurely with code ${code}.`));
|
|
175975
|
+
});
|
|
175976
|
+
});
|
|
175977
|
+
await this.connectWs(wsUrl);
|
|
175978
|
+
const createTargetRes = await this.sendCommand("Target.createTarget", {
|
|
175979
|
+
url: "about:blank"
|
|
175980
|
+
});
|
|
175981
|
+
const targetId = createTargetRes.targetId;
|
|
175982
|
+
const attachRes = await this.sendCommand("Target.attachToTarget", {
|
|
175983
|
+
targetId,
|
|
175984
|
+
flatten: true
|
|
175985
|
+
});
|
|
175986
|
+
this.sessionId = attachRes.sessionId;
|
|
175987
|
+
await this.sendSessionCommand("Page.enable");
|
|
175988
|
+
await this.sendSessionCommand("Runtime.enable");
|
|
175989
|
+
await this.sendSessionCommand("Network.enable");
|
|
175990
|
+
}
|
|
175991
|
+
async connectWs(wsUrl) {
|
|
175992
|
+
return new Promise((resolve, reject) => {
|
|
175993
|
+
const ws = new WebSocket(wsUrl);
|
|
175994
|
+
this.ws = ws;
|
|
175995
|
+
ws.onopen = () => resolve();
|
|
175996
|
+
ws.onerror = (err) => reject(err);
|
|
175997
|
+
ws.onmessage = (event) => {
|
|
175998
|
+
try {
|
|
175999
|
+
const msg = JSON.parse(event.data.toString());
|
|
176000
|
+
if (typeof msg.id === "number") {
|
|
176001
|
+
const pending = this.pendingCommands.get(msg.id);
|
|
176002
|
+
if (pending) {
|
|
176003
|
+
this.pendingCommands.delete(msg.id);
|
|
176004
|
+
if (msg.error) {
|
|
176005
|
+
pending.reject(new Error(msg.error.message || "CDP Error"));
|
|
176006
|
+
} else {
|
|
176007
|
+
pending.resolve(msg.result);
|
|
176008
|
+
}
|
|
176009
|
+
}
|
|
176010
|
+
return;
|
|
176011
|
+
}
|
|
176012
|
+
this.handleEvent(msg);
|
|
176013
|
+
} catch {}
|
|
176014
|
+
};
|
|
176015
|
+
});
|
|
176016
|
+
}
|
|
176017
|
+
handleEvent(msg) {
|
|
176018
|
+
const method = msg.method;
|
|
176019
|
+
if (method === "Page.loadEventFired" || method === "Page.domContentEventFired") {
|
|
176020
|
+
this.isLoaded = true;
|
|
176021
|
+
} else if (method === "Runtime.exceptionThrown") {
|
|
176022
|
+
const details = msg.params?.exceptionDetails;
|
|
176023
|
+
const desc = details?.exception?.description || details?.text || "Unknown runtime exception";
|
|
176024
|
+
this.consoleErrors.push(`Exception: ${desc}`);
|
|
176025
|
+
} else if (method === "Runtime.consoleAPICalled") {
|
|
176026
|
+
const type = msg.params?.type;
|
|
176027
|
+
if (type === "error" || type === "warning") {
|
|
176028
|
+
const args = (msg.params?.args || []).map((a) => a.value ?? a.description ?? "").join(" ");
|
|
176029
|
+
this.consoleErrors.push(`[console.${type}] ${args}`);
|
|
176030
|
+
}
|
|
176031
|
+
} else if (method === "Network.responseReceived") {
|
|
176032
|
+
const res = msg.params?.response;
|
|
176033
|
+
if (res && typeof res.status === "number" && res.status >= 400) {
|
|
176034
|
+
this.networkErrors.push(`HTTP ${res.status} ${res.statusText || ""} - ${res.url}`);
|
|
176035
|
+
}
|
|
176036
|
+
} else if (method === "Network.loadingFailed") {
|
|
176037
|
+
const err = msg.params;
|
|
176038
|
+
if (err) {
|
|
176039
|
+
this.networkErrors.push(`Network failure: ${err.errorText || "Unknown error"} (${err.type || "request"})`);
|
|
176040
|
+
}
|
|
176041
|
+
}
|
|
176042
|
+
}
|
|
176043
|
+
sendCommand(method, params) {
|
|
176044
|
+
return new Promise((resolve, reject) => {
|
|
176045
|
+
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
|
|
176046
|
+
return reject(new Error("WebSocket is not open"));
|
|
176047
|
+
}
|
|
176048
|
+
const id = this.nextId++;
|
|
176049
|
+
this.pendingCommands.set(id, { resolve, reject });
|
|
176050
|
+
this.ws.send(JSON.stringify({ id, method, params }));
|
|
176051
|
+
});
|
|
176052
|
+
}
|
|
176053
|
+
sendSessionCommand(method, params) {
|
|
176054
|
+
return new Promise((resolve, reject) => {
|
|
176055
|
+
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
|
|
176056
|
+
return reject(new Error("WebSocket is not open"));
|
|
176057
|
+
}
|
|
176058
|
+
const id = this.nextId++;
|
|
176059
|
+
this.pendingCommands.set(id, { resolve, reject });
|
|
176060
|
+
const payload = { id, method, params };
|
|
176061
|
+
if (this.sessionId) {
|
|
176062
|
+
payload.sessionId = this.sessionId;
|
|
176063
|
+
}
|
|
176064
|
+
this.ws.send(JSON.stringify(payload));
|
|
176065
|
+
});
|
|
176066
|
+
}
|
|
176067
|
+
async navigate(url, timeoutMs = 12000) {
|
|
176068
|
+
this.consoleErrors = [];
|
|
176069
|
+
this.networkErrors = [];
|
|
176070
|
+
this.isLoaded = false;
|
|
176071
|
+
await this.sendSessionCommand("Page.navigate", { url });
|
|
176072
|
+
const startTime = Date.now();
|
|
176073
|
+
while (!this.isLoaded && Date.now() - startTime < timeoutMs) {
|
|
176074
|
+
await new Promise((r) => setTimeout(r, 100));
|
|
176075
|
+
}
|
|
176076
|
+
await new Promise((r) => setTimeout(r, 300));
|
|
176077
|
+
const evalRes = await this.sendSessionCommand("Runtime.evaluate", {
|
|
176078
|
+
expression: '(function() { return document.body ? (document.body.innerText || document.documentElement.innerText || "") : ""; })()',
|
|
176079
|
+
returnByValue: true
|
|
176080
|
+
});
|
|
176081
|
+
const text = evalRes?.result?.value || "";
|
|
176082
|
+
return {
|
|
176083
|
+
text: text.trim(),
|
|
176084
|
+
consoleErrors: [...this.consoleErrors],
|
|
176085
|
+
networkErrors: [...this.networkErrors]
|
|
176086
|
+
};
|
|
176087
|
+
}
|
|
176088
|
+
async click(selector) {
|
|
176089
|
+
const expression = `
|
|
176090
|
+
(function(sel) {
|
|
176091
|
+
var el = document.querySelector(sel);
|
|
176092
|
+
if (!el) {
|
|
176093
|
+
var buttons = Array.from(document.querySelectorAll('button, a, input[type=button], input[type=submit], [role=button]'));
|
|
176094
|
+
el = buttons.find(function(b) {
|
|
176095
|
+
return (b.textContent || '').trim().toLowerCase() === sel.trim().toLowerCase();
|
|
176096
|
+
});
|
|
176097
|
+
}
|
|
176098
|
+
if (!el) {
|
|
176099
|
+
return { success: false, error: 'Could not find element matching: ' + sel };
|
|
176100
|
+
}
|
|
176101
|
+
el.scrollIntoView({ behavior: 'instant', block: 'center' });
|
|
176102
|
+
el.click();
|
|
176103
|
+
return {
|
|
176104
|
+
success: true,
|
|
176105
|
+
tagName: el.tagName,
|
|
176106
|
+
text: (el.textContent || '').trim().slice(0, 50)
|
|
176107
|
+
};
|
|
176108
|
+
})(${JSON.stringify(selector)})
|
|
176109
|
+
`;
|
|
176110
|
+
const evalRes = await this.sendSessionCommand("Runtime.evaluate", {
|
|
176111
|
+
expression,
|
|
176112
|
+
returnByValue: true
|
|
176113
|
+
});
|
|
176114
|
+
const result = evalRes?.result?.value;
|
|
176115
|
+
if (!result || !result.success) {
|
|
176116
|
+
return {
|
|
176117
|
+
success: false,
|
|
176118
|
+
output: "",
|
|
176119
|
+
error: result?.error || `Element "${selector}" not found.`,
|
|
176120
|
+
consoleErrors: [...this.consoleErrors],
|
|
176121
|
+
networkErrors: [...this.networkErrors]
|
|
176122
|
+
};
|
|
176123
|
+
}
|
|
176124
|
+
await new Promise((r) => setTimeout(r, 300));
|
|
176125
|
+
return {
|
|
176126
|
+
success: true,
|
|
176127
|
+
output: `Clicked <${result.tagName}>: "${result.text || selector}"`,
|
|
176128
|
+
consoleErrors: [...this.consoleErrors],
|
|
176129
|
+
networkErrors: [...this.networkErrors]
|
|
176130
|
+
};
|
|
176131
|
+
}
|
|
176132
|
+
async type(selector, text) {
|
|
176133
|
+
const expression = `
|
|
176134
|
+
(function(sel, val) {
|
|
176135
|
+
var el = document.querySelector(sel);
|
|
176136
|
+
if (!el) {
|
|
176137
|
+
var inputs = Array.from(document.querySelectorAll('input, textarea'));
|
|
176138
|
+
el = inputs.find(function(i) {
|
|
176139
|
+
return i.name === sel || i.id === sel || i.placeholder === sel;
|
|
176140
|
+
});
|
|
176141
|
+
}
|
|
176142
|
+
if (!el) {
|
|
176143
|
+
return { success: false, error: 'Could not find input element matching: ' + sel };
|
|
176144
|
+
}
|
|
176145
|
+
el.focus();
|
|
176146
|
+
el.value = val;
|
|
176147
|
+
el.dispatchEvent(new Event('input', { bubbles: true }));
|
|
176148
|
+
el.dispatchEvent(new Event('change', { bubbles: true }));
|
|
176149
|
+
return { success: true, tagName: el.tagName, value: el.value };
|
|
176150
|
+
})(${JSON.stringify(selector)}, ${JSON.stringify(text)})
|
|
176151
|
+
`;
|
|
176152
|
+
const evalRes = await this.sendSessionCommand("Runtime.evaluate", {
|
|
176153
|
+
expression,
|
|
176154
|
+
returnByValue: true
|
|
176155
|
+
});
|
|
176156
|
+
const result = evalRes?.result?.value;
|
|
176157
|
+
if (!result || !result.success) {
|
|
176158
|
+
return {
|
|
176159
|
+
success: false,
|
|
176160
|
+
output: "",
|
|
176161
|
+
error: result?.error || `Input element "${selector}" not found.`,
|
|
176162
|
+
consoleErrors: [...this.consoleErrors],
|
|
176163
|
+
networkErrors: [...this.networkErrors]
|
|
176164
|
+
};
|
|
176165
|
+
}
|
|
176166
|
+
return {
|
|
176167
|
+
success: true,
|
|
176168
|
+
output: `Typed "${text}" into <${result.tagName}> (${selector})`,
|
|
176169
|
+
consoleErrors: [...this.consoleErrors],
|
|
176170
|
+
networkErrors: [...this.networkErrors]
|
|
176171
|
+
};
|
|
176172
|
+
}
|
|
176173
|
+
async screenshot(fullPage = false, outputPath) {
|
|
176174
|
+
const params = { format: "png" };
|
|
176175
|
+
if (fullPage) {
|
|
176176
|
+
params.captureBeyondViewport = true;
|
|
176177
|
+
}
|
|
176178
|
+
const res = await this.sendSessionCommand("Page.captureScreenshot", params);
|
|
176179
|
+
const base64Data = res?.data;
|
|
176180
|
+
if (!base64Data) {
|
|
176181
|
+
return {
|
|
176182
|
+
success: false,
|
|
176183
|
+
output: "",
|
|
176184
|
+
error: "Failed to capture screenshot data from Chrome."
|
|
176185
|
+
};
|
|
176186
|
+
}
|
|
176187
|
+
const targetFile = outputPath || path29.join(os15.tmpdir(), `december-screenshot-${Date.now()}-${Math.random().toString(36).slice(2, 6)}.png`);
|
|
176188
|
+
await fs28.writeFile(targetFile, Buffer.from(base64Data, "base64"));
|
|
176189
|
+
return {
|
|
176190
|
+
success: true,
|
|
176191
|
+
output: `Screenshot captured successfully.`,
|
|
176192
|
+
screenshotPath: targetFile,
|
|
176193
|
+
screenshotBase64: base64Data,
|
|
176194
|
+
consoleErrors: [...this.consoleErrors],
|
|
176195
|
+
networkErrors: [...this.networkErrors]
|
|
176196
|
+
};
|
|
176197
|
+
}
|
|
176198
|
+
async getConsoleErrors() {
|
|
176199
|
+
return {
|
|
176200
|
+
consoleErrors: [...this.consoleErrors],
|
|
176201
|
+
networkErrors: [...this.networkErrors]
|
|
176202
|
+
};
|
|
176203
|
+
}
|
|
176204
|
+
async close() {
|
|
176205
|
+
if (this.ws) {
|
|
176206
|
+
try {
|
|
176207
|
+
this.ws.close();
|
|
176208
|
+
} catch {}
|
|
176209
|
+
this.ws = null;
|
|
176210
|
+
}
|
|
176211
|
+
if (this.chromeProc) {
|
|
176212
|
+
try {
|
|
176213
|
+
this.chromeProc.kill("SIGTERM");
|
|
176214
|
+
setTimeout(() => {
|
|
176215
|
+
if (this.chromeProc && !this.chromeProc.killed) {
|
|
176216
|
+
this.chromeProc.kill("SIGKILL");
|
|
176217
|
+
}
|
|
176218
|
+
}, 1000);
|
|
176219
|
+
} catch {}
|
|
176220
|
+
this.chromeProc = null;
|
|
176221
|
+
}
|
|
176222
|
+
if (this.tmpProfileDir) {
|
|
176223
|
+
try {
|
|
176224
|
+
await fs28.rm(this.tmpProfileDir, { recursive: true, force: true });
|
|
176225
|
+
} catch {}
|
|
176226
|
+
this.tmpProfileDir = null;
|
|
176227
|
+
}
|
|
176228
|
+
}
|
|
176229
|
+
}
|
|
176230
|
+
var init_cdp_client = () => {};
|
|
176231
|
+
|
|
176232
|
+
// src/utils/browser/browser-runner.ts
|
|
176233
|
+
class BrowserRunner {
|
|
176234
|
+
activeSession = null;
|
|
176235
|
+
cleanupRegistered = false;
|
|
176236
|
+
registerCleanup() {
|
|
176237
|
+
if (this.cleanupRegistered)
|
|
176238
|
+
return;
|
|
176239
|
+
this.cleanupRegistered = true;
|
|
176240
|
+
const cleanup = () => {
|
|
176241
|
+
if (this.activeSession) {
|
|
176242
|
+
this.activeSession.close().catch(() => {});
|
|
176243
|
+
this.activeSession = null;
|
|
176244
|
+
}
|
|
176245
|
+
};
|
|
176246
|
+
process.once("exit", cleanup);
|
|
176247
|
+
process.once("SIGINT", cleanup);
|
|
176248
|
+
process.once("SIGTERM", cleanup);
|
|
176249
|
+
}
|
|
176250
|
+
async getSession() {
|
|
176251
|
+
if (this.activeSession) {
|
|
176252
|
+
return this.activeSession;
|
|
176253
|
+
}
|
|
176254
|
+
const chromePath = await findSystemChrome();
|
|
176255
|
+
if (!chromePath) {
|
|
176256
|
+
return null;
|
|
176257
|
+
}
|
|
176258
|
+
try {
|
|
176259
|
+
await Promise.resolve().then(() => init_config());
|
|
176260
|
+
const config = await loadConfig().catch(() => null);
|
|
176261
|
+
const hasDisplay = process.platform !== "linux" || Boolean(process.env.DISPLAY || process.env.WAYLAND_DISPLAY);
|
|
176262
|
+
const isVisible = hasDisplay && config?.browserVisible !== false && process.env.HEADED !== "0" && process.env.DECEMBER_HEADED !== "0";
|
|
176263
|
+
const session = new CdpBrowserSession({
|
|
176264
|
+
chromePath,
|
|
176265
|
+
headless: !isVisible
|
|
176266
|
+
});
|
|
176267
|
+
await session.launch();
|
|
176268
|
+
this.activeSession = session;
|
|
176269
|
+
this.registerCleanup();
|
|
176270
|
+
return session;
|
|
176271
|
+
} catch {
|
|
176272
|
+
return null;
|
|
176273
|
+
}
|
|
176274
|
+
}
|
|
176275
|
+
async staticFallbackFetch(url) {
|
|
176276
|
+
try {
|
|
176277
|
+
const res = await fetch(url, {
|
|
176278
|
+
headers: {
|
|
176279
|
+
"User-Agent": "Mozilla/5.0 (compatible; DecemberAgent/1.0)"
|
|
176280
|
+
}
|
|
176281
|
+
});
|
|
176282
|
+
const html = await res.text();
|
|
176283
|
+
if (!res.ok) {
|
|
176284
|
+
return {
|
|
176285
|
+
text: "",
|
|
176286
|
+
error: `HTTP Error (${res.status}): ${html}`,
|
|
176287
|
+
networkErrors: [`HTTP ${res.status} - ${url}`]
|
|
176288
|
+
};
|
|
176289
|
+
}
|
|
176290
|
+
const cleanText = html.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, "").replace(/<style\b[^<]*(?:(?!<\/style>)<[^<]*)*<\/style>/gi, "").replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
|
|
176291
|
+
const notice = `
|
|
176292
|
+
|
|
176293
|
+
[Note: Local Chrome/Chromium not detected. Displaying static HTML text. Install Chrome or Chromium for client-side JavaScript rendering and interactive actions.]`;
|
|
176294
|
+
return {
|
|
176295
|
+
text: cleanText + notice,
|
|
176296
|
+
consoleErrors: [],
|
|
176297
|
+
networkErrors: []
|
|
176298
|
+
};
|
|
176299
|
+
} catch (err) {
|
|
176300
|
+
return {
|
|
176301
|
+
text: "",
|
|
176302
|
+
error: err.message,
|
|
176303
|
+
networkErrors: [`Network request failed: ${err.message}`]
|
|
176304
|
+
};
|
|
176305
|
+
}
|
|
176306
|
+
}
|
|
176307
|
+
navigate = async (url) => {
|
|
176308
|
+
const session = await this.getSession();
|
|
176309
|
+
if (session) {
|
|
176310
|
+
try {
|
|
176311
|
+
return await session.navigate(url);
|
|
176312
|
+
} catch {}
|
|
176313
|
+
}
|
|
176314
|
+
return this.staticFallbackFetch(url);
|
|
176315
|
+
};
|
|
176316
|
+
action = async (params) => {
|
|
176317
|
+
const { action, url, selector, text, fullPage } = params;
|
|
176318
|
+
if (action === "navigate") {
|
|
176319
|
+
if (!url) {
|
|
176320
|
+
return {
|
|
176321
|
+
success: false,
|
|
176322
|
+
action: "navigate",
|
|
176323
|
+
error: 'Action "navigate" requires a valid "url" parameter.'
|
|
176324
|
+
};
|
|
176325
|
+
}
|
|
176326
|
+
const navResult = await this.navigate(url);
|
|
176327
|
+
if (navResult.error) {
|
|
176328
|
+
return {
|
|
176329
|
+
success: false,
|
|
176330
|
+
action: "navigate",
|
|
176331
|
+
error: navResult.error,
|
|
176332
|
+
networkErrors: navResult.networkErrors
|
|
176333
|
+
};
|
|
176334
|
+
}
|
|
176335
|
+
return {
|
|
176336
|
+
success: true,
|
|
176337
|
+
action: "navigate",
|
|
176338
|
+
text: navResult.text,
|
|
176339
|
+
consoleErrors: navResult.consoleErrors,
|
|
176340
|
+
networkErrors: navResult.networkErrors
|
|
176341
|
+
};
|
|
176342
|
+
}
|
|
176343
|
+
if (action === "get_console_errors") {
|
|
176344
|
+
if (this.activeSession) {
|
|
176345
|
+
const errors = await this.activeSession.getConsoleErrors();
|
|
176346
|
+
const count = errors.consoleErrors.length + errors.networkErrors.length;
|
|
176347
|
+
return {
|
|
176348
|
+
success: true,
|
|
176349
|
+
action: "get_console_errors",
|
|
176350
|
+
output: count > 0 ? `Captured ${errors.consoleErrors.length} console error(s) and ${errors.networkErrors.length} network error(s).` : "No console or network errors detected.",
|
|
176351
|
+
consoleErrors: errors.consoleErrors,
|
|
176352
|
+
networkErrors: errors.networkErrors
|
|
176353
|
+
};
|
|
176354
|
+
}
|
|
176355
|
+
return {
|
|
176356
|
+
success: true,
|
|
176357
|
+
action: "get_console_errors",
|
|
176358
|
+
output: "No active browser session running."
|
|
176359
|
+
};
|
|
176360
|
+
}
|
|
176361
|
+
const session = await this.getSession();
|
|
176362
|
+
if (!session) {
|
|
176363
|
+
return {
|
|
176364
|
+
success: false,
|
|
176365
|
+
action,
|
|
176366
|
+
error: `Interactive browser action "${action}" requires Google Chrome or Chromium. Please install Chrome or Chromium, or set the CHROME_PATH environment variable.`
|
|
176367
|
+
};
|
|
176368
|
+
}
|
|
176369
|
+
switch (action) {
|
|
176370
|
+
case "click": {
|
|
176371
|
+
if (!selector) {
|
|
176372
|
+
return {
|
|
176373
|
+
success: false,
|
|
176374
|
+
action: "click",
|
|
176375
|
+
error: 'Action "click" requires a "selector" parameter.'
|
|
176376
|
+
};
|
|
176377
|
+
}
|
|
176378
|
+
const res = await session.click(selector);
|
|
176379
|
+
return {
|
|
176380
|
+
success: res.success,
|
|
176381
|
+
action: "click",
|
|
176382
|
+
output: res.output,
|
|
176383
|
+
error: res.error,
|
|
176384
|
+
consoleErrors: res.consoleErrors,
|
|
176385
|
+
networkErrors: res.networkErrors
|
|
176386
|
+
};
|
|
176387
|
+
}
|
|
176388
|
+
case "type": {
|
|
176389
|
+
if (!selector) {
|
|
176390
|
+
return {
|
|
176391
|
+
success: false,
|
|
176392
|
+
action: "type",
|
|
176393
|
+
error: 'Action "type" requires a "selector" parameter.'
|
|
176394
|
+
};
|
|
176395
|
+
}
|
|
176396
|
+
const res = await session.type(selector, text || "");
|
|
176397
|
+
return {
|
|
176398
|
+
success: res.success,
|
|
176399
|
+
action: "type",
|
|
176400
|
+
output: res.output,
|
|
176401
|
+
error: res.error,
|
|
176402
|
+
consoleErrors: res.consoleErrors,
|
|
176403
|
+
networkErrors: res.networkErrors
|
|
176404
|
+
};
|
|
176405
|
+
}
|
|
176406
|
+
case "screenshot": {
|
|
176407
|
+
const res = await session.screenshot(Boolean(fullPage));
|
|
176408
|
+
return {
|
|
176409
|
+
success: res.success,
|
|
176410
|
+
action: "screenshot",
|
|
176411
|
+
output: res.output,
|
|
176412
|
+
screenshotPath: res.screenshotPath,
|
|
176413
|
+
screenshotBase64: res.screenshotBase64,
|
|
176414
|
+
error: res.error,
|
|
176415
|
+
consoleErrors: res.consoleErrors,
|
|
176416
|
+
networkErrors: res.networkErrors
|
|
176417
|
+
};
|
|
176418
|
+
}
|
|
176419
|
+
default:
|
|
176420
|
+
return {
|
|
176421
|
+
success: false,
|
|
176422
|
+
action,
|
|
176423
|
+
error: `Unsupported browser action: ${action}`
|
|
176424
|
+
};
|
|
176425
|
+
}
|
|
176426
|
+
};
|
|
176427
|
+
close = async () => {
|
|
176428
|
+
if (this.activeSession) {
|
|
176429
|
+
await this.activeSession.close();
|
|
176430
|
+
this.activeSession = null;
|
|
176431
|
+
}
|
|
176432
|
+
};
|
|
176433
|
+
}
|
|
176434
|
+
var browserRunner;
|
|
176435
|
+
var init_browser_runner = __esm(() => {
|
|
176436
|
+
init_cdp_client();
|
|
176437
|
+
init_detector();
|
|
176438
|
+
browserRunner = new BrowserRunner;
|
|
176439
|
+
});
|
|
176440
|
+
|
|
176441
|
+
// src/utils/browser/index.ts
|
|
176442
|
+
var init_browser2 = __esm(() => {
|
|
176443
|
+
init_detector();
|
|
176444
|
+
init_cdp_client();
|
|
176445
|
+
init_browser_runner();
|
|
176446
|
+
});
|
|
176447
|
+
|
|
175521
176448
|
// src/local-operations.ts
|
|
175522
176449
|
var exports_local_operations = {};
|
|
175523
176450
|
__export(exports_local_operations, {
|
|
@@ -175525,22 +176452,22 @@ __export(exports_local_operations, {
|
|
|
175525
176452
|
localOperations: () => localOperations,
|
|
175526
176453
|
setActiveScopeDir: () => setActiveScopeDir
|
|
175527
176454
|
});
|
|
175528
|
-
import { exec as exec4, spawn as
|
|
176455
|
+
import { exec as exec4, spawn as spawn5 } from "node:child_process";
|
|
175529
176456
|
import nodeFs from "node:fs";
|
|
175530
|
-
import
|
|
175531
|
-
import
|
|
176457
|
+
import fs29 from "node:fs/promises";
|
|
176458
|
+
import path30 from "node:path";
|
|
175532
176459
|
import { promisify as promisify4 } from "node:util";
|
|
175533
176460
|
function setActiveScopeDir(dir) {
|
|
175534
176461
|
activeScopeDir = dir;
|
|
175535
176462
|
}
|
|
175536
176463
|
function getScopedCwd() {
|
|
175537
176464
|
if (activeScopeDir) {
|
|
175538
|
-
return
|
|
176465
|
+
return path30.resolve(process.cwd(), activeScopeDir);
|
|
175539
176466
|
}
|
|
175540
176467
|
return process.cwd();
|
|
175541
176468
|
}
|
|
175542
176469
|
function isTypeScriptProject(workspaceDir) {
|
|
175543
|
-
return nodeFs.existsSync(
|
|
176470
|
+
return nodeFs.existsSync(path30.join(workspaceDir, "tsconfig.json")) || nodeFs.existsSync(path30.join(workspaceDir, "package.json"));
|
|
175544
176471
|
}
|
|
175545
176472
|
async function getOrLaunchLspClient(customWorkspaceDir) {
|
|
175546
176473
|
const workspaceDir = customWorkspaceDir || getScopedCwd();
|
|
@@ -175575,6 +176502,7 @@ var init_local_operations = __esm(() => {
|
|
|
175575
176502
|
init_src();
|
|
175576
176503
|
init_src4();
|
|
175577
176504
|
init_task_manager();
|
|
176505
|
+
init_browser2();
|
|
175578
176506
|
import_fast_glob = __toESM(require_out4(), 1);
|
|
175579
176507
|
execAsync2 = promisify4(exec4);
|
|
175580
176508
|
localBashOps = createLocalBashOperations();
|
|
@@ -175587,7 +176515,7 @@ var init_local_operations = __esm(() => {
|
|
|
175587
176515
|
const fallbackTimeoutMs = actualOptions.waitMsBeforeAsync ?? DEFAULT_BG_TIMEOUT_MS;
|
|
175588
176516
|
const serverDelayMs = actualOptions.serverReadyDelayMs ?? DEFAULT_SERVER_READY_DELAY_MS;
|
|
175589
176517
|
return new Promise((resolve, reject) => {
|
|
175590
|
-
const child =
|
|
176518
|
+
const child = spawn5(command, {
|
|
175591
176519
|
cwd: targetCwd,
|
|
175592
176520
|
detached: process.platform !== "win32",
|
|
175593
176521
|
env: actualOptions.env ?? process.env,
|
|
@@ -175717,19 +176645,19 @@ Failed to start process: ${err?.message || err}
|
|
|
175717
176645
|
fs: {
|
|
175718
176646
|
readFile: async (filepath) => {
|
|
175719
176647
|
const root = getScopedCwd();
|
|
175720
|
-
const absolutePath =
|
|
175721
|
-
return
|
|
176648
|
+
const absolutePath = path30.isAbsolute(filepath) ? filepath : path30.resolve(root, filepath);
|
|
176649
|
+
return fs29.readFile(absolutePath, "utf8");
|
|
175722
176650
|
},
|
|
175723
176651
|
writeFile: async (filepath, content) => {
|
|
175724
176652
|
const root = getScopedCwd();
|
|
175725
|
-
const absolutePath =
|
|
175726
|
-
await
|
|
175727
|
-
await
|
|
176653
|
+
const absolutePath = path30.isAbsolute(filepath) ? filepath : path30.resolve(root, filepath);
|
|
176654
|
+
await fs29.mkdir(path30.dirname(absolutePath), { recursive: true });
|
|
176655
|
+
await fs29.writeFile(absolutePath, content, "utf8");
|
|
175728
176656
|
},
|
|
175729
176657
|
readdir: async (dirPath) => {
|
|
175730
176658
|
const root = getScopedCwd();
|
|
175731
|
-
const absolutePath =
|
|
175732
|
-
const entries = await
|
|
176659
|
+
const absolutePath = path30.isAbsolute(dirPath) ? dirPath : path30.resolve(root, dirPath);
|
|
176660
|
+
const entries = await fs29.readdir(absolutePath, { withFileTypes: true });
|
|
175733
176661
|
const ignores = getWorkspaceIgnores(root);
|
|
175734
176662
|
return entries.filter((entry) => !isPathIgnored(entry.name, ignores)).map((entry) => {
|
|
175735
176663
|
const type = entry.isDirectory() ? "DIR " : "FILE";
|
|
@@ -175738,14 +176666,14 @@ Failed to start process: ${err?.message || err}
|
|
|
175738
176666
|
},
|
|
175739
176667
|
mkdir: async (dirPath, options) => {
|
|
175740
176668
|
const root = getScopedCwd();
|
|
175741
|
-
const absolutePath =
|
|
175742
|
-
await
|
|
176669
|
+
const absolutePath = path30.isAbsolute(dirPath) ? dirPath : path30.resolve(root, dirPath);
|
|
176670
|
+
await fs29.mkdir(absolutePath, options);
|
|
175743
176671
|
},
|
|
175744
176672
|
exists: async (filepath) => {
|
|
175745
176673
|
const root = getScopedCwd();
|
|
175746
|
-
const absolutePath =
|
|
176674
|
+
const absolutePath = path30.isAbsolute(filepath) ? filepath : path30.resolve(root, filepath);
|
|
175747
176675
|
try {
|
|
175748
|
-
await
|
|
176676
|
+
await fs29.access(absolutePath);
|
|
175749
176677
|
return true;
|
|
175750
176678
|
} catch {
|
|
175751
176679
|
return false;
|
|
@@ -175755,7 +176683,7 @@ Failed to start process: ${err?.message || err}
|
|
|
175755
176683
|
search: {
|
|
175756
176684
|
find: async (dirPath, query) => {
|
|
175757
176685
|
const root = getScopedCwd();
|
|
175758
|
-
const targetDir =
|
|
176686
|
+
const targetDir = path30.isAbsolute(dirPath) ? dirPath : path30.resolve(root, dirPath);
|
|
175759
176687
|
const ignores = getWorkspaceIgnores(root);
|
|
175760
176688
|
const files = await import_fast_glob.default([query], {
|
|
175761
176689
|
cwd: targetDir,
|
|
@@ -175767,7 +176695,7 @@ Failed to start process: ${err?.message || err}
|
|
|
175767
176695
|
},
|
|
175768
176696
|
grep: async (dirPath, query) => {
|
|
175769
176697
|
const root = getScopedCwd();
|
|
175770
|
-
const targetDir =
|
|
176698
|
+
const targetDir = path30.isAbsolute(dirPath) ? dirPath : path30.resolve(root, dirPath);
|
|
175771
176699
|
const ignores = getWorkspaceIgnores(root);
|
|
175772
176700
|
try {
|
|
175773
176701
|
const escapedQuery = query.replace(/"/g, "\\\"");
|
|
@@ -175781,7 +176709,7 @@ Failed to start process: ${err?.message || err}
|
|
|
175781
176709
|
if (!line.trim())
|
|
175782
176710
|
return false;
|
|
175783
176711
|
const rawPath = line.split(":")[0];
|
|
175784
|
-
const relPath =
|
|
176712
|
+
const relPath = path30.isAbsolute(rawPath) ? path30.relative(root, rawPath) : rawPath;
|
|
175785
176713
|
return !isPathIgnored(relPath, ignores);
|
|
175786
176714
|
});
|
|
175787
176715
|
return filtered.join(`
|
|
@@ -175806,23 +176734,9 @@ Failed to start process: ${err?.message || err}
|
|
|
175806
176734
|
}
|
|
175807
176735
|
},
|
|
175808
176736
|
browser: {
|
|
175809
|
-
navigate: async (url) =>
|
|
175810
|
-
|
|
175811
|
-
|
|
175812
|
-
headers: {
|
|
175813
|
-
"User-Agent": "Mozilla/5.0 (compatible; DecemberAgent/1.0)"
|
|
175814
|
-
}
|
|
175815
|
-
});
|
|
175816
|
-
const html = await res.text();
|
|
175817
|
-
if (!res.ok) {
|
|
175818
|
-
return { text: "", error: `HTTP Error (${res.status}): ${html}` };
|
|
175819
|
-
}
|
|
175820
|
-
const cleanText = html.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, "").replace(/<style\b[^<]*(?:(?!<\/style>)<[^<]*)*<\/style>/gi, "").replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
|
|
175821
|
-
return { text: cleanText };
|
|
175822
|
-
} catch (error) {
|
|
175823
|
-
return { text: "", error: error.message };
|
|
175824
|
-
}
|
|
175825
|
-
}
|
|
176737
|
+
navigate: async (url) => browserRunner.navigate(url),
|
|
176738
|
+
action: async (params) => browserRunner.action(params),
|
|
176739
|
+
close: async () => browserRunner.close()
|
|
175826
176740
|
},
|
|
175827
176741
|
diagnostics: {
|
|
175828
176742
|
getDiagnostics: async (filePath) => {
|
|
@@ -177515,7 +178429,7 @@ var init_environment = __esm(() => {
|
|
|
177515
178429
|
|
|
177516
178430
|
// ../../node_modules/.bun/ansi-escapes@7.3.0/node_modules/ansi-escapes/base.js
|
|
177517
178431
|
import process2 from "node:process";
|
|
177518
|
-
import
|
|
178432
|
+
import os16 from "node:os";
|
|
177519
178433
|
var ESC = "\x1B[", SEP = ";", isTerminalApp, isWindows2, isTmux, cwdFunction, cursorTo = (x, y) => {
|
|
177520
178434
|
if (typeof x !== "number") {
|
|
177521
178435
|
throw new TypeError("The `x` argument is required");
|
|
@@ -177537,7 +178451,7 @@ var ESC = "\x1B[", SEP = ";", isTerminalApp, isWindows2, isTmux, cwdFunction, cu
|
|
|
177537
178451
|
if (isBrowser || !isWindows2) {
|
|
177538
178452
|
return false;
|
|
177539
178453
|
}
|
|
177540
|
-
const parts =
|
|
178454
|
+
const parts = os16.release().split(".");
|
|
177541
178455
|
const major = Number(parts[0]);
|
|
177542
178456
|
const build = Number(parts[2] ?? 0);
|
|
177543
178457
|
if (major < 10) {
|
|
@@ -180224,7 +181138,7 @@ var init_wrap_ansi = __esm(() => {
|
|
|
180224
181138
|
// ../../node_modules/.bun/terminal-size@4.0.1/node_modules/terminal-size/index.js
|
|
180225
181139
|
import process3 from "node:process";
|
|
180226
181140
|
import { execFileSync } from "node:child_process";
|
|
180227
|
-
import
|
|
181141
|
+
import fs30 from "node:fs";
|
|
180228
181142
|
import tty from "node:tty";
|
|
180229
181143
|
function terminalSize() {
|
|
180230
181144
|
const { env, stdout, stderr } = process3;
|
|
@@ -180272,7 +181186,7 @@ var defaultColumns = 80, defaultRows = 24, exec6 = (command, arguments_, { shell
|
|
|
180272
181186
|
return true;
|
|
180273
181187
|
}
|
|
180274
181188
|
try {
|
|
180275
|
-
const statContents =
|
|
181189
|
+
const statContents = fs30.readFileSync("/proc/self/stat", "utf8");
|
|
180276
181190
|
const closingParenthesisIndex = statContents.lastIndexOf(") ");
|
|
180277
181191
|
if (closingParenthesisIndex === -1) {
|
|
180278
181192
|
return false;
|
|
@@ -180292,8 +181206,8 @@ var defaultColumns = 80, defaultRows = 24, exec6 = (command, arguments_, { shell
|
|
|
180292
181206
|
}
|
|
180293
181207
|
}, devTty = () => {
|
|
180294
181208
|
try {
|
|
180295
|
-
const flags = process3.platform === "darwin" ?
|
|
180296
|
-
const { columns, rows } = tty.WriteStream(
|
|
181209
|
+
const flags = process3.platform === "darwin" ? fs30.constants.O_EVTONLY | fs30.constants.O_NONBLOCK : fs30.constants.O_NONBLOCK;
|
|
181210
|
+
const { columns, rows } = tty.WriteStream(fs30.openSync("/dev/tty", flags));
|
|
180297
181211
|
return { columns, rows };
|
|
180298
181212
|
} catch {}
|
|
180299
181213
|
}, tput = () => {
|
|
@@ -210285,7 +211199,7 @@ var init_ansi_styles2 = __esm(() => {
|
|
|
210285
211199
|
|
|
210286
211200
|
// ../../node_modules/.bun/chalk@5.6.2/node_modules/chalk/source/vendor/supports-color/index.js
|
|
210287
211201
|
import process5 from "node:process";
|
|
210288
|
-
import
|
|
211202
|
+
import os17 from "node:os";
|
|
210289
211203
|
import tty2 from "node:tty";
|
|
210290
211204
|
function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : process5.argv) {
|
|
210291
211205
|
const prefix = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--";
|
|
@@ -210343,7 +211257,7 @@ function _supportsColor(haveStream, { streamIsTTY, sniffFlags = true } = {}) {
|
|
|
210343
211257
|
return min;
|
|
210344
211258
|
}
|
|
210345
211259
|
if (process5.platform === "win32") {
|
|
210346
|
-
const osRelease =
|
|
211260
|
+
const osRelease = os17.release().split(".");
|
|
210347
211261
|
if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
|
|
210348
211262
|
return Number(osRelease[2]) >= 14931 ? 3 : 2;
|
|
210349
211263
|
}
|
|
@@ -212495,7 +213409,7 @@ var init_Text = __esm(() => {
|
|
|
212495
213409
|
});
|
|
212496
213410
|
|
|
212497
213411
|
// ../../node_modules/.bun/ink@7.1.0+90ffd46201e3176f/node_modules/ink/build/components/ErrorOverview.js
|
|
212498
|
-
import * as
|
|
213412
|
+
import * as fs31 from "node:fs";
|
|
212499
213413
|
import { cwd } from "node:process";
|
|
212500
213414
|
function ErrorOverview({ error }) {
|
|
212501
213415
|
const stack = error.stack ? error.stack.split(`
|
|
@@ -212505,8 +213419,8 @@ function ErrorOverview({ error }) {
|
|
|
212505
213419
|
let excerpt;
|
|
212506
213420
|
let lineWidth = 0;
|
|
212507
213421
|
const stackLineCounts = new Map;
|
|
212508
|
-
if (filePath && origin?.line &&
|
|
212509
|
-
const sourceCode =
|
|
213422
|
+
if (filePath && origin?.line && fs31.existsSync(filePath)) {
|
|
213423
|
+
const sourceCode = fs31.readFileSync(filePath, "utf8");
|
|
212510
213424
|
excerpt = dist_default4(sourceCode, origin.line);
|
|
212511
213425
|
if (excerpt) {
|
|
212512
213426
|
for (const { line } of excerpt) {
|
|
@@ -213937,7 +214851,7 @@ var init_render_to_string = __esm(async () => {
|
|
|
213937
214851
|
});
|
|
213938
214852
|
|
|
213939
214853
|
// ../../node_modules/.bun/ink@7.1.0+90ffd46201e3176f/node_modules/ink/build/components/Static.js
|
|
213940
|
-
function
|
|
214854
|
+
function Static16(props) {
|
|
213941
214855
|
const { items, children: render, style: customStyle } = props;
|
|
213942
214856
|
const [index, setIndex] = import_react17.useState(0);
|
|
213943
214857
|
const itemsToRender = import_react17.useMemo(() => {
|
|
@@ -215180,9 +216094,9 @@ var init_paste_manager = __esm(() => {
|
|
|
215180
216094
|
});
|
|
215181
216095
|
|
|
215182
216096
|
// ../../packages/tui/src/utils/prompt-history.ts
|
|
215183
|
-
import
|
|
215184
|
-
import
|
|
215185
|
-
import
|
|
216097
|
+
import fs32 from "node:fs";
|
|
216098
|
+
import os18 from "node:os";
|
|
216099
|
+
import path31 from "node:path";
|
|
215186
216100
|
|
|
215187
216101
|
class PromptHistory {
|
|
215188
216102
|
historyPath;
|
|
@@ -215193,17 +216107,17 @@ class PromptHistory {
|
|
|
215193
216107
|
if (customPath) {
|
|
215194
216108
|
this.historyPath = customPath;
|
|
215195
216109
|
} else {
|
|
215196
|
-
const home = process.env.HOME || process.env.USERPROFILE ||
|
|
215197
|
-
const canonicalPath =
|
|
215198
|
-
const legacyPath =
|
|
215199
|
-
this.historyPath =
|
|
216110
|
+
const home = process.env.HOME || process.env.USERPROFILE || os18.homedir();
|
|
216111
|
+
const canonicalPath = path31.join(home, ".december", "history");
|
|
216112
|
+
const legacyPath = path31.join(home, ".config", "december", "history");
|
|
216113
|
+
this.historyPath = fs32.existsSync(canonicalPath) || !fs32.existsSync(legacyPath) ? canonicalPath : legacyPath;
|
|
215200
216114
|
}
|
|
215201
216115
|
this.load();
|
|
215202
216116
|
}
|
|
215203
216117
|
load() {
|
|
215204
216118
|
try {
|
|
215205
|
-
if (
|
|
215206
|
-
const raw =
|
|
216119
|
+
if (fs32.existsSync(this.historyPath)) {
|
|
216120
|
+
const raw = fs32.readFileSync(this.historyPath, "utf8");
|
|
215207
216121
|
this.entries = raw.split(/\r?\n/).map((l) => l.trim()).filter(Boolean);
|
|
215208
216122
|
}
|
|
215209
216123
|
} catch {
|
|
@@ -215219,11 +216133,11 @@ class PromptHistory {
|
|
|
215219
216133
|
this.cursor = this.entries.length;
|
|
215220
216134
|
this.currentDraft = "";
|
|
215221
216135
|
try {
|
|
215222
|
-
const dir =
|
|
215223
|
-
if (!
|
|
215224
|
-
|
|
216136
|
+
const dir = path31.dirname(this.historyPath);
|
|
216137
|
+
if (!fs32.existsSync(dir)) {
|
|
216138
|
+
fs32.mkdirSync(dir, { recursive: true });
|
|
215225
216139
|
}
|
|
215226
|
-
|
|
216140
|
+
fs32.appendFileSync(this.historyPath, trimmed + `
|
|
215227
216141
|
`, "utf8");
|
|
215228
216142
|
} catch {}
|
|
215229
216143
|
}
|
|
@@ -215262,11 +216176,11 @@ var init_prompt_history = __esm(() => {
|
|
|
215262
216176
|
|
|
215263
216177
|
// ../../packages/tui/src/utils/clipboard.ts
|
|
215264
216178
|
import { spawnSync } from "child_process";
|
|
215265
|
-
import * as
|
|
216179
|
+
import * as os19 from "os";
|
|
215266
216180
|
function writeToClipboard(text) {
|
|
215267
|
-
const platform =
|
|
216181
|
+
const platform = os19.platform();
|
|
215268
216182
|
try {
|
|
215269
|
-
const isWsl = platform === "linux" && (!!process.env.WSL_DISTRO_NAME ||
|
|
216183
|
+
const isWsl = platform === "linux" && (!!process.env.WSL_DISTRO_NAME || os19.release().toLowerCase().includes("microsoft"));
|
|
215270
216184
|
if (platform === "darwin") {
|
|
215271
216185
|
spawnSync("pbcopy", { input: text });
|
|
215272
216186
|
} else if (platform === "win32") {
|
|
@@ -215287,16 +216201,16 @@ var init_clipboard = () => {};
|
|
|
215287
216201
|
|
|
215288
216202
|
// ../../packages/tui/src/utils/handoff.ts
|
|
215289
216203
|
import { exec as exec7 } from "node:child_process";
|
|
215290
|
-
import
|
|
215291
|
-
import
|
|
216204
|
+
import fs33 from "node:fs";
|
|
216205
|
+
import path32 from "node:path";
|
|
215292
216206
|
import { promisify as promisify5 } from "node:util";
|
|
215293
216207
|
function getHandoffExcludes(baseDir = process.cwd()) {
|
|
215294
216208
|
const excludes = [...MANDATORY_HANDOFF_EXCLUDES];
|
|
215295
216209
|
const readIgnoreFile = (fileName) => {
|
|
215296
|
-
const filePath =
|
|
216210
|
+
const filePath = path32.join(baseDir, fileName);
|
|
215297
216211
|
try {
|
|
215298
|
-
if (
|
|
215299
|
-
const lines =
|
|
216212
|
+
if (fs33.existsSync(filePath)) {
|
|
216213
|
+
const lines = fs33.readFileSync(filePath, "utf8").split(`
|
|
215300
216214
|
`);
|
|
215301
216215
|
for (const line of lines) {
|
|
215302
216216
|
const trimmed = line.trim();
|
|
@@ -215365,9 +216279,9 @@ var init_handoff = __esm(() => {
|
|
|
215365
216279
|
});
|
|
215366
216280
|
|
|
215367
216281
|
// ../../packages/tui/src/components/command-menu/commands.tsx
|
|
215368
|
-
import
|
|
215369
|
-
import
|
|
215370
|
-
import
|
|
216282
|
+
import fs34 from "node:fs";
|
|
216283
|
+
import os20 from "node:os";
|
|
216284
|
+
import path33 from "node:path";
|
|
215371
216285
|
var COMMANDS;
|
|
215372
216286
|
var init_commands2 = __esm(() => {
|
|
215373
216287
|
init_clipboard();
|
|
@@ -215470,14 +216384,14 @@ var init_commands2 = __esm(() => {
|
|
|
215470
216384
|
action: async (ctx) => {
|
|
215471
216385
|
const archivePath = ".december-handoff.tar.gz";
|
|
215472
216386
|
try {
|
|
215473
|
-
const home = process.env.HOME || process.env.USERPROFILE ||
|
|
215474
|
-
const canonicalConfigPath =
|
|
215475
|
-
const legacyConfigPath =
|
|
215476
|
-
const configPath =
|
|
216387
|
+
const home = process.env.HOME || process.env.USERPROFILE || os20.homedir();
|
|
216388
|
+
const canonicalConfigPath = path33.join(home, ".december", "config.json");
|
|
216389
|
+
const legacyConfigPath = path33.join(home, ".config", "december", "config.json");
|
|
216390
|
+
const configPath = fs34.existsSync(canonicalConfigPath) || !fs34.existsSync(legacyConfigPath) ? canonicalConfigPath : legacyConfigPath;
|
|
215477
216391
|
let config = {};
|
|
215478
216392
|
try {
|
|
215479
|
-
if (
|
|
215480
|
-
config = JSON.parse(
|
|
216393
|
+
if (fs34.existsSync(configPath)) {
|
|
216394
|
+
config = JSON.parse(fs34.readFileSync(configPath, "utf8"));
|
|
215481
216395
|
}
|
|
215482
216396
|
} catch {}
|
|
215483
216397
|
if (!config.decemberToken) {
|
|
@@ -215512,7 +216426,7 @@ var init_commands2 = __esm(() => {
|
|
|
215512
216426
|
headers: { Authorization: `Bearer ${config.decemberToken}` }
|
|
215513
216427
|
});
|
|
215514
216428
|
if (!urlRes.ok) {
|
|
215515
|
-
await
|
|
216429
|
+
await fs34.promises.unlink(archivePath).catch(() => {});
|
|
215516
216430
|
if (urlRes.status === 401) {
|
|
215517
216431
|
ctx.toast.show({
|
|
215518
216432
|
variant: "error",
|
|
@@ -215533,7 +216447,7 @@ var init_commands2 = __esm(() => {
|
|
|
215533
216447
|
const urlJson = await urlRes.json();
|
|
215534
216448
|
const { uploadUrl, objectKey } = urlJson.data || urlJson;
|
|
215535
216449
|
ctx.toast.show({ variant: "info", message: "Uploading to MinIO..." });
|
|
215536
|
-
const fileData = await
|
|
216450
|
+
const fileData = await fs34.promises.readFile(archivePath);
|
|
215537
216451
|
const uploadRes = await fetch(uploadUrl, {
|
|
215538
216452
|
method: "PUT",
|
|
215539
216453
|
body: fileData
|
|
@@ -215557,11 +216471,11 @@ var init_commands2 = __esm(() => {
|
|
|
215557
216471
|
const errJson = await sessionRes.json().catch(() => ({}));
|
|
215558
216472
|
throw new Error(errJson.message || await sessionRes.text());
|
|
215559
216473
|
}
|
|
215560
|
-
await
|
|
216474
|
+
await fs34.promises.unlink(archivePath).catch(() => {});
|
|
215561
216475
|
ctx.toast.show({ variant: "success", message: "Handoff complete! Exiting in 3s." });
|
|
215562
216476
|
setTimeout(() => ctx.exit(), 3000);
|
|
215563
216477
|
} catch (e) {
|
|
215564
|
-
await
|
|
216478
|
+
await fs34.promises.unlink(archivePath).catch(() => {});
|
|
215565
216479
|
ctx.toast.show({ variant: "error", message: `Handoff failed: ${e.message}` });
|
|
215566
216480
|
}
|
|
215567
216481
|
}
|
|
@@ -215633,6 +216547,12 @@ var init_commands2 = __esm(() => {
|
|
|
215633
216547
|
description: "View quota usage",
|
|
215634
216548
|
value: "/usage",
|
|
215635
216549
|
action: (ctx) => {}
|
|
216550
|
+
},
|
|
216551
|
+
{
|
|
216552
|
+
name: "voice",
|
|
216553
|
+
description: "Dictate a prompt using your microphone (Deepgram)",
|
|
216554
|
+
value: "/voice",
|
|
216555
|
+
action: (ctx) => {}
|
|
215636
216556
|
}
|
|
215637
216557
|
];
|
|
215638
216558
|
});
|
|
@@ -216065,6 +216985,7 @@ function TextArea({
|
|
|
216065
216985
|
onScrollUp,
|
|
216066
216986
|
onScrollDown,
|
|
216067
216987
|
placeholder = "",
|
|
216988
|
+
placeholderColor,
|
|
216068
216989
|
focus = true,
|
|
216069
216990
|
disableHistoryNav = false
|
|
216070
216991
|
}) {
|
|
@@ -216318,7 +217239,7 @@ function TextArea({
|
|
|
216318
217239
|
});
|
|
216319
217240
|
if (!value && placeholder) {
|
|
216320
217241
|
return /* @__PURE__ */ jsx_runtime7.jsxs(Text3, {
|
|
216321
|
-
color: THEME.colors.subtle,
|
|
217242
|
+
color: placeholderColor || THEME.colors.subtle,
|
|
216322
217243
|
wrap: "wrap",
|
|
216323
217244
|
children: [
|
|
216324
217245
|
focus ? /* @__PURE__ */ jsx_runtime7.jsx(Text3, {
|
|
@@ -216543,9 +217464,13 @@ var init_input_bar = __esm(async () => {
|
|
|
216543
217464
|
queuedPrompts,
|
|
216544
217465
|
tasks,
|
|
216545
217466
|
onScrollUp,
|
|
216546
|
-
onScrollDown
|
|
217467
|
+
onScrollDown,
|
|
217468
|
+
onStartVoice
|
|
216547
217469
|
}) {
|
|
216548
217470
|
const [value, setValue] = import_react42.useState("");
|
|
217471
|
+
const [isVoiceActive, setIsVoiceActive] = import_react42.useState(false);
|
|
217472
|
+
const [isTranscribing, setIsTranscribing] = import_react42.useState(false);
|
|
217473
|
+
const voiceSessionRef = import_react42.useRef(null);
|
|
216549
217474
|
const toast = useToast();
|
|
216550
217475
|
const dialog = useDialog();
|
|
216551
217476
|
const columns = useTerminalColumns();
|
|
@@ -216553,6 +217478,71 @@ var init_input_bar = __esm(async () => {
|
|
|
216553
217478
|
const [allWorkspaceFiles, setAllWorkspaceFiles] = import_react42.useState([]);
|
|
216554
217479
|
const activeToast = toasts && toasts.length > 0 ? toasts[toasts.length - 1] : toast.currentToast ? { message: toast.currentToast.message, variant: toast.currentToast.variant } : null;
|
|
216555
217480
|
const handleContentChangeRef = import_react42.useRef(() => {});
|
|
217481
|
+
const handleStopVoice = import_react42.useCallback(async (sendPrompt = false) => {
|
|
217482
|
+
const session = voiceSessionRef.current;
|
|
217483
|
+
if (!session) {
|
|
217484
|
+
setIsVoiceActive(false);
|
|
217485
|
+
setIsTranscribing(false);
|
|
217486
|
+
return;
|
|
217487
|
+
}
|
|
217488
|
+
voiceSessionRef.current = null;
|
|
217489
|
+
setIsVoiceActive(false);
|
|
217490
|
+
if (sendPrompt) {
|
|
217491
|
+
setIsTranscribing(true);
|
|
217492
|
+
try {
|
|
217493
|
+
const finalTranscript = await session.stop();
|
|
217494
|
+
const promptToSend = (finalTranscript || value).trim();
|
|
217495
|
+
setValue("");
|
|
217496
|
+
handleContentChangeRef.current("");
|
|
217497
|
+
if (promptToSend) {
|
|
217498
|
+
onSubmit(promptToSend);
|
|
217499
|
+
}
|
|
217500
|
+
} finally {
|
|
217501
|
+
setIsTranscribing(false);
|
|
217502
|
+
}
|
|
217503
|
+
} else {
|
|
217504
|
+
session.cancel();
|
|
217505
|
+
setValue("");
|
|
217506
|
+
handleContentChangeRef.current("");
|
|
217507
|
+
setIsTranscribing(false);
|
|
217508
|
+
}
|
|
217509
|
+
}, [onSubmit, value]);
|
|
217510
|
+
const handleStartVoice = import_react42.useCallback(async () => {
|
|
217511
|
+
if (!onStartVoice) {
|
|
217512
|
+
onSubmit("/voice");
|
|
217513
|
+
return;
|
|
217514
|
+
}
|
|
217515
|
+
setIsVoiceActive(true);
|
|
217516
|
+
setValue("");
|
|
217517
|
+
handleContentChangeRef.current("");
|
|
217518
|
+
setIsTranscribing(false);
|
|
217519
|
+
try {
|
|
217520
|
+
const session = await onStartVoice({
|
|
217521
|
+
onTranscript: (text) => {
|
|
217522
|
+
setValue(text);
|
|
217523
|
+
handleContentChangeRef.current(text);
|
|
217524
|
+
},
|
|
217525
|
+
onError: (err) => {
|
|
217526
|
+
setIsVoiceActive(false);
|
|
217527
|
+
setIsTranscribing(false);
|
|
217528
|
+
voiceSessionRef.current = null;
|
|
217529
|
+
toast.show({
|
|
217530
|
+
variant: "error",
|
|
217531
|
+
message: err.message || "Voice dictation error."
|
|
217532
|
+
});
|
|
217533
|
+
}
|
|
217534
|
+
});
|
|
217535
|
+
if (!session) {
|
|
217536
|
+
setIsVoiceActive(false);
|
|
217537
|
+
setIsTranscribing(false);
|
|
217538
|
+
return;
|
|
217539
|
+
}
|
|
217540
|
+
voiceSessionRef.current = session;
|
|
217541
|
+
} catch {
|
|
217542
|
+
setIsVoiceActive(false);
|
|
217543
|
+
setIsTranscribing(false);
|
|
217544
|
+
}
|
|
217545
|
+
}, [onStartVoice, onSubmit, toast]);
|
|
216556
217546
|
const handleAutocompleteCommand = import_react42.useCallback((completedText) => {
|
|
216557
217547
|
setValue(completedText);
|
|
216558
217548
|
handleContentChangeRef.current(completedText);
|
|
@@ -216618,7 +217608,10 @@ var init_input_bar = __esm(async () => {
|
|
|
216618
217608
|
handleContentChange,
|
|
216619
217609
|
grillMode,
|
|
216620
217610
|
onSubmit,
|
|
216621
|
-
onCopy
|
|
217611
|
+
onCopy,
|
|
217612
|
+
isVoiceActive,
|
|
217613
|
+
isTranscribing,
|
|
217614
|
+
handleStopVoice
|
|
216622
217615
|
});
|
|
216623
217616
|
stateRef.current = {
|
|
216624
217617
|
showFileMenu,
|
|
@@ -216628,11 +217621,26 @@ var init_input_bar = __esm(async () => {
|
|
|
216628
217621
|
handleContentChange,
|
|
216629
217622
|
grillMode,
|
|
216630
217623
|
onSubmit,
|
|
216631
|
-
onCopy
|
|
217624
|
+
onCopy,
|
|
217625
|
+
isVoiceActive,
|
|
217626
|
+
isTranscribing,
|
|
217627
|
+
handleStopVoice
|
|
216632
217628
|
};
|
|
216633
217629
|
const isCtrlW = import_react42.useRef(false);
|
|
216634
217630
|
use_input_default((input, key) => {
|
|
216635
217631
|
const state = stateRef.current;
|
|
217632
|
+
if (key.escape) {
|
|
217633
|
+
if (state.isVoiceActive || state.isTranscribing || voiceSessionRef.current) {
|
|
217634
|
+
state.handleStopVoice(false);
|
|
217635
|
+
return;
|
|
217636
|
+
}
|
|
217637
|
+
if (state.showFileMenu && state.matchingFiles.length > 0) {
|
|
217638
|
+
const nextVal = state.value.replace(/@\S*$/, "");
|
|
217639
|
+
setValue(nextVal);
|
|
217640
|
+
state.handleContentChange(nextVal);
|
|
217641
|
+
return;
|
|
217642
|
+
}
|
|
217643
|
+
}
|
|
216636
217644
|
if (state.showFileMenu && state.matchingFiles.length > 0) {
|
|
216637
217645
|
if (key.upArrow) {
|
|
216638
217646
|
setSelectedFileIndex((prev) => Math.max(0, prev - 1));
|
|
@@ -216652,12 +217660,6 @@ var init_input_bar = __esm(async () => {
|
|
|
216652
217660
|
}
|
|
216653
217661
|
return;
|
|
216654
217662
|
}
|
|
216655
|
-
if (key.escape) {
|
|
216656
|
-
const nextVal = state.value.replace(/@\S*$/, "");
|
|
216657
|
-
setValue(nextVal);
|
|
216658
|
-
state.handleContentChange(nextVal);
|
|
216659
|
-
return;
|
|
216660
|
-
}
|
|
216661
217663
|
}
|
|
216662
217664
|
if (key.ctrl && input === "w") {
|
|
216663
217665
|
isCtrlW.current = true;
|
|
@@ -216748,6 +217750,12 @@ var init_input_bar = __esm(async () => {
|
|
|
216748
217750
|
"/handoff",
|
|
216749
217751
|
"/docs"
|
|
216750
217752
|
];
|
|
217753
|
+
if (command.value === "/voice") {
|
|
217754
|
+
setValue("");
|
|
217755
|
+
handleContentChange("");
|
|
217756
|
+
handleStartVoice();
|
|
217757
|
+
return;
|
|
217758
|
+
}
|
|
216751
217759
|
if (forwardCommands.includes(command.value) || !command.action) {
|
|
216752
217760
|
if (hasArguments) {
|
|
216753
217761
|
onSubmit(currentValue);
|
|
@@ -216766,10 +217774,24 @@ var init_input_bar = __esm(async () => {
|
|
|
216766
217774
|
onUpdateSuccess
|
|
216767
217775
|
});
|
|
216768
217776
|
}
|
|
216769
|
-
}, [
|
|
217777
|
+
}, [
|
|
217778
|
+
toast,
|
|
217779
|
+
dialog,
|
|
217780
|
+
agent,
|
|
217781
|
+
resetChat,
|
|
217782
|
+
onUpdateSuccess,
|
|
217783
|
+
handleContentChange,
|
|
217784
|
+
onSubmit,
|
|
217785
|
+
value,
|
|
217786
|
+
handleStartVoice
|
|
217787
|
+
]);
|
|
216770
217788
|
const handleSubmit = import_react42.useCallback(async (text) => {
|
|
216771
217789
|
if (disabled)
|
|
216772
217790
|
return;
|
|
217791
|
+
if (isVoiceActive || isTranscribing) {
|
|
217792
|
+
await handleStopVoice(true);
|
|
217793
|
+
return;
|
|
217794
|
+
}
|
|
216773
217795
|
if (showCommandMenu) {
|
|
216774
217796
|
const command = resolveCommand(selectedIndex);
|
|
216775
217797
|
handleCommand(command);
|
|
@@ -216781,6 +217803,12 @@ var init_input_bar = __esm(async () => {
|
|
|
216781
217803
|
const rawTrimmed = text.trim();
|
|
216782
217804
|
if (rawTrimmed.length === 0)
|
|
216783
217805
|
return;
|
|
217806
|
+
if (rawTrimmed === "/voice") {
|
|
217807
|
+
setValue("");
|
|
217808
|
+
handleContentChange("");
|
|
217809
|
+
handleStartVoice();
|
|
217810
|
+
return;
|
|
217811
|
+
}
|
|
216784
217812
|
const trimmed = expandPastes(rawTrimmed);
|
|
216785
217813
|
defaultPromptHistory.append(trimmed);
|
|
216786
217814
|
defaultPromptHistory.resetCursor();
|
|
@@ -216939,7 +217967,8 @@ var init_input_bar = __esm(async () => {
|
|
|
216939
217967
|
onHistoryDown: handleHistoryDown,
|
|
216940
217968
|
onScrollUp,
|
|
216941
217969
|
onScrollDown,
|
|
216942
|
-
placeholder: grillMode ? "" : planRefineMode ? "Enter feedback to refine plan (or Esc to cancel)..." : interactivePlanGoalMode ? "Enter your goal (e.g. add dark mode) or Esc to cancel..." : placeholder,
|
|
217970
|
+
placeholder: isTranscribing ? "Transcribing speech..." : isVoiceActive ? "Listening..." : grillMode ? "" : planRefineMode ? "Enter feedback to refine plan (or Esc to cancel)..." : interactivePlanGoalMode ? "Enter your goal (e.g. add dark mode) or Esc to cancel..." : placeholder,
|
|
217971
|
+
placeholderColor: isVoiceActive ? THEME.colors.brand : undefined,
|
|
216943
217972
|
focus: !disabled && !dialog.isOpen,
|
|
216944
217973
|
disableHistoryNav: showCommandMenu || showFileMenu || showShortcutsMenu
|
|
216945
217974
|
})
|
|
@@ -217254,7 +218283,7 @@ var init_scroll_viewport = __esm(async () => {
|
|
|
217254
218283
|
});
|
|
217255
218284
|
|
|
217256
218285
|
// ../../packages/tui/src/utils/terminal-link.ts
|
|
217257
|
-
import
|
|
218286
|
+
import path34 from "node:path";
|
|
217258
218287
|
function terminalLink(text, uri) {
|
|
217259
218288
|
if (!uri)
|
|
217260
218289
|
return text;
|
|
@@ -217263,7 +218292,7 @@ function terminalLink(text, uri) {
|
|
|
217263
218292
|
function fileLink(displayPath, targetPath, line, col) {
|
|
217264
218293
|
if (!targetPath)
|
|
217265
218294
|
return displayPath;
|
|
217266
|
-
const absPath =
|
|
218295
|
+
const absPath = path34.isAbsolute(targetPath) ? targetPath : path34.resolve(process.cwd(), targetPath);
|
|
217267
218296
|
const lineFragment = line ? `#L${line}${col ? `:${col}` : ""}` : "";
|
|
217268
218297
|
const uri = `file://${absPath}${lineFragment}`;
|
|
217269
218298
|
return terminalLink(displayPath, uri);
|
|
@@ -217272,9 +218301,9 @@ function toRelativePath(filePath, cwd = process.cwd()) {
|
|
|
217272
218301
|
if (!filePath)
|
|
217273
218302
|
return "";
|
|
217274
218303
|
const trimmed = filePath.trim();
|
|
217275
|
-
if (!
|
|
218304
|
+
if (!path34.isAbsolute(trimmed))
|
|
217276
218305
|
return trimmed;
|
|
217277
|
-
const rel =
|
|
218306
|
+
const rel = path34.relative(cwd, trimmed);
|
|
217278
218307
|
if (!rel || rel.startsWith("..")) {
|
|
217279
218308
|
return trimmed;
|
|
217280
218309
|
}
|
|
@@ -263642,27 +264671,27 @@ ${r}`;
|
|
|
263642
264671
|
});
|
|
263643
264672
|
|
|
263644
264673
|
// ../../packages/tui/src/components/header.tsx
|
|
263645
|
-
import
|
|
264674
|
+
import fs35 from "node:fs";
|
|
263646
264675
|
import { homedir } from "node:os";
|
|
263647
|
-
import
|
|
264676
|
+
import path35 from "node:path";
|
|
263648
264677
|
function getGitBranch(workspaceRoot = process.cwd()) {
|
|
263649
264678
|
if (cachedBranch !== undefined) {
|
|
263650
264679
|
return cachedBranch;
|
|
263651
264680
|
}
|
|
263652
264681
|
try {
|
|
263653
|
-
const gitPath =
|
|
263654
|
-
if (
|
|
263655
|
-
const stat =
|
|
263656
|
-
let headPath =
|
|
264682
|
+
const gitPath = path35.resolve(workspaceRoot, ".git");
|
|
264683
|
+
if (fs35.existsSync(gitPath)) {
|
|
264684
|
+
const stat = fs35.statSync(gitPath);
|
|
264685
|
+
let headPath = path35.resolve(gitPath, "HEAD");
|
|
263657
264686
|
if (stat.isFile()) {
|
|
263658
|
-
const content =
|
|
264687
|
+
const content = fs35.readFileSync(gitPath, "utf-8").trim();
|
|
263659
264688
|
if (content.startsWith("gitdir:")) {
|
|
263660
264689
|
const gitDir = content.slice(7).trim();
|
|
263661
|
-
headPath =
|
|
264690
|
+
headPath = path35.resolve(workspaceRoot, gitDir, "HEAD");
|
|
263662
264691
|
}
|
|
263663
264692
|
}
|
|
263664
|
-
if (
|
|
263665
|
-
const headContent =
|
|
264693
|
+
if (fs35.existsSync(headPath)) {
|
|
264694
|
+
const headContent = fs35.readFileSync(headPath, "utf-8").trim();
|
|
263666
264695
|
if (headContent.startsWith("ref: refs/heads/")) {
|
|
263667
264696
|
cachedBranch = headContent.replace("ref: refs/heads/", "").trim();
|
|
263668
264697
|
return cachedBranch;
|
|
@@ -263936,7 +264965,7 @@ var init_message_list = __esm(async () => {
|
|
|
263936
264965
|
flexDirection: "column",
|
|
263937
264966
|
width: "100%",
|
|
263938
264967
|
children: [
|
|
263939
|
-
staticMessages.length > 0 && /* @__PURE__ */ jsx_runtime20.jsx(
|
|
264968
|
+
staticMessages.length > 0 && /* @__PURE__ */ jsx_runtime20.jsx(Static16, {
|
|
263940
264969
|
items: staticMessages,
|
|
263941
264970
|
style: { width: "100%" },
|
|
263942
264971
|
children: (msg, index) => renderSingleMessage(msg, index, staticMessages, cliVersion, latestVersion, userEmail, expandCommands, announcement)
|
|
@@ -264504,6 +265533,7 @@ function ByokKeyMenu(props) {
|
|
|
264504
265533
|
const { selectedProvider, apiKey, setApiKey, handleKeySubmit, isStreaming, authError } = props;
|
|
264505
265534
|
const formattedProvider = formatProviderName2(selectedProvider);
|
|
264506
265535
|
const keyUrl = selectedProvider ? PROVIDER_KEY_URLS[selectedProvider] : undefined;
|
|
265536
|
+
const keyNote = selectedProvider ? PROVIDER_KEY_NOTES[selectedProvider.toLowerCase().trim()] : undefined;
|
|
264507
265537
|
return /* @__PURE__ */ jsx_runtime25.jsxs(Box_default, {
|
|
264508
265538
|
flexDirection: "column",
|
|
264509
265539
|
paddingX: THEME.padding.paddingX,
|
|
@@ -264528,7 +265558,8 @@ function ByokKeyMenu(props) {
|
|
|
264528
265558
|
/* @__PURE__ */ jsx_runtime25.jsx(Text3, {
|
|
264529
265559
|
color: THEME.colors.brand,
|
|
264530
265560
|
children: keyUrl
|
|
264531
|
-
})
|
|
265561
|
+
}),
|
|
265562
|
+
keyNote
|
|
264532
265563
|
]
|
|
264533
265564
|
})
|
|
264534
265565
|
]
|
|
@@ -264573,7 +265604,7 @@ function ByokKeyMenu(props) {
|
|
|
264573
265604
|
]
|
|
264574
265605
|
});
|
|
264575
265606
|
}
|
|
264576
|
-
var jsx_runtime25, PROVIDER_NAMES, PROVIDER_KEY_URLS;
|
|
265607
|
+
var jsx_runtime25, PROVIDER_NAMES, PROVIDER_KEY_URLS, PROVIDER_KEY_NOTES;
|
|
264577
265608
|
var init_byok_key_menu = __esm(async () => {
|
|
264578
265609
|
init_theme();
|
|
264579
265610
|
await __promiseAll([
|
|
@@ -264619,6 +265650,7 @@ var init_byok_key_menu = __esm(async () => {
|
|
|
264619
265650
|
december: "December Cloud",
|
|
264620
265651
|
december_proxy: "December Cloud",
|
|
264621
265652
|
deepseek: "DeepSeek",
|
|
265653
|
+
deepgram: "Deepgram",
|
|
264622
265654
|
fireworks: "Fireworks AI",
|
|
264623
265655
|
google: "Google",
|
|
264624
265656
|
gemini: "Google AI Studio",
|
|
@@ -264737,6 +265769,7 @@ var init_byok_key_menu = __esm(async () => {
|
|
|
264737
265769
|
deepinfra: "https://deepinfra.com/dash/api_keys",
|
|
264738
265770
|
deepseek: "https://platform.deepseek.com/api_keys",
|
|
264739
265771
|
digitalocean: "https://cloud.digitalocean.com/account/api/tokens",
|
|
265772
|
+
deepgram: "https://console.deepgram.com",
|
|
264740
265773
|
dinference: "https://dinference.com/",
|
|
264741
265774
|
drun: "https://d.run/",
|
|
264742
265775
|
ebcloud: "https://ebcloud.com/",
|
|
@@ -264910,6 +265943,9 @@ var init_byok_key_menu = __esm(async () => {
|
|
|
264910
265943
|
zhipu: "https://open.bigmodel.cn/usercenter/apikeys",
|
|
264911
265944
|
zhipuai: "https://open.bigmodel.cn/usercenter/apikeys"
|
|
264912
265945
|
};
|
|
265946
|
+
PROVIDER_KEY_NOTES = {
|
|
265947
|
+
deepgram: " ($200 free credit on signup)"
|
|
265948
|
+
};
|
|
264913
265949
|
});
|
|
264914
265950
|
|
|
264915
265951
|
// ../../packages/tui/src/components/menus/context-select-menu.tsx
|
|
@@ -266835,6 +267871,7 @@ function SettingsMainMenu(props) {
|
|
|
266835
267871
|
settingsPathGuard = true,
|
|
266836
267872
|
settingsSteeringMode = "all",
|
|
266837
267873
|
settingsFollowUpMode = "all",
|
|
267874
|
+
settingsBrowserVisible = true,
|
|
266838
267875
|
handleSettingsMainSelect
|
|
266839
267876
|
} = props;
|
|
266840
267877
|
const providerKey = selectedProvider || activeProvider || "";
|
|
@@ -266873,6 +267910,10 @@ function SettingsMainMenu(props) {
|
|
|
266873
267910
|
{
|
|
266874
267911
|
label: `Follow-Up Mode [${settingsFollowUpMode}]`,
|
|
266875
267912
|
value: "followUpMode"
|
|
267913
|
+
},
|
|
267914
|
+
{
|
|
267915
|
+
label: `Browser Window [${settingsBrowserVisible !== false ? "on" : "off"}]`,
|
|
267916
|
+
value: "browserVisible"
|
|
266876
267917
|
}
|
|
266877
267918
|
];
|
|
266878
267919
|
return /* @__PURE__ */ jsx_runtime34.jsxs(Box_default, {
|
|
@@ -269025,25 +270066,25 @@ var init_global_shortcuts = __esm(async () => {
|
|
|
269025
270066
|
|
|
269026
270067
|
// ../../packages/tui/src/utils/pager.ts
|
|
269027
270068
|
import * as cp3 from "node:child_process";
|
|
269028
|
-
import
|
|
269029
|
-
import
|
|
269030
|
-
import
|
|
270069
|
+
import fs36 from "node:fs";
|
|
270070
|
+
import os21 from "node:os";
|
|
270071
|
+
import path36 from "node:path";
|
|
269031
270072
|
function openPlanInPager(planText, title = "december-plan") {
|
|
269032
270073
|
if (Boolean(process.env.BUN_TEST) || Boolean(process.env.VITEST)) {
|
|
269033
270074
|
return Promise.resolve();
|
|
269034
270075
|
}
|
|
269035
270076
|
return new Promise((resolve) => {
|
|
269036
270077
|
try {
|
|
269037
|
-
const tmpFile =
|
|
269038
|
-
|
|
269039
|
-
const pager = process.env.PAGER || process.env.EDITOR || (
|
|
270078
|
+
const tmpFile = path36.join(os21.tmpdir(), `${title}-${Date.now()}.md`);
|
|
270079
|
+
fs36.writeFileSync(tmpFile, planText, "utf8");
|
|
270080
|
+
const pager = process.env.PAGER || process.env.EDITOR || (os21.platform() === "win32" ? "notepad" : "less -R");
|
|
269040
270081
|
const child = cp3.spawn(pager, [tmpFile], {
|
|
269041
270082
|
stdio: "inherit",
|
|
269042
270083
|
shell: true
|
|
269043
270084
|
});
|
|
269044
270085
|
child.on("exit", () => {
|
|
269045
270086
|
try {
|
|
269046
|
-
|
|
270087
|
+
fs36.unlinkSync(tmpFile);
|
|
269047
270088
|
} catch {}
|
|
269048
270089
|
resolve();
|
|
269049
270090
|
});
|
|
@@ -269203,6 +270244,7 @@ function ChatApp({
|
|
|
269203
270244
|
onSubmit: handleFormSubmit,
|
|
269204
270245
|
onScrollUp: handleScrollUp,
|
|
269205
270246
|
onScrollDown: handleScrollDown,
|
|
270247
|
+
onStartVoice: session.onStartVoice,
|
|
269206
270248
|
disabled: authMode !== "none" || Boolean(workflowUI) && !session.customInputMode,
|
|
269207
270249
|
onCopy: () => {
|
|
269208
270250
|
Promise.resolve().then(() => (init_clipboard(), {})).then((cb) => {
|
|
@@ -269579,6 +270621,8 @@ var init_store = __esm(() => {
|
|
|
269579
270621
|
setSettingsSteeringMode: (settingsSteeringMode) => set({ settingsSteeringMode }),
|
|
269580
270622
|
settingsFollowUpMode: "all",
|
|
269581
270623
|
setSettingsFollowUpMode: (settingsFollowUpMode) => set({ settingsFollowUpMode }),
|
|
270624
|
+
settingsBrowserVisible: true,
|
|
270625
|
+
setSettingsBrowserVisible: (settingsBrowserVisible) => set({ settingsBrowserVisible }),
|
|
269582
270626
|
tasksData: [],
|
|
269583
270627
|
setTasksData: (tasksData) => set({ tasksData }),
|
|
269584
270628
|
taskSelectedIndex: 0,
|
|
@@ -269612,9 +270656,9 @@ var init_store = __esm(() => {
|
|
|
269612
270656
|
});
|
|
269613
270657
|
|
|
269614
270658
|
// src/store/interceptors.ts
|
|
269615
|
-
import { execSync as
|
|
269616
|
-
import
|
|
269617
|
-
import
|
|
270659
|
+
import { execSync as execSync4 } from "node:child_process";
|
|
270660
|
+
import fs37 from "node:fs/promises";
|
|
270661
|
+
import path37 from "node:path";
|
|
269618
270662
|
async function computeToolCallDiff(toolCall) {
|
|
269619
270663
|
if (toolCall.input?.diff) {
|
|
269620
270664
|
return toolCall.input.diff;
|
|
@@ -269623,11 +270667,11 @@ async function computeToolCallDiff(toolCall) {
|
|
|
269623
270667
|
if (!targetPath)
|
|
269624
270668
|
return;
|
|
269625
270669
|
const cwd = process.cwd();
|
|
269626
|
-
const resolved =
|
|
269627
|
-
const relative =
|
|
270670
|
+
const resolved = path37.resolve(cwd, targetPath);
|
|
270671
|
+
const relative = path37.relative(cwd, resolved);
|
|
269628
270672
|
let oldContent = "";
|
|
269629
270673
|
try {
|
|
269630
|
-
oldContent = await
|
|
270674
|
+
oldContent = await fs37.readFile(resolved, "utf-8");
|
|
269631
270675
|
} catch {}
|
|
269632
270676
|
if (toolCall.name === "write_to_file" || toolCall.name === "write") {
|
|
269633
270677
|
const newContent = toolCall.input?.CodeContent ?? toolCall.input?.content ?? "";
|
|
@@ -269691,9 +270735,9 @@ function setupAgentInterceptors(agent, storeState) {
|
|
|
269691
270735
|
];
|
|
269692
270736
|
if (fileTools.includes(toolCall.name)) {
|
|
269693
270737
|
const cwd = process.cwd();
|
|
269694
|
-
const resolved =
|
|
269695
|
-
const relative =
|
|
269696
|
-
const isOutside = relative.startsWith("..") ||
|
|
270738
|
+
const resolved = path37.resolve(cwd, targetPath);
|
|
270739
|
+
const relative = path37.relative(cwd, resolved);
|
|
270740
|
+
const isOutside = relative.startsWith("..") || path37.isAbsolute(relative);
|
|
269697
270741
|
if (!config.nonWorkspaceAccess && isOutside) {
|
|
269698
270742
|
return {
|
|
269699
270743
|
block: true,
|
|
@@ -269757,10 +270801,10 @@ function setupAgentInterceptors(agent, storeState) {
|
|
|
269757
270801
|
const targetPath = toolCall.input?.TargetFile || toolCall.input?.AbsolutePath || toolCall.input?.filePath || toolCall.input?.path;
|
|
269758
270802
|
if (targetPath) {
|
|
269759
270803
|
const cwd = process.cwd();
|
|
269760
|
-
const resolved =
|
|
269761
|
-
const relative =
|
|
270804
|
+
const resolved = path37.resolve(cwd, targetPath);
|
|
270805
|
+
const relative = path37.relative(cwd, resolved);
|
|
269762
270806
|
try {
|
|
269763
|
-
|
|
270807
|
+
execSync4(`git ls-files --error-unmatch "${relative}"`, {
|
|
269764
270808
|
cwd,
|
|
269765
270809
|
stdio: "pipe"
|
|
269766
270810
|
});
|
|
@@ -269785,7 +270829,7 @@ var init_interceptors = __esm(() => {
|
|
|
269785
270829
|
});
|
|
269786
270830
|
|
|
269787
270831
|
// src/utils/direct-shell.ts
|
|
269788
|
-
import { spawn as
|
|
270832
|
+
import { spawn as spawn7 } from "node:child_process";
|
|
269789
270833
|
function startDirectCommand(command, options = {}) {
|
|
269790
270834
|
const { timeoutMs = 20000, serverReadyDelayMs = 2500, onData, onBackground } = options;
|
|
269791
270835
|
let output = "";
|
|
@@ -269795,7 +270839,7 @@ function startDirectCommand(command, options = {}) {
|
|
|
269795
270839
|
const isWindows = process.platform === "win32";
|
|
269796
270840
|
const shellCmd = isWindows ? "cmd.exe" : "/bin/bash";
|
|
269797
270841
|
const shellArgs = isWindows ? ["/d", "/s", "/c", command] : ["-c", command];
|
|
269798
|
-
const child =
|
|
270842
|
+
const child = spawn7(shellCmd, shellArgs, {
|
|
269799
270843
|
cwd: process.cwd(),
|
|
269800
270844
|
env: process.env,
|
|
269801
270845
|
stdio: ["pipe", "pipe", "pipe"],
|
|
@@ -269947,15 +270991,15 @@ var init_direct_shell = __esm(() => {
|
|
|
269947
270991
|
});
|
|
269948
270992
|
|
|
269949
270993
|
// src/utils/usage-tracker.ts
|
|
269950
|
-
import
|
|
269951
|
-
import
|
|
270994
|
+
import fs38 from "node:fs/promises";
|
|
270995
|
+
import path38 from "node:path";
|
|
269952
270996
|
function getUsageFilePath() {
|
|
269953
|
-
return
|
|
270997
|
+
return path38.join(getConfigDir(), "usage.json");
|
|
269954
270998
|
}
|
|
269955
270999
|
async function loadUsageLedger() {
|
|
269956
271000
|
const filePath = getUsageFilePath();
|
|
269957
271001
|
try {
|
|
269958
|
-
const raw = await
|
|
271002
|
+
const raw = await fs38.readFile(filePath, "utf-8");
|
|
269959
271003
|
const parsed = JSON.parse(raw);
|
|
269960
271004
|
if (parsed && typeof parsed === "object" && parsed.version === 1 && parsed.days) {
|
|
269961
271005
|
return parsed;
|
|
@@ -269968,8 +271012,8 @@ async function loadUsageLedger() {
|
|
|
269968
271012
|
}
|
|
269969
271013
|
async function saveUsageLedger(ledger) {
|
|
269970
271014
|
const configDir = getConfigDir();
|
|
269971
|
-
const filePath =
|
|
269972
|
-
const tmpPath =
|
|
271015
|
+
const filePath = path38.join(configDir, "usage.json");
|
|
271016
|
+
const tmpPath = path38.join(configDir, `usage.json.tmp.${Date.now()}`);
|
|
269973
271017
|
const cutoffDate = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000).toISOString().slice(0, 10);
|
|
269974
271018
|
const prunedDays = {};
|
|
269975
271019
|
for (const [dateKey, dayRecord] of Object.entries(ledger.days)) {
|
|
@@ -269979,12 +271023,12 @@ async function saveUsageLedger(ledger) {
|
|
|
269979
271023
|
}
|
|
269980
271024
|
ledger.days = prunedDays;
|
|
269981
271025
|
try {
|
|
269982
|
-
await
|
|
269983
|
-
await
|
|
269984
|
-
await
|
|
271026
|
+
await fs38.mkdir(configDir, { recursive: true });
|
|
271027
|
+
await fs38.writeFile(tmpPath, JSON.stringify(ledger, null, 2), "utf-8");
|
|
271028
|
+
await fs38.rename(tmpPath, filePath);
|
|
269985
271029
|
} catch {
|
|
269986
271030
|
try {
|
|
269987
|
-
await
|
|
271031
|
+
await fs38.unlink(tmpPath);
|
|
269988
271032
|
} catch {}
|
|
269989
271033
|
}
|
|
269990
271034
|
}
|
|
@@ -271421,14 +272465,14 @@ function extractJsonArray(rawText) {
|
|
|
271421
272465
|
}
|
|
271422
272466
|
|
|
271423
272467
|
// src/utils/project-context.ts
|
|
271424
|
-
import
|
|
271425
|
-
import
|
|
272468
|
+
import fs39 from "node:fs";
|
|
272469
|
+
import path39 from "node:path";
|
|
271426
272470
|
function getProjectContext(workspaceDir = process.cwd()) {
|
|
271427
272471
|
const parts = [];
|
|
271428
272472
|
try {
|
|
271429
|
-
const pkgPath =
|
|
271430
|
-
if (
|
|
271431
|
-
const pkg = JSON.parse(
|
|
272473
|
+
const pkgPath = path39.join(workspaceDir, "package.json");
|
|
272474
|
+
if (fs39.existsSync(pkgPath)) {
|
|
272475
|
+
const pkg = JSON.parse(fs39.readFileSync(pkgPath, "utf8"));
|
|
271432
272476
|
const deps = Object.keys(pkg.dependencies || {}).slice(0, 15).join(", ");
|
|
271433
272477
|
const devDeps = Object.keys(pkg.devDependencies || {}).slice(0, 10).join(", ");
|
|
271434
272478
|
parts.push(`Project: ${pkg.name || "Unnamed"}`);
|
|
@@ -271437,13 +272481,13 @@ function getProjectContext(workspaceDir = process.cwd()) {
|
|
|
271437
272481
|
if (devDeps)
|
|
271438
272482
|
parts.push(`DevDependencies: ${devDeps}`);
|
|
271439
272483
|
}
|
|
271440
|
-
const agentsPath =
|
|
271441
|
-
if (
|
|
271442
|
-
const content =
|
|
272484
|
+
const agentsPath = path39.join(workspaceDir, "AGENTS.md");
|
|
272485
|
+
if (fs39.existsSync(agentsPath)) {
|
|
272486
|
+
const content = fs39.readFileSync(agentsPath, "utf8");
|
|
271443
272487
|
parts.push(`Guidelines (from AGENTS.md):
|
|
271444
272488
|
${content.slice(0, 500)}`);
|
|
271445
272489
|
}
|
|
271446
|
-
const entries =
|
|
272490
|
+
const entries = fs39.readdirSync(workspaceDir, { withFileTypes: true }).filter((e) => !e.name.startsWith(".") && e.name !== "node_modules").map((e) => e.isDirectory() ? `${e.name}/` : e.name).slice(0, 20);
|
|
271447
272491
|
if (entries.length > 0) {
|
|
271448
272492
|
parts.push(`Workspace layout: ${entries.join(", ")}`);
|
|
271449
272493
|
}
|
|
@@ -271598,14 +272642,14 @@ async function fetchProviderBalance(provider, apiKey, timeoutMs = 2000) {
|
|
|
271598
272642
|
}
|
|
271599
272643
|
|
|
271600
272644
|
// src/utils/formatters.ts
|
|
271601
|
-
import
|
|
272645
|
+
import path40 from "node:path";
|
|
271602
272646
|
function toRelativePath2(filePath, cwd = process.cwd()) {
|
|
271603
272647
|
if (!filePath)
|
|
271604
272648
|
return "";
|
|
271605
272649
|
const trimmed = filePath.trim();
|
|
271606
|
-
if (!
|
|
272650
|
+
if (!path40.isAbsolute(trimmed))
|
|
271607
272651
|
return trimmed;
|
|
271608
|
-
const rel =
|
|
272652
|
+
const rel = path40.relative(cwd, trimmed);
|
|
271609
272653
|
if (!rel || rel.startsWith("..")) {
|
|
271610
272654
|
return trimmed;
|
|
271611
272655
|
}
|
|
@@ -272328,6 +273372,30 @@ ${formatSubscriptionCard(bundle, targetModel)}`
|
|
|
272328
273372
|
if (!trimmedKey)
|
|
272329
273373
|
return;
|
|
272330
273374
|
const selectedProvider = useCliStore.getState().selectedProvider;
|
|
273375
|
+
if (selectedProvider === "deepgram") {
|
|
273376
|
+
setIsStreaming(true);
|
|
273377
|
+
setAuthError(null);
|
|
273378
|
+
try {
|
|
273379
|
+
const res = await fetch("https://api.deepgram.com/v1/projects", {
|
|
273380
|
+
headers: { Authorization: `Token ${trimmedKey}` }
|
|
273381
|
+
});
|
|
273382
|
+
if (!res.ok) {
|
|
273383
|
+
throw new Error("Invalid Deepgram API key. Please check your key from console.deepgram.com.");
|
|
273384
|
+
}
|
|
273385
|
+
const config = await loadConfig();
|
|
273386
|
+
config.providers = config.providers || {};
|
|
273387
|
+
config.providers.deepgram = trimmedKey;
|
|
273388
|
+
await saveConfig(config);
|
|
273389
|
+
setApiKey("");
|
|
273390
|
+
setAuthMode("none");
|
|
273391
|
+
addToast("Saved Deepgram API key for voice dictation.", "success");
|
|
273392
|
+
} catch (err) {
|
|
273393
|
+
setAuthError(err.message || "Failed to verify Deepgram API key.");
|
|
273394
|
+
} finally {
|
|
273395
|
+
setIsStreaming(false);
|
|
273396
|
+
}
|
|
273397
|
+
return;
|
|
273398
|
+
}
|
|
272331
273399
|
setIsStreaming(true);
|
|
272332
273400
|
setAuthError(null);
|
|
272333
273401
|
let testProvider;
|
|
@@ -272684,6 +273752,8 @@ function useSettingsHandlers() {
|
|
|
272684
273752
|
setSettingsSteeringMode,
|
|
272685
273753
|
settingsFollowUpMode,
|
|
272686
273754
|
setSettingsFollowUpMode,
|
|
273755
|
+
settingsBrowserVisible,
|
|
273756
|
+
setSettingsBrowserVisible,
|
|
272687
273757
|
settingsAuthPriority,
|
|
272688
273758
|
setSettingsAuthPriority,
|
|
272689
273759
|
setAuthMethod,
|
|
@@ -272694,7 +273764,7 @@ function useSettingsHandlers() {
|
|
|
272694
273764
|
setOllamaModels,
|
|
272695
273765
|
agent,
|
|
272696
273766
|
addToast
|
|
272697
|
-
} = useCliStore();
|
|
273767
|
+
} = useCliStore.getState();
|
|
272698
273768
|
const handleSettingsMainSelect = async (item) => {
|
|
272699
273769
|
const config = await loadConfig();
|
|
272700
273770
|
let updated = false;
|
|
@@ -272802,6 +273872,15 @@ function useSettingsHandlers() {
|
|
|
272802
273872
|
updated = true;
|
|
272803
273873
|
break;
|
|
272804
273874
|
}
|
|
273875
|
+
case "browserVisible": {
|
|
273876
|
+
const current = useCliStore.getState().settingsBrowserVisible;
|
|
273877
|
+
const nextVal = !(current !== false);
|
|
273878
|
+
config.browserVisible = nextVal;
|
|
273879
|
+
setSettingsBrowserVisible(nextVal);
|
|
273880
|
+
addToast(`Browser window set to ${nextVal ? "visible (on)" : "headless (off)"}`);
|
|
273881
|
+
updated = true;
|
|
273882
|
+
break;
|
|
273883
|
+
}
|
|
272805
273884
|
case "authPriority": {
|
|
272806
273885
|
const priorities = [
|
|
272807
273886
|
"subscription",
|
|
@@ -272858,6 +273937,503 @@ var init_use_settings_handlers = __esm(() => {
|
|
|
272858
273937
|
init_provider_factory();
|
|
272859
273938
|
});
|
|
272860
273939
|
|
|
273940
|
+
// src/utils/audio/detector.ts
|
|
273941
|
+
import { execSync as execSync5 } from "node:child_process";
|
|
273942
|
+
function checkBinary(name) {
|
|
273943
|
+
try {
|
|
273944
|
+
const isWindows = process.platform === "win32";
|
|
273945
|
+
const checkCmd = isWindows ? `where ${name}` : `which ${name}`;
|
|
273946
|
+
const stdout = execSync5(checkCmd, {
|
|
273947
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
273948
|
+
encoding: "utf8"
|
|
273949
|
+
}).trim();
|
|
273950
|
+
return stdout ? stdout.split(`
|
|
273951
|
+
`)[0].trim() : null;
|
|
273952
|
+
} catch {
|
|
273953
|
+
return null;
|
|
273954
|
+
}
|
|
273955
|
+
}
|
|
273956
|
+
function detectAudioBinary() {
|
|
273957
|
+
const ffmpegPath = checkBinary("ffmpeg");
|
|
273958
|
+
if (ffmpegPath) {
|
|
273959
|
+
return { available: true, binary: "ffmpeg", path: ffmpegPath };
|
|
273960
|
+
}
|
|
273961
|
+
const soxPath = checkBinary("rec") || checkBinary("sox");
|
|
273962
|
+
if (soxPath) {
|
|
273963
|
+
return { available: true, binary: "sox", path: soxPath };
|
|
273964
|
+
}
|
|
273965
|
+
if (process.platform === "linux") {
|
|
273966
|
+
const arecordPath = checkBinary("arecord");
|
|
273967
|
+
if (arecordPath) {
|
|
273968
|
+
return { available: true, binary: "arecord", path: arecordPath };
|
|
273969
|
+
}
|
|
273970
|
+
}
|
|
273971
|
+
return {
|
|
273972
|
+
available: false,
|
|
273973
|
+
binary: null,
|
|
273974
|
+
error: process.platform === "darwin" ? 'No audio recording binary found. Please install ffmpeg or sox (e.g. "brew install ffmpeg").' : process.platform === "linux" ? 'No audio recording binary found. Please install ffmpeg, sox, or alsa-utils (e.g. "sudo apt install ffmpeg").' : "No audio recording binary found. Please install ffmpeg or sox in your system PATH."
|
|
273975
|
+
};
|
|
273976
|
+
}
|
|
273977
|
+
var init_detector2 = () => {};
|
|
273978
|
+
|
|
273979
|
+
// src/utils/audio/recorder.ts
|
|
273980
|
+
import { spawn as spawn8 } from "node:child_process";
|
|
273981
|
+
import { EventEmitter as EventEmitter4 } from "node:events";
|
|
273982
|
+
var AudioRecorder;
|
|
273983
|
+
var init_recorder = __esm(() => {
|
|
273984
|
+
init_detector2();
|
|
273985
|
+
AudioRecorder = class AudioRecorder extends EventEmitter4 {
|
|
273986
|
+
process = null;
|
|
273987
|
+
isRecording = false;
|
|
273988
|
+
start(options = {}) {
|
|
273989
|
+
if (this.isRecording)
|
|
273990
|
+
return true;
|
|
273991
|
+
const detection = detectAudioBinary();
|
|
273992
|
+
if (!detection.available || !detection.binary) {
|
|
273993
|
+
this.emit("error", new Error(detection.error || "Audio recording binary not found."));
|
|
273994
|
+
return false;
|
|
273995
|
+
}
|
|
273996
|
+
const sampleRate = options.sampleRate ?? 16000;
|
|
273997
|
+
const channels = options.channels ?? 1;
|
|
273998
|
+
try {
|
|
273999
|
+
this.process = this.spawnRecorderProcess(detection.binary, sampleRate, channels);
|
|
274000
|
+
this.isRecording = true;
|
|
274001
|
+
this.process.stdout.on("data", (chunk) => {
|
|
274002
|
+
this.emit("data", chunk);
|
|
274003
|
+
});
|
|
274004
|
+
this.process.stderr.on("data", (data) => {
|
|
274005
|
+
const msg = data.toString();
|
|
274006
|
+
if (msg.includes("No such device") || msg.includes("Device or resource busy")) {
|
|
274007
|
+
this.emit("error", new Error(msg.trim()));
|
|
274008
|
+
}
|
|
274009
|
+
});
|
|
274010
|
+
this.process.on("error", (err) => {
|
|
274011
|
+
this.emit("error", err);
|
|
274012
|
+
this.stop();
|
|
274013
|
+
});
|
|
274014
|
+
this.process.on("close", (code) => {
|
|
274015
|
+
this.isRecording = false;
|
|
274016
|
+
this.process = null;
|
|
274017
|
+
this.emit("close", code);
|
|
274018
|
+
});
|
|
274019
|
+
return true;
|
|
274020
|
+
} catch (err) {
|
|
274021
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
274022
|
+
this.emit("error", error);
|
|
274023
|
+
this.stop();
|
|
274024
|
+
return false;
|
|
274025
|
+
}
|
|
274026
|
+
}
|
|
274027
|
+
spawnRecorderProcess(binary, sampleRate, channels) {
|
|
274028
|
+
if (binary === "ffmpeg") {
|
|
274029
|
+
const isLinux = process.platform === "linux";
|
|
274030
|
+
const isMac = process.platform === "darwin";
|
|
274031
|
+
const isWindows = process.platform === "win32";
|
|
274032
|
+
const args = [
|
|
274033
|
+
"-loglevel",
|
|
274034
|
+
"error",
|
|
274035
|
+
"-fflags",
|
|
274036
|
+
"nobuffer",
|
|
274037
|
+
"-flags",
|
|
274038
|
+
"low_delay"
|
|
274039
|
+
];
|
|
274040
|
+
if (isLinux) {
|
|
274041
|
+
args.push("-f", "pulse", "-i", "default");
|
|
274042
|
+
} else if (isMac) {
|
|
274043
|
+
args.push("-f", "avfoundation", "-i", ":default");
|
|
274044
|
+
} else if (isWindows) {
|
|
274045
|
+
args.push("-f", "dshow", "-i", "audio=default");
|
|
274046
|
+
}
|
|
274047
|
+
args.push("-ac", channels.toString(), "-ar", sampleRate.toString(), "-f", "s16le", "-flush_packets", "1", "-");
|
|
274048
|
+
return spawn8("ffmpeg", args);
|
|
274049
|
+
}
|
|
274050
|
+
if (binary === "sox") {
|
|
274051
|
+
const detection = detectAudioBinary();
|
|
274052
|
+
const binaryName = detection.path?.endsWith("rec") ? "rec" : "sox";
|
|
274053
|
+
const args = binaryName === "rec" ? [
|
|
274054
|
+
"-q",
|
|
274055
|
+
"-c",
|
|
274056
|
+
channels.toString(),
|
|
274057
|
+
"-r",
|
|
274058
|
+
sampleRate.toString(),
|
|
274059
|
+
"-b",
|
|
274060
|
+
"16",
|
|
274061
|
+
"-e",
|
|
274062
|
+
"signed",
|
|
274063
|
+
"-t",
|
|
274064
|
+
"raw",
|
|
274065
|
+
"-"
|
|
274066
|
+
] : [
|
|
274067
|
+
"-d",
|
|
274068
|
+
"-q",
|
|
274069
|
+
"-c",
|
|
274070
|
+
channels.toString(),
|
|
274071
|
+
"-r",
|
|
274072
|
+
sampleRate.toString(),
|
|
274073
|
+
"-b",
|
|
274074
|
+
"16",
|
|
274075
|
+
"-e",
|
|
274076
|
+
"signed",
|
|
274077
|
+
"-t",
|
|
274078
|
+
"raw",
|
|
274079
|
+
"-"
|
|
274080
|
+
];
|
|
274081
|
+
return spawn8(binaryName, args);
|
|
274082
|
+
}
|
|
274083
|
+
return spawn8("arecord", [
|
|
274084
|
+
"-q",
|
|
274085
|
+
"-c",
|
|
274086
|
+
channels.toString(),
|
|
274087
|
+
"-r",
|
|
274088
|
+
sampleRate.toString(),
|
|
274089
|
+
"-f",
|
|
274090
|
+
"S16_LE",
|
|
274091
|
+
"-t",
|
|
274092
|
+
"raw"
|
|
274093
|
+
]);
|
|
274094
|
+
}
|
|
274095
|
+
stop() {
|
|
274096
|
+
if (!this.isRecording && !this.process)
|
|
274097
|
+
return;
|
|
274098
|
+
this.isRecording = false;
|
|
274099
|
+
if (this.process) {
|
|
274100
|
+
try {
|
|
274101
|
+
this.process.kill("SIGTERM");
|
|
274102
|
+
} catch {}
|
|
274103
|
+
this.process = null;
|
|
274104
|
+
}
|
|
274105
|
+
}
|
|
274106
|
+
get recording() {
|
|
274107
|
+
return this.isRecording;
|
|
274108
|
+
}
|
|
274109
|
+
};
|
|
274110
|
+
});
|
|
274111
|
+
|
|
274112
|
+
// src/utils/audio/stt.ts
|
|
274113
|
+
import dns from "node:dns";
|
|
274114
|
+
async function resolveSTTKey() {
|
|
274115
|
+
const envDeepgram = process.env.DEEPGRAM_API_KEY?.trim();
|
|
274116
|
+
if (envDeepgram)
|
|
274117
|
+
return { provider: "deepgram", key: envDeepgram };
|
|
274118
|
+
const config = await loadConfig();
|
|
274119
|
+
const configDeepgram = config.providers?.deepgram?.trim();
|
|
274120
|
+
if (configDeepgram)
|
|
274121
|
+
return { provider: "deepgram", key: configDeepgram };
|
|
274122
|
+
return { provider: null, key: null };
|
|
274123
|
+
}
|
|
274124
|
+
function appendTranscript(base, next) {
|
|
274125
|
+
const trimmedBase = base.trim();
|
|
274126
|
+
const trimmedNext = next.trim();
|
|
274127
|
+
if (!trimmedBase)
|
|
274128
|
+
return trimmedNext;
|
|
274129
|
+
if (!trimmedNext)
|
|
274130
|
+
return trimmedBase;
|
|
274131
|
+
if (/^[.,!?;:]/.test(trimmedNext)) {
|
|
274132
|
+
return `${trimmedBase}${trimmedNext}`;
|
|
274133
|
+
}
|
|
274134
|
+
const baseWords = trimmedBase.split(/\s+/);
|
|
274135
|
+
const nextWords = trimmedNext.split(/\s+/);
|
|
274136
|
+
const maxOverlap = Math.min(3, baseWords.length, nextWords.length);
|
|
274137
|
+
let overlapCount = 0;
|
|
274138
|
+
const cleanWord = (w) => w.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
274139
|
+
for (let count = maxOverlap;count >= 1; count--) {
|
|
274140
|
+
const baseSlice = baseWords.slice(baseWords.length - count).map(cleanWord);
|
|
274141
|
+
const nextSlice = nextWords.slice(0, count).map(cleanWord);
|
|
274142
|
+
if (baseSlice.length === nextSlice.length && baseSlice.every((w, i) => w.length > 0 && w === nextSlice[i])) {
|
|
274143
|
+
overlapCount = count;
|
|
274144
|
+
break;
|
|
274145
|
+
}
|
|
274146
|
+
}
|
|
274147
|
+
if (overlapCount > 0) {
|
|
274148
|
+
const remainingNextWords = nextWords.slice(overlapCount);
|
|
274149
|
+
if (remainingNextWords.length === 0) {
|
|
274150
|
+
return trimmedBase;
|
|
274151
|
+
}
|
|
274152
|
+
return `${trimmedBase} ${remainingNextWords.join(" ")}`;
|
|
274153
|
+
}
|
|
274154
|
+
return `${trimmedBase} ${trimmedNext}`;
|
|
274155
|
+
}
|
|
274156
|
+
|
|
274157
|
+
class STTSession {
|
|
274158
|
+
key = null;
|
|
274159
|
+
ws = null;
|
|
274160
|
+
finalTranscript = "";
|
|
274161
|
+
interimTranscript = "";
|
|
274162
|
+
pendingChunks = [];
|
|
274163
|
+
heartbeatTimer = null;
|
|
274164
|
+
onTranscript;
|
|
274165
|
+
onError;
|
|
274166
|
+
isClosed = false;
|
|
274167
|
+
constructor(options) {
|
|
274168
|
+
this.onTranscript = options.onTranscript;
|
|
274169
|
+
this.onError = options.onError;
|
|
274170
|
+
}
|
|
274171
|
+
async init() {
|
|
274172
|
+
const resolved = await resolveSTTKey();
|
|
274173
|
+
if (!resolved.key) {
|
|
274174
|
+
this.onError(new Error("No Deepgram API key found. Set DEEPGRAM_API_KEY or configure via BYOK key menu."));
|
|
274175
|
+
return false;
|
|
274176
|
+
}
|
|
274177
|
+
this.key = resolved.key;
|
|
274178
|
+
return this.initDeepgram(this.key);
|
|
274179
|
+
}
|
|
274180
|
+
initDeepgram(key) {
|
|
274181
|
+
return new Promise((resolve) => {
|
|
274182
|
+
try {
|
|
274183
|
+
const url = "wss://api.deepgram.com/v1/listen?model=nova-2&smart_format=true&interim_results=true&endpointing=300&encoding=linear16&sample_rate=16000&channels=1";
|
|
274184
|
+
this.ws = new WebSocket(url, ["token", key]);
|
|
274185
|
+
let isHandshakeComplete = false;
|
|
274186
|
+
const handshakeTimeout = setTimeout(() => {
|
|
274187
|
+
if (!isHandshakeComplete) {
|
|
274188
|
+
isHandshakeComplete = true;
|
|
274189
|
+
try {
|
|
274190
|
+
if (this.ws && (this.ws.readyState === WebSocket.CONNECTING || this.ws.readyState === WebSocket.OPEN)) {
|
|
274191
|
+
this.ws.close();
|
|
274192
|
+
}
|
|
274193
|
+
} catch {}
|
|
274194
|
+
this.ws = null;
|
|
274195
|
+
this.onError(new Error("Deepgram WebSocket connection timed out. Check your internet connection."));
|
|
274196
|
+
resolve(false);
|
|
274197
|
+
}
|
|
274198
|
+
}, 1e4);
|
|
274199
|
+
this.ws.onopen = () => {
|
|
274200
|
+
if (isHandshakeComplete)
|
|
274201
|
+
return;
|
|
274202
|
+
isHandshakeComplete = true;
|
|
274203
|
+
clearTimeout(handshakeTimeout);
|
|
274204
|
+
this.startHeartbeat();
|
|
274205
|
+
this.flushPendingChunks();
|
|
274206
|
+
resolve(true);
|
|
274207
|
+
};
|
|
274208
|
+
this.ws.onmessage = (event) => {
|
|
274209
|
+
if (this.isClosed)
|
|
274210
|
+
return;
|
|
274211
|
+
try {
|
|
274212
|
+
const data = typeof event.data === "string" ? JSON.parse(event.data) : null;
|
|
274213
|
+
if (!data || data.type !== "Results")
|
|
274214
|
+
return;
|
|
274215
|
+
const alt = data.channel?.alternatives?.[0];
|
|
274216
|
+
const transcript = alt?.transcript?.trim();
|
|
274217
|
+
if (!transcript) {
|
|
274218
|
+
if (data.is_final) {
|
|
274219
|
+
this.interimTranscript = "";
|
|
274220
|
+
}
|
|
274221
|
+
return;
|
|
274222
|
+
}
|
|
274223
|
+
if (data.is_final) {
|
|
274224
|
+
this.finalTranscript = appendTranscript(this.finalTranscript, transcript);
|
|
274225
|
+
this.interimTranscript = "";
|
|
274226
|
+
this.onTranscript(this.finalTranscript, true);
|
|
274227
|
+
} else {
|
|
274228
|
+
this.interimTranscript = transcript;
|
|
274229
|
+
const fullText = appendTranscript(this.finalTranscript, this.interimTranscript);
|
|
274230
|
+
this.onTranscript(fullText, false);
|
|
274231
|
+
}
|
|
274232
|
+
} catch {}
|
|
274233
|
+
};
|
|
274234
|
+
this.ws.onerror = (_err) => {
|
|
274235
|
+
if (!isHandshakeComplete) {
|
|
274236
|
+
isHandshakeComplete = true;
|
|
274237
|
+
clearTimeout(handshakeTimeout);
|
|
274238
|
+
this.onError(new Error("Deepgram WebSocket connection error."));
|
|
274239
|
+
resolve(false);
|
|
274240
|
+
return;
|
|
274241
|
+
}
|
|
274242
|
+
if (!this.isClosed) {
|
|
274243
|
+
this.onError(new Error("Deepgram WebSocket connection error."));
|
|
274244
|
+
}
|
|
274245
|
+
};
|
|
274246
|
+
this.ws.onclose = () => {
|
|
274247
|
+
this.stopHeartbeat();
|
|
274248
|
+
};
|
|
274249
|
+
} catch (err) {
|
|
274250
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
274251
|
+
this.onError(error);
|
|
274252
|
+
resolve(false);
|
|
274253
|
+
}
|
|
274254
|
+
});
|
|
274255
|
+
}
|
|
274256
|
+
sendAudioChunk(chunk) {
|
|
274257
|
+
if (this.isClosed)
|
|
274258
|
+
return;
|
|
274259
|
+
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
|
274260
|
+
this.ws.send(chunk);
|
|
274261
|
+
} else if (!this.ws || this.ws.readyState === WebSocket.CONNECTING) {
|
|
274262
|
+
this.pendingChunks.push(chunk);
|
|
274263
|
+
}
|
|
274264
|
+
}
|
|
274265
|
+
flushPendingChunks() {
|
|
274266
|
+
if (!this.ws || this.ws.readyState !== WebSocket.OPEN)
|
|
274267
|
+
return;
|
|
274268
|
+
while (this.pendingChunks.length > 0) {
|
|
274269
|
+
const chunk = this.pendingChunks.shift();
|
|
274270
|
+
if (chunk) {
|
|
274271
|
+
try {
|
|
274272
|
+
this.ws.send(chunk);
|
|
274273
|
+
} catch {}
|
|
274274
|
+
}
|
|
274275
|
+
}
|
|
274276
|
+
}
|
|
274277
|
+
startHeartbeat() {
|
|
274278
|
+
this.stopHeartbeat();
|
|
274279
|
+
this.heartbeatTimer = setInterval(() => {
|
|
274280
|
+
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
|
274281
|
+
try {
|
|
274282
|
+
this.ws.send(JSON.stringify({ type: "KeepAlive" }));
|
|
274283
|
+
} catch {}
|
|
274284
|
+
}
|
|
274285
|
+
}, 4000);
|
|
274286
|
+
}
|
|
274287
|
+
stopHeartbeat() {
|
|
274288
|
+
if (this.heartbeatTimer) {
|
|
274289
|
+
clearInterval(this.heartbeatTimer);
|
|
274290
|
+
this.heartbeatTimer = null;
|
|
274291
|
+
}
|
|
274292
|
+
}
|
|
274293
|
+
async finish() {
|
|
274294
|
+
this.isClosed = true;
|
|
274295
|
+
this.stopHeartbeat();
|
|
274296
|
+
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
|
274297
|
+
try {
|
|
274298
|
+
this.ws.send(JSON.stringify({ type: "CloseStream" }));
|
|
274299
|
+
} catch {}
|
|
274300
|
+
await new Promise((resolve) => setTimeout(resolve, 150));
|
|
274301
|
+
try {
|
|
274302
|
+
if (this.ws.readyState === WebSocket.OPEN) {
|
|
274303
|
+
this.ws.close();
|
|
274304
|
+
}
|
|
274305
|
+
} catch {}
|
|
274306
|
+
this.ws = null;
|
|
274307
|
+
} else if (this.ws) {
|
|
274308
|
+
try {
|
|
274309
|
+
this.ws.close();
|
|
274310
|
+
} catch {}
|
|
274311
|
+
this.ws = null;
|
|
274312
|
+
}
|
|
274313
|
+
this.pendingChunks = [];
|
|
274314
|
+
const fullText = appendTranscript(this.finalTranscript, this.interimTranscript);
|
|
274315
|
+
return fullText.trim();
|
|
274316
|
+
}
|
|
274317
|
+
cancel() {
|
|
274318
|
+
this.isClosed = true;
|
|
274319
|
+
this.stopHeartbeat();
|
|
274320
|
+
this.pendingChunks = [];
|
|
274321
|
+
if (this.ws) {
|
|
274322
|
+
try {
|
|
274323
|
+
this.ws.close();
|
|
274324
|
+
} catch {}
|
|
274325
|
+
this.ws = null;
|
|
274326
|
+
}
|
|
274327
|
+
this.finalTranscript = "";
|
|
274328
|
+
this.interimTranscript = "";
|
|
274329
|
+
}
|
|
274330
|
+
}
|
|
274331
|
+
var init_stt = __esm(() => {
|
|
274332
|
+
init_config();
|
|
274333
|
+
try {
|
|
274334
|
+
dns.setDefaultResultOrder?.("ipv4first");
|
|
274335
|
+
} catch {}
|
|
274336
|
+
});
|
|
274337
|
+
|
|
274338
|
+
// src/utils/audio/index.ts
|
|
274339
|
+
async function isVoiceConfigured() {
|
|
274340
|
+
const binaryDetection = detectAudioBinary();
|
|
274341
|
+
const sttConfig = await resolveSTTKey();
|
|
274342
|
+
if (!binaryDetection.available) {
|
|
274343
|
+
return {
|
|
274344
|
+
available: false,
|
|
274345
|
+
hasBinary: false,
|
|
274346
|
+
hasKey: Boolean(sttConfig.key),
|
|
274347
|
+
error: binaryDetection.error
|
|
274348
|
+
};
|
|
274349
|
+
}
|
|
274350
|
+
if (!sttConfig.key) {
|
|
274351
|
+
return {
|
|
274352
|
+
available: false,
|
|
274353
|
+
hasBinary: true,
|
|
274354
|
+
hasKey: false,
|
|
274355
|
+
binary: binaryDetection.binary,
|
|
274356
|
+
error: "Deepgram API key not configured."
|
|
274357
|
+
};
|
|
274358
|
+
}
|
|
274359
|
+
return {
|
|
274360
|
+
available: true,
|
|
274361
|
+
hasBinary: true,
|
|
274362
|
+
hasKey: true,
|
|
274363
|
+
binary: binaryDetection.binary,
|
|
274364
|
+
provider: "deepgram"
|
|
274365
|
+
};
|
|
274366
|
+
}
|
|
274367
|
+
function getVoiceSetupNotice(status) {
|
|
274368
|
+
if (!status.hasBinary) {
|
|
274369
|
+
return [
|
|
274370
|
+
"Voice dictation requires an audio recording tool.",
|
|
274371
|
+
"",
|
|
274372
|
+
"Install:",
|
|
274373
|
+
" • macOS: brew install ffmpeg",
|
|
274374
|
+
" • Linux: sudo apt install ffmpeg"
|
|
274375
|
+
].join(`
|
|
274376
|
+
`);
|
|
274377
|
+
}
|
|
274378
|
+
return [
|
|
274379
|
+
"Voice dictation requires a Deepgram API key for real-time live streaming.",
|
|
274380
|
+
"",
|
|
274381
|
+
"Get a free key ($200 credit) at https://console.deepgram.com",
|
|
274382
|
+
"",
|
|
274383
|
+
"Configure key:",
|
|
274384
|
+
" december key deepgram <key>"
|
|
274385
|
+
].join(`
|
|
274386
|
+
`);
|
|
274387
|
+
}
|
|
274388
|
+
async function startVoiceDictation(options) {
|
|
274389
|
+
const configCheck = await isVoiceConfigured();
|
|
274390
|
+
if (!configCheck.available) {
|
|
274391
|
+
options.onError(new Error(configCheck.error || "Voice dictation is not available."));
|
|
274392
|
+
return null;
|
|
274393
|
+
}
|
|
274394
|
+
const stt = new STTSession({
|
|
274395
|
+
onTranscript: options.onTranscript,
|
|
274396
|
+
onError: options.onError
|
|
274397
|
+
});
|
|
274398
|
+
const initialized = await stt.init();
|
|
274399
|
+
if (!initialized) {
|
|
274400
|
+
return null;
|
|
274401
|
+
}
|
|
274402
|
+
const recorder = new AudioRecorder;
|
|
274403
|
+
recorder.on("data", (chunk) => {
|
|
274404
|
+
stt.sendAudioChunk(chunk);
|
|
274405
|
+
});
|
|
274406
|
+
recorder.on("error", (err) => {
|
|
274407
|
+
options.onError(err);
|
|
274408
|
+
stt.cancel();
|
|
274409
|
+
});
|
|
274410
|
+
const started = recorder.start();
|
|
274411
|
+
if (!started) {
|
|
274412
|
+
stt.cancel();
|
|
274413
|
+
return null;
|
|
274414
|
+
}
|
|
274415
|
+
return {
|
|
274416
|
+
stop: async () => {
|
|
274417
|
+
recorder.stop();
|
|
274418
|
+
return await stt.finish();
|
|
274419
|
+
},
|
|
274420
|
+
cancel: () => {
|
|
274421
|
+
recorder.stop();
|
|
274422
|
+
stt.cancel();
|
|
274423
|
+
},
|
|
274424
|
+
get isRecording() {
|
|
274425
|
+
return recorder.recording;
|
|
274426
|
+
}
|
|
274427
|
+
};
|
|
274428
|
+
}
|
|
274429
|
+
var init_audio2 = __esm(() => {
|
|
274430
|
+
init_detector2();
|
|
274431
|
+
init_recorder();
|
|
274432
|
+
init_stt();
|
|
274433
|
+
init_detector2();
|
|
274434
|
+
init_recorder();
|
|
274435
|
+
});
|
|
274436
|
+
|
|
272861
274437
|
// src/hooks/use-agent-session.ts
|
|
272862
274438
|
var exports_use_agent_session = {};
|
|
272863
274439
|
__export(exports_use_agent_session, {
|
|
@@ -272993,7 +274569,9 @@ function useAgentSession({
|
|
|
272993
274569
|
settingsSteeringMode,
|
|
272994
274570
|
setSettingsSteeringMode,
|
|
272995
274571
|
settingsFollowUpMode,
|
|
272996
|
-
setSettingsFollowUpMode
|
|
274572
|
+
setSettingsFollowUpMode,
|
|
274573
|
+
settingsBrowserVisible,
|
|
274574
|
+
setSettingsBrowserVisible
|
|
272997
274575
|
} = state;
|
|
272998
274576
|
const [expandCommands, setExpandCommands] = import_react71.useState(false);
|
|
272999
274577
|
const toggleExpandCommands = import_react71.useCallback(() => {
|
|
@@ -274046,6 +275624,36 @@ ${decStatus}
|
|
|
274046
275624
|
}
|
|
274047
275625
|
return;
|
|
274048
275626
|
}
|
|
275627
|
+
if (text.trim() === "/voice") {
|
|
275628
|
+
await Promise.resolve().then(() => init_audio2());
|
|
275629
|
+
const status = await isVoiceConfigured();
|
|
275630
|
+
if (!status.available) {
|
|
275631
|
+
const userMsg = {
|
|
275632
|
+
id: getNextMsgId(),
|
|
275633
|
+
role: "user",
|
|
275634
|
+
displayText: "/voice",
|
|
275635
|
+
text: "/voice"
|
|
275636
|
+
};
|
|
275637
|
+
const noticeMsg = {
|
|
275638
|
+
id: getNextMsgId(),
|
|
275639
|
+
role: "assistant",
|
|
275640
|
+
blocks: [
|
|
275641
|
+
{
|
|
275642
|
+
type: "text",
|
|
275643
|
+
content: getVoiceSetupNotice(status)
|
|
275644
|
+
}
|
|
275645
|
+
]
|
|
275646
|
+
};
|
|
275647
|
+
setStaticMessages((prev) => [
|
|
275648
|
+
...prev,
|
|
275649
|
+
...useCliStore.getState().activeMessages,
|
|
275650
|
+
userMsg,
|
|
275651
|
+
noticeMsg
|
|
275652
|
+
]);
|
|
275653
|
+
setActiveMessages([]);
|
|
275654
|
+
return;
|
|
275655
|
+
}
|
|
275656
|
+
}
|
|
274049
275657
|
if (text.trim() === "/copy") {
|
|
274050
275658
|
try {
|
|
274051
275659
|
await init_src7();
|
|
@@ -274433,6 +276041,7 @@ ${decStatus}
|
|
|
274433
276041
|
setSettingsThinkingLevel(config.thinkingLevel ?? "auto");
|
|
274434
276042
|
setSettingsSteeringMode(config.steeringMode ?? "all");
|
|
274435
276043
|
setSettingsFollowUpMode(config.followUpMode ?? "all");
|
|
276044
|
+
setSettingsBrowserVisible(config.browserVisible !== false);
|
|
274436
276045
|
setAuthMode("settings_main");
|
|
274437
276046
|
});
|
|
274438
276047
|
return;
|
|
@@ -274837,7 +276446,46 @@ If it doesn't open automatically, please click here:
|
|
|
274837
276446
|
setStaticMessages
|
|
274838
276447
|
]);
|
|
274839
276448
|
const handleContextSelect = () => {};
|
|
276449
|
+
const handleStartVoice = import_react71.useCallback(async (callbacks) => {
|
|
276450
|
+
await Promise.resolve().then(() => init_audio2());
|
|
276451
|
+
const status = await isVoiceConfigured();
|
|
276452
|
+
if (!status.hasBinary) {
|
|
276453
|
+
const userMsg = {
|
|
276454
|
+
id: getNextMsgId(),
|
|
276455
|
+
role: "user",
|
|
276456
|
+
displayText: "/voice",
|
|
276457
|
+
text: "/voice"
|
|
276458
|
+
};
|
|
276459
|
+
const noticeMsg = {
|
|
276460
|
+
id: getNextMsgId(),
|
|
276461
|
+
role: "assistant",
|
|
276462
|
+
blocks: [
|
|
276463
|
+
{
|
|
276464
|
+
type: "text",
|
|
276465
|
+
content: getVoiceSetupNotice(status)
|
|
276466
|
+
}
|
|
276467
|
+
]
|
|
276468
|
+
};
|
|
276469
|
+
setStaticMessages((prev) => [
|
|
276470
|
+
...prev,
|
|
276471
|
+
...useCliStore.getState().activeMessages,
|
|
276472
|
+
userMsg,
|
|
276473
|
+
noticeMsg
|
|
276474
|
+
]);
|
|
276475
|
+
setActiveMessages([]);
|
|
276476
|
+
return null;
|
|
276477
|
+
}
|
|
276478
|
+
if (!status.hasKey) {
|
|
276479
|
+
useCliStore.getState().setSelectedProvider("deepgram");
|
|
276480
|
+
useCliStore.getState().setApiKey("");
|
|
276481
|
+
useCliStore.getState().setAuthError(null);
|
|
276482
|
+
useCliStore.getState().setAuthMode("byok_key");
|
|
276483
|
+
return null;
|
|
276484
|
+
}
|
|
276485
|
+
return await startVoiceDictation(callbacks);
|
|
276486
|
+
}, [setStaticMessages, setActiveMessages]);
|
|
274840
276487
|
return {
|
|
276488
|
+
onStartVoice: handleStartVoice,
|
|
274841
276489
|
currentPlannedPrompt,
|
|
274842
276490
|
setCurrentPlannedPrompt,
|
|
274843
276491
|
currentPlanText,
|
|
@@ -274932,6 +276580,8 @@ If it doesn't open automatically, please click here:
|
|
|
274932
276580
|
setSettingsSteeringMode,
|
|
274933
276581
|
settingsFollowUpMode,
|
|
274934
276582
|
setSettingsFollowUpMode,
|
|
276583
|
+
settingsBrowserVisible,
|
|
276584
|
+
setSettingsBrowserVisible,
|
|
274935
276585
|
handleSubmit,
|
|
274936
276586
|
sessionRepository,
|
|
274937
276587
|
handleSettingsMainSelect,
|
|
@@ -275008,7 +276658,7 @@ var init_use_agent_session = __esm(async () => {
|
|
|
275008
276658
|
|
|
275009
276659
|
// src/index.ts
|
|
275010
276660
|
init_package();
|
|
275011
|
-
import
|
|
276661
|
+
import path41 from "node:path";
|
|
275012
276662
|
|
|
275013
276663
|
// src/args.ts
|
|
275014
276664
|
import { parseArgs } from "node:util";
|
|
@@ -275146,12 +276796,11 @@ Options:
|
|
|
275146
276796
|
}
|
|
275147
276797
|
// src/constants/release-highlights.json
|
|
275148
276798
|
var release_highlights_default = {
|
|
275149
|
-
version: "0.4.
|
|
275150
|
-
title: "What's New in v0.4.
|
|
276799
|
+
version: "0.4.5",
|
|
276800
|
+
title: "What's New in v0.4.5",
|
|
275151
276801
|
bullets: [
|
|
275152
|
-
"*(
|
|
275153
|
-
"*(
|
|
275154
|
-
"*(tools)* Prefer non-import lines when resolving symbol definition in code_intelligence"
|
|
276802
|
+
"*(cli,tui)* Add voice input dictation and workspace trust verification",
|
|
276803
|
+
"*(tools,cli)* Interactive cdp browser engine and browser_action tool (#506, #509)"
|
|
275155
276804
|
],
|
|
275156
276805
|
url: "https://trydecember.com/docs/changelog"
|
|
275157
276806
|
};
|
|
@@ -275161,6 +276810,7 @@ init_env_sanitizer();
|
|
|
275161
276810
|
init_env_sanitizer();
|
|
275162
276811
|
init_commands();
|
|
275163
276812
|
init_headless_runner();
|
|
276813
|
+
init_workspace_trust();
|
|
275164
276814
|
purgeProjectEnvApiKeys();
|
|
275165
276815
|
async function readPipedStdin() {
|
|
275166
276816
|
if (process.stdin.isTTY)
|
|
@@ -275279,6 +276929,11 @@ To define project-specific instructions, create an AGENTS.md file in your projec
|
|
|
275279
276929
|
}
|
|
275280
276930
|
parsedArgs.prompt = question;
|
|
275281
276931
|
}
|
|
276932
|
+
await Promise.resolve().then(() => init_workspace_trust());
|
|
276933
|
+
await ensureWorkspaceTrust({
|
|
276934
|
+
targetDir: parsedArgs.scope,
|
|
276935
|
+
isHeadless: Boolean(parsedArgs.prompt)
|
|
276936
|
+
});
|
|
275282
276937
|
if (parsedArgs.prompt) {
|
|
275283
276938
|
const [
|
|
275284
276939
|
{ AgentHarness },
|
|
@@ -275352,7 +277007,7 @@ To define project-specific instructions, create an AGENTS.md file in your projec
|
|
|
275352
277007
|
sessionRepository,
|
|
275353
277008
|
sessionId,
|
|
275354
277009
|
runtime: "cli",
|
|
275355
|
-
workspaceDir: parsedArgs.scope ?
|
|
277010
|
+
workspaceDir: parsedArgs.scope ? path41.resolve(process.cwd(), parsedArgs.scope) : process.cwd(),
|
|
275356
277011
|
thinkingLevel: config.thinkingLevel || "auto",
|
|
275357
277012
|
steeringMode: config.steeringMode || "all",
|
|
275358
277013
|
followUpMode: config.followUpMode || "all"
|
|
@@ -275456,7 +277111,7 @@ Executing Headless Task: "${parsedArgs.prompt}"
|
|
|
275456
277111
|
sessionRepository,
|
|
275457
277112
|
sessionId,
|
|
275458
277113
|
runtime: "cli",
|
|
275459
|
-
workspaceDir: parsedArgs.scope ?
|
|
277114
|
+
workspaceDir: parsedArgs.scope ? path41.resolve(process.cwd(), parsedArgs.scope) : process.cwd(),
|
|
275460
277115
|
thinkingLevel: config.thinkingLevel || "auto",
|
|
275461
277116
|
steeringMode: config.steeringMode || "all",
|
|
275462
277117
|
followUpMode: config.followUpMode || "all"
|
|
@@ -275541,6 +277196,8 @@ Executing Headless Task: "${parsedArgs.prompt}"
|
|
|
275541
277196
|
}
|
|
275542
277197
|
main().catch(console.error);
|
|
275543
277198
|
export {
|
|
277199
|
+
addTrustedWorkspace,
|
|
277200
|
+
ensureWorkspaceTrust,
|
|
275544
277201
|
getHelpText,
|
|
275545
277202
|
handleAuthCommand,
|
|
275546
277203
|
handleDoctorCommand,
|
|
@@ -275550,9 +277207,11 @@ export {
|
|
|
275550
277207
|
handleLogoutCommand,
|
|
275551
277208
|
handleSwitchCommand,
|
|
275552
277209
|
handleUpdateCommand,
|
|
277210
|
+
isWorkspaceTrusted,
|
|
275553
277211
|
parseCliArgs,
|
|
275554
277212
|
purgeProjectEnvApiKeys,
|
|
275555
277213
|
readPipedStdin,
|
|
277214
|
+
resolveWorkspaceRoot,
|
|
275556
277215
|
restoreConsole,
|
|
275557
277216
|
runHeadlessTask,
|
|
275558
277217
|
suppressConsole
|