codex-to-im 0.1.2 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +51 -4
- package/README_CN.md +49 -3
- package/config.env.example +36 -12
- package/dist/cli.mjs +9 -4
- package/dist/daemon.mjs +1766 -356
- package/dist/ui-server.mjs +1046 -110
- package/docs/install-windows.md +44 -6
- package/package.json +2 -1
- package/scripts/patch-codex-sdk-windows-hide.js +83 -0
package/dist/daemon.mjs
CHANGED
|
@@ -9999,9 +9999,9 @@ var require_form_data = __commonJS({
|
|
|
9999
9999
|
var http = __require("http");
|
|
10000
10000
|
var https = __require("https");
|
|
10001
10001
|
var parseUrl = __require("url").parse;
|
|
10002
|
-
var
|
|
10002
|
+
var fs11 = __require("fs");
|
|
10003
10003
|
var Stream = __require("stream").Stream;
|
|
10004
|
-
var
|
|
10004
|
+
var crypto11 = __require("crypto");
|
|
10005
10005
|
var mime = require_mime_types();
|
|
10006
10006
|
var asynckit = require_asynckit();
|
|
10007
10007
|
var setToStringTag = require_es_set_tostringtag();
|
|
@@ -10066,7 +10066,7 @@ var require_form_data = __commonJS({
|
|
|
10066
10066
|
if (value.end != void 0 && value.end != Infinity && value.start != void 0) {
|
|
10067
10067
|
callback(null, value.end + 1 - (value.start ? value.start : 0));
|
|
10068
10068
|
} else {
|
|
10069
|
-
|
|
10069
|
+
fs11.stat(value.path, function(err, stat) {
|
|
10070
10070
|
if (err) {
|
|
10071
10071
|
callback(err);
|
|
10072
10072
|
return;
|
|
@@ -10207,7 +10207,7 @@ var require_form_data = __commonJS({
|
|
|
10207
10207
|
return Buffer.concat([dataBuffer, Buffer.from(this._lastBoundary())]);
|
|
10208
10208
|
};
|
|
10209
10209
|
FormData2.prototype._generateBoundary = function() {
|
|
10210
|
-
this._boundary = "--------------------------" +
|
|
10210
|
+
this._boundary = "--------------------------" + crypto11.randomBytes(12).toString("hex");
|
|
10211
10211
|
};
|
|
10212
10212
|
FormData2.prototype.getLengthSync = function() {
|
|
10213
10213
|
var knownLength = this._overheadLength + this._valueLength;
|
|
@@ -10899,7 +10899,7 @@ var require_axios = __commonJS({
|
|
|
10899
10899
|
"node_modules/axios/dist/node/axios.cjs"(exports2, module2) {
|
|
10900
10900
|
"use strict";
|
|
10901
10901
|
var FormData$1 = require_form_data();
|
|
10902
|
-
var
|
|
10902
|
+
var crypto11 = __require("crypto");
|
|
10903
10903
|
var url = __require("url");
|
|
10904
10904
|
var proxyFromEnv = require_proxy_from_env();
|
|
10905
10905
|
var http = __require("http");
|
|
@@ -10914,7 +10914,7 @@ var require_axios = __commonJS({
|
|
|
10914
10914
|
return e && typeof e === "object" && "default" in e ? e : { "default": e };
|
|
10915
10915
|
}
|
|
10916
10916
|
var FormData__default = /* @__PURE__ */ _interopDefaultLegacy(FormData$1);
|
|
10917
|
-
var crypto__default = /* @__PURE__ */ _interopDefaultLegacy(
|
|
10917
|
+
var crypto__default = /* @__PURE__ */ _interopDefaultLegacy(crypto11);
|
|
10918
10918
|
var url__default = /* @__PURE__ */ _interopDefaultLegacy(url);
|
|
10919
10919
|
var proxyFromEnv__default = /* @__PURE__ */ _interopDefaultLegacy(proxyFromEnv);
|
|
10920
10920
|
var http__default = /* @__PURE__ */ _interopDefaultLegacy(http);
|
|
@@ -22889,11 +22889,11 @@ var require_lib2 = __commonJS({
|
|
|
22889
22889
|
"use strict";
|
|
22890
22890
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
22891
22891
|
var axios = require_axios();
|
|
22892
|
-
var
|
|
22892
|
+
var crypto11 = __require("crypto");
|
|
22893
22893
|
var qs = require_lib();
|
|
22894
22894
|
var identity = require_lodash();
|
|
22895
22895
|
var pickBy = require_lodash2();
|
|
22896
|
-
var
|
|
22896
|
+
var fs11 = __require("fs");
|
|
22897
22897
|
var merge = require_lodash3();
|
|
22898
22898
|
var qs$1 = __require("querystring");
|
|
22899
22899
|
var WebSocket2 = require_ws();
|
|
@@ -22901,10 +22901,10 @@ var require_lib2 = __commonJS({
|
|
|
22901
22901
|
return e && typeof e === "object" && "default" in e ? e : { "default": e };
|
|
22902
22902
|
}
|
|
22903
22903
|
var axios__default = /* @__PURE__ */ _interopDefaultLegacy(axios);
|
|
22904
|
-
var crypto__default = /* @__PURE__ */ _interopDefaultLegacy(
|
|
22904
|
+
var crypto__default = /* @__PURE__ */ _interopDefaultLegacy(crypto11);
|
|
22905
22905
|
var identity__default = /* @__PURE__ */ _interopDefaultLegacy(identity);
|
|
22906
22906
|
var pickBy__default = /* @__PURE__ */ _interopDefaultLegacy(pickBy);
|
|
22907
|
-
var fs__default = /* @__PURE__ */ _interopDefaultLegacy(
|
|
22907
|
+
var fs__default = /* @__PURE__ */ _interopDefaultLegacy(fs11);
|
|
22908
22908
|
var merge__default = /* @__PURE__ */ _interopDefaultLegacy(merge);
|
|
22909
22909
|
var qs__default = /* @__PURE__ */ _interopDefaultLegacy(qs$1);
|
|
22910
22910
|
var WebSocket__default = /* @__PURE__ */ _interopDefaultLegacy(WebSocket2);
|
|
@@ -106854,11 +106854,11 @@ var require_util2 = __commonJS({
|
|
|
106854
106854
|
var { isUint8Array } = __require("node:util/types");
|
|
106855
106855
|
var { webidl } = require_webidl();
|
|
106856
106856
|
var supportedHashes = [];
|
|
106857
|
-
var
|
|
106857
|
+
var crypto11;
|
|
106858
106858
|
try {
|
|
106859
|
-
|
|
106859
|
+
crypto11 = __require("node:crypto");
|
|
106860
106860
|
const possibleRelevantHashes = ["sha256", "sha384", "sha512"];
|
|
106861
|
-
supportedHashes =
|
|
106861
|
+
supportedHashes = crypto11.getHashes().filter((hash) => possibleRelevantHashes.includes(hash));
|
|
106862
106862
|
} catch {
|
|
106863
106863
|
}
|
|
106864
106864
|
function responseURL(response) {
|
|
@@ -107131,7 +107131,7 @@ var require_util2 = __commonJS({
|
|
|
107131
107131
|
}
|
|
107132
107132
|
}
|
|
107133
107133
|
function bytesMatch(bytes, metadataList) {
|
|
107134
|
-
if (
|
|
107134
|
+
if (crypto11 === void 0) {
|
|
107135
107135
|
return true;
|
|
107136
107136
|
}
|
|
107137
107137
|
const parsedMetadata = parseMetadata(metadataList);
|
|
@@ -107146,7 +107146,7 @@ var require_util2 = __commonJS({
|
|
|
107146
107146
|
for (const item of metadata) {
|
|
107147
107147
|
const algorithm = item.algo;
|
|
107148
107148
|
const expectedValue = item.hash;
|
|
107149
|
-
let actualValue =
|
|
107149
|
+
let actualValue = crypto11.createHash(algorithm).update(bytes).digest("base64");
|
|
107150
107150
|
if (actualValue[actualValue.length - 1] === "=") {
|
|
107151
107151
|
if (actualValue[actualValue.length - 2] === "=") {
|
|
107152
107152
|
actualValue = actualValue.slice(0, -2);
|
|
@@ -108210,8 +108210,8 @@ var require_body = __commonJS({
|
|
|
108210
108210
|
var { multipartFormDataParser } = require_formdata_parser();
|
|
108211
108211
|
var random;
|
|
108212
108212
|
try {
|
|
108213
|
-
const
|
|
108214
|
-
random = (max) =>
|
|
108213
|
+
const crypto11 = __require("node:crypto");
|
|
108214
|
+
random = (max) => crypto11.randomInt(0, max);
|
|
108215
108215
|
} catch {
|
|
108216
108216
|
random = (max) => Math.floor(Math.random(max));
|
|
108217
108217
|
}
|
|
@@ -119619,13 +119619,13 @@ var require_frame = __commonJS({
|
|
|
119619
119619
|
"use strict";
|
|
119620
119620
|
var { maxUnsigned16Bit } = require_constants6();
|
|
119621
119621
|
var BUFFER_SIZE = 16386;
|
|
119622
|
-
var
|
|
119622
|
+
var crypto11;
|
|
119623
119623
|
var buffer = null;
|
|
119624
119624
|
var bufIdx = BUFFER_SIZE;
|
|
119625
119625
|
try {
|
|
119626
|
-
|
|
119626
|
+
crypto11 = __require("node:crypto");
|
|
119627
119627
|
} catch {
|
|
119628
|
-
|
|
119628
|
+
crypto11 = {
|
|
119629
119629
|
// not full compatibility, but minimum.
|
|
119630
119630
|
randomFillSync: function randomFillSync(buffer2, _offset, _size) {
|
|
119631
119631
|
for (let i = 0; i < buffer2.length; ++i) {
|
|
@@ -119638,7 +119638,7 @@ var require_frame = __commonJS({
|
|
|
119638
119638
|
function generateMask() {
|
|
119639
119639
|
if (bufIdx === BUFFER_SIZE) {
|
|
119640
119640
|
bufIdx = 0;
|
|
119641
|
-
|
|
119641
|
+
crypto11.randomFillSync(buffer ??= Buffer.allocUnsafe(BUFFER_SIZE), 0, BUFFER_SIZE);
|
|
119642
119642
|
}
|
|
119643
119643
|
return [buffer[bufIdx++], buffer[bufIdx++], buffer[bufIdx++], buffer[bufIdx++]];
|
|
119644
119644
|
}
|
|
@@ -119710,9 +119710,9 @@ var require_connection = __commonJS({
|
|
|
119710
119710
|
var { Headers, getHeadersList } = require_headers();
|
|
119711
119711
|
var { getDecodeSplit } = require_util2();
|
|
119712
119712
|
var { WebsocketFrameSend } = require_frame();
|
|
119713
|
-
var
|
|
119713
|
+
var crypto11;
|
|
119714
119714
|
try {
|
|
119715
|
-
|
|
119715
|
+
crypto11 = __require("node:crypto");
|
|
119716
119716
|
} catch {
|
|
119717
119717
|
}
|
|
119718
119718
|
function establishWebSocketConnection(url, protocols, client, ws, onEstablish, options) {
|
|
@@ -119732,7 +119732,7 @@ var require_connection = __commonJS({
|
|
|
119732
119732
|
const headersList = getHeadersList(new Headers(options.headers));
|
|
119733
119733
|
request.headersList = headersList;
|
|
119734
119734
|
}
|
|
119735
|
-
const keyValue =
|
|
119735
|
+
const keyValue = crypto11.randomBytes(16).toString("base64");
|
|
119736
119736
|
request.headersList.append("sec-websocket-key", keyValue);
|
|
119737
119737
|
request.headersList.append("sec-websocket-version", "13");
|
|
119738
119738
|
for (const protocol of protocols) {
|
|
@@ -119762,7 +119762,7 @@ var require_connection = __commonJS({
|
|
|
119762
119762
|
return;
|
|
119763
119763
|
}
|
|
119764
119764
|
const secWSAccept = response.headersList.get("Sec-WebSocket-Accept");
|
|
119765
|
-
const digest =
|
|
119765
|
+
const digest = crypto11.createHash("sha1").update(keyValue + uid).digest("base64");
|
|
119766
119766
|
if (secWSAccept !== digest) {
|
|
119767
119767
|
failWebsocketConnection(ws, "Incorrect hash received in Sec-WebSocket-Accept header.");
|
|
119768
119768
|
return;
|
|
@@ -136304,11 +136304,11 @@ var require_util10 = __commonJS({
|
|
|
136304
136304
|
var { isUint8Array } = __require("node:util/types");
|
|
136305
136305
|
var { webidl } = require_webidl2();
|
|
136306
136306
|
var supportedHashes = [];
|
|
136307
|
-
var
|
|
136307
|
+
var crypto11;
|
|
136308
136308
|
try {
|
|
136309
|
-
|
|
136309
|
+
crypto11 = __require("node:crypto");
|
|
136310
136310
|
const possibleRelevantHashes = ["sha256", "sha384", "sha512"];
|
|
136311
|
-
supportedHashes =
|
|
136311
|
+
supportedHashes = crypto11.getHashes().filter((hash) => possibleRelevantHashes.includes(hash));
|
|
136312
136312
|
} catch {
|
|
136313
136313
|
}
|
|
136314
136314
|
function responseURL(response) {
|
|
@@ -136581,7 +136581,7 @@ var require_util10 = __commonJS({
|
|
|
136581
136581
|
}
|
|
136582
136582
|
}
|
|
136583
136583
|
function bytesMatch(bytes, metadataList) {
|
|
136584
|
-
if (
|
|
136584
|
+
if (crypto11 === void 0) {
|
|
136585
136585
|
return true;
|
|
136586
136586
|
}
|
|
136587
136587
|
const parsedMetadata = parseMetadata(metadataList);
|
|
@@ -136596,7 +136596,7 @@ var require_util10 = __commonJS({
|
|
|
136596
136596
|
for (const item of metadata) {
|
|
136597
136597
|
const algorithm = item.algo;
|
|
136598
136598
|
const expectedValue = item.hash;
|
|
136599
|
-
let actualValue =
|
|
136599
|
+
let actualValue = crypto11.createHash(algorithm).update(bytes).digest("base64");
|
|
136600
136600
|
if (actualValue[actualValue.length - 1] === "=") {
|
|
136601
136601
|
if (actualValue[actualValue.length - 2] === "=") {
|
|
136602
136602
|
actualValue = actualValue.slice(0, -2);
|
|
@@ -137660,8 +137660,8 @@ var require_body2 = __commonJS({
|
|
|
137660
137660
|
var { multipartFormDataParser } = require_formdata_parser2();
|
|
137661
137661
|
var random;
|
|
137662
137662
|
try {
|
|
137663
|
-
const
|
|
137664
|
-
random = (max) =>
|
|
137663
|
+
const crypto11 = __require("node:crypto");
|
|
137664
|
+
random = (max) => crypto11.randomInt(0, max);
|
|
137665
137665
|
} catch {
|
|
137666
137666
|
random = (max) => Math.floor(Math.random(max));
|
|
137667
137667
|
}
|
|
@@ -148990,13 +148990,13 @@ var require_frame2 = __commonJS({
|
|
|
148990
148990
|
"use strict";
|
|
148991
148991
|
var { maxUnsigned16Bit } = require_constants11();
|
|
148992
148992
|
var BUFFER_SIZE = 16386;
|
|
148993
|
-
var
|
|
148993
|
+
var crypto11;
|
|
148994
148994
|
var buffer = null;
|
|
148995
148995
|
var bufIdx = BUFFER_SIZE;
|
|
148996
148996
|
try {
|
|
148997
|
-
|
|
148997
|
+
crypto11 = __require("node:crypto");
|
|
148998
148998
|
} catch {
|
|
148999
|
-
|
|
148999
|
+
crypto11 = {
|
|
149000
149000
|
// not full compatibility, but minimum.
|
|
149001
149001
|
randomFillSync: function randomFillSync(buffer2, _offset, _size) {
|
|
149002
149002
|
for (let i = 0; i < buffer2.length; ++i) {
|
|
@@ -149009,7 +149009,7 @@ var require_frame2 = __commonJS({
|
|
|
149009
149009
|
function generateMask() {
|
|
149010
149010
|
if (bufIdx === BUFFER_SIZE) {
|
|
149011
149011
|
bufIdx = 0;
|
|
149012
|
-
|
|
149012
|
+
crypto11.randomFillSync(buffer ??= Buffer.allocUnsafe(BUFFER_SIZE), 0, BUFFER_SIZE);
|
|
149013
149013
|
}
|
|
149014
149014
|
return [buffer[bufIdx++], buffer[bufIdx++], buffer[bufIdx++], buffer[bufIdx++]];
|
|
149015
149015
|
}
|
|
@@ -149081,9 +149081,9 @@ var require_connection2 = __commonJS({
|
|
|
149081
149081
|
var { Headers, getHeadersList } = require_headers2();
|
|
149082
149082
|
var { getDecodeSplit } = require_util10();
|
|
149083
149083
|
var { WebsocketFrameSend } = require_frame2();
|
|
149084
|
-
var
|
|
149084
|
+
var crypto11;
|
|
149085
149085
|
try {
|
|
149086
|
-
|
|
149086
|
+
crypto11 = __require("node:crypto");
|
|
149087
149087
|
} catch {
|
|
149088
149088
|
}
|
|
149089
149089
|
function establishWebSocketConnection(url, protocols, client, ws, onEstablish, options) {
|
|
@@ -149103,7 +149103,7 @@ var require_connection2 = __commonJS({
|
|
|
149103
149103
|
const headersList = getHeadersList(new Headers(options.headers));
|
|
149104
149104
|
request.headersList = headersList;
|
|
149105
149105
|
}
|
|
149106
|
-
const keyValue =
|
|
149106
|
+
const keyValue = crypto11.randomBytes(16).toString("base64");
|
|
149107
149107
|
request.headersList.append("sec-websocket-key", keyValue);
|
|
149108
149108
|
request.headersList.append("sec-websocket-version", "13");
|
|
149109
149109
|
for (const protocol of protocols) {
|
|
@@ -149133,7 +149133,7 @@ var require_connection2 = __commonJS({
|
|
|
149133
149133
|
return;
|
|
149134
149134
|
}
|
|
149135
149135
|
const secWSAccept = response.headersList.get("Sec-WebSocket-Accept");
|
|
149136
|
-
const digest =
|
|
149136
|
+
const digest = crypto11.createHash("sha1").update(keyValue + uid).digest("base64");
|
|
149137
149137
|
if (secWSAccept !== digest) {
|
|
149138
149138
|
failWebsocketConnection(ws, "Incorrect hash received in Sec-WebSocket-Accept header.");
|
|
149139
149139
|
return;
|
|
@@ -155919,7 +155919,7 @@ var require_DataResolver = __commonJS({
|
|
|
155919
155919
|
"node_modules/discord.js/src/util/DataResolver.js"(exports2, module2) {
|
|
155920
155920
|
"use strict";
|
|
155921
155921
|
var { Buffer: Buffer2 } = __require("node:buffer");
|
|
155922
|
-
var
|
|
155922
|
+
var fs11 = __require("node:fs/promises");
|
|
155923
155923
|
var path12 = __require("node:path");
|
|
155924
155924
|
var { fetch: fetch2 } = require_undici2();
|
|
155925
155925
|
var { DiscordjsError: DiscordjsError2, DiscordjsTypeError: DiscordjsTypeError2, ErrorCodes: ErrorCodes2 } = require_errors2();
|
|
@@ -155947,9 +155947,9 @@ var require_DataResolver = __commonJS({
|
|
|
155947
155947
|
return { data: Buffer2.from(await res.arrayBuffer()), contentType: res.headers.get("content-type") };
|
|
155948
155948
|
}
|
|
155949
155949
|
const file = path12.resolve(resource);
|
|
155950
|
-
const stats = await
|
|
155950
|
+
const stats = await fs11.stat(file);
|
|
155951
155951
|
if (!stats.isFile()) throw new DiscordjsError2(ErrorCodes2.FileNotFound, file);
|
|
155952
|
-
return { data: await
|
|
155952
|
+
return { data: await fs11.readFile(file) };
|
|
155953
155953
|
}
|
|
155954
155954
|
throw new DiscordjsTypeError2(ErrorCodes2.ReqResourceType);
|
|
155955
155955
|
}
|
|
@@ -191204,7 +191204,7 @@ var require_ShardingManager = __commonJS({
|
|
|
191204
191204
|
"node_modules/discord.js/src/sharding/ShardingManager.js"(exports2, module2) {
|
|
191205
191205
|
"use strict";
|
|
191206
191206
|
var EventEmitter = __require("node:events");
|
|
191207
|
-
var
|
|
191207
|
+
var fs11 = __require("node:fs");
|
|
191208
191208
|
var path12 = __require("node:path");
|
|
191209
191209
|
var process2 = __require("node:process");
|
|
191210
191210
|
var { setTimeout: sleep2 } = __require("node:timers/promises");
|
|
@@ -191251,7 +191251,7 @@ var require_ShardingManager = __commonJS({
|
|
|
191251
191251
|
this.file = file;
|
|
191252
191252
|
if (!file) throw new DiscordjsError2(ErrorCodes2.ClientInvalidOption, "File", "specified.");
|
|
191253
191253
|
if (!path12.isAbsolute(file)) this.file = path12.resolve(process2.cwd(), file);
|
|
191254
|
-
const stats =
|
|
191254
|
+
const stats = fs11.statSync(this.file);
|
|
191255
191255
|
if (!stats.isFile()) throw new DiscordjsError2(ErrorCodes2.ClientInvalidOption, "File", "a file");
|
|
191256
191256
|
this.shardList = _options.shardList ?? "auto";
|
|
191257
191257
|
if (this.shardList !== "auto") {
|
|
@@ -192469,11 +192469,13 @@ var codex_provider_exports = {};
|
|
|
192469
192469
|
__export(codex_provider_exports, {
|
|
192470
192470
|
CodexProvider: () => CodexProvider
|
|
192471
192471
|
});
|
|
192472
|
-
import
|
|
192472
|
+
import fs9 from "node:fs";
|
|
192473
192473
|
import os3 from "node:os";
|
|
192474
192474
|
import path10 from "node:path";
|
|
192475
192475
|
function toApprovalPolicy(permissionMode) {
|
|
192476
192476
|
switch (permissionMode) {
|
|
192477
|
+
case "never":
|
|
192478
|
+
return "never";
|
|
192477
192479
|
case "acceptEdits":
|
|
192478
192480
|
return "on-failure";
|
|
192479
192481
|
case "plan":
|
|
@@ -192490,6 +192492,18 @@ function shouldPassModelToCodex() {
|
|
|
192490
192492
|
function shouldSkipGitRepoCheck() {
|
|
192491
192493
|
return process.env.CTI_CODEX_SKIP_GIT_REPO_CHECK === "true";
|
|
192492
192494
|
}
|
|
192495
|
+
function normalizeSandboxMode(mode) {
|
|
192496
|
+
if (mode === "read-only" || mode === "workspace-write" || mode === "danger-full-access") {
|
|
192497
|
+
return mode;
|
|
192498
|
+
}
|
|
192499
|
+
return "workspace-write";
|
|
192500
|
+
}
|
|
192501
|
+
function normalizeReasoningEffort2(value) {
|
|
192502
|
+
if (value === "minimal" || value === "low" || value === "medium" || value === "high" || value === "xhigh") {
|
|
192503
|
+
return value;
|
|
192504
|
+
}
|
|
192505
|
+
return void 0;
|
|
192506
|
+
}
|
|
192493
192507
|
function shouldRetryFreshThread(message) {
|
|
192494
192508
|
const lower = message.toLowerCase();
|
|
192495
192509
|
return lower.includes("resuming session with different model") || lower.includes("no such session") || lower.includes("resume") && lower.includes("session");
|
|
@@ -192549,10 +192563,14 @@ var init_codex_provider = __esm({
|
|
|
192549
192563
|
let savedThreadId = inMemoryThreadId || params.sdkSessionId || void 0;
|
|
192550
192564
|
const approvalPolicy = toApprovalPolicy(params.permissionMode);
|
|
192551
192565
|
const passModel = shouldPassModelToCodex();
|
|
192566
|
+
const sandboxMode = normalizeSandboxMode(params.sandboxMode);
|
|
192567
|
+
const modelReasoningEffort = normalizeReasoningEffort2(params.modelReasoningEffort);
|
|
192552
192568
|
const threadOptions = {
|
|
192553
192569
|
...passModel && params.model ? { model: params.model } : {},
|
|
192554
192570
|
...params.workingDirectory ? { workingDirectory: params.workingDirectory } : {},
|
|
192555
192571
|
...shouldSkipGitRepoCheck() ? { skipGitRepoCheck: true } : {},
|
|
192572
|
+
sandboxMode,
|
|
192573
|
+
...modelReasoningEffort ? { modelReasoningEffort } : {},
|
|
192556
192574
|
approvalPolicy
|
|
192557
192575
|
};
|
|
192558
192576
|
const imageFiles = params.files?.filter(
|
|
@@ -192564,13 +192582,13 @@ var init_codex_provider = __esm({
|
|
|
192564
192582
|
{ type: "text", text: params.prompt }
|
|
192565
192583
|
];
|
|
192566
192584
|
for (const file of imageFiles) {
|
|
192567
|
-
if (file.filePath &&
|
|
192585
|
+
if (file.filePath && fs9.existsSync(file.filePath)) {
|
|
192568
192586
|
parts.push({ type: "local_image", path: file.filePath });
|
|
192569
192587
|
continue;
|
|
192570
192588
|
}
|
|
192571
192589
|
const ext = MIME_EXT[file.type] || ".png";
|
|
192572
192590
|
const tmpPath = path10.join(os3.tmpdir(), `cti-img-${Date.now()}-${Math.random().toString(36).slice(2)}${ext}`);
|
|
192573
|
-
|
|
192591
|
+
fs9.writeFileSync(tmpPath, Buffer.from(file.data, "base64"));
|
|
192574
192592
|
tempFiles.push(tmpPath);
|
|
192575
192593
|
parts.push({ type: "local_image", path: tmpPath });
|
|
192576
192594
|
}
|
|
@@ -192661,7 +192679,7 @@ var init_codex_provider = __esm({
|
|
|
192661
192679
|
} finally {
|
|
192662
192680
|
for (const tmp of tempFiles) {
|
|
192663
192681
|
try {
|
|
192664
|
-
|
|
192682
|
+
fs9.unlinkSync(tmp);
|
|
192665
192683
|
} catch {
|
|
192666
192684
|
}
|
|
192667
192685
|
}
|
|
@@ -192753,9 +192771,9 @@ var init_codex_provider = __esm({
|
|
|
192753
192771
|
});
|
|
192754
192772
|
|
|
192755
192773
|
// src/main.ts
|
|
192756
|
-
import
|
|
192774
|
+
import fs10 from "node:fs";
|
|
192757
192775
|
import path11 from "node:path";
|
|
192758
|
-
import
|
|
192776
|
+
import crypto10 from "node:crypto";
|
|
192759
192777
|
|
|
192760
192778
|
// src/lib/bridge/context.ts
|
|
192761
192779
|
var CONTEXT_KEY = "__bridge_context__";
|
|
@@ -192794,6 +192812,7 @@ function getRegisteredTypes() {
|
|
|
192794
192812
|
}
|
|
192795
192813
|
|
|
192796
192814
|
// src/lib/bridge/bridge-manager.ts
|
|
192815
|
+
import fs5 from "node:fs";
|
|
192797
192816
|
import path7 from "node:path";
|
|
192798
192817
|
|
|
192799
192818
|
// src/lib/bridge/adapters/telegram-adapter.ts
|
|
@@ -194740,20 +194759,20 @@ var FeishuAdapter = class extends BaseChannelAdapter {
|
|
|
194740
194759
|
buffer = Buffer.concat(chunks);
|
|
194741
194760
|
} catch (streamErr) {
|
|
194742
194761
|
console.warn("[feishu-adapter] Stream read failed, falling back to writeFile:", streamErr instanceof Error ? streamErr.message : streamErr);
|
|
194743
|
-
const
|
|
194762
|
+
const fs11 = await import("fs");
|
|
194744
194763
|
const os4 = await import("os");
|
|
194745
194764
|
const path12 = await import("path");
|
|
194746
194765
|
const tmpPath = path12.join(os4.tmpdir(), `feishu-dl-${crypto2.randomUUID()}`);
|
|
194747
194766
|
try {
|
|
194748
194767
|
await res.writeFile(tmpPath);
|
|
194749
|
-
buffer =
|
|
194768
|
+
buffer = fs11.readFileSync(tmpPath);
|
|
194750
194769
|
if (buffer.length > MAX_FILE_SIZE) {
|
|
194751
194770
|
console.warn(`[feishu-adapter] Resource too large (>${MAX_FILE_SIZE} bytes), key: ${fileKey}`);
|
|
194752
194771
|
return null;
|
|
194753
194772
|
}
|
|
194754
194773
|
} finally {
|
|
194755
194774
|
try {
|
|
194756
|
-
|
|
194775
|
+
fs11.unlinkSync(tmpPath);
|
|
194757
194776
|
} catch {
|
|
194758
194777
|
}
|
|
194759
194778
|
}
|
|
@@ -195797,6 +195816,7 @@ import os from "node:os";
|
|
|
195797
195816
|
import path from "node:path";
|
|
195798
195817
|
var LEGACY_CTI_HOME = path.join(os.homedir(), ".claude-to-im");
|
|
195799
195818
|
var DEFAULT_CTI_HOME = path.join(os.homedir(), ".codex-to-im");
|
|
195819
|
+
var DEFAULT_WORKSPACE_ROOT = path.join(os.homedir(), "cx2im");
|
|
195800
195820
|
function resolveDefaultCtiHome() {
|
|
195801
195821
|
if (fs.existsSync(DEFAULT_CTI_HOME)) return DEFAULT_CTI_HOME;
|
|
195802
195822
|
if (fs.existsSync(LEGACY_CTI_HOME)) return LEGACY_CTI_HOME;
|
|
@@ -195804,6 +195824,14 @@ function resolveDefaultCtiHome() {
|
|
|
195804
195824
|
}
|
|
195805
195825
|
var CTI_HOME = process.env.CTI_HOME || resolveDefaultCtiHome();
|
|
195806
195826
|
var CONFIG_PATH = path.join(CTI_HOME, "config.env");
|
|
195827
|
+
function expandHomePath(value) {
|
|
195828
|
+
if (!value) return value;
|
|
195829
|
+
if (value === "~") return os.homedir();
|
|
195830
|
+
if (value.startsWith("~/") || value.startsWith("~\\")) {
|
|
195831
|
+
return path.join(os.homedir(), value.slice(2));
|
|
195832
|
+
}
|
|
195833
|
+
return value;
|
|
195834
|
+
}
|
|
195807
195835
|
function parseEnvFile(content) {
|
|
195808
195836
|
const entries = /* @__PURE__ */ new Map();
|
|
195809
195837
|
for (const line of content.split("\n")) {
|
|
@@ -195837,6 +195865,18 @@ function parsePositiveInt(value) {
|
|
|
195837
195865
|
if (!Number.isFinite(parsed) || parsed <= 0) return void 0;
|
|
195838
195866
|
return Math.floor(parsed);
|
|
195839
195867
|
}
|
|
195868
|
+
function parseSandboxMode(value) {
|
|
195869
|
+
if (value === "read-only" || value === "workspace-write" || value === "danger-full-access") {
|
|
195870
|
+
return value;
|
|
195871
|
+
}
|
|
195872
|
+
return void 0;
|
|
195873
|
+
}
|
|
195874
|
+
function parseReasoningEffort(value) {
|
|
195875
|
+
if (value === "minimal" || value === "low" || value === "medium" || value === "high" || value === "xhigh") {
|
|
195876
|
+
return value;
|
|
195877
|
+
}
|
|
195878
|
+
return void 0;
|
|
195879
|
+
}
|
|
195840
195880
|
function loadConfig() {
|
|
195841
195881
|
const env = loadRawConfigEnv();
|
|
195842
195882
|
const rawRuntime = env.get("CTI_RUNTIME") || "codex";
|
|
@@ -195844,11 +195884,16 @@ function loadConfig() {
|
|
|
195844
195884
|
return {
|
|
195845
195885
|
runtime,
|
|
195846
195886
|
enabledChannels: splitCsv(env.get("CTI_ENABLED_CHANNELS")) ?? ["feishu"],
|
|
195847
|
-
defaultWorkDir: env.get("CTI_DEFAULT_WORKDIR") || process.cwd(),
|
|
195887
|
+
defaultWorkDir: expandHomePath(env.get("CTI_DEFAULT_WORKDIR")) || process.cwd(),
|
|
195888
|
+
defaultWorkspaceRoot: expandHomePath(env.get("CTI_DEFAULT_WORKSPACE_ROOT")) || DEFAULT_WORKSPACE_ROOT,
|
|
195848
195889
|
defaultModel: env.get("CTI_DEFAULT_MODEL") || void 0,
|
|
195849
195890
|
defaultMode: env.get("CTI_DEFAULT_MODE") || "code",
|
|
195850
195891
|
historyMessageLimit: parsePositiveInt(env.get("CTI_HISTORY_MESSAGE_LIMIT")) ?? 8,
|
|
195851
195892
|
codexSkipGitRepoCheck: env.has("CTI_CODEX_SKIP_GIT_REPO_CHECK") ? env.get("CTI_CODEX_SKIP_GIT_REPO_CHECK") === "true" : true,
|
|
195893
|
+
codexSandboxMode: parseSandboxMode(env.get("CTI_CODEX_SANDBOX_MODE")) ?? "workspace-write",
|
|
195894
|
+
codexReasoningEffort: parseReasoningEffort(env.get("CTI_CODEX_REASONING_EFFORT")) ?? "medium",
|
|
195895
|
+
uiAllowLan: env.get("CTI_UI_ALLOW_LAN") === "true",
|
|
195896
|
+
uiAccessToken: env.get("CTI_UI_ACCESS_TOKEN") || void 0,
|
|
195852
195897
|
tgBotToken: env.get("CTI_TG_BOT_TOKEN") || void 0,
|
|
195853
195898
|
tgChatId: env.get("CTI_TG_CHAT_ID") || void 0,
|
|
195854
195899
|
tgAllowedUsers: splitCsv(env.get("CTI_TG_ALLOWED_USERS")),
|
|
@@ -195857,6 +195902,7 @@ function loadConfig() {
|
|
|
195857
195902
|
feishuDomain: env.get("CTI_FEISHU_DOMAIN") || void 0,
|
|
195858
195903
|
feishuAllowedUsers: splitCsv(env.get("CTI_FEISHU_ALLOWED_USERS")),
|
|
195859
195904
|
feishuStreamingEnabled: env.has("CTI_FEISHU_STREAMING_ENABLED") ? env.get("CTI_FEISHU_STREAMING_ENABLED") === "true" : true,
|
|
195905
|
+
feishuCommandMarkdownEnabled: env.has("CTI_FEISHU_COMMAND_MARKDOWN_ENABLED") ? env.get("CTI_FEISHU_COMMAND_MARKDOWN_ENABLED") === "true" : true,
|
|
195860
195906
|
discordBotToken: env.get("CTI_DISCORD_BOT_TOKEN") || void 0,
|
|
195861
195907
|
discordAllowedUsers: splitCsv(env.get("CTI_DISCORD_ALLOWED_USERS")),
|
|
195862
195908
|
discordAllowedChannels: splitCsv(
|
|
@@ -195871,6 +195917,7 @@ function loadConfig() {
|
|
|
195871
195917
|
weixinBaseUrl: env.get("CTI_WEIXIN_BASE_URL") || void 0,
|
|
195872
195918
|
weixinCdnBaseUrl: env.get("CTI_WEIXIN_CDN_BASE_URL") || void 0,
|
|
195873
195919
|
weixinMediaEnabled: env.has("CTI_WEIXIN_MEDIA_ENABLED") ? env.get("CTI_WEIXIN_MEDIA_ENABLED") === "true" : void 0,
|
|
195920
|
+
weixinCommandMarkdownEnabled: env.has("CTI_WEIXIN_COMMAND_MARKDOWN_ENABLED") ? env.get("CTI_WEIXIN_COMMAND_MARKDOWN_ENABLED") === "true" : false,
|
|
195874
195921
|
autoApprove: env.get("CTI_AUTO_APPROVE") === "true"
|
|
195875
195922
|
};
|
|
195876
195923
|
}
|
|
@@ -195917,6 +195964,10 @@ function configToSettings(config2) {
|
|
|
195917
195964
|
"bridge_feishu_streaming_enabled",
|
|
195918
195965
|
config2.feishuStreamingEnabled === false ? "false" : "true"
|
|
195919
195966
|
);
|
|
195967
|
+
m.set(
|
|
195968
|
+
"bridge_feishu_command_markdown_enabled",
|
|
195969
|
+
config2.feishuCommandMarkdownEnabled === false ? "false" : "true"
|
|
195970
|
+
);
|
|
195920
195971
|
m.set(
|
|
195921
195972
|
"bridge_qq_enabled",
|
|
195922
195973
|
config2.enabledChannels.includes("qq") ? "true" : "false"
|
|
@@ -195935,11 +195986,18 @@ function configToSettings(config2) {
|
|
|
195935
195986
|
);
|
|
195936
195987
|
if (config2.weixinMediaEnabled !== void 0)
|
|
195937
195988
|
m.set("bridge_weixin_media_enabled", String(config2.weixinMediaEnabled));
|
|
195989
|
+
m.set(
|
|
195990
|
+
"bridge_weixin_command_markdown_enabled",
|
|
195991
|
+
config2.weixinCommandMarkdownEnabled === true ? "true" : "false"
|
|
195992
|
+
);
|
|
195938
195993
|
if (config2.weixinBaseUrl)
|
|
195939
195994
|
m.set("bridge_weixin_base_url", config2.weixinBaseUrl);
|
|
195940
195995
|
if (config2.weixinCdnBaseUrl)
|
|
195941
195996
|
m.set("bridge_weixin_cdn_base_url", config2.weixinCdnBaseUrl);
|
|
195942
195997
|
m.set("bridge_default_work_dir", config2.defaultWorkDir);
|
|
195998
|
+
if (config2.defaultWorkspaceRoot) {
|
|
195999
|
+
m.set("bridge_default_workspace_root", config2.defaultWorkspaceRoot);
|
|
196000
|
+
}
|
|
195943
196001
|
if (config2.defaultModel) {
|
|
195944
196002
|
m.set("bridge_default_model", config2.defaultModel);
|
|
195945
196003
|
m.set("default_model", config2.defaultModel);
|
|
@@ -195953,6 +196011,14 @@ function configToSettings(config2) {
|
|
|
195953
196011
|
"bridge_codex_skip_git_repo_check",
|
|
195954
196012
|
config2.codexSkipGitRepoCheck === true ? "true" : "false"
|
|
195955
196013
|
);
|
|
196014
|
+
m.set(
|
|
196015
|
+
"bridge_codex_sandbox_mode",
|
|
196016
|
+
config2.codexSandboxMode || "workspace-write"
|
|
196017
|
+
);
|
|
196018
|
+
m.set(
|
|
196019
|
+
"bridge_codex_reasoning_effort",
|
|
196020
|
+
config2.codexReasoningEffort || "medium"
|
|
196021
|
+
);
|
|
195956
196022
|
return m;
|
|
195957
196023
|
}
|
|
195958
196024
|
|
|
@@ -196773,8 +196839,10 @@ import path4 from "node:path";
|
|
|
196773
196839
|
import fs3 from "node:fs";
|
|
196774
196840
|
import os2 from "node:os";
|
|
196775
196841
|
import path3 from "node:path";
|
|
196842
|
+
import crypto7 from "node:crypto";
|
|
196776
196843
|
var ACTIVE_WINDOW_MS = 15 * 60 * 1e3;
|
|
196777
196844
|
var MAX_SESSION_META_BYTES = 4 * 1024 * 1024;
|
|
196845
|
+
var MAX_SESSION_TITLE_SCAN_BYTES = 512 * 1024;
|
|
196778
196846
|
var TITLE_MAX_CHARS = 72;
|
|
196779
196847
|
function getCodexHome() {
|
|
196780
196848
|
return process.env.CODEX_HOME || path3.join(os2.homedir(), ".codex");
|
|
@@ -196832,6 +196900,24 @@ function readFirstLine(filePath, maxBytes = MAX_SESSION_META_BYTES) {
|
|
|
196832
196900
|
fs3.closeSync(fd);
|
|
196833
196901
|
}
|
|
196834
196902
|
}
|
|
196903
|
+
function readFilePrefix(filePath, maxBytes = MAX_SESSION_TITLE_SCAN_BYTES) {
|
|
196904
|
+
const fd = fs3.openSync(filePath, "r");
|
|
196905
|
+
try {
|
|
196906
|
+
const buffer = Buffer.alloc(Math.min(maxBytes, 64 * 1024));
|
|
196907
|
+
const chunks = [];
|
|
196908
|
+
let offset = 0;
|
|
196909
|
+
while (offset < maxBytes) {
|
|
196910
|
+
const bytesToRead = Math.min(buffer.length, maxBytes - offset);
|
|
196911
|
+
const bytesRead = fs3.readSync(fd, buffer, 0, bytesToRead, offset);
|
|
196912
|
+
if (bytesRead <= 0) break;
|
|
196913
|
+
chunks.push(Buffer.from(buffer.subarray(0, bytesRead)));
|
|
196914
|
+
offset += bytesRead;
|
|
196915
|
+
}
|
|
196916
|
+
return Buffer.concat(chunks).toString("utf-8");
|
|
196917
|
+
} finally {
|
|
196918
|
+
fs3.closeSync(fd);
|
|
196919
|
+
}
|
|
196920
|
+
}
|
|
196835
196921
|
function walkSessionFiles(dirPath, target) {
|
|
196836
196922
|
let entries;
|
|
196837
196923
|
try {
|
|
@@ -196853,6 +196939,7 @@ function walkSessionFiles(dirPath, target) {
|
|
|
196853
196939
|
function isDesktopLike(meta) {
|
|
196854
196940
|
const originator = meta?.originator?.toLowerCase() || "";
|
|
196855
196941
|
const source = meta?.source?.toLowerCase() || "";
|
|
196942
|
+
if (source === "exec") return false;
|
|
196856
196943
|
return originator.includes("desktop") || source === "vscode" || source === "desktop";
|
|
196857
196944
|
}
|
|
196858
196945
|
function loadThreadNameIndex(archivedThreadIds) {
|
|
@@ -196884,6 +196971,27 @@ function loadThreadNameIndex(archivedThreadIds) {
|
|
|
196884
196971
|
}
|
|
196885
196972
|
return new Map(Array.from(titles.entries()).map(([threadId, entry]) => [threadId, entry.title]));
|
|
196886
196973
|
}
|
|
196974
|
+
function buildFallbackTitle(threadId, filePath, cwd) {
|
|
196975
|
+
try {
|
|
196976
|
+
const content = readFilePrefix(filePath);
|
|
196977
|
+
for (const line of content.split(/\r?\n/)) {
|
|
196978
|
+
if (!line.trim()) continue;
|
|
196979
|
+
let parsed;
|
|
196980
|
+
try {
|
|
196981
|
+
parsed = JSON.parse(line);
|
|
196982
|
+
} catch {
|
|
196983
|
+
continue;
|
|
196984
|
+
}
|
|
196985
|
+
if (!isSessionEventLine(parsed) || parsed.payload?.type !== "user_message") continue;
|
|
196986
|
+
const firstUserMessage = trimTitle(normalizeFreeText(parsed.payload.message || ""));
|
|
196987
|
+
if (firstUserMessage) return firstUserMessage;
|
|
196988
|
+
}
|
|
196989
|
+
} catch {
|
|
196990
|
+
}
|
|
196991
|
+
const dirName = trimTitle(path3.basename(cwd || ""));
|
|
196992
|
+
if (dirName) return dirName;
|
|
196993
|
+
return `Session ${threadId.slice(0, 8)}`;
|
|
196994
|
+
}
|
|
196887
196995
|
function parseDesktopSession(filePath, threadNames, archivedThreadIds) {
|
|
196888
196996
|
const firstLine = readFirstLine(filePath);
|
|
196889
196997
|
if (!firstLine) return null;
|
|
@@ -196909,8 +197017,7 @@ function parseDesktopSession(filePath, threadNames, archivedThreadIds) {
|
|
|
196909
197017
|
const lastEventAt = stat.mtime.toISOString();
|
|
196910
197018
|
const firstSeenAt = parsed.payload.timestamp || parsed.timestamp || stat.birthtime.toISOString();
|
|
196911
197019
|
const threadId = parsed.payload.id;
|
|
196912
|
-
const title = threadNames.get(threadId);
|
|
196913
|
-
if (!title) return null;
|
|
197020
|
+
const title = threadNames.get(threadId) || buildFallbackTitle(threadId, filePath, cwd);
|
|
196914
197021
|
return {
|
|
196915
197022
|
threadId,
|
|
196916
197023
|
filePath,
|
|
@@ -196933,6 +197040,28 @@ function trimTitle(text2) {
|
|
|
196933
197040
|
function normalizeFreeText(text2) {
|
|
196934
197041
|
return text2.replace(/\s+/g, " ").trim();
|
|
196935
197042
|
}
|
|
197043
|
+
function createDesktopEventSignature(rawLine) {
|
|
197044
|
+
return crypto7.createHash("sha1").update(rawLine).digest("hex");
|
|
197045
|
+
}
|
|
197046
|
+
function readFileUtf8Range(filePath, startOffset, endOffset) {
|
|
197047
|
+
const safeStart = Math.max(0, startOffset);
|
|
197048
|
+
const safeEnd = Math.max(safeStart, endOffset);
|
|
197049
|
+
const bytesToRead = safeEnd - safeStart;
|
|
197050
|
+
if (bytesToRead <= 0) return "";
|
|
197051
|
+
const fd = fs3.openSync(filePath, "r");
|
|
197052
|
+
try {
|
|
197053
|
+
const buffer = Buffer.alloc(bytesToRead);
|
|
197054
|
+
let totalRead = 0;
|
|
197055
|
+
while (totalRead < bytesToRead) {
|
|
197056
|
+
const bytesRead = fs3.readSync(fd, buffer, totalRead, bytesToRead - totalRead, safeStart + totalRead);
|
|
197057
|
+
if (bytesRead <= 0) break;
|
|
197058
|
+
totalRead += bytesRead;
|
|
197059
|
+
}
|
|
197060
|
+
return buffer.subarray(0, totalRead).toString("utf-8");
|
|
197061
|
+
} finally {
|
|
197062
|
+
fs3.closeSync(fd);
|
|
197063
|
+
}
|
|
197064
|
+
}
|
|
196936
197065
|
function isSessionEventLine(line) {
|
|
196937
197066
|
return line.type === "event_msg";
|
|
196938
197067
|
}
|
|
@@ -196944,7 +197073,6 @@ function listDesktopSessions(limit = 12) {
|
|
|
196944
197073
|
if (!fs3.existsSync(root)) return [];
|
|
196945
197074
|
const archivedThreadIds = loadArchivedThreadIds();
|
|
196946
197075
|
const threadNames = loadThreadNameIndex(archivedThreadIds);
|
|
196947
|
-
if (threadNames.size === 0) return [];
|
|
196948
197076
|
const files = [];
|
|
196949
197077
|
walkSessionFiles(root, files);
|
|
196950
197078
|
const sessions = [];
|
|
@@ -196968,47 +197096,124 @@ ${text2}`;
|
|
|
196968
197096
|
}
|
|
196969
197097
|
return text2;
|
|
196970
197098
|
}
|
|
196971
|
-
function
|
|
196972
|
-
|
|
196973
|
-
|
|
196974
|
-
|
|
196975
|
-
|
|
196976
|
-
|
|
196977
|
-
|
|
196978
|
-
|
|
197099
|
+
function pushDesktopSessionEvent(events, parsed, rawLine) {
|
|
197100
|
+
if (isSessionEventLine(parsed) && parsed.payload?.type === "user_message") {
|
|
197101
|
+
const text2 = normalizeFreeText(parsed.payload.message || "");
|
|
197102
|
+
if (!text2) return;
|
|
197103
|
+
events.push({
|
|
197104
|
+
signature: createDesktopEventSignature(rawLine),
|
|
197105
|
+
role: "user",
|
|
197106
|
+
content: text2,
|
|
197107
|
+
timestamp: parsed.timestamp || ""
|
|
197108
|
+
});
|
|
197109
|
+
return;
|
|
196979
197110
|
}
|
|
196980
|
-
|
|
196981
|
-
|
|
196982
|
-
if (!
|
|
197111
|
+
if (isSessionEventLine(parsed) && parsed.payload?.type === "task_complete") {
|
|
197112
|
+
const text2 = normalizeFreeText(parsed.payload.last_agent_message || "");
|
|
197113
|
+
if (!text2) return;
|
|
197114
|
+
const lastEvent = events[events.length - 1];
|
|
197115
|
+
if (lastEvent?.role === "assistant" && lastEvent.content === text2) {
|
|
197116
|
+
return;
|
|
197117
|
+
}
|
|
197118
|
+
events.push({
|
|
197119
|
+
signature: createDesktopEventSignature(rawLine),
|
|
197120
|
+
role: "assistant",
|
|
197121
|
+
content: text2,
|
|
197122
|
+
timestamp: parsed.timestamp || ""
|
|
197123
|
+
});
|
|
197124
|
+
return;
|
|
197125
|
+
}
|
|
197126
|
+
if (isSessionMessageLine(parsed) && parsed.payload?.type === "message" && parsed.payload.role === "assistant") {
|
|
197127
|
+
const text2 = extractDesktopMessageText(parsed);
|
|
197128
|
+
if (!text2) return;
|
|
197129
|
+
events.push({
|
|
197130
|
+
signature: createDesktopEventSignature(rawLine),
|
|
197131
|
+
role: parsed.payload.phase === "commentary" ? "commentary" : "assistant",
|
|
197132
|
+
content: parsed.payload.phase === "commentary" ? text2.replace(/^\[commentary\]\n/, "") : text2,
|
|
197133
|
+
timestamp: parsed.timestamp || ""
|
|
197134
|
+
});
|
|
197135
|
+
}
|
|
197136
|
+
}
|
|
197137
|
+
function parseDesktopSessionEventText(content, leadingText = "", flushTrailingText = false) {
|
|
197138
|
+
const combined = `${leadingText}${content}`;
|
|
197139
|
+
if (!combined) {
|
|
197140
|
+
return {
|
|
197141
|
+
events: [],
|
|
197142
|
+
nextOffset: 0,
|
|
197143
|
+
trailingText: ""
|
|
197144
|
+
};
|
|
197145
|
+
}
|
|
197146
|
+
const hasTrailingNewline = combined.endsWith("\n") || combined.endsWith("\r");
|
|
197147
|
+
const rawLines = combined.split(/\r?\n/);
|
|
197148
|
+
let trailingText = hasTrailingNewline ? "" : rawLines.pop() || "";
|
|
197149
|
+
if (flushTrailingText && trailingText) {
|
|
197150
|
+
rawLines.push(trailingText);
|
|
197151
|
+
trailingText = "";
|
|
197152
|
+
}
|
|
197153
|
+
const events = [];
|
|
197154
|
+
for (const line of rawLines) {
|
|
197155
|
+
const trimmed = line.trim();
|
|
197156
|
+
if (!trimmed) continue;
|
|
196983
197157
|
let parsed;
|
|
196984
197158
|
try {
|
|
196985
|
-
parsed = JSON.parse(
|
|
197159
|
+
parsed = JSON.parse(trimmed);
|
|
196986
197160
|
} catch {
|
|
196987
197161
|
continue;
|
|
196988
197162
|
}
|
|
196989
|
-
|
|
196990
|
-
const text2 = normalizeFreeText(parsed.payload.message || "");
|
|
196991
|
-
if (!text2) continue;
|
|
196992
|
-
messages.push({
|
|
196993
|
-
role: "user",
|
|
196994
|
-
content: text2
|
|
196995
|
-
});
|
|
196996
|
-
continue;
|
|
196997
|
-
}
|
|
196998
|
-
if (isSessionMessageLine(parsed) && parsed.payload?.type === "message" && parsed.payload.role === "assistant") {
|
|
196999
|
-
const text2 = extractDesktopMessageText(parsed);
|
|
197000
|
-
if (!text2) continue;
|
|
197001
|
-
messages.push({
|
|
197002
|
-
role: parsed.payload.role,
|
|
197003
|
-
content: text2
|
|
197004
|
-
});
|
|
197005
|
-
}
|
|
197163
|
+
pushDesktopSessionEvent(events, parsed, trimmed);
|
|
197006
197164
|
}
|
|
197165
|
+
return {
|
|
197166
|
+
events,
|
|
197167
|
+
nextOffset: 0,
|
|
197168
|
+
trailingText
|
|
197169
|
+
};
|
|
197170
|
+
}
|
|
197171
|
+
function readDesktopSessionMessages(threadId, limit = 8) {
|
|
197172
|
+
const messages = readDesktopSessionEventStream(threadId).map((event) => ({
|
|
197173
|
+
role: event.role === "commentary" ? "assistant" : event.role,
|
|
197174
|
+
content: event.role === "commentary" ? `[commentary]
|
|
197175
|
+
${event.content}` : event.content
|
|
197176
|
+
}));
|
|
197007
197177
|
const safeLimit = Number.isFinite(limit) && limit > 0 ? Math.floor(limit) : 8;
|
|
197008
197178
|
return messages.slice(-safeLimit);
|
|
197009
197179
|
}
|
|
197180
|
+
function readDesktopSessionEventStreamByFilePath(filePath) {
|
|
197181
|
+
let content = "";
|
|
197182
|
+
try {
|
|
197183
|
+
content = fs3.readFileSync(filePath, "utf-8");
|
|
197184
|
+
} catch {
|
|
197185
|
+
return [];
|
|
197186
|
+
}
|
|
197187
|
+
return parseDesktopSessionEventText(content, "", true).events;
|
|
197188
|
+
}
|
|
197189
|
+
function readDesktopSessionEventDeltaByFilePath(filePath, startOffset, endOffset, trailingText = "") {
|
|
197190
|
+
let content = "";
|
|
197191
|
+
try {
|
|
197192
|
+
content = readFileUtf8Range(filePath, startOffset, endOffset);
|
|
197193
|
+
} catch {
|
|
197194
|
+
return {
|
|
197195
|
+
events: [],
|
|
197196
|
+
nextOffset: startOffset,
|
|
197197
|
+
trailingText
|
|
197198
|
+
};
|
|
197199
|
+
}
|
|
197200
|
+
const parsed = parseDesktopSessionEventText(content, trailingText);
|
|
197201
|
+
return {
|
|
197202
|
+
events: parsed.events,
|
|
197203
|
+
nextOffset: Math.max(startOffset, endOffset),
|
|
197204
|
+
trailingText: parsed.trailingText
|
|
197205
|
+
};
|
|
197206
|
+
}
|
|
197207
|
+
function readDesktopSessionEventStream(threadId) {
|
|
197208
|
+
const session = getDesktopSessionByThreadId(threadId);
|
|
197209
|
+
if (!session) return [];
|
|
197210
|
+
return readDesktopSessionEventStreamByFilePath(session.filePath);
|
|
197211
|
+
}
|
|
197010
197212
|
|
|
197011
197213
|
// src/session-bindings.ts
|
|
197214
|
+
function getSessionMode(store, session) {
|
|
197215
|
+
return session.preferred_mode || store.getSetting("bridge_default_mode") || "code";
|
|
197216
|
+
}
|
|
197012
197217
|
function bindStoreToSession(store, channelType, chatId, sessionId) {
|
|
197013
197218
|
const session = store.getSession(sessionId);
|
|
197014
197219
|
if (!session) return null;
|
|
@@ -197018,7 +197223,8 @@ function bindStoreToSession(store, channelType, chatId, sessionId) {
|
|
|
197018
197223
|
codepilotSessionId: session.id,
|
|
197019
197224
|
sdkSessionId: session.sdk_session_id || "",
|
|
197020
197225
|
workingDirectory: session.working_directory,
|
|
197021
|
-
model: session.model
|
|
197226
|
+
model: session.model,
|
|
197227
|
+
mode: getSessionMode(store, session)
|
|
197022
197228
|
});
|
|
197023
197229
|
}
|
|
197024
197230
|
function bindStoreToSdkSession(store, channelType, chatId, sdkSessionId, opts) {
|
|
@@ -197030,7 +197236,8 @@ function bindStoreToSdkSession(store, channelType, chatId, sdkSessionId, opts) {
|
|
|
197030
197236
|
codepilotSessionId: existing.id,
|
|
197031
197237
|
sdkSessionId,
|
|
197032
197238
|
workingDirectory: opts?.workingDirectory || existing.working_directory,
|
|
197033
|
-
model: opts?.model || existing.model
|
|
197239
|
+
model: opts?.model || existing.model,
|
|
197240
|
+
mode: getSessionMode(store, existing)
|
|
197034
197241
|
});
|
|
197035
197242
|
}
|
|
197036
197243
|
const workingDirectory = opts?.workingDirectory || store.getSetting("bridge_default_work_dir") || process.env.HOME || "";
|
|
@@ -197050,7 +197257,8 @@ function bindStoreToSdkSession(store, channelType, chatId, sdkSessionId, opts) {
|
|
|
197050
197257
|
codepilotSessionId: session.id,
|
|
197051
197258
|
sdkSessionId,
|
|
197052
197259
|
workingDirectory: workingDirectory || session.working_directory,
|
|
197053
|
-
model: model || session.model
|
|
197260
|
+
model: model || session.model,
|
|
197261
|
+
mode: getSessionMode(store, session)
|
|
197054
197262
|
});
|
|
197055
197263
|
}
|
|
197056
197264
|
|
|
@@ -197088,7 +197296,7 @@ function createBinding(address, workingDirectory) {
|
|
|
197088
197296
|
sdkSessionId: "",
|
|
197089
197297
|
workingDirectory: defaultCwd,
|
|
197090
197298
|
model: defaultModel,
|
|
197091
|
-
mode: "code"
|
|
197299
|
+
mode: session.preferred_mode || "code"
|
|
197092
197300
|
});
|
|
197093
197301
|
}
|
|
197094
197302
|
function bindToSession(address, codepilotSessionId) {
|
|
@@ -197104,7 +197312,21 @@ function updateBinding(id, updates) {
|
|
|
197104
197312
|
// src/lib/bridge/conversation-engine.ts
|
|
197105
197313
|
import fs4 from "fs";
|
|
197106
197314
|
import path5 from "path";
|
|
197107
|
-
import
|
|
197315
|
+
import crypto8 from "crypto";
|
|
197316
|
+
function resolveSandboxMode(store) {
|
|
197317
|
+
const configured = store.getSetting("bridge_codex_sandbox_mode");
|
|
197318
|
+
if (configured === "read-only" || configured === "workspace-write" || configured === "danger-full-access") {
|
|
197319
|
+
return configured;
|
|
197320
|
+
}
|
|
197321
|
+
return "workspace-write";
|
|
197322
|
+
}
|
|
197323
|
+
function resolveReasoningEffort(store, session) {
|
|
197324
|
+
const configured = session?.reasoning_effort || store.getSetting("bridge_codex_reasoning_effort");
|
|
197325
|
+
if (configured === "minimal" || configured === "low" || configured === "medium" || configured === "high" || configured === "xhigh") {
|
|
197326
|
+
return configured;
|
|
197327
|
+
}
|
|
197328
|
+
return "medium";
|
|
197329
|
+
}
|
|
197108
197330
|
function formatAttachmentSize(size) {
|
|
197109
197331
|
if (!Number.isFinite(size) || size < 1024) return `${size} B`;
|
|
197110
197332
|
if (size < 1024 * 1024) return `${(size / 1024).toFixed(1)} KB`;
|
|
@@ -197135,7 +197357,7 @@ function buildLocalAttachmentPromptSupplement(files) {
|
|
|
197135
197357
|
async function processMessage(binding, text2, onPermissionRequest, abortSignal, files, onPartialText, onToolEvent) {
|
|
197136
197358
|
const { store, llm } = getBridgeContext();
|
|
197137
197359
|
const sessionId = binding.codepilotSessionId;
|
|
197138
|
-
const lockId =
|
|
197360
|
+
const lockId = crypto8.randomBytes(8).toString("hex");
|
|
197139
197361
|
const lockAcquired = store.acquireSessionLock(sessionId, lockId, `bridge-${binding.channelType}`, 600);
|
|
197140
197362
|
if (!lockAcquired) {
|
|
197141
197363
|
return {
|
|
@@ -197157,6 +197379,8 @@ async function processMessage(binding, text2, onPermissionRequest, abortSignal,
|
|
|
197157
197379
|
try {
|
|
197158
197380
|
const session = store.getSession(sessionId);
|
|
197159
197381
|
const workDir = binding.workingDirectory || session?.working_directory || "";
|
|
197382
|
+
const sandboxMode = resolveSandboxMode(store);
|
|
197383
|
+
const modelReasoningEffort = resolveReasoningEffort(store, session);
|
|
197160
197384
|
let savedContent = text2;
|
|
197161
197385
|
let llmFiles = files;
|
|
197162
197386
|
let persistedFileMeta = [];
|
|
@@ -197233,6 +197457,8 @@ ${attachmentSupplement}` : attachmentSupplement : text2;
|
|
|
197233
197457
|
sessionId,
|
|
197234
197458
|
sdkSessionId: binding.sdkSessionId || void 0,
|
|
197235
197459
|
model: effectiveModel,
|
|
197460
|
+
sandboxMode,
|
|
197461
|
+
modelReasoningEffort,
|
|
197236
197462
|
systemPrompt: session?.system_prompt || void 0,
|
|
197237
197463
|
workingDirectory: workDir || void 0,
|
|
197238
197464
|
abortController,
|
|
@@ -197851,6 +198077,7 @@ async function forwardPermissionRequest(adapter, address, permissionRequestId, t
|
|
|
197851
198077
|
channelType: adapter.channelType,
|
|
197852
198078
|
chatId: address.chatId,
|
|
197853
198079
|
messageId: result.messageId,
|
|
198080
|
+
sessionId,
|
|
197854
198081
|
toolName,
|
|
197855
198082
|
suggestions: suggestions ? JSON.stringify(suggestions) : ""
|
|
197856
198083
|
});
|
|
@@ -204152,6 +204379,112 @@ function markdownToDiscordChunks(markdown, limit = 2e3) {
|
|
|
204152
204379
|
return result;
|
|
204153
204380
|
}
|
|
204154
204381
|
|
|
204382
|
+
// src/desktop-session-mirror.ts
|
|
204383
|
+
function makeCursor(events) {
|
|
204384
|
+
const lastEvent = events.length > 0 ? events[events.length - 1] : void 0;
|
|
204385
|
+
return {
|
|
204386
|
+
initialized: true,
|
|
204387
|
+
lastEventSignature: lastEvent?.signature,
|
|
204388
|
+
lastEventTimestamp: lastEvent?.timestamp,
|
|
204389
|
+
lastEventRole: lastEvent?.role,
|
|
204390
|
+
lastEventContent: lastEvent?.content,
|
|
204391
|
+
lastEventCount: events.length
|
|
204392
|
+
};
|
|
204393
|
+
}
|
|
204394
|
+
function advanceDesktopMirrorCursor(cursor, appendedEvents) {
|
|
204395
|
+
if (appendedEvents.length === 0) {
|
|
204396
|
+
return cursor ? { ...cursor } : {
|
|
204397
|
+
initialized: false,
|
|
204398
|
+
lastEventCount: 0
|
|
204399
|
+
};
|
|
204400
|
+
}
|
|
204401
|
+
if (!cursor?.initialized) {
|
|
204402
|
+
return makeCursor(appendedEvents);
|
|
204403
|
+
}
|
|
204404
|
+
const lastEvent = appendedEvents[appendedEvents.length - 1];
|
|
204405
|
+
return {
|
|
204406
|
+
initialized: true,
|
|
204407
|
+
lastEventSignature: lastEvent?.signature,
|
|
204408
|
+
lastEventTimestamp: lastEvent?.timestamp,
|
|
204409
|
+
lastEventRole: lastEvent?.role,
|
|
204410
|
+
lastEventContent: lastEvent?.content,
|
|
204411
|
+
lastEventCount: cursor.lastEventCount + appendedEvents.length
|
|
204412
|
+
};
|
|
204413
|
+
}
|
|
204414
|
+
function filterDuplicateAssistantEvents(cursor, events) {
|
|
204415
|
+
if (events.length === 0) return events;
|
|
204416
|
+
let startIndex = 0;
|
|
204417
|
+
while (startIndex < events.length && cursor?.lastEventRole === "assistant" && events[startIndex]?.role === "assistant" && cursor.lastEventContent === events[startIndex]?.content) {
|
|
204418
|
+
startIndex += 1;
|
|
204419
|
+
}
|
|
204420
|
+
return startIndex === 0 ? events : events.slice(startIndex);
|
|
204421
|
+
}
|
|
204422
|
+
function findLastEventIndex(events, signature) {
|
|
204423
|
+
for (let index = events.length - 1; index >= 0; index -= 1) {
|
|
204424
|
+
if (events[index]?.signature === signature) {
|
|
204425
|
+
return index;
|
|
204426
|
+
}
|
|
204427
|
+
}
|
|
204428
|
+
return -1;
|
|
204429
|
+
}
|
|
204430
|
+
function collectEventsAfterTimestamp(events, timestamp) {
|
|
204431
|
+
if (!timestamp) return [];
|
|
204432
|
+
return events.filter((event) => Boolean(event.timestamp) && event.timestamp > timestamp);
|
|
204433
|
+
}
|
|
204434
|
+
function reconcileDesktopMirrorCursor(cursor, events) {
|
|
204435
|
+
const nextCursor = makeCursor(events);
|
|
204436
|
+
if (!cursor?.initialized) {
|
|
204437
|
+
return {
|
|
204438
|
+
nextCursor,
|
|
204439
|
+
deliverableEvents: [],
|
|
204440
|
+
reset: false
|
|
204441
|
+
};
|
|
204442
|
+
}
|
|
204443
|
+
if (events.length === 0) {
|
|
204444
|
+
return {
|
|
204445
|
+
nextCursor,
|
|
204446
|
+
deliverableEvents: [],
|
|
204447
|
+
reset: cursor.lastEventCount > 0
|
|
204448
|
+
};
|
|
204449
|
+
}
|
|
204450
|
+
if (cursor.lastEventSignature) {
|
|
204451
|
+
const lastSeenIndex = findLastEventIndex(events, cursor.lastEventSignature);
|
|
204452
|
+
if (lastSeenIndex === -1) {
|
|
204453
|
+
const recoveredEvents = collectEventsAfterTimestamp(events, cursor.lastEventTimestamp);
|
|
204454
|
+
return {
|
|
204455
|
+
nextCursor,
|
|
204456
|
+
deliverableEvents: recoveredEvents,
|
|
204457
|
+
reset: true
|
|
204458
|
+
};
|
|
204459
|
+
}
|
|
204460
|
+
return {
|
|
204461
|
+
nextCursor,
|
|
204462
|
+
deliverableEvents: events.slice(lastSeenIndex + 1),
|
|
204463
|
+
reset: false
|
|
204464
|
+
};
|
|
204465
|
+
}
|
|
204466
|
+
if (cursor.lastEventCount === 0) {
|
|
204467
|
+
return {
|
|
204468
|
+
nextCursor,
|
|
204469
|
+
deliverableEvents: events,
|
|
204470
|
+
reset: false
|
|
204471
|
+
};
|
|
204472
|
+
}
|
|
204473
|
+
if (events.length < cursor.lastEventCount) {
|
|
204474
|
+
const recoveredEvents = collectEventsAfterTimestamp(events, cursor.lastEventTimestamp);
|
|
204475
|
+
return {
|
|
204476
|
+
nextCursor,
|
|
204477
|
+
deliverableEvents: recoveredEvents,
|
|
204478
|
+
reset: true
|
|
204479
|
+
};
|
|
204480
|
+
}
|
|
204481
|
+
return {
|
|
204482
|
+
nextCursor,
|
|
204483
|
+
deliverableEvents: events.slice(cursor.lastEventCount),
|
|
204484
|
+
reset: false
|
|
204485
|
+
};
|
|
204486
|
+
}
|
|
204487
|
+
|
|
204155
204488
|
// src/lib/bridge/security/validators.ts
|
|
204156
204489
|
import * as path6 from "path";
|
|
204157
204490
|
var MAX_INPUT_LENGTH = 32e3;
|
|
@@ -204212,6 +204545,19 @@ function validateMode(mode) {
|
|
|
204212
204545
|
|
|
204213
204546
|
// src/lib/bridge/bridge-manager.ts
|
|
204214
204547
|
var GLOBAL_KEY = "__bridge_manager__";
|
|
204548
|
+
var DRAFT_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
204549
|
+
var HISTORY_SUMMARY_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
204550
|
+
var MAX_HIDDEN_DRAFT_SESSIONS = 20;
|
|
204551
|
+
var INTERNAL_SESSION_ROOT = path7.join(CTI_HOME, "runtime", "internal-sessions");
|
|
204552
|
+
var DRAFT_SESSION_PREFIX = "Draft";
|
|
204553
|
+
var HISTORY_SESSION_PREFIX = "History Summary";
|
|
204554
|
+
var REASONING_LEVELS = ["minimal", "low", "medium", "high", "xhigh"];
|
|
204555
|
+
var MODE_OPTIONS_TEXT = "\u53EF\u9009\uFF1A`code`\uFF08\u76F4\u63A5\u6267\u884C\uFF0C\u9ED8\u8BA4\uFF09 `plan`\uFF08\u5148\u5206\u6790\u518D\u884C\u52A8\uFF09 `ask`\uFF08\u8F7B\u5BF9\u8BDD / \u8349\u7A3F\uFF09";
|
|
204556
|
+
var REASONING_OPTIONS_TEXT = "\u53EF\u9009\uFF1A`1=minimal` `2=low` `3=medium` `4=high` `5=xhigh`";
|
|
204557
|
+
var MIRROR_POLL_INTERVAL_MS = 2500;
|
|
204558
|
+
var MIRROR_WATCH_DEBOUNCE_MS = 350;
|
|
204559
|
+
var MIRROR_EVENT_BATCH_LIMIT = 8;
|
|
204560
|
+
var MIRROR_SUPPRESSION_WINDOW_MS = 4e3;
|
|
204215
204561
|
function generateDraftId() {
|
|
204216
204562
|
return Math.floor(Math.random() * 2147483646) + 1;
|
|
204217
204563
|
}
|
|
@@ -204235,6 +204581,28 @@ function parseListIndex(raw) {
|
|
|
204235
204581
|
if (!Number.isInteger(parsed) || parsed < 1) return null;
|
|
204236
204582
|
return parsed;
|
|
204237
204583
|
}
|
|
204584
|
+
function resolveCommandAlias(rawCommand, args) {
|
|
204585
|
+
switch (rawCommand) {
|
|
204586
|
+
case "/":
|
|
204587
|
+
return "/status";
|
|
204588
|
+
case "/h":
|
|
204589
|
+
return "/help";
|
|
204590
|
+
case "/t":
|
|
204591
|
+
return args ? "/thread" : "/threads";
|
|
204592
|
+
case "/s":
|
|
204593
|
+
return args ? "/use" : "/sessions";
|
|
204594
|
+
case "/n":
|
|
204595
|
+
return "/new";
|
|
204596
|
+
case "/m":
|
|
204597
|
+
return "/mode";
|
|
204598
|
+
case "/r":
|
|
204599
|
+
return "/reasoning";
|
|
204600
|
+
case "/his":
|
|
204601
|
+
return "/history";
|
|
204602
|
+
default:
|
|
204603
|
+
return rawCommand;
|
|
204604
|
+
}
|
|
204605
|
+
}
|
|
204238
204606
|
function resolveByIndexOrPrefix(raw, items, getId) {
|
|
204239
204607
|
const token = raw.trim().toLowerCase();
|
|
204240
204608
|
if (!token) return { match: null, ambiguous: false };
|
|
@@ -204258,7 +204626,7 @@ function getDisplayedDesktopThreads(limit = 10) {
|
|
|
204258
204626
|
}
|
|
204259
204627
|
function getDisplayedBridgeSessions(currentSessionId) {
|
|
204260
204628
|
const { store } = getBridgeContext();
|
|
204261
|
-
const sessions = store.listSessions().toReversed();
|
|
204629
|
+
const sessions = store.listSessions().filter((session) => session.hidden !== true).toReversed();
|
|
204262
204630
|
return sessions.sort((a, b) => {
|
|
204263
204631
|
if (a.id === currentSessionId && b.id !== currentSessionId) return -1;
|
|
204264
204632
|
if (b.id === currentSessionId && a.id !== currentSessionId) return 1;
|
|
@@ -204275,38 +204643,368 @@ function getSessionDisplayName(session, fallbackDirectory) {
|
|
|
204275
204643
|
if (session?.id) return session.id.slice(0, 8);
|
|
204276
204644
|
return "\u672A\u547D\u540D\u4F1A\u8BDD";
|
|
204277
204645
|
}
|
|
204278
|
-
function
|
|
204279
|
-
|
|
204280
|
-
return getDesktopSessionByThreadId(threadId)?.title || null;
|
|
204646
|
+
function nowIso() {
|
|
204647
|
+
return (/* @__PURE__ */ new Date()).toISOString();
|
|
204281
204648
|
}
|
|
204282
|
-
function
|
|
204283
|
-
|
|
204284
|
-
return id;
|
|
204649
|
+
function ensureDirectory(dirPath) {
|
|
204650
|
+
fs5.mkdirSync(dirPath, { recursive: true });
|
|
204285
204651
|
}
|
|
204286
|
-
function
|
|
204287
|
-
|
|
204652
|
+
function getWorkspaceRoot() {
|
|
204653
|
+
const { store } = getBridgeContext();
|
|
204654
|
+
return store.getSetting("bridge_default_workspace_root") || DEFAULT_WORKSPACE_ROOT;
|
|
204655
|
+
}
|
|
204656
|
+
function normalizeReasoningEffort(raw) {
|
|
204657
|
+
const token = raw.trim().toLowerCase();
|
|
204658
|
+
if (!token) return null;
|
|
204659
|
+
if (REASONING_LEVELS.includes(token)) {
|
|
204660
|
+
return token;
|
|
204661
|
+
}
|
|
204662
|
+
switch (token) {
|
|
204663
|
+
case "1":
|
|
204664
|
+
return "minimal";
|
|
204665
|
+
case "2":
|
|
204666
|
+
return "low";
|
|
204667
|
+
case "3":
|
|
204668
|
+
return "medium";
|
|
204669
|
+
case "4":
|
|
204670
|
+
return "high";
|
|
204671
|
+
case "5":
|
|
204672
|
+
return "xhigh";
|
|
204673
|
+
default:
|
|
204674
|
+
return null;
|
|
204675
|
+
}
|
|
204676
|
+
}
|
|
204677
|
+
function formatReasoningEffort(reasoning) {
|
|
204678
|
+
switch (reasoning) {
|
|
204679
|
+
case "minimal":
|
|
204680
|
+
return "minimal (1)";
|
|
204681
|
+
case "low":
|
|
204682
|
+
return "low (2)";
|
|
204683
|
+
case "medium":
|
|
204684
|
+
return "medium (3)";
|
|
204685
|
+
case "high":
|
|
204686
|
+
return "high (4)";
|
|
204687
|
+
case "xhigh":
|
|
204688
|
+
return "xhigh (5)";
|
|
204689
|
+
default:
|
|
204690
|
+
return reasoning;
|
|
204691
|
+
}
|
|
204288
204692
|
}
|
|
204289
|
-
function
|
|
204693
|
+
function buildCommandFields(title, fields, notes = [], markdown = false) {
|
|
204694
|
+
const normalizedFields = fields.filter(([, value]) => value !== null && value !== void 0 && String(value).trim() !== "");
|
|
204695
|
+
const normalizedNotes = notes.filter((note) => note.trim().length > 0);
|
|
204696
|
+
if (markdown) {
|
|
204697
|
+
const lines = [`**${title}**`, ""];
|
|
204698
|
+
for (const [label, value] of normalizedFields) {
|
|
204699
|
+
lines.push(`- **${label}**\uFF1A${value}`);
|
|
204700
|
+
}
|
|
204701
|
+
if (normalizedNotes.length > 0) {
|
|
204702
|
+
lines.push("", "**\u8BF4\u660E**");
|
|
204703
|
+
for (const note of normalizedNotes) {
|
|
204704
|
+
lines.push(`- ${note}`);
|
|
204705
|
+
}
|
|
204706
|
+
}
|
|
204707
|
+
return lines.join("\n").trim();
|
|
204708
|
+
}
|
|
204290
204709
|
return [
|
|
204291
|
-
|
|
204292
|
-
|
|
204293
|
-
|
|
204294
|
-
|
|
204295
|
-
];
|
|
204710
|
+
title,
|
|
204711
|
+
"",
|
|
204712
|
+
...normalizedFields.map(([label, value]) => `${label}: ${value}`),
|
|
204713
|
+
...normalizedNotes.length > 0 ? ["", ...normalizedNotes] : []
|
|
204714
|
+
].join("\n").trim();
|
|
204296
204715
|
}
|
|
204297
|
-
function
|
|
204298
|
-
|
|
204299
|
-
|
|
204300
|
-
|
|
204301
|
-
|
|
204302
|
-
|
|
204303
|
-
|
|
204304
|
-
|
|
204305
|
-
|
|
204306
|
-
|
|
204307
|
-
|
|
204716
|
+
function buildIndexedCommandList(title, items, footer = [], markdown = false) {
|
|
204717
|
+
if (markdown) {
|
|
204718
|
+
const lines2 = [`**${title}**`, ""];
|
|
204719
|
+
items.forEach((item, index) => {
|
|
204720
|
+
const marker = `${index + 1}.`;
|
|
204721
|
+
const childIndent = " ".repeat(marker.length + 1);
|
|
204722
|
+
lines2.push(`${marker} **${item.heading}**`);
|
|
204723
|
+
item.details.filter(Boolean).forEach((detail) => lines2.push(`${childIndent}- ${detail}`));
|
|
204724
|
+
lines2.push("");
|
|
204725
|
+
});
|
|
204726
|
+
footer.filter(Boolean).forEach((line) => lines2.push(`- ${line}`));
|
|
204727
|
+
return lines2.join("\n").trim();
|
|
204728
|
+
}
|
|
204729
|
+
const lines = [title, ""];
|
|
204730
|
+
items.forEach((item, index) => {
|
|
204731
|
+
lines.push(`${index + 1}. ${item.heading}`);
|
|
204732
|
+
item.details.filter(Boolean).forEach((detail) => lines.push(` ${detail}`));
|
|
204733
|
+
lines.push("");
|
|
204734
|
+
});
|
|
204735
|
+
footer.filter(Boolean).forEach((line) => lines.push(line));
|
|
204736
|
+
return lines.join("\n").trim();
|
|
204737
|
+
}
|
|
204738
|
+
function isCommandMarkdownEnabled(channelType) {
|
|
204739
|
+
const { store } = getBridgeContext();
|
|
204740
|
+
if (channelType === "feishu") {
|
|
204741
|
+
return store.getSetting("bridge_feishu_command_markdown_enabled") !== "false";
|
|
204742
|
+
}
|
|
204743
|
+
if (channelType === "weixin") {
|
|
204744
|
+
return store.getSetting("bridge_weixin_command_markdown_enabled") === "true";
|
|
204745
|
+
}
|
|
204746
|
+
return false;
|
|
204747
|
+
}
|
|
204748
|
+
function getCommandResponseParseMode(channelType) {
|
|
204749
|
+
return isCommandMarkdownEnabled(channelType) ? "Markdown" : "plain";
|
|
204750
|
+
}
|
|
204751
|
+
function resolveEffectiveReasoningEffort(session) {
|
|
204752
|
+
const { store } = getBridgeContext();
|
|
204753
|
+
const configured = session?.reasoning_effort || store.getSetting("bridge_codex_reasoning_effort");
|
|
204754
|
+
if (configured === "minimal" || configured === "low" || configured === "medium" || configured === "high" || configured === "xhigh") {
|
|
204755
|
+
return configured;
|
|
204756
|
+
}
|
|
204757
|
+
return "medium";
|
|
204758
|
+
}
|
|
204759
|
+
function resolveEffectiveSandboxMode() {
|
|
204760
|
+
const { store } = getBridgeContext();
|
|
204761
|
+
const configured = store.getSetting("bridge_codex_sandbox_mode");
|
|
204762
|
+
if (configured === "read-only" || configured === "workspace-write" || configured === "danger-full-access") {
|
|
204763
|
+
return configured;
|
|
204764
|
+
}
|
|
204765
|
+
return "workspace-write";
|
|
204766
|
+
}
|
|
204767
|
+
function isSessionExpired(session) {
|
|
204768
|
+
if (!session?.expires_at) return false;
|
|
204769
|
+
const expiresAt = Date.parse(session.expires_at);
|
|
204770
|
+
return Number.isFinite(expiresAt) && expiresAt <= Date.now();
|
|
204771
|
+
}
|
|
204772
|
+
function sanitizePathSlug(raw) {
|
|
204773
|
+
return raw.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "scratch";
|
|
204774
|
+
}
|
|
204775
|
+
function getInternalScratchDir(kind, key) {
|
|
204776
|
+
const dir = path7.join(INTERNAL_SESSION_ROOT, kind, sanitizePathSlug(key));
|
|
204777
|
+
ensureDirectory(dir);
|
|
204778
|
+
return dir;
|
|
204779
|
+
}
|
|
204780
|
+
function resolveNewWorkingDirectory(rawArgs) {
|
|
204781
|
+
const trimmed = rawArgs.trim();
|
|
204782
|
+
if (!trimmed) {
|
|
204783
|
+
return { ok: false, message: "\u7F3A\u5C11\u8DEF\u5F84\u53C2\u6570\u3002" };
|
|
204784
|
+
}
|
|
204785
|
+
if (path7.isAbsolute(trimmed)) {
|
|
204786
|
+
const validated2 = validateWorkingDirectory(trimmed);
|
|
204787
|
+
if (!validated2) {
|
|
204788
|
+
return { ok: false, message: "\u8DEF\u5F84\u65E0\u6548\u3002\u5FC5\u987B\u662F\u7EDD\u5BF9\u8DEF\u5F84\uFF0C\u4E14\u4E0D\u80FD\u5305\u542B\u76EE\u5F55\u7A7F\u8D8A\u6216\u7279\u6B8A\u5B57\u7B26\u3002" };
|
|
204789
|
+
}
|
|
204790
|
+
return { ok: true, workDir: validated2 };
|
|
204791
|
+
}
|
|
204792
|
+
const workspaceRoot = getWorkspaceRoot();
|
|
204793
|
+
if (trimmed.includes("\0") || /[$`;|&><(){}\x00-\x1f]/.test(trimmed)) {
|
|
204794
|
+
return { ok: false, message: "\u9879\u76EE\u540D\u65E0\u6548\u3002" };
|
|
204795
|
+
}
|
|
204796
|
+
const normalizedRelative = path7.normalize(trimmed);
|
|
204797
|
+
if (!normalizedRelative || normalizedRelative === "." || normalizedRelative.split(/[\\/]/).some((segment) => segment === "..")) {
|
|
204798
|
+
return { ok: false, message: "\u9879\u76EE\u540D\u65E0\u6548\u3002\u4E0D\u80FD\u4F7F\u7528 .. \u6216\u7A7A\u8DEF\u5F84\u3002" };
|
|
204799
|
+
}
|
|
204800
|
+
const resolvedRoot = path7.resolve(workspaceRoot);
|
|
204801
|
+
const resolvedPath = path7.resolve(resolvedRoot, normalizedRelative);
|
|
204802
|
+
const relative = path7.relative(resolvedRoot, resolvedPath);
|
|
204803
|
+
if (relative.startsWith("..") || path7.isAbsolute(relative)) {
|
|
204804
|
+
return { ok: false, message: "\u9879\u76EE\u8DEF\u5F84\u8D8A\u754C\u3002\u65B0\u9879\u76EE\u5FC5\u987B\u521B\u5EFA\u5728\u9ED8\u8BA4\u5DE5\u4F5C\u7A7A\u95F4\u5185\u3002" };
|
|
204805
|
+
}
|
|
204806
|
+
const validated = validateWorkingDirectory(resolvedPath);
|
|
204807
|
+
if (!validated) {
|
|
204808
|
+
return { ok: false, message: "\u89E3\u6790\u540E\u7684\u5DE5\u4F5C\u76EE\u5F55\u65E0\u6548\u3002" };
|
|
204308
204809
|
}
|
|
204309
|
-
return
|
|
204810
|
+
return { ok: true, workDir: validated };
|
|
204811
|
+
}
|
|
204812
|
+
function ensureWorkingDirectoryExists(workDir) {
|
|
204813
|
+
ensureDirectory(workDir);
|
|
204814
|
+
}
|
|
204815
|
+
function makeDraftSessionName(address) {
|
|
204816
|
+
return `${DRAFT_SESSION_PREFIX}:${address.channelType}:${address.chatId}`;
|
|
204817
|
+
}
|
|
204818
|
+
function makeHistorySummarySessionName(parentSessionId) {
|
|
204819
|
+
return `${HISTORY_SESSION_PREFIX}:${parentSessionId}`;
|
|
204820
|
+
}
|
|
204821
|
+
function cleanupHiddenSessions() {
|
|
204822
|
+
const { store } = getBridgeContext();
|
|
204823
|
+
const bindings = store.listChannelBindings();
|
|
204824
|
+
const boundSessionIds = new Set(bindings.map((binding) => binding.codepilotSessionId));
|
|
204825
|
+
const hiddenSessions = store.listSessions().filter((session) => session.hidden === true);
|
|
204826
|
+
for (const session of hiddenSessions) {
|
|
204827
|
+
if (isSessionExpired(session) && !boundSessionIds.has(session.id)) {
|
|
204828
|
+
store.deleteSession(session.id);
|
|
204829
|
+
}
|
|
204830
|
+
}
|
|
204831
|
+
const draftSessions = store.listSessions().filter((session) => session.hidden === true && session.session_type === "draft" && !boundSessionIds.has(session.id)).sort((a, b) => Date.parse(b.updated_at || b.created_at || "") - Date.parse(a.updated_at || a.created_at || ""));
|
|
204832
|
+
for (const session of draftSessions.slice(MAX_HIDDEN_DRAFT_SESSIONS)) {
|
|
204833
|
+
store.deleteSession(session.id);
|
|
204834
|
+
}
|
|
204835
|
+
}
|
|
204836
|
+
function getOrCreateDraftSession(address) {
|
|
204837
|
+
const { store } = getBridgeContext();
|
|
204838
|
+
cleanupHiddenSessions();
|
|
204839
|
+
const expectedName = makeDraftSessionName(address);
|
|
204840
|
+
const existing = store.listSessions().find(
|
|
204841
|
+
(session) => session.hidden === true && session.session_type === "draft" && session.name === expectedName && !isSessionExpired(session)
|
|
204842
|
+
);
|
|
204843
|
+
if (existing) {
|
|
204844
|
+
store.updateSession(existing.id, {
|
|
204845
|
+
preferred_mode: "ask",
|
|
204846
|
+
expires_at: new Date(Date.now() + DRAFT_TTL_MS).toISOString()
|
|
204847
|
+
});
|
|
204848
|
+
return store.getSession(existing.id) || existing;
|
|
204849
|
+
}
|
|
204850
|
+
const scratchDir = getInternalScratchDir("draft", `${address.channelType}-${address.chatId}`);
|
|
204851
|
+
return store.createSession(
|
|
204852
|
+
expectedName,
|
|
204853
|
+
store.getSetting("bridge_default_model") || "",
|
|
204854
|
+
void 0,
|
|
204855
|
+
scratchDir,
|
|
204856
|
+
"ask",
|
|
204857
|
+
{
|
|
204858
|
+
hidden: true,
|
|
204859
|
+
sessionType: "draft",
|
|
204860
|
+
expiresAt: new Date(Date.now() + DRAFT_TTL_MS).toISOString(),
|
|
204861
|
+
reasoningEffort: "low"
|
|
204862
|
+
}
|
|
204863
|
+
);
|
|
204864
|
+
}
|
|
204865
|
+
function getPendingPermissionLinksForCurrentSession(chatId, sessionId) {
|
|
204866
|
+
const { store } = getBridgeContext();
|
|
204867
|
+
const pending = store.listPendingPermissionLinksByChat(chatId);
|
|
204868
|
+
if (!sessionId) return pending;
|
|
204869
|
+
return pending.filter((link2) => !link2.sessionId || link2.sessionId === sessionId);
|
|
204870
|
+
}
|
|
204871
|
+
function resetDraftSession(address) {
|
|
204872
|
+
const { store } = getBridgeContext();
|
|
204873
|
+
const expectedName = makeDraftSessionName(address);
|
|
204874
|
+
for (const session of store.listSessions()) {
|
|
204875
|
+
if (session.hidden === true && session.session_type === "draft" && session.name === expectedName) {
|
|
204876
|
+
store.deleteSession(session.id);
|
|
204877
|
+
}
|
|
204878
|
+
}
|
|
204879
|
+
return getOrCreateDraftSession(address);
|
|
204880
|
+
}
|
|
204881
|
+
function getOrCreateHistorySummarySession(parentSession) {
|
|
204882
|
+
const { store } = getBridgeContext();
|
|
204883
|
+
cleanupHiddenSessions();
|
|
204884
|
+
const existing = store.listSessions().find(
|
|
204885
|
+
(session) => session.hidden === true && session.session_type === "history_summary" && session.parent_session_id === parentSession.id && !isSessionExpired(session)
|
|
204886
|
+
);
|
|
204887
|
+
if (existing) {
|
|
204888
|
+
store.updateSession(existing.id, {
|
|
204889
|
+
expires_at: new Date(Date.now() + HISTORY_SUMMARY_TTL_MS).toISOString()
|
|
204890
|
+
});
|
|
204891
|
+
return store.getSession(existing.id) || existing;
|
|
204892
|
+
}
|
|
204893
|
+
const scratchDir = getInternalScratchDir("history_summary", parentSession.id);
|
|
204894
|
+
return store.createSession(
|
|
204895
|
+
makeHistorySummarySessionName(parentSession.id),
|
|
204896
|
+
parentSession.model,
|
|
204897
|
+
void 0,
|
|
204898
|
+
scratchDir,
|
|
204899
|
+
"ask",
|
|
204900
|
+
{
|
|
204901
|
+
hidden: true,
|
|
204902
|
+
sessionType: "history_summary",
|
|
204903
|
+
parentSessionId: parentSession.id,
|
|
204904
|
+
expiresAt: new Date(Date.now() + HISTORY_SUMMARY_TTL_MS).toISOString(),
|
|
204905
|
+
reasoningEffort: "low"
|
|
204906
|
+
}
|
|
204907
|
+
);
|
|
204908
|
+
}
|
|
204909
|
+
async function collectInternalTextResponse(llm, params) {
|
|
204910
|
+
const stream = llm.streamChat(params);
|
|
204911
|
+
const reader = stream.getReader();
|
|
204912
|
+
let text2 = "";
|
|
204913
|
+
let sessionId = null;
|
|
204914
|
+
let error = "";
|
|
204915
|
+
while (true) {
|
|
204916
|
+
const { done, value } = await reader.read();
|
|
204917
|
+
if (done) break;
|
|
204918
|
+
for (const line of value.split("\n")) {
|
|
204919
|
+
if (!line.startsWith("data: ")) continue;
|
|
204920
|
+
let event;
|
|
204921
|
+
try {
|
|
204922
|
+
event = JSON.parse(line.slice(6));
|
|
204923
|
+
} catch {
|
|
204924
|
+
continue;
|
|
204925
|
+
}
|
|
204926
|
+
if (event.type === "text") {
|
|
204927
|
+
text2 += event.data;
|
|
204928
|
+
continue;
|
|
204929
|
+
}
|
|
204930
|
+
if (event.type === "status" || event.type === "result") {
|
|
204931
|
+
try {
|
|
204932
|
+
const parsed = JSON.parse(event.data);
|
|
204933
|
+
if (parsed.session_id) sessionId = parsed.session_id;
|
|
204934
|
+
} catch {
|
|
204935
|
+
}
|
|
204936
|
+
continue;
|
|
204937
|
+
}
|
|
204938
|
+
if (event.type === "error") {
|
|
204939
|
+
error = event.data || "Internal summary failed";
|
|
204940
|
+
}
|
|
204941
|
+
}
|
|
204942
|
+
}
|
|
204943
|
+
return {
|
|
204944
|
+
ok: !error,
|
|
204945
|
+
text: text2.trim(),
|
|
204946
|
+
sessionId,
|
|
204947
|
+
...error ? { error } : {}
|
|
204948
|
+
};
|
|
204949
|
+
}
|
|
204950
|
+
function buildHistoryTranscript(messages) {
|
|
204951
|
+
return messages.map((message, index) => {
|
|
204952
|
+
const role = formatHistoryRole(message.role);
|
|
204953
|
+
return `${index + 1}. ${role}
|
|
204954
|
+
${truncateHistoryContent(formatStoredMessageContent(message.content), 1600)}`;
|
|
204955
|
+
}).join("\n\n");
|
|
204956
|
+
}
|
|
204957
|
+
async function summarizeHistory(currentBinding) {
|
|
204958
|
+
const { store, llm } = getBridgeContext();
|
|
204959
|
+
const currentSession = store.getSession(currentBinding.codepilotSessionId);
|
|
204960
|
+
if (!currentSession) {
|
|
204961
|
+
return "\u5F53\u524D\u4F1A\u8BDD\u4E0D\u5B58\u5728\uFF0C\u65E0\u6CD5\u6574\u7406\u5386\u53F2\u8BB0\u5F55\u3002";
|
|
204962
|
+
}
|
|
204963
|
+
const limit = getHistoryMessageLimit();
|
|
204964
|
+
const desktopMessages = currentBinding.sdkSessionId ? readDesktopSessionMessages(currentBinding.sdkSessionId, limit) : [];
|
|
204965
|
+
const { messages: storedMessages } = store.getMessages(currentBinding.codepilotSessionId, { limit });
|
|
204966
|
+
const messages = desktopMessages.length > 0 ? desktopMessages : storedMessages;
|
|
204967
|
+
if (messages.length === 0) {
|
|
204968
|
+
return "\u5F53\u524D\u4F1A\u8BDD\u8FD8\u6CA1\u6709\u5386\u53F2\u6D88\u606F\u3002";
|
|
204969
|
+
}
|
|
204970
|
+
const summarySession = getOrCreateHistorySummarySession(currentSession);
|
|
204971
|
+
const transcript = buildHistoryTranscript(messages);
|
|
204972
|
+
const prompt = [
|
|
204973
|
+
"\u8BF7\u53EA\u57FA\u4E8E\u4E0B\u9762\u7684\u4F1A\u8BDD\u8BB0\u5F55\u505A\u6574\u7406\uFF0C\u4E0D\u8981\u8C03\u7528\u4EFB\u4F55\u5DE5\u5177\uFF0C\u4E5F\u4E0D\u8981\u5F15\u7528\u5DE5\u4F5C\u533A\u5916\u7684\u4FE1\u606F\u3002",
|
|
204974
|
+
"\u8F93\u51FA\u683C\u5F0F\u56FA\u5B9A\u4E3A 4 \u6BB5\uFF1A",
|
|
204975
|
+
"1. \u5F53\u524D\u76EE\u6807",
|
|
204976
|
+
"2. \u6700\u8FD1\u8FDB\u5C55",
|
|
204977
|
+
"3. \u5F53\u524D\u963B\u585E/\u98CE\u9669",
|
|
204978
|
+
"4. \u4E0B\u4E00\u6B65\u5EFA\u8BAE",
|
|
204979
|
+
"\u6BCF\u6BB5\u63A7\u5236\u5728 1-3 \u53E5\uFF0C\u4E2D\u6587\u8F93\u51FA\uFF0C\u76F4\u63A5\u7ED9\u7ED3\u679C\u3002",
|
|
204980
|
+
"",
|
|
204981
|
+
transcript
|
|
204982
|
+
].join("\n");
|
|
204983
|
+
const result = await collectInternalTextResponse(llm, {
|
|
204984
|
+
prompt,
|
|
204985
|
+
sessionId: summarySession.id,
|
|
204986
|
+
sdkSessionId: summarySession.sdk_session_id || void 0,
|
|
204987
|
+
model: currentSession.model || currentBinding.model || void 0,
|
|
204988
|
+
modelReasoningEffort: "low",
|
|
204989
|
+
sandboxMode: "read-only",
|
|
204990
|
+
permissionMode: "never",
|
|
204991
|
+
workingDirectory: summarySession.working_directory,
|
|
204992
|
+
conversationHistory: []
|
|
204993
|
+
});
|
|
204994
|
+
if (result.sessionId) {
|
|
204995
|
+
store.updateSdkSessionId(summarySession.id, result.sessionId);
|
|
204996
|
+
}
|
|
204997
|
+
if (!result.ok) {
|
|
204998
|
+
return `\u5386\u53F2\u6574\u7406\u5931\u8D25\uFF1A${result.error || "unknown error"}`;
|
|
204999
|
+
}
|
|
205000
|
+
return result.text || "\u5F53\u524D\u6CA1\u6709\u53EF\u6574\u7406\u7684\u5386\u53F2\u6458\u8981\u3002";
|
|
205001
|
+
}
|
|
205002
|
+
function getDesktopThreadTitle(threadId) {
|
|
205003
|
+
if (!threadId) return null;
|
|
205004
|
+
return getDesktopSessionByThreadId(threadId)?.title || null;
|
|
205005
|
+
}
|
|
205006
|
+
function formatCommandPath(cwd) {
|
|
205007
|
+
return cwd?.trim() || "~";
|
|
204310
205008
|
}
|
|
204311
205009
|
function getHistoryMessageLimit() {
|
|
204312
205010
|
const { store } = getBridgeContext();
|
|
@@ -204421,7 +205119,14 @@ function getState() {
|
|
|
204421
205119
|
running: false,
|
|
204422
205120
|
startedAt: null,
|
|
204423
205121
|
loopAborts: /* @__PURE__ */ new Map(),
|
|
205122
|
+
reconcileTimer: null,
|
|
205123
|
+
mirrorPollTimer: null,
|
|
205124
|
+
mirrorWakeTimer: null,
|
|
204424
205125
|
activeTasks: /* @__PURE__ */ new Map(),
|
|
205126
|
+
mirrorSubscriptions: /* @__PURE__ */ new Map(),
|
|
205127
|
+
mirrorSyncInFlight: false,
|
|
205128
|
+
mirrorSuppressUntil: /* @__PURE__ */ new Map(),
|
|
205129
|
+
queuedCounts: /* @__PURE__ */ new Map(),
|
|
204425
205130
|
sessionLocks: /* @__PURE__ */ new Map(),
|
|
204426
205131
|
autoStartChecked: false
|
|
204427
205132
|
};
|
|
@@ -204429,12 +205134,398 @@ function getState() {
|
|
|
204429
205134
|
if (!g[GLOBAL_KEY].sessionLocks) {
|
|
204430
205135
|
g[GLOBAL_KEY].sessionLocks = /* @__PURE__ */ new Map();
|
|
204431
205136
|
}
|
|
205137
|
+
if (!g[GLOBAL_KEY].mirrorSubscriptions) {
|
|
205138
|
+
g[GLOBAL_KEY].mirrorSubscriptions = /* @__PURE__ */ new Map();
|
|
205139
|
+
}
|
|
205140
|
+
if (!g[GLOBAL_KEY].queuedCounts) {
|
|
205141
|
+
g[GLOBAL_KEY].queuedCounts = /* @__PURE__ */ new Map();
|
|
205142
|
+
}
|
|
205143
|
+
if (!g[GLOBAL_KEY].mirrorSuppressUntil) {
|
|
205144
|
+
g[GLOBAL_KEY].mirrorSuppressUntil = /* @__PURE__ */ new Map();
|
|
205145
|
+
}
|
|
205146
|
+
if (!Object.prototype.hasOwnProperty.call(g[GLOBAL_KEY], "mirrorSyncInFlight")) {
|
|
205147
|
+
g[GLOBAL_KEY].mirrorSyncInFlight = false;
|
|
205148
|
+
}
|
|
204432
205149
|
return g[GLOBAL_KEY];
|
|
204433
205150
|
}
|
|
205151
|
+
function getQueuedCount(sessionId) {
|
|
205152
|
+
const state = getState();
|
|
205153
|
+
return state.queuedCounts.get(sessionId) || 0;
|
|
205154
|
+
}
|
|
205155
|
+
function syncSessionRuntimeState(sessionId) {
|
|
205156
|
+
const { store } = getBridgeContext();
|
|
205157
|
+
const session = store.getSession(sessionId);
|
|
205158
|
+
if (!session) return;
|
|
205159
|
+
const queuedCount = getQueuedCount(sessionId);
|
|
205160
|
+
const isRunning = getState().activeTasks.has(sessionId);
|
|
205161
|
+
const runtimeStatus = queuedCount > 0 ? "queued" : isRunning ? "running" : "idle";
|
|
205162
|
+
if (session.queued_count === queuedCount && session.runtime_status === runtimeStatus) {
|
|
205163
|
+
return;
|
|
205164
|
+
}
|
|
205165
|
+
store.updateSession(sessionId, {
|
|
205166
|
+
queued_count: queuedCount,
|
|
205167
|
+
runtime_status: runtimeStatus,
|
|
205168
|
+
last_runtime_update_at: nowIso()
|
|
205169
|
+
});
|
|
205170
|
+
}
|
|
205171
|
+
function incrementQueuedCount(sessionId) {
|
|
205172
|
+
const state = getState();
|
|
205173
|
+
state.queuedCounts.set(sessionId, getQueuedCount(sessionId) + 1);
|
|
205174
|
+
syncSessionRuntimeState(sessionId);
|
|
205175
|
+
}
|
|
205176
|
+
function decrementQueuedCount(sessionId) {
|
|
205177
|
+
const state = getState();
|
|
205178
|
+
const next = Math.max(0, getQueuedCount(sessionId) - 1);
|
|
205179
|
+
if (next > 0) {
|
|
205180
|
+
state.queuedCounts.set(sessionId, next);
|
|
205181
|
+
} else {
|
|
205182
|
+
state.queuedCounts.delete(sessionId);
|
|
205183
|
+
}
|
|
205184
|
+
syncSessionRuntimeState(sessionId);
|
|
205185
|
+
}
|
|
205186
|
+
function formatRuntimeStatus(session) {
|
|
205187
|
+
const status = session?.runtime_status || "idle";
|
|
205188
|
+
const queuedCount = session?.queued_count && session.queued_count > 0 ? session.queued_count : 0;
|
|
205189
|
+
if (status === "queued") {
|
|
205190
|
+
return queuedCount > 0 ? `\u6392\u961F\u4E2D\uFF08${queuedCount}\uFF09` : "\u6392\u961F\u4E2D";
|
|
205191
|
+
}
|
|
205192
|
+
if (status === "running") {
|
|
205193
|
+
return "\u8FD0\u884C\u4E2D";
|
|
205194
|
+
}
|
|
205195
|
+
return "\u7A7A\u95F2";
|
|
205196
|
+
}
|
|
205197
|
+
function formatMirrorStatus(session) {
|
|
205198
|
+
if (session?.mirror_status === "watching") {
|
|
205199
|
+
return session.mirror_last_event_at ? `\u76D1\u542C\u4E2D \xB7 \u6700\u8FD1\u540C\u6B65 ${session.mirror_last_event_at}` : "\u76D1\u542C\u4E2D";
|
|
205200
|
+
}
|
|
205201
|
+
if (session?.mirror_status === "stale") {
|
|
205202
|
+
return "\u5F85\u6062\u590D\uFF08\u6682\u65F6\u6CA1\u5B9A\u4F4D\u5230\u684C\u9762 thread \u6587\u4EF6\uFF09";
|
|
205203
|
+
}
|
|
205204
|
+
return "\u672A\u76D1\u542C";
|
|
205205
|
+
}
|
|
205206
|
+
function markMirrorSuppressed(sessionId, durationMs = MIRROR_SUPPRESSION_WINDOW_MS) {
|
|
205207
|
+
getState().mirrorSuppressUntil.set(sessionId, Date.now() + durationMs);
|
|
205208
|
+
}
|
|
205209
|
+
function isMirrorSuppressed(sessionId) {
|
|
205210
|
+
const state = getState();
|
|
205211
|
+
const until = state.mirrorSuppressUntil.get(sessionId);
|
|
205212
|
+
if (!until) return false;
|
|
205213
|
+
if (until <= Date.now()) {
|
|
205214
|
+
state.mirrorSuppressUntil.delete(sessionId);
|
|
205215
|
+
return false;
|
|
205216
|
+
}
|
|
205217
|
+
return true;
|
|
205218
|
+
}
|
|
205219
|
+
function resetMirrorReadState(subscription) {
|
|
205220
|
+
subscription.fileOffset = 0;
|
|
205221
|
+
subscription.fileSize = null;
|
|
205222
|
+
subscription.fileMtimeMs = null;
|
|
205223
|
+
subscription.fileIdentity = null;
|
|
205224
|
+
subscription.trailingText = "";
|
|
205225
|
+
}
|
|
205226
|
+
function statMirrorFile(filePath) {
|
|
205227
|
+
try {
|
|
205228
|
+
const stat = fs5.statSync(filePath);
|
|
205229
|
+
if (!stat.isFile()) return null;
|
|
205230
|
+
return {
|
|
205231
|
+
size: stat.size,
|
|
205232
|
+
mtimeMs: stat.mtimeMs,
|
|
205233
|
+
identity: `${stat.dev}:${stat.ino}`
|
|
205234
|
+
};
|
|
205235
|
+
} catch {
|
|
205236
|
+
return null;
|
|
205237
|
+
}
|
|
205238
|
+
}
|
|
205239
|
+
function closeMirrorWatcher(subscription) {
|
|
205240
|
+
if (subscription.watcher) {
|
|
205241
|
+
try {
|
|
205242
|
+
subscription.watcher.close();
|
|
205243
|
+
} catch {
|
|
205244
|
+
}
|
|
205245
|
+
}
|
|
205246
|
+
subscription.watcher = null;
|
|
205247
|
+
subscription.watcherTarget = null;
|
|
205248
|
+
}
|
|
205249
|
+
function scheduleMirrorWake(delayMs = MIRROR_WATCH_DEBOUNCE_MS) {
|
|
205250
|
+
const state = getState();
|
|
205251
|
+
if (!state.running) return;
|
|
205252
|
+
if (state.mirrorWakeTimer) return;
|
|
205253
|
+
state.mirrorWakeTimer = setTimeout(() => {
|
|
205254
|
+
state.mirrorWakeTimer = null;
|
|
205255
|
+
void reconcileMirrorSubscriptions();
|
|
205256
|
+
}, delayMs);
|
|
205257
|
+
}
|
|
205258
|
+
function watchMirrorFile(subscription, filePath) {
|
|
205259
|
+
if (!filePath) {
|
|
205260
|
+
closeMirrorWatcher(subscription);
|
|
205261
|
+
return;
|
|
205262
|
+
}
|
|
205263
|
+
if (subscription.watcherTarget === filePath && subscription.watcher) {
|
|
205264
|
+
return;
|
|
205265
|
+
}
|
|
205266
|
+
closeMirrorWatcher(subscription);
|
|
205267
|
+
try {
|
|
205268
|
+
subscription.watcher = fs5.watch(filePath, () => {
|
|
205269
|
+
subscription.dirty = true;
|
|
205270
|
+
scheduleMirrorWake();
|
|
205271
|
+
});
|
|
205272
|
+
subscription.watcherTarget = filePath;
|
|
205273
|
+
} catch {
|
|
205274
|
+
subscription.watcher = null;
|
|
205275
|
+
subscription.watcherTarget = null;
|
|
205276
|
+
}
|
|
205277
|
+
}
|
|
205278
|
+
function syncMirrorSessionState(sessionId) {
|
|
205279
|
+
const { store } = getBridgeContext();
|
|
205280
|
+
const session = store.getSession(sessionId);
|
|
205281
|
+
if (!session) return;
|
|
205282
|
+
const subscriptions = Array.from(getState().mirrorSubscriptions.values()).filter((item) => item.sessionId === sessionId);
|
|
205283
|
+
const mirrorStatus = subscriptions.length === 0 ? "inactive" : subscriptions.some((item) => item.status === "watching") ? "watching" : subscriptions.some((item) => item.status === "stale") ? "stale" : "inactive";
|
|
205284
|
+
const deliveredAt = subscriptions.map((item) => item.lastDeliveredAt).filter((value) => Boolean(value)).sort().at(-1) || session.mirror_last_event_at;
|
|
205285
|
+
if (session.mirror_status === mirrorStatus && session.mirror_last_event_at === deliveredAt) {
|
|
205286
|
+
return;
|
|
205287
|
+
}
|
|
205288
|
+
store.updateSession(sessionId, {
|
|
205289
|
+
mirror_status: mirrorStatus,
|
|
205290
|
+
mirror_last_event_at: deliveredAt
|
|
205291
|
+
});
|
|
205292
|
+
}
|
|
205293
|
+
function formatMirrorMessage(threadTitle, events) {
|
|
205294
|
+
const recentEvents = events.filter((event) => event.role !== "user").slice(-MIRROR_EVENT_BATCH_LIMIT).map((event) => event.content.trim()).filter(Boolean);
|
|
205295
|
+
if (recentEvents.length === 0) {
|
|
205296
|
+
return "";
|
|
205297
|
+
}
|
|
205298
|
+
const title = threadTitle?.trim() || "\u684C\u9762\u7EBF\u7A0B";
|
|
205299
|
+
return `${title} \u56DE\u590D:
|
|
205300
|
+
${recentEvents.join("\n\n")}`;
|
|
205301
|
+
}
|
|
205302
|
+
async function deliverMirrorEvents(subscription, events) {
|
|
205303
|
+
if (events.length === 0) return;
|
|
205304
|
+
const state = getState();
|
|
205305
|
+
const adapter = state.adapters.get(subscription.channelType);
|
|
205306
|
+
if (!adapter || !adapter.isRunning()) return;
|
|
205307
|
+
const text2 = formatMirrorMessage(getDesktopThreadTitle(subscription.threadId), events);
|
|
205308
|
+
if (!text2) return;
|
|
205309
|
+
const response = await deliver(adapter, {
|
|
205310
|
+
address: {
|
|
205311
|
+
channelType: subscription.channelType,
|
|
205312
|
+
chatId: subscription.chatId
|
|
205313
|
+
},
|
|
205314
|
+
text: text2,
|
|
205315
|
+
parseMode: "plain"
|
|
205316
|
+
}, {
|
|
205317
|
+
sessionId: subscription.sessionId,
|
|
205318
|
+
dedupKey: `mirror:${subscription.bindingId}:${events[0]?.signature}:${events[events.length - 1]?.signature}`
|
|
205319
|
+
});
|
|
205320
|
+
if (!response.ok) {
|
|
205321
|
+
throw new Error(response.error || "mirror delivery failed");
|
|
205322
|
+
}
|
|
205323
|
+
subscription.lastDeliveredAt = events[events.length - 1]?.timestamp || nowIso();
|
|
205324
|
+
}
|
|
205325
|
+
function removeMirrorSubscription(bindingId) {
|
|
205326
|
+
const state = getState();
|
|
205327
|
+
const existing = state.mirrorSubscriptions.get(bindingId);
|
|
205328
|
+
if (!existing) return;
|
|
205329
|
+
closeMirrorWatcher(existing);
|
|
205330
|
+
state.mirrorSubscriptions.delete(bindingId);
|
|
205331
|
+
syncMirrorSessionState(existing.sessionId);
|
|
205332
|
+
}
|
|
205333
|
+
function upsertMirrorSubscription(binding) {
|
|
205334
|
+
const { store } = getBridgeContext();
|
|
205335
|
+
const state = getState();
|
|
205336
|
+
const session = store.getSession(binding.codepilotSessionId);
|
|
205337
|
+
if (!session) {
|
|
205338
|
+
removeMirrorSubscription(binding.id);
|
|
205339
|
+
return;
|
|
205340
|
+
}
|
|
205341
|
+
const threadId = binding.sdkSessionId || session.sdk_session_id || "";
|
|
205342
|
+
if (!threadId) {
|
|
205343
|
+
removeMirrorSubscription(binding.id);
|
|
205344
|
+
return;
|
|
205345
|
+
}
|
|
205346
|
+
const desktopSession = getDesktopSessionByThreadId(threadId);
|
|
205347
|
+
const filePath = desktopSession?.filePath || null;
|
|
205348
|
+
const existing = state.mirrorSubscriptions.get(binding.id);
|
|
205349
|
+
if (!existing) {
|
|
205350
|
+
const created = {
|
|
205351
|
+
bindingId: binding.id,
|
|
205352
|
+
sessionId: binding.codepilotSessionId,
|
|
205353
|
+
channelType: binding.channelType,
|
|
205354
|
+
chatId: binding.chatId,
|
|
205355
|
+
threadId,
|
|
205356
|
+
filePath,
|
|
205357
|
+
cursor: { initialized: false, lastEventCount: 0 },
|
|
205358
|
+
dirty: true,
|
|
205359
|
+
status: filePath ? "watching" : "stale",
|
|
205360
|
+
watcher: null,
|
|
205361
|
+
watcherTarget: null,
|
|
205362
|
+
lastDeliveredAt: session.mirror_last_event_at || null,
|
|
205363
|
+
lastReconciledAt: null,
|
|
205364
|
+
fileOffset: 0,
|
|
205365
|
+
fileSize: null,
|
|
205366
|
+
fileMtimeMs: null,
|
|
205367
|
+
fileIdentity: null,
|
|
205368
|
+
trailingText: ""
|
|
205369
|
+
};
|
|
205370
|
+
watchMirrorFile(created, filePath);
|
|
205371
|
+
state.mirrorSubscriptions.set(binding.id, created);
|
|
205372
|
+
syncMirrorSessionState(binding.codepilotSessionId);
|
|
205373
|
+
return;
|
|
205374
|
+
}
|
|
205375
|
+
const previousSessionId = existing.sessionId;
|
|
205376
|
+
const threadChanged = existing.threadId !== threadId;
|
|
205377
|
+
const filePathChanged = existing.filePath !== filePath;
|
|
205378
|
+
existing.sessionId = binding.codepilotSessionId;
|
|
205379
|
+
existing.channelType = binding.channelType;
|
|
205380
|
+
existing.chatId = binding.chatId;
|
|
205381
|
+
existing.threadId = threadId;
|
|
205382
|
+
existing.filePath = filePath;
|
|
205383
|
+
existing.status = filePath ? "watching" : "stale";
|
|
205384
|
+
if (threadChanged) {
|
|
205385
|
+
existing.cursor = { initialized: false, lastEventCount: 0 };
|
|
205386
|
+
existing.lastDeliveredAt = session.mirror_last_event_at || null;
|
|
205387
|
+
existing.dirty = true;
|
|
205388
|
+
resetMirrorReadState(existing);
|
|
205389
|
+
} else if (filePathChanged) {
|
|
205390
|
+
existing.dirty = true;
|
|
205391
|
+
resetMirrorReadState(existing);
|
|
205392
|
+
}
|
|
205393
|
+
watchMirrorFile(existing, filePath);
|
|
205394
|
+
if (previousSessionId !== binding.codepilotSessionId) {
|
|
205395
|
+
syncMirrorSessionState(previousSessionId);
|
|
205396
|
+
}
|
|
205397
|
+
syncMirrorSessionState(binding.codepilotSessionId);
|
|
205398
|
+
}
|
|
205399
|
+
function syncMirrorSubscriptionSet() {
|
|
205400
|
+
const { store } = getBridgeContext();
|
|
205401
|
+
const state = getState();
|
|
205402
|
+
const desiredBindings = store.listChannelBindings().filter((binding) => {
|
|
205403
|
+
if (binding.active === false) return false;
|
|
205404
|
+
if (!state.adapters.has(binding.channelType)) return false;
|
|
205405
|
+
const session = store.getSession(binding.codepilotSessionId);
|
|
205406
|
+
return Boolean(binding.sdkSessionId || session?.sdk_session_id);
|
|
205407
|
+
});
|
|
205408
|
+
const desiredIds = /* @__PURE__ */ new Set();
|
|
205409
|
+
for (const binding of desiredBindings) {
|
|
205410
|
+
desiredIds.add(binding.id);
|
|
205411
|
+
upsertMirrorSubscription(binding);
|
|
205412
|
+
}
|
|
205413
|
+
for (const bindingId of Array.from(state.mirrorSubscriptions.keys())) {
|
|
205414
|
+
if (!desiredIds.has(bindingId)) {
|
|
205415
|
+
removeMirrorSubscription(bindingId);
|
|
205416
|
+
}
|
|
205417
|
+
}
|
|
205418
|
+
}
|
|
205419
|
+
async function reconcileMirrorSubscription(subscription) {
|
|
205420
|
+
const { store } = getBridgeContext();
|
|
205421
|
+
const session = store.getSession(subscription.sessionId);
|
|
205422
|
+
if (!session) {
|
|
205423
|
+
removeMirrorSubscription(subscription.bindingId);
|
|
205424
|
+
return;
|
|
205425
|
+
}
|
|
205426
|
+
const desktopSession = getDesktopSessionByThreadId(subscription.threadId);
|
|
205427
|
+
const filePathChanged = subscription.filePath !== (desktopSession?.filePath || null);
|
|
205428
|
+
subscription.filePath = desktopSession?.filePath || null;
|
|
205429
|
+
subscription.status = subscription.filePath ? "watching" : "stale";
|
|
205430
|
+
if (filePathChanged) {
|
|
205431
|
+
subscription.dirty = true;
|
|
205432
|
+
resetMirrorReadState(subscription);
|
|
205433
|
+
}
|
|
205434
|
+
watchMirrorFile(subscription, subscription.filePath);
|
|
205435
|
+
subscription.lastReconciledAt = nowIso();
|
|
205436
|
+
if (!subscription.filePath) {
|
|
205437
|
+
syncMirrorSessionState(subscription.sessionId);
|
|
205438
|
+
return;
|
|
205439
|
+
}
|
|
205440
|
+
const snapshot = statMirrorFile(subscription.filePath);
|
|
205441
|
+
if (!snapshot) {
|
|
205442
|
+
subscription.status = "stale";
|
|
205443
|
+
subscription.dirty = true;
|
|
205444
|
+
resetMirrorReadState(subscription);
|
|
205445
|
+
syncMirrorSessionState(subscription.sessionId);
|
|
205446
|
+
return;
|
|
205447
|
+
}
|
|
205448
|
+
const unchanged = !subscription.dirty && subscription.fileIdentity === snapshot.identity && subscription.fileSize === snapshot.size && subscription.fileMtimeMs === snapshot.mtimeMs;
|
|
205449
|
+
if (unchanged) {
|
|
205450
|
+
syncMirrorSessionState(subscription.sessionId);
|
|
205451
|
+
return;
|
|
205452
|
+
}
|
|
205453
|
+
let deliverableEvents = [];
|
|
205454
|
+
const requiresFullRecover = !subscription.cursor.initialized || subscription.fileOffset === 0 || subscription.fileIdentity !== null && subscription.fileIdentity !== snapshot.identity || subscription.fileSize !== null && snapshot.size < subscription.fileOffset || subscription.fileSize !== null && snapshot.size === subscription.fileOffset && subscription.fileMtimeMs !== null && snapshot.mtimeMs !== subscription.fileMtimeMs;
|
|
205455
|
+
if (requiresFullRecover) {
|
|
205456
|
+
const previousCursor = subscription.cursor;
|
|
205457
|
+
const events = readDesktopSessionEventStreamByFilePath(subscription.filePath);
|
|
205458
|
+
const delta = reconcileDesktopMirrorCursor(subscription.cursor, events);
|
|
205459
|
+
subscription.cursor = delta.nextCursor;
|
|
205460
|
+
deliverableEvents = filterDuplicateAssistantEvents(previousCursor, delta.deliverableEvents);
|
|
205461
|
+
subscription.trailingText = "";
|
|
205462
|
+
subscription.fileOffset = snapshot.size;
|
|
205463
|
+
} else if (snapshot.size > subscription.fileOffset || subscription.trailingText) {
|
|
205464
|
+
const previousCursor = subscription.cursor;
|
|
205465
|
+
const delta = readDesktopSessionEventDeltaByFilePath(
|
|
205466
|
+
subscription.filePath,
|
|
205467
|
+
subscription.fileOffset,
|
|
205468
|
+
snapshot.size,
|
|
205469
|
+
subscription.trailingText
|
|
205470
|
+
);
|
|
205471
|
+
deliverableEvents = filterDuplicateAssistantEvents(previousCursor, delta.events);
|
|
205472
|
+
subscription.cursor = advanceDesktopMirrorCursor(subscription.cursor, delta.events);
|
|
205473
|
+
subscription.trailingText = delta.trailingText;
|
|
205474
|
+
subscription.fileOffset = delta.nextOffset;
|
|
205475
|
+
}
|
|
205476
|
+
subscription.fileSize = snapshot.size;
|
|
205477
|
+
subscription.fileMtimeMs = snapshot.mtimeMs;
|
|
205478
|
+
subscription.fileIdentity = snapshot.identity;
|
|
205479
|
+
subscription.dirty = false;
|
|
205480
|
+
if (deliverableEvents.length === 0) {
|
|
205481
|
+
syncMirrorSessionState(subscription.sessionId);
|
|
205482
|
+
return;
|
|
205483
|
+
}
|
|
205484
|
+
if (getState().activeTasks.has(subscription.sessionId) || isMirrorSuppressed(subscription.sessionId)) {
|
|
205485
|
+
syncMirrorSessionState(subscription.sessionId);
|
|
205486
|
+
return;
|
|
205487
|
+
}
|
|
205488
|
+
try {
|
|
205489
|
+
await deliverMirrorEvents(subscription, deliverableEvents);
|
|
205490
|
+
} catch (error) {
|
|
205491
|
+
subscription.dirty = true;
|
|
205492
|
+
console.warn("[bridge-manager] Mirror delivery failed:", error instanceof Error ? error.message : error);
|
|
205493
|
+
}
|
|
205494
|
+
syncMirrorSessionState(subscription.sessionId);
|
|
205495
|
+
}
|
|
205496
|
+
async function reconcileMirrorSubscriptions() {
|
|
205497
|
+
const state = getState();
|
|
205498
|
+
if (!state.running || state.mirrorSyncInFlight) return;
|
|
205499
|
+
state.mirrorSyncInFlight = true;
|
|
205500
|
+
try {
|
|
205501
|
+
syncMirrorSubscriptionSet();
|
|
205502
|
+
for (const subscription of state.mirrorSubscriptions.values()) {
|
|
205503
|
+
await reconcileMirrorSubscription(subscription);
|
|
205504
|
+
}
|
|
205505
|
+
} finally {
|
|
205506
|
+
state.mirrorSyncInFlight = false;
|
|
205507
|
+
}
|
|
205508
|
+
}
|
|
205509
|
+
function clearMirrorSubscriptions() {
|
|
205510
|
+
const state = getState();
|
|
205511
|
+
for (const bindingId of Array.from(state.mirrorSubscriptions.keys())) {
|
|
205512
|
+
removeMirrorSubscription(bindingId);
|
|
205513
|
+
}
|
|
205514
|
+
}
|
|
204434
205515
|
function processWithSessionLock(sessionId, fn) {
|
|
204435
205516
|
const state = getState();
|
|
204436
205517
|
const prev = state.sessionLocks.get(sessionId) || Promise.resolve();
|
|
204437
|
-
const
|
|
205518
|
+
const queued = state.sessionLocks.has(sessionId);
|
|
205519
|
+
if (queued) {
|
|
205520
|
+
incrementQueuedCount(sessionId);
|
|
205521
|
+
}
|
|
205522
|
+
const wrapped = async () => {
|
|
205523
|
+
if (queued) {
|
|
205524
|
+
decrementQueuedCount(sessionId);
|
|
205525
|
+
}
|
|
205526
|
+
await fn();
|
|
205527
|
+
};
|
|
205528
|
+
const current = prev.then(wrapped, wrapped);
|
|
204438
205529
|
state.sessionLocks.set(sessionId, current);
|
|
204439
205530
|
current.finally(() => {
|
|
204440
205531
|
if (state.sessionLocks.get(sessionId) === current) {
|
|
@@ -204444,37 +205535,85 @@ function processWithSessionLock(sessionId, fn) {
|
|
|
204444
205535
|
});
|
|
204445
205536
|
return current;
|
|
204446
205537
|
}
|
|
204447
|
-
|
|
205538
|
+
function getActiveChannelTypes(state = getState()) {
|
|
205539
|
+
return Array.from(state.adapters.keys()).sort();
|
|
205540
|
+
}
|
|
205541
|
+
function notifyAdapterSetChanged() {
|
|
205542
|
+
const { lifecycle } = getBridgeContext();
|
|
205543
|
+
lifecycle.onBridgeAdaptersChanged?.(getActiveChannelTypes());
|
|
205544
|
+
}
|
|
205545
|
+
async function stopAdapterInstance(channelType) {
|
|
204448
205546
|
const state = getState();
|
|
204449
|
-
|
|
204450
|
-
|
|
204451
|
-
|
|
204452
|
-
|
|
204453
|
-
|
|
204454
|
-
|
|
205547
|
+
const adapter = state.adapters.get(channelType);
|
|
205548
|
+
if (!adapter) return;
|
|
205549
|
+
state.loopAborts.get(channelType)?.abort();
|
|
205550
|
+
state.loopAborts.delete(channelType);
|
|
205551
|
+
try {
|
|
205552
|
+
await adapter.stop();
|
|
205553
|
+
console.log(`[bridge-manager] Stopped adapter: ${channelType}`);
|
|
205554
|
+
} catch (err) {
|
|
205555
|
+
console.error(`[bridge-manager] Error stopping adapter ${channelType}:`, err);
|
|
204455
205556
|
}
|
|
205557
|
+
state.adapters.delete(channelType);
|
|
205558
|
+
state.adapterMeta.delete(channelType);
|
|
205559
|
+
}
|
|
205560
|
+
async function syncConfiguredAdapters(options) {
|
|
205561
|
+
const state = getState();
|
|
205562
|
+
const { store } = getBridgeContext();
|
|
205563
|
+
let changed = false;
|
|
204456
205564
|
for (const channelType of getRegisteredTypes()) {
|
|
204457
|
-
const
|
|
204458
|
-
|
|
205565
|
+
const enabled = store.getSetting(`bridge_${channelType}_enabled`) === "true";
|
|
205566
|
+
const existing = state.adapters.get(channelType);
|
|
205567
|
+
if (!enabled) {
|
|
205568
|
+
if (existing) {
|
|
205569
|
+
await stopAdapterInstance(channelType);
|
|
205570
|
+
changed = true;
|
|
205571
|
+
}
|
|
205572
|
+
continue;
|
|
205573
|
+
}
|
|
205574
|
+
if (existing) {
|
|
205575
|
+
continue;
|
|
205576
|
+
}
|
|
204459
205577
|
const adapter = createAdapter(channelType);
|
|
204460
205578
|
if (!adapter) continue;
|
|
204461
205579
|
const configError = adapter.validateConfig();
|
|
204462
|
-
if (
|
|
204463
|
-
registerAdapter(adapter);
|
|
204464
|
-
} else {
|
|
205580
|
+
if (configError) {
|
|
204465
205581
|
console.warn(`[bridge-manager] ${channelType} adapter not valid:`, configError);
|
|
205582
|
+
continue;
|
|
204466
205583
|
}
|
|
204467
|
-
}
|
|
204468
|
-
let startedCount = 0;
|
|
204469
|
-
for (const [type, adapter] of state.adapters) {
|
|
204470
205584
|
try {
|
|
205585
|
+
state.adapters.set(channelType, adapter);
|
|
205586
|
+
state.adapterMeta.set(channelType, {
|
|
205587
|
+
lastMessageAt: null,
|
|
205588
|
+
lastError: null
|
|
205589
|
+
});
|
|
204471
205590
|
await adapter.start();
|
|
204472
|
-
console.log(`[bridge-manager] Started adapter: ${
|
|
204473
|
-
|
|
205591
|
+
console.log(`[bridge-manager] Started adapter: ${channelType}`);
|
|
205592
|
+
if (options.startLoops && state.running && adapter.isRunning()) {
|
|
205593
|
+
runAdapterLoop(adapter);
|
|
205594
|
+
}
|
|
205595
|
+
changed = true;
|
|
204474
205596
|
} catch (err) {
|
|
204475
|
-
|
|
205597
|
+
state.adapters.delete(channelType);
|
|
205598
|
+
state.adapterMeta.delete(channelType);
|
|
205599
|
+
console.error(`[bridge-manager] Failed to start adapter ${channelType}:`, err);
|
|
204476
205600
|
}
|
|
204477
205601
|
}
|
|
205602
|
+
if (changed) {
|
|
205603
|
+
notifyAdapterSetChanged();
|
|
205604
|
+
}
|
|
205605
|
+
}
|
|
205606
|
+
async function start() {
|
|
205607
|
+
const state = getState();
|
|
205608
|
+
if (state.running) return;
|
|
205609
|
+
const { store, lifecycle } = getBridgeContext();
|
|
205610
|
+
const bridgeEnabled = store.getSetting("remote_bridge_enabled") === "true";
|
|
205611
|
+
if (!bridgeEnabled) {
|
|
205612
|
+
console.log("[bridge-manager] Bridge not enabled (remote_bridge_enabled != true)");
|
|
205613
|
+
return;
|
|
205614
|
+
}
|
|
205615
|
+
await syncConfiguredAdapters({ startLoops: false });
|
|
205616
|
+
const startedCount = state.adapters.size;
|
|
204478
205617
|
if (startedCount === 0) {
|
|
204479
205618
|
console.warn("[bridge-manager] No adapters started successfully, bridge not activated");
|
|
204480
205619
|
state.adapters.clear();
|
|
@@ -204489,6 +205628,19 @@ async function start() {
|
|
|
204489
205628
|
runAdapterLoop(adapter);
|
|
204490
205629
|
}
|
|
204491
205630
|
}
|
|
205631
|
+
state.reconcileTimer = setInterval(() => {
|
|
205632
|
+
void syncConfiguredAdapters({ startLoops: true }).catch((err) => {
|
|
205633
|
+
console.error("[bridge-manager] Adapter reconcile failed:", err);
|
|
205634
|
+
});
|
|
205635
|
+
}, 5e3);
|
|
205636
|
+
state.mirrorPollTimer = setInterval(() => {
|
|
205637
|
+
void reconcileMirrorSubscriptions().catch((err) => {
|
|
205638
|
+
console.error("[bridge-manager] Mirror reconcile failed:", err);
|
|
205639
|
+
});
|
|
205640
|
+
}, MIRROR_POLL_INTERVAL_MS);
|
|
205641
|
+
void reconcileMirrorSubscriptions().catch((err) => {
|
|
205642
|
+
console.error("[bridge-manager] Initial mirror reconcile failed:", err);
|
|
205643
|
+
});
|
|
204492
205644
|
console.log(`[bridge-manager] Bridge started with ${startedCount} adapter(s)`);
|
|
204493
205645
|
}
|
|
204494
205646
|
async function stop() {
|
|
@@ -204496,27 +205648,56 @@ async function stop() {
|
|
|
204496
205648
|
if (!state.running) return;
|
|
204497
205649
|
const { lifecycle } = getBridgeContext();
|
|
204498
205650
|
state.running = false;
|
|
205651
|
+
if (state.reconcileTimer) {
|
|
205652
|
+
clearInterval(state.reconcileTimer);
|
|
205653
|
+
state.reconcileTimer = null;
|
|
205654
|
+
}
|
|
205655
|
+
if (state.mirrorPollTimer) {
|
|
205656
|
+
clearInterval(state.mirrorPollTimer);
|
|
205657
|
+
state.mirrorPollTimer = null;
|
|
205658
|
+
}
|
|
205659
|
+
if (state.mirrorWakeTimer) {
|
|
205660
|
+
clearTimeout(state.mirrorWakeTimer);
|
|
205661
|
+
state.mirrorWakeTimer = null;
|
|
205662
|
+
}
|
|
204499
205663
|
for (const [, abort] of state.loopAborts) {
|
|
204500
205664
|
abort.abort();
|
|
204501
205665
|
}
|
|
204502
205666
|
state.loopAborts.clear();
|
|
204503
|
-
|
|
204504
|
-
|
|
204505
|
-
|
|
204506
|
-
|
|
204507
|
-
|
|
204508
|
-
|
|
204509
|
-
|
|
205667
|
+
const activeSessionIds = Array.from(state.activeTasks.keys());
|
|
205668
|
+
for (const abort of state.activeTasks.values()) {
|
|
205669
|
+
abort.abort();
|
|
205670
|
+
}
|
|
205671
|
+
state.activeTasks.clear();
|
|
205672
|
+
state.mirrorSuppressUntil.clear();
|
|
205673
|
+
state.queuedCounts.clear();
|
|
205674
|
+
for (const sessionId of activeSessionIds) {
|
|
205675
|
+
syncSessionRuntimeState(sessionId);
|
|
205676
|
+
}
|
|
205677
|
+
clearMirrorSubscriptions();
|
|
205678
|
+
for (const type of Array.from(state.adapters.keys())) {
|
|
205679
|
+
await stopAdapterInstance(type);
|
|
204510
205680
|
}
|
|
204511
|
-
state.adapters.clear();
|
|
204512
|
-
state.adapterMeta.clear();
|
|
204513
205681
|
state.startedAt = null;
|
|
204514
205682
|
lifecycle.onBridgeStop?.();
|
|
204515
205683
|
console.log("[bridge-manager] Bridge stopped");
|
|
204516
205684
|
}
|
|
204517
|
-
function
|
|
205685
|
+
function getStatus() {
|
|
204518
205686
|
const state = getState();
|
|
204519
|
-
|
|
205687
|
+
return {
|
|
205688
|
+
running: state.running,
|
|
205689
|
+
startedAt: state.startedAt,
|
|
205690
|
+
adapters: Array.from(state.adapters.entries()).map(([type, adapter]) => {
|
|
205691
|
+
const meta = state.adapterMeta.get(type);
|
|
205692
|
+
return {
|
|
205693
|
+
channelType: adapter.channelType,
|
|
205694
|
+
running: adapter.isRunning(),
|
|
205695
|
+
connectedAt: state.startedAt,
|
|
205696
|
+
lastMessageAt: meta?.lastMessageAt ?? null,
|
|
205697
|
+
error: meta?.lastError ?? null
|
|
205698
|
+
};
|
|
205699
|
+
})
|
|
205700
|
+
};
|
|
204520
205701
|
}
|
|
204521
205702
|
function runAdapterLoop(adapter) {
|
|
204522
205703
|
const state = getState();
|
|
@@ -204575,7 +205756,7 @@ async function handleMessage(adapter, msg) {
|
|
|
204575
205756
|
const confirmMsg = {
|
|
204576
205757
|
address: msg.address,
|
|
204577
205758
|
text: "Permission response recorded.",
|
|
204578
|
-
parseMode:
|
|
205759
|
+
parseMode: getCommandResponseParseMode(adapter.channelType)
|
|
204579
205760
|
};
|
|
204580
205761
|
await deliver(adapter, confirmMsg);
|
|
204581
205762
|
}
|
|
@@ -204590,7 +205771,7 @@ async function handleMessage(adapter, msg) {
|
|
|
204590
205771
|
await deliver(adapter, {
|
|
204591
205772
|
address: msg.address,
|
|
204592
205773
|
text: rawData.userVisibleError,
|
|
204593
|
-
parseMode:
|
|
205774
|
+
parseMode: getCommandResponseParseMode(adapter.channelType),
|
|
204594
205775
|
replyToMessageId: msg.messageId
|
|
204595
205776
|
});
|
|
204596
205777
|
} else if (rawData?.imageDownloadFailed || rawData?.attachmentDownloadFailed) {
|
|
@@ -204598,7 +205779,7 @@ async function handleMessage(adapter, msg) {
|
|
|
204598
205779
|
await deliver(adapter, {
|
|
204599
205780
|
address: msg.address,
|
|
204600
205781
|
text: `Failed to download ${rawData.failedCount ?? 1} ${failureLabel}. Please try sending again.`,
|
|
204601
|
-
parseMode:
|
|
205782
|
+
parseMode: getCommandResponseParseMode(adapter.channelType),
|
|
204602
205783
|
replyToMessageId: msg.messageId
|
|
204603
205784
|
});
|
|
204604
205785
|
}
|
|
@@ -204608,7 +205789,11 @@ async function handleMessage(adapter, msg) {
|
|
|
204608
205789
|
if (adapter.channelType === "feishu" || adapter.channelType === "qq" || adapter.channelType === "weixin") {
|
|
204609
205790
|
const normalized = rawText.normalize("NFKC").replace(/[\u200B-\u200D\uFEFF]/g, "").trim();
|
|
204610
205791
|
if (/^[123]$/.test(normalized)) {
|
|
204611
|
-
const
|
|
205792
|
+
const currentBinding = store.getChannelBinding(msg.address.channelType, msg.address.chatId);
|
|
205793
|
+
const pendingLinks = getPendingPermissionLinksForCurrentSession(
|
|
205794
|
+
msg.address.chatId,
|
|
205795
|
+
currentBinding?.codepilotSessionId
|
|
205796
|
+
);
|
|
204612
205797
|
if (pendingLinks.length === 1) {
|
|
204613
205798
|
const actionMap = { "1": "allow", "2": "allow_session", "3": "deny" };
|
|
204614
205799
|
const action = actionMap[normalized];
|
|
@@ -204620,14 +205805,14 @@ async function handleMessage(adapter, msg) {
|
|
|
204620
205805
|
await deliver(adapter, {
|
|
204621
205806
|
address: msg.address,
|
|
204622
205807
|
text: `${label}: recorded.`,
|
|
204623
|
-
parseMode:
|
|
205808
|
+
parseMode: getCommandResponseParseMode(adapter.channelType),
|
|
204624
205809
|
replyToMessageId: msg.messageId
|
|
204625
205810
|
});
|
|
204626
205811
|
} else {
|
|
204627
205812
|
await deliver(adapter, {
|
|
204628
205813
|
address: msg.address,
|
|
204629
205814
|
text: `Permission not found or already resolved.`,
|
|
204630
|
-
parseMode:
|
|
205815
|
+
parseMode: getCommandResponseParseMode(adapter.channelType),
|
|
204631
205816
|
replyToMessageId: msg.messageId
|
|
204632
205817
|
});
|
|
204633
205818
|
}
|
|
@@ -204639,7 +205824,7 @@ async function handleMessage(adapter, msg) {
|
|
|
204639
205824
|
address: msg.address,
|
|
204640
205825
|
text: `Multiple pending permissions (${pendingLinks.length}). Please use the full command:
|
|
204641
205826
|
/perm allow|allow_session|deny <id>`,
|
|
204642
|
-
parseMode:
|
|
205827
|
+
parseMode: getCommandResponseParseMode(adapter.channelType),
|
|
204643
205828
|
replyToMessageId: msg.messageId
|
|
204644
205829
|
});
|
|
204645
205830
|
ack();
|
|
@@ -204675,6 +205860,8 @@ async function handleMessage(adapter, msg) {
|
|
|
204675
205860
|
const taskAbort = new AbortController();
|
|
204676
205861
|
const state = getState();
|
|
204677
205862
|
state.activeTasks.set(binding.codepilotSessionId, taskAbort);
|
|
205863
|
+
markMirrorSuppressed(binding.codepilotSessionId);
|
|
205864
|
+
syncSessionRuntimeState(binding.codepilotSessionId);
|
|
204678
205865
|
let previewState = null;
|
|
204679
205866
|
const caps = adapter.getPreviewCapabilities?.(msg.address.chatId) ?? null;
|
|
204680
205867
|
if (caps?.supported) {
|
|
@@ -204803,7 +205990,9 @@ async function handleMessage(adapter, msg) {
|
|
|
204803
205990
|
} catch {
|
|
204804
205991
|
}
|
|
204805
205992
|
}
|
|
205993
|
+
markMirrorSuppressed(binding.codepilotSessionId);
|
|
204806
205994
|
state.activeTasks.delete(binding.codepilotSessionId);
|
|
205995
|
+
syncSessionRuntimeState(binding.codepilotSessionId);
|
|
204807
205996
|
adapter.onMessageEnd?.(msg.address.chatId);
|
|
204808
205997
|
ack();
|
|
204809
205998
|
}
|
|
@@ -204811,8 +206000,9 @@ async function handleMessage(adapter, msg) {
|
|
|
204811
206000
|
async function handleCommand(adapter, msg, text2) {
|
|
204812
206001
|
const { store } = getBridgeContext();
|
|
204813
206002
|
const parts = text2.split(/\s+/);
|
|
204814
|
-
const
|
|
206003
|
+
const rawCommand = parts[0].split("@")[0].toLowerCase();
|
|
204815
206004
|
const args = parts.slice(1).join(" ").trim();
|
|
206005
|
+
const command = resolveCommandAlias(rawCommand, args);
|
|
204816
206006
|
const dangerCheck = isDangerousInput(text2);
|
|
204817
206007
|
if (dangerCheck.dangerous) {
|
|
204818
206008
|
store.insertAuditLog({
|
|
@@ -204826,12 +206016,13 @@ async function handleCommand(adapter, msg, text2) {
|
|
|
204826
206016
|
await deliver(adapter, {
|
|
204827
206017
|
address: msg.address,
|
|
204828
206018
|
text: `Command rejected: invalid input detected.`,
|
|
204829
|
-
parseMode:
|
|
206019
|
+
parseMode: getCommandResponseParseMode(adapter.channelType),
|
|
204830
206020
|
replyToMessageId: msg.messageId
|
|
204831
206021
|
});
|
|
204832
206022
|
return;
|
|
204833
206023
|
}
|
|
204834
206024
|
let response = "";
|
|
206025
|
+
let responseParseMode = getCommandResponseParseMode(adapter.channelType);
|
|
204835
206026
|
const currentBinding = store.getChannelBinding(msg.address.channelType, msg.address.chatId);
|
|
204836
206027
|
switch (command) {
|
|
204837
206028
|
case "/start":
|
|
@@ -204841,44 +206032,50 @@ async function handleCommand(adapter, msg, text2) {
|
|
|
204841
206032
|
"\u76F4\u63A5\u53D1\u9001\u6587\u672C\uFF0C\u5C31\u4F1A\u7EE7\u7EED\u5F53\u524D\u804A\u5929\u7ED1\u5B9A\u7684\u4F1A\u8BDD\u3002",
|
|
204842
206033
|
"",
|
|
204843
206034
|
"\u5E38\u7528\u6D41\u7A0B",
|
|
204844
|
-
"1. /
|
|
204845
|
-
"2. /
|
|
206035
|
+
"1. /t \u67E5\u770B\u6700\u8FD1\u684C\u9762\u4F1A\u8BDD",
|
|
206036
|
+
"2. /t 1 \u63A5\u7BA1\u7B2C 1 \u6761\u684C\u9762\u4F1A\u8BDD",
|
|
204846
206037
|
"3. \u4E4B\u540E\u76F4\u63A5\u53D1\u6D88\u606F\u5373\u53EF\u7EE7\u7EED\u8FD9\u6761\u4F1A\u8BDD",
|
|
204847
206038
|
"",
|
|
204848
|
-
"\u53D1\u9001 /
|
|
206039
|
+
"\u53D1\u9001 /h \u67E5\u770B\u5B8C\u6574\u8BF4\u660E\u3002"
|
|
204849
206040
|
].join("\n");
|
|
204850
206041
|
break;
|
|
204851
206042
|
case "/new": {
|
|
204852
|
-
|
|
204853
|
-
|
|
204854
|
-
|
|
204855
|
-
|
|
204856
|
-
|
|
204857
|
-
|
|
206043
|
+
if (currentBinding) {
|
|
206044
|
+
const st = getState();
|
|
206045
|
+
const oldTask = st.activeTasks.get(currentBinding.codepilotSessionId);
|
|
206046
|
+
if (oldTask) {
|
|
206047
|
+
oldTask.abort();
|
|
206048
|
+
st.activeTasks.delete(currentBinding.codepilotSessionId);
|
|
206049
|
+
syncSessionRuntimeState(currentBinding.codepilotSessionId);
|
|
206050
|
+
}
|
|
204858
206051
|
}
|
|
204859
206052
|
let workDir;
|
|
204860
206053
|
if (args) {
|
|
204861
|
-
const
|
|
204862
|
-
if (!
|
|
204863
|
-
response =
|
|
206054
|
+
const resolved = resolveNewWorkingDirectory(args);
|
|
206055
|
+
if (!resolved.ok) {
|
|
206056
|
+
response = resolved.message;
|
|
204864
206057
|
break;
|
|
204865
206058
|
}
|
|
204866
|
-
workDir =
|
|
206059
|
+
workDir = resolved.workDir;
|
|
206060
|
+
ensureWorkingDirectoryExists(workDir);
|
|
204867
206061
|
}
|
|
204868
206062
|
const binding = createBinding(msg.address, workDir);
|
|
204869
206063
|
const session = store.getSession(binding.codepilotSessionId);
|
|
204870
|
-
response =
|
|
206064
|
+
response = buildCommandFields(
|
|
204871
206065
|
"\u5DF2\u65B0\u5EFA\u4F1A\u8BDD",
|
|
204872
|
-
|
|
204873
|
-
|
|
204874
|
-
|
|
204875
|
-
|
|
204876
|
-
|
|
206066
|
+
[
|
|
206067
|
+
["\u6807\u9898", getSessionDisplayName(session, binding.workingDirectory)],
|
|
206068
|
+
["\u76EE\u5F55", formatCommandPath(binding.workingDirectory)],
|
|
206069
|
+
["\u6A21\u5F0F", binding.mode]
|
|
206070
|
+
],
|
|
206071
|
+
["\u63A5\u4E0B\u6765\u76F4\u63A5\u53D1\u9001\u6587\u672C\u5373\u53EF\u7EE7\u7EED\u3002"],
|
|
206072
|
+
responseParseMode === "Markdown"
|
|
206073
|
+
);
|
|
204877
206074
|
break;
|
|
204878
206075
|
}
|
|
204879
206076
|
case "/bind": {
|
|
204880
206077
|
if (!args) {
|
|
204881
|
-
response = "\u7528\u6CD5\uFF1A/bind
|
|
206078
|
+
response = "\u7528\u6CD5\uFF1A/bind <\u5E8F\u53F7>";
|
|
204882
206079
|
break;
|
|
204883
206080
|
}
|
|
204884
206081
|
const prefersThreadList = parseListIndex(args) !== null;
|
|
@@ -204891,47 +206088,46 @@ async function handleCommand(adapter, msg, text2) {
|
|
|
204891
206088
|
displayName: threadPick2.match.title
|
|
204892
206089
|
});
|
|
204893
206090
|
const session = store.getSession(importedBinding2.codepilotSessionId);
|
|
204894
|
-
response =
|
|
206091
|
+
response = buildCommandFields(
|
|
204895
206092
|
"\u5DF2\u7ED1\u5B9A\u684C\u9762\u4F1A\u8BDD",
|
|
204896
|
-
|
|
204897
|
-
|
|
204898
|
-
|
|
204899
|
-
|
|
204900
|
-
|
|
204901
|
-
""
|
|
204902
|
-
|
|
204903
|
-
].join("\n");
|
|
206093
|
+
[
|
|
206094
|
+
["\u6807\u9898", threadPick2.match.title || getSessionDisplayName(session, importedBinding2.workingDirectory)],
|
|
206095
|
+
["\u76EE\u5F55", formatCommandPath(importedBinding2.workingDirectory)]
|
|
206096
|
+
],
|
|
206097
|
+
["\u63A5\u4E0B\u6765\u76F4\u63A5\u53D1\u9001\u6587\u672C\u5373\u53EF\u7EE7\u7EED\u3002"],
|
|
206098
|
+
responseParseMode === "Markdown"
|
|
206099
|
+
);
|
|
204904
206100
|
break;
|
|
204905
206101
|
}
|
|
204906
206102
|
}
|
|
204907
206103
|
const displayedSessions = getDisplayedBridgeSessions(currentBinding?.codepilotSessionId);
|
|
204908
206104
|
const sessionPick = resolveByIndexOrPrefix(args, displayedSessions, (session) => session.id);
|
|
204909
206105
|
if (sessionPick.ambiguous) {
|
|
204910
|
-
response = "\u5339\u914D\u5230\u591A\u4E2A\
|
|
206106
|
+
response = "\u5339\u914D\u5230\u591A\u4E2A\u517C\u5BB9\u4F1A\u8BDD\uFF0C\u8BF7\u4F7F\u7528\u66F4\u957F\u7684\u7F16\u53F7\uFF0C\u6216\u76F4\u63A5\u6539\u7528 `/t` \u5207\u6362\u684C\u9762\u4F1A\u8BDD\u3002";
|
|
204911
206107
|
break;
|
|
204912
206108
|
}
|
|
204913
206109
|
if (sessionPick.match) {
|
|
204914
206110
|
const binding = bindToSession(msg.address, sessionPick.match.id);
|
|
204915
206111
|
if (binding) {
|
|
204916
|
-
|
|
204917
|
-
|
|
204918
|
-
|
|
204919
|
-
|
|
204920
|
-
|
|
204921
|
-
|
|
204922
|
-
|
|
204923
|
-
|
|
204924
|
-
|
|
206112
|
+
response = buildCommandFields(
|
|
206113
|
+
"\u5DF2\u5207\u6362\u4F1A\u8BDD\uFF08\u517C\u5BB9\u547D\u4EE4\uFF09",
|
|
206114
|
+
[
|
|
206115
|
+
["\u6807\u9898", getSessionDisplayName(sessionPick.match, binding.workingDirectory)],
|
|
206116
|
+
["\u76EE\u5F55", formatCommandPath(binding.workingDirectory)]
|
|
206117
|
+
],
|
|
206118
|
+
["\u666E\u901A\u4F7F\u7528\u5EFA\u8BAE\u76F4\u63A5\u901A\u8FC7 `/t` \u5207\u6362\u684C\u9762\u4F1A\u8BDD\u3002"],
|
|
206119
|
+
responseParseMode === "Markdown"
|
|
206120
|
+
);
|
|
204925
206121
|
break;
|
|
204926
206122
|
}
|
|
204927
206123
|
}
|
|
204928
206124
|
const threadPick = resolveByIndexOrPrefix(args, displayedThreads, (session) => session.threadId);
|
|
204929
206125
|
if (threadPick.ambiguous) {
|
|
204930
|
-
response = "\u5339\u914D\u5230\u591A\u4E2A\u684C\u9762
|
|
206126
|
+
response = "\u5339\u914D\u5230\u591A\u4E2A\u684C\u9762\u4F1A\u8BDD\uFF0C\u8BF7\u5148\u53D1\u9001 `/t` \u67E5\u770B\u5217\u8868\uFF0C\u518D\u7528 `/t 1` \u8FD9\u79CD\u5E8F\u53F7\u5207\u6362\u3002";
|
|
204931
206127
|
break;
|
|
204932
206128
|
}
|
|
204933
206129
|
if (!threadPick.match) {
|
|
204934
|
-
response = "\u6CA1\u6709\u627E\u5230\u5BF9\u5E94\
|
|
206130
|
+
response = "\u6CA1\u6709\u627E\u5230\u5BF9\u5E94\u76EE\u6807\u3002\u5148\u53D1\u9001 `/t` \u67E5\u770B\u684C\u9762\u4F1A\u8BDD\uFF0C\u518D\u6309\u5E8F\u53F7\u5207\u6362\u3002";
|
|
204935
206131
|
break;
|
|
204936
206132
|
}
|
|
204937
206133
|
const importedBinding = bindToSdkSession(msg.address, threadPick.match.threadId, {
|
|
@@ -204939,27 +206135,51 @@ async function handleCommand(adapter, msg, text2) {
|
|
|
204939
206135
|
displayName: threadPick.match.title
|
|
204940
206136
|
});
|
|
204941
206137
|
const importedSession = store.getSession(importedBinding.codepilotSessionId);
|
|
204942
|
-
response =
|
|
206138
|
+
response = buildCommandFields(
|
|
204943
206139
|
"\u5DF2\u7ED1\u5B9A\u684C\u9762\u4F1A\u8BDD",
|
|
204944
|
-
|
|
204945
|
-
|
|
204946
|
-
|
|
204947
|
-
|
|
204948
|
-
|
|
204949
|
-
""
|
|
204950
|
-
|
|
204951
|
-
].join("\n");
|
|
206140
|
+
[
|
|
206141
|
+
["\u6807\u9898", threadPick.match.title || getSessionDisplayName(importedSession, importedBinding.workingDirectory)],
|
|
206142
|
+
["\u76EE\u5F55", formatCommandPath(importedBinding.workingDirectory)]
|
|
206143
|
+
],
|
|
206144
|
+
["\u63A5\u4E0B\u6765\u76F4\u63A5\u53D1\u9001\u6587\u672C\u5373\u53EF\u7EE7\u7EED\u3002"],
|
|
206145
|
+
responseParseMode === "Markdown"
|
|
206146
|
+
);
|
|
204952
206147
|
break;
|
|
204953
206148
|
}
|
|
204954
206149
|
case "/thread": {
|
|
206150
|
+
if (args === "0" || args === "0 reset") {
|
|
206151
|
+
const draftSession = args === "0 reset" ? resetDraftSession(msg.address) : getOrCreateDraftSession(msg.address);
|
|
206152
|
+
const binding2 = bindToSession(msg.address, draftSession.id);
|
|
206153
|
+
if (!binding2) {
|
|
206154
|
+
response = "\u8349\u7A3F\u7EBF\u7A0B\u5207\u6362\u5931\u8D25\u3002";
|
|
206155
|
+
break;
|
|
206156
|
+
}
|
|
206157
|
+
updateBinding(binding2.id, {
|
|
206158
|
+
mode: "ask",
|
|
206159
|
+
workingDirectory: draftSession.working_directory,
|
|
206160
|
+
model: draftSession.model || binding2.model
|
|
206161
|
+
});
|
|
206162
|
+
response = buildCommandFields(
|
|
206163
|
+
args === "0 reset" ? "\u5DF2\u91CD\u7F6E\u4E34\u65F6\u8349\u7A3F\u7EBF\u7A0B" : "\u5DF2\u5207\u6362\u5230\u4E34\u65F6\u8349\u7A3F\u7EBF\u7A0B",
|
|
206164
|
+
[
|
|
206165
|
+
["\u6807\u9898", getSessionDisplayName(draftSession, draftSession.working_directory)],
|
|
206166
|
+
["\u76EE\u5F55", formatCommandPath(draftSession.working_directory)],
|
|
206167
|
+
["\u8FC7\u671F\u65F6\u95F4", draftSession.expires_at || "-"],
|
|
206168
|
+
["\u6A21\u5F0F", "ask"]
|
|
206169
|
+
],
|
|
206170
|
+
["\u8FD9\u662F\u9690\u85CF\u7684\u8349\u7A3F\u7EBF\u7A0B\uFF0C\u4E0D\u4F1A\u51FA\u73B0\u5728\u5E38\u89C4\u4F1A\u8BDD\u5217\u8868\u4E2D\u3002"],
|
|
206171
|
+
responseParseMode === "Markdown"
|
|
206172
|
+
);
|
|
206173
|
+
break;
|
|
206174
|
+
}
|
|
204955
206175
|
if (!args) {
|
|
204956
|
-
response = "\u7528\u6CD5\uFF1A/thread
|
|
206176
|
+
response = "\u7528\u6CD5\uFF1A/thread <\u5E8F\u53F7>\uFF0C\u6216 /thread 0 \u8FDB\u5165\u4E34\u65F6\u8349\u7A3F\u7EBF\u7A0B";
|
|
204957
206177
|
break;
|
|
204958
206178
|
}
|
|
204959
206179
|
const displayedThreads = getDisplayedDesktopThreads(10);
|
|
204960
206180
|
const threadPick = resolveByIndexOrPrefix(args, displayedThreads, (session) => session.threadId);
|
|
204961
206181
|
if (threadPick.ambiguous) {
|
|
204962
|
-
response = "\u5339\u914D\u5230\u591A\u4E2A\u684C\u9762
|
|
206182
|
+
response = "\u5339\u914D\u5230\u591A\u4E2A\u684C\u9762\u4F1A\u8BDD\uFF0C\u8BF7\u5148\u53D1\u9001 `/t` \u67E5\u770B\u5217\u8868\uFF0C\u518D\u7528 `/t 1` \u8FD9\u79CD\u5E8F\u53F7\u5207\u6362\u3002";
|
|
204963
206183
|
break;
|
|
204964
206184
|
}
|
|
204965
206185
|
if (!threadPick.match) {
|
|
@@ -204970,50 +206190,56 @@ async function handleCommand(adapter, msg, text2) {
|
|
|
204970
206190
|
displayName: desktop.title
|
|
204971
206191
|
} : void 0);
|
|
204972
206192
|
const session = store.getSession(binding2.codepilotSessionId);
|
|
204973
|
-
response =
|
|
204974
|
-
"\u5DF2\
|
|
204975
|
-
|
|
204976
|
-
|
|
204977
|
-
|
|
204978
|
-
|
|
204979
|
-
|
|
204980
|
-
""
|
|
204981
|
-
|
|
204982
|
-
].join("\n");
|
|
206193
|
+
response = buildCommandFields(
|
|
206194
|
+
"\u5DF2\u5207\u6362\u5230\u684C\u9762\u4F1A\u8BDD",
|
|
206195
|
+
[
|
|
206196
|
+
["\u6807\u9898", desktop?.title || getSessionDisplayName(session, binding2.workingDirectory)],
|
|
206197
|
+
["\u76EE\u5F55", formatCommandPath(binding2.workingDirectory)]
|
|
206198
|
+
],
|
|
206199
|
+
["\u63A5\u4E0B\u6765\u76F4\u63A5\u53D1\u9001\u6587\u672C\u5373\u53EF\u7EE7\u7EED\u3002"],
|
|
206200
|
+
responseParseMode === "Markdown"
|
|
206201
|
+
);
|
|
204983
206202
|
break;
|
|
204984
206203
|
}
|
|
204985
|
-
response = "\u6CA1\u6709\u627E\u5230\u5BF9\u5E94\u7684\u684C\u9762
|
|
206204
|
+
response = "\u6CA1\u6709\u627E\u5230\u5BF9\u5E94\u7684\u684C\u9762\u4F1A\u8BDD\u3002\u5148\u53D1\u9001 `/t` \u67E5\u770B\u6700\u8FD1\u4F1A\u8BDD\uFF0C\u518D\u7528 `/t 1` \u63A5\u7BA1\u3002";
|
|
204986
206205
|
break;
|
|
204987
206206
|
}
|
|
204988
206207
|
const binding = bindToSdkSession(msg.address, threadPick.match.threadId, {
|
|
204989
206208
|
workingDirectory: threadPick.match.cwd,
|
|
204990
206209
|
displayName: threadPick.match.title
|
|
204991
206210
|
});
|
|
204992
|
-
response =
|
|
204993
|
-
"\u5DF2\
|
|
204994
|
-
|
|
204995
|
-
|
|
204996
|
-
|
|
204997
|
-
|
|
204998
|
-
|
|
204999
|
-
""
|
|
205000
|
-
|
|
205001
|
-
].join("\n");
|
|
206211
|
+
response = buildCommandFields(
|
|
206212
|
+
"\u5DF2\u5207\u6362\u5230\u684C\u9762\u4F1A\u8BDD",
|
|
206213
|
+
[
|
|
206214
|
+
["\u6807\u9898", threadPick.match.title || "\u672A\u547D\u540D\u7EBF\u7A0B"],
|
|
206215
|
+
["\u76EE\u5F55", formatCommandPath(binding.workingDirectory)]
|
|
206216
|
+
],
|
|
206217
|
+
["\u63A5\u4E0B\u6765\u76F4\u63A5\u53D1\u9001\u6587\u672C\u5373\u53EF\u7EE7\u7EED\u3002"],
|
|
206218
|
+
responseParseMode === "Markdown"
|
|
206219
|
+
);
|
|
205002
206220
|
break;
|
|
205003
206221
|
}
|
|
205004
206222
|
case "/threads": {
|
|
205005
206223
|
const desktopSessions = getDisplayedDesktopThreads(10);
|
|
205006
206224
|
if (desktopSessions.length === 0) {
|
|
205007
|
-
response = "\u6CA1\u6709\u627E\u5230\u6700\u8FD1\u684C\u9762\u4F1A\u8BDD\u3002\u5148\u5728 Codex
|
|
206225
|
+
response = "\u6CA1\u6709\u627E\u5230\u6700\u8FD1\u684C\u9762\u4F1A\u8BDD\u3002\u5148\u5728 Codex Desktop App \u4E2D\u6253\u5F00\u4E00\u4E2A\u4F1A\u8BDD\uFF0C\u518D\u56DE\u6765\u8BD5\u4E00\u6B21\u3002";
|
|
205008
206226
|
break;
|
|
205009
206227
|
}
|
|
205010
|
-
|
|
205011
|
-
|
|
205012
|
-
|
|
205013
|
-
|
|
205014
|
-
|
|
205015
|
-
|
|
205016
|
-
|
|
206228
|
+
response = buildIndexedCommandList(
|
|
206229
|
+
"\u6700\u8FD1\u684C\u9762\u4F1A\u8BDD",
|
|
206230
|
+
desktopSessions.map((session) => ({
|
|
206231
|
+
heading: session.title || "\u672A\u547D\u540D\u7EBF\u7A0B",
|
|
206232
|
+
details: [
|
|
206233
|
+
`\u76EE\u5F55\uFF1A${formatCommandPath(session.cwd)}`,
|
|
206234
|
+
`\u6765\u6E90\uFF1A${session.originator || "Codex Desktop"}`
|
|
206235
|
+
]
|
|
206236
|
+
})),
|
|
206237
|
+
[
|
|
206238
|
+
"\u53D1\u9001 `/t 1` \u53EF\u63A5\u7BA1\u7B2C 1 \u6761\u684C\u9762\u4F1A\u8BDD\u3002",
|
|
206239
|
+
"\u5B8C\u6574\u547D\u4EE4\u4ECD\u517C\u5BB9\uFF0C\u4F8B\u5982 `/thread 1`\u3002"
|
|
206240
|
+
],
|
|
206241
|
+
responseParseMode === "Markdown"
|
|
206242
|
+
);
|
|
205017
206243
|
break;
|
|
205018
206244
|
}
|
|
205019
206245
|
case "/use": {
|
|
@@ -205024,7 +206250,7 @@ async function handleCommand(adapter, msg, text2) {
|
|
|
205024
206250
|
const displayedSessions = getDisplayedBridgeSessions(currentBinding?.codepilotSessionId);
|
|
205025
206251
|
const sessionPick = resolveByIndexOrPrefix(args, displayedSessions, (session) => session.id);
|
|
205026
206252
|
if (sessionPick.ambiguous) {
|
|
205027
|
-
response = "\u5339\u914D\u5230\u591A\u4E2A\u5185\u90E8\u4F1A\u8BDD\uFF0C\u8BF7\u4F7F\u7528\u66F4\u957F\u7684
|
|
206253
|
+
response = "\u5339\u914D\u5230\u591A\u4E2A\u5185\u90E8\u4F1A\u8BDD\uFF0C\u8BF7\u4F7F\u7528\u66F4\u957F\u7684\u7F16\u53F7\u3002";
|
|
205028
206254
|
break;
|
|
205029
206255
|
}
|
|
205030
206256
|
if (!sessionPick.match) {
|
|
@@ -205036,63 +206262,126 @@ async function handleCommand(adapter, msg, text2) {
|
|
|
205036
206262
|
response = "\u5207\u6362\u5931\u8D25\uFF0C\u8BE5\u4F1A\u8BDD\u4E0D\u5B58\u5728\u3002";
|
|
205037
206263
|
break;
|
|
205038
206264
|
}
|
|
205039
|
-
|
|
205040
|
-
|
|
205041
|
-
|
|
205042
|
-
|
|
205043
|
-
|
|
205044
|
-
|
|
205045
|
-
|
|
205046
|
-
|
|
205047
|
-
|
|
206265
|
+
response = buildCommandFields(
|
|
206266
|
+
"\u5DF2\u5207\u6362\u4F1A\u8BDD\uFF08\u517C\u5BB9\u547D\u4EE4\uFF09",
|
|
206267
|
+
[
|
|
206268
|
+
["\u6807\u9898", getSessionDisplayName(sessionPick.match, binding.workingDirectory)],
|
|
206269
|
+
["\u76EE\u5F55", formatCommandPath(binding.workingDirectory)]
|
|
206270
|
+
],
|
|
206271
|
+
["\u666E\u901A\u4F7F\u7528\u5EFA\u8BAE\u76F4\u63A5\u901A\u8FC7 `/t` \u5207\u6362\u684C\u9762\u4F1A\u8BDD\u3002"],
|
|
206272
|
+
responseParseMode === "Markdown"
|
|
206273
|
+
);
|
|
205048
206274
|
break;
|
|
205049
206275
|
}
|
|
205050
|
-
case "/
|
|
206276
|
+
case "/reasoning": {
|
|
206277
|
+
if (!currentBinding) {
|
|
206278
|
+
response = "\u5F53\u524D\u804A\u5929\u8FD8\u6CA1\u6709\u7ED1\u5B9A\u4F1A\u8BDD\u3002\u5148\u53D1\u9001\u6D88\u606F\u521B\u5EFA\u4F1A\u8BDD\uFF0C\u6216\u5148\u7528 `/t 1` \u63A5\u7BA1\u684C\u9762\u4F1A\u8BDD\u3002";
|
|
206279
|
+
break;
|
|
206280
|
+
}
|
|
206281
|
+
const session = store.getSession(currentBinding.codepilotSessionId);
|
|
206282
|
+
if (!session) {
|
|
206283
|
+
response = "\u5F53\u524D\u4F1A\u8BDD\u4E0D\u5B58\u5728\u3002";
|
|
206284
|
+
break;
|
|
206285
|
+
}
|
|
205051
206286
|
if (!args) {
|
|
205052
|
-
response =
|
|
206287
|
+
response = buildCommandFields(
|
|
206288
|
+
"\u5F53\u524D\u601D\u8003\u7EA7\u522B",
|
|
206289
|
+
[["\u7EA7\u522B", formatReasoningEffort(resolveEffectiveReasoningEffort(session))]],
|
|
206290
|
+
[REASONING_OPTIONS_TEXT, "\u53D1\u9001 `/r 4` \u6216 `/r high` \u53EF\u5207\u6362\u3002"],
|
|
206291
|
+
responseParseMode === "Markdown"
|
|
206292
|
+
);
|
|
205053
206293
|
break;
|
|
205054
206294
|
}
|
|
205055
|
-
const
|
|
205056
|
-
if (!
|
|
205057
|
-
response =
|
|
206295
|
+
const reasoning = normalizeReasoningEffort(args);
|
|
206296
|
+
if (!reasoning) {
|
|
206297
|
+
response = buildCommandFields(
|
|
206298
|
+
"\u601D\u8003\u7EA7\u522B\u7528\u6CD5",
|
|
206299
|
+
[["\u547D\u4EE4", "`/reasoning minimal|low|medium|high|xhigh`"]],
|
|
206300
|
+
["\u4E5F\u652F\u6301\u5B8C\u6574\u547D\u4EE4\uFF1A`/reasoning 1|2|3|4|5`", REASONING_OPTIONS_TEXT],
|
|
206301
|
+
responseParseMode === "Markdown"
|
|
206302
|
+
);
|
|
205058
206303
|
break;
|
|
205059
206304
|
}
|
|
205060
|
-
|
|
205061
|
-
|
|
205062
|
-
|
|
206305
|
+
store.updateSession(session.id, {
|
|
206306
|
+
reasoning_effort: reasoning
|
|
206307
|
+
});
|
|
206308
|
+
response = buildCommandFields(
|
|
206309
|
+
"\u5DF2\u66F4\u65B0\u601D\u8003\u7EA7\u522B",
|
|
206310
|
+
[["\u7EA7\u522B", formatReasoningEffort(reasoning)]],
|
|
206311
|
+
[REASONING_OPTIONS_TEXT],
|
|
206312
|
+
responseParseMode === "Markdown"
|
|
206313
|
+
);
|
|
206314
|
+
break;
|
|
206315
|
+
}
|
|
206316
|
+
case "/cwd": {
|
|
206317
|
+
response = "\u5F53\u524D\u7248\u672C\u5DF2\u4E0D\u652F\u6301 /cwd\u3002\u8BF7\u4F7F\u7528 /new \u65B0\u5EFA\u4F1A\u8BDD\uFF0C\u6216\u4F7F\u7528 /thread /bind /use \u5207\u6362\u5230\u5DF2\u6709\u5DE5\u4F5C\u7A7A\u95F4\u3002";
|
|
205063
206318
|
break;
|
|
205064
206319
|
}
|
|
205065
206320
|
case "/mode": {
|
|
206321
|
+
const binding = currentBinding || resolve(msg.address);
|
|
206322
|
+
if (!args) {
|
|
206323
|
+
response = buildCommandFields(
|
|
206324
|
+
"\u5F53\u524D\u6A21\u5F0F",
|
|
206325
|
+
[["\u6A21\u5F0F", binding.mode]],
|
|
206326
|
+
[MODE_OPTIONS_TEXT, "\u53D1\u9001 `/m code`\u3001`/m plan` \u6216 `/m ask` \u5207\u6362\u3002\u5B8C\u6574\u547D\u4EE4\u4E5F\u517C\u5BB9\uFF1A`/mode code`\u3002"],
|
|
206327
|
+
responseParseMode === "Markdown"
|
|
206328
|
+
);
|
|
206329
|
+
break;
|
|
206330
|
+
}
|
|
205066
206331
|
if (!validateMode(args)) {
|
|
205067
|
-
response =
|
|
206332
|
+
response = buildCommandFields(
|
|
206333
|
+
"\u6A21\u5F0F\u7528\u6CD5",
|
|
206334
|
+
[["\u547D\u4EE4", "`/mode plan|code|ask`"]],
|
|
206335
|
+
[MODE_OPTIONS_TEXT],
|
|
206336
|
+
responseParseMode === "Markdown"
|
|
206337
|
+
);
|
|
205068
206338
|
break;
|
|
205069
206339
|
}
|
|
205070
|
-
const
|
|
206340
|
+
const session = store.getSession(binding.codepilotSessionId);
|
|
206341
|
+
if (session) {
|
|
206342
|
+
store.updateSession(session.id, {
|
|
206343
|
+
preferred_mode: args
|
|
206344
|
+
});
|
|
206345
|
+
}
|
|
205071
206346
|
updateBinding(binding.id, { mode: args });
|
|
205072
|
-
response =
|
|
206347
|
+
response = buildCommandFields(
|
|
206348
|
+
"\u5DF2\u5207\u6362\u6A21\u5F0F",
|
|
206349
|
+
[["\u6A21\u5F0F", args]],
|
|
206350
|
+
[MODE_OPTIONS_TEXT],
|
|
206351
|
+
responseParseMode === "Markdown"
|
|
206352
|
+
);
|
|
205073
206353
|
break;
|
|
205074
206354
|
}
|
|
205075
206355
|
case "/status": {
|
|
205076
206356
|
const binding = resolve(msg.address);
|
|
205077
206357
|
const session = store.getSession(binding.codepilotSessionId);
|
|
205078
206358
|
const threadTitle = getDesktopThreadTitle(binding.sdkSessionId);
|
|
205079
|
-
|
|
206359
|
+
const sandboxMode = resolveEffectiveSandboxMode();
|
|
206360
|
+
const reasoningEffort = resolveEffectiveReasoningEffort(session);
|
|
206361
|
+
const sessionKind = session?.session_type === "draft" ? "\u4E34\u65F6\u8349\u7A3F\u7EBF\u7A0B" : session?.session_type === "history_summary" ? "\u5386\u53F2\u6458\u8981\u7EBF\u7A0B" : "\u666E\u901A\u4F1A\u8BDD";
|
|
206362
|
+
response = buildCommandFields(
|
|
205080
206363
|
"\u5F53\u524D\u4F1A\u8BDD",
|
|
205081
|
-
|
|
205082
|
-
|
|
205083
|
-
|
|
205084
|
-
|
|
205085
|
-
|
|
205086
|
-
|
|
205087
|
-
|
|
205088
|
-
|
|
205089
|
-
|
|
205090
|
-
|
|
206364
|
+
[
|
|
206365
|
+
["\u6807\u9898", threadTitle || getSessionDisplayName(session, binding.workingDirectory)],
|
|
206366
|
+
["\u76EE\u5F55", formatCommandPath(binding.workingDirectory)],
|
|
206367
|
+
["\u6A21\u5F0F", binding.mode],
|
|
206368
|
+
["\u6A21\u578B", binding.model || "default"],
|
|
206369
|
+
["\u7C7B\u578B", sessionKind],
|
|
206370
|
+
["\u8FD0\u884C\u72B6\u6001", formatRuntimeStatus(session)],
|
|
206371
|
+
["\u5171\u4EAB\u955C\u50CF", formatMirrorStatus(session)],
|
|
206372
|
+
["\u6587\u4EF6\u7CFB\u7EDF\u6743\u9650", sandboxMode],
|
|
206373
|
+
["\u601D\u8003\u7EA7\u522B", formatReasoningEffort(reasoningEffort)]
|
|
206374
|
+
],
|
|
206375
|
+
[
|
|
206376
|
+
binding.sdkSessionId ? "\u5F53\u524D\u804A\u5929\u5DF2\u7ED1\u5B9A\u5230\u4E00\u6761\u5171\u4EAB\u4F1A\u8BDD\uFF0C\u76F4\u63A5\u53D1\u9001\u6D88\u606F\u5373\u53EF\u7EE7\u7EED\u3002" : "\u5F53\u524D\u804A\u5929\u8FD8\u6CA1\u6709\u7ED1\u5B9A\u684C\u9762\u4F1A\u8BDD\u3002\u53EF\u5148\u53D1\u9001 `/t`\uFF0C\u518D\u7528 `/t 1` \u63A5\u7BA1\u3002"
|
|
206377
|
+
],
|
|
206378
|
+
responseParseMode === "Markdown"
|
|
206379
|
+
);
|
|
205091
206380
|
break;
|
|
205092
206381
|
}
|
|
205093
206382
|
case "/history": {
|
|
205094
206383
|
if (!currentBinding) {
|
|
205095
|
-
response = "\u5F53\u524D\u804A\u5929\u8FD8\u6CA1\u6709\u7ED1\u5B9A\u4F1A\u8BDD\u3002\u5148\u53D1\u9001\u6D88\u606F\u521B\u5EFA\u4F1A\u8BDD\uFF0C\u6216\u5148\u7528
|
|
206384
|
+
response = "\u5F53\u524D\u804A\u5929\u8FD8\u6CA1\u6709\u7ED1\u5B9A\u4F1A\u8BDD\u3002\u5148\u53D1\u9001\u6D88\u606F\u521B\u5EFA\u4F1A\u8BDD\uFF0C\u6216\u5148\u7528 `/t 1` \u63A5\u7BA1\u684C\u9762\u4F1A\u8BDD\u3002";
|
|
205096
206385
|
break;
|
|
205097
206386
|
}
|
|
205098
206387
|
const limit = getHistoryMessageLimit();
|
|
@@ -205105,35 +206394,63 @@ async function handleCommand(adapter, msg, text2) {
|
|
|
205105
206394
|
}
|
|
205106
206395
|
const threadTitle = getDesktopThreadTitle(currentBinding.sdkSessionId);
|
|
205107
206396
|
const session = store.getSession(currentBinding.codepilotSessionId);
|
|
205108
|
-
|
|
205109
|
-
|
|
205110
|
-
|
|
205111
|
-
|
|
205112
|
-
|
|
205113
|
-
|
|
205114
|
-
|
|
205115
|
-
|
|
205116
|
-
|
|
205117
|
-
|
|
205118
|
-
|
|
205119
|
-
|
|
205120
|
-
|
|
205121
|
-
|
|
206397
|
+
if (args === "raw") {
|
|
206398
|
+
const header2 = buildCommandFields(
|
|
206399
|
+
"\u6700\u8FD1\u5BF9\u8BDD\uFF08raw\uFF09",
|
|
206400
|
+
[
|
|
206401
|
+
["\u6807\u9898", threadTitle || getSessionDisplayName(session, currentBinding.workingDirectory)],
|
|
206402
|
+
["\u6765\u6E90", desktopMessages.length > 0 ? "desktop thread" : "bridge cache"],
|
|
206403
|
+
["\u8FD4\u56DE\u6761\u6570", `${messages.length} / \u914D\u7F6E ${limit}`]
|
|
206404
|
+
],
|
|
206405
|
+
[],
|
|
206406
|
+
responseParseMode === "Markdown"
|
|
206407
|
+
);
|
|
206408
|
+
const body = messages.map((message, index) => {
|
|
206409
|
+
if (responseParseMode === "Markdown") {
|
|
206410
|
+
return `${index + 1}. **${formatHistoryRole(message.role)}**
|
|
206411
|
+
|
|
206412
|
+
${truncateHistoryContent(formatStoredMessageContent(message.content))}`;
|
|
206413
|
+
}
|
|
206414
|
+
return `${index + 1}. ${formatHistoryRole(message.role)}
|
|
206415
|
+
${truncateHistoryContent(formatStoredMessageContent(message.content))}`;
|
|
206416
|
+
}).join("\n\n");
|
|
206417
|
+
response = [header2, body].join("\n\n").trim();
|
|
206418
|
+
break;
|
|
205122
206419
|
}
|
|
205123
|
-
|
|
206420
|
+
const summary = await summarizeHistory(currentBinding);
|
|
206421
|
+
const header = buildCommandFields(
|
|
206422
|
+
"\u6700\u8FD1\u5BF9\u8BDD\uFF08\u6574\u7406\uFF09",
|
|
206423
|
+
[
|
|
206424
|
+
["\u6807\u9898", threadTitle || getSessionDisplayName(session, currentBinding.workingDirectory)]
|
|
206425
|
+
],
|
|
206426
|
+
[`\u539F\u59CB\u8BB0\u5F55\u53EF\u53D1\u9001 \`/his raw\` \u67E5\u770B\uFF08\u5B8C\u6574\u547D\u4EE4\uFF1A\`/history raw\`\uFF1B\u5F53\u524D\u6293\u53D6 ${messages.length} \u6761\uFF0C\u914D\u7F6E ${limit} \u6761\uFF09\u3002`],
|
|
206427
|
+
responseParseMode === "Markdown"
|
|
206428
|
+
);
|
|
206429
|
+
response = [header, summary].join("\n\n").trim();
|
|
205124
206430
|
break;
|
|
205125
206431
|
}
|
|
205126
206432
|
case "/sessions": {
|
|
205127
206433
|
const sessions = getDisplayedBridgeSessions(currentBinding?.codepilotSessionId);
|
|
205128
206434
|
if (sessions.length === 0) {
|
|
205129
|
-
response = "\u5F53\u524D\u6CA1\u6709\u5185\u90E8\u4F1A\u8BDD\u3002\
|
|
206435
|
+
response = "\u5F53\u524D\u6CA1\u6709\u5185\u90E8\u4F1A\u8BDD\u3002\u666E\u901A\u4F7F\u7528\u5EFA\u8BAE\u76F4\u63A5\u53D1\u9001\u6D88\u606F\u521B\u5EFA\u4F1A\u8BDD\uFF0C\u6216\u5148\u7528 `/t 1` \u63A5\u7BA1\u684C\u9762\u4F1A\u8BDD\u3002";
|
|
205130
206436
|
} else {
|
|
205131
|
-
|
|
205132
|
-
|
|
205133
|
-
|
|
205134
|
-
|
|
205135
|
-
|
|
205136
|
-
|
|
206437
|
+
response = buildIndexedCommandList(
|
|
206438
|
+
"\u53EF\u5207\u6362\u7684\u5185\u90E8\u4F1A\u8BDD\uFF08\u517C\u5BB9\u547D\u4EE4\uFF09",
|
|
206439
|
+
sessions.slice(0, 10).map((session) => {
|
|
206440
|
+
const threadTitle = session.sdk_session_id ? getDesktopThreadTitle(session.sdk_session_id) : null;
|
|
206441
|
+
return {
|
|
206442
|
+
heading: `${getSessionDisplayName(session, session.working_directory)}${session.id === currentBinding?.codepilotSessionId ? " [\u5F53\u524D]" : ""}`,
|
|
206443
|
+
details: [
|
|
206444
|
+
`\u76EE\u5F55\uFF1A${formatCommandPath(session.working_directory)}`
|
|
206445
|
+
]
|
|
206446
|
+
};
|
|
206447
|
+
}),
|
|
206448
|
+
[
|
|
206449
|
+
"\u666E\u901A\u4F7F\u7528\u5EFA\u8BAE\u76F4\u63A5\u901A\u8FC7 `/t` \u5207\u6362\u684C\u9762\u4F1A\u8BDD\u3002",
|
|
206450
|
+
"\u517C\u5BB9\u547D\u4EE4\u4ECD\u53EF\u7528\uFF0C\u4F8B\u5982 `/use 2`\u3002"
|
|
206451
|
+
],
|
|
206452
|
+
responseParseMode === "Markdown"
|
|
206453
|
+
);
|
|
205137
206454
|
}
|
|
205138
206455
|
break;
|
|
205139
206456
|
}
|
|
@@ -205144,6 +206461,7 @@ async function handleCommand(adapter, msg, text2) {
|
|
|
205144
206461
|
if (taskAbort) {
|
|
205145
206462
|
taskAbort.abort();
|
|
205146
206463
|
st.activeTasks.delete(binding.codepilotSessionId);
|
|
206464
|
+
syncSessionRuntimeState(binding.codepilotSessionId);
|
|
205147
206465
|
response = "Stopping current task...";
|
|
205148
206466
|
} else {
|
|
205149
206467
|
response = "No task is currently running.";
|
|
@@ -205158,6 +206476,15 @@ async function handleCommand(adapter, msg, text2) {
|
|
|
205158
206476
|
response = "\u7528\u6CD5\uFF1A/perm allow|allow_session|deny <permission_id>";
|
|
205159
206477
|
break;
|
|
205160
206478
|
}
|
|
206479
|
+
const link2 = store.getPermissionLink(permId);
|
|
206480
|
+
if (!link2) {
|
|
206481
|
+
response = "\u6CA1\u6709\u627E\u5230\u5BF9\u5E94\u6743\u9650\uFF0C\u6216\u8BE5\u6743\u9650\u5DF2\u5904\u7406\u3002";
|
|
206482
|
+
break;
|
|
206483
|
+
}
|
|
206484
|
+
if (currentBinding?.codepilotSessionId && link2.sessionId && link2.sessionId !== currentBinding.codepilotSessionId) {
|
|
206485
|
+
response = "\u8FD9\u6761\u6743\u9650\u8BF7\u6C42\u4E0D\u5C5E\u4E8E\u5F53\u524D\u4F1A\u8BDD\u3002\u8BF7\u5148\u5207\u56DE\u5BF9\u5E94\u4F1A\u8BDD\uFF0C\u518D\u5904\u7406\u8BE5\u6743\u9650\u3002";
|
|
206486
|
+
break;
|
|
206487
|
+
}
|
|
205161
206488
|
const callbackData = `perm:${permAction}:${permId}`;
|
|
205162
206489
|
const handled = handlePermissionCallback(callbackData, msg.address.chatId);
|
|
205163
206490
|
if (handled) {
|
|
@@ -205168,47 +206495,39 @@ async function handleCommand(adapter, msg, text2) {
|
|
|
205168
206495
|
break;
|
|
205169
206496
|
}
|
|
205170
206497
|
case "/help":
|
|
206498
|
+
responseParseMode = getCommandResponseParseMode(adapter.channelType);
|
|
205171
206499
|
response = [
|
|
205172
|
-
"
|
|
205173
|
-
"",
|
|
205174
|
-
"\u6700\u5E38\u7528",
|
|
205175
|
-
"/threads \u67E5\u770B\u6700\u8FD1\u684C\u9762\u4F1A\u8BDD",
|
|
205176
|
-
"/thread 1 \u63A5\u7BA1\u7B2C 1 \u6761\u684C\u9762\u4F1A\u8BDD",
|
|
205177
|
-
"\u76F4\u63A5\u53D1\u9001\u6587\u672C \u7EE7\u7EED\u5F53\u524D\u5DF2\u7ED1\u5B9A\u4F1A\u8BDD",
|
|
205178
|
-
"/status \u67E5\u770B\u5F53\u524D\u804A\u5929\u7ED1\u5B9A\u5230\u4E86\u54EA\u6761\u4F1A\u8BDD",
|
|
205179
|
-
"/history \u67E5\u770B\u5F53\u524D\u4F1A\u8BDD\u6700\u8FD1 N \u6761\u6D88\u606F",
|
|
205180
|
-
"",
|
|
205181
|
-
"\u5207\u6362\u4E0E\u7ED1\u5B9A",
|
|
205182
|
-
"/threads \u5217\u51FA\u6700\u8FD1\u684C\u9762\u4F1A\u8BDD",
|
|
205183
|
-
"/thread <thread-id | \u5E8F\u53F7> \u7ED1\u5B9A\u684C\u9762 thread",
|
|
205184
|
-
"/sessions \u5217\u51FA\u5185\u90E8\u4F1A\u8BDD",
|
|
205185
|
-
"/use <session-id | \u5E8F\u53F7> \u5207\u6362\u5230\u5185\u90E8\u4F1A\u8BDD",
|
|
205186
|
-
"/bind <session-id | thread-id | \u5E8F\u53F7> \u667A\u80FD\u7ED1\u5B9A\uFF0C\u517C\u5BB9\u65E7\u7528\u6CD5",
|
|
206500
|
+
"**\u547D\u4EE4\u901F\u89C8**",
|
|
205187
206501
|
"",
|
|
205188
|
-
"\
|
|
205189
|
-
"
|
|
205190
|
-
"
|
|
205191
|
-
"
|
|
205192
|
-
"
|
|
205193
|
-
"
|
|
206502
|
+
"**\u5E38\u7528**",
|
|
206503
|
+
"- `/` \u5F53\u524D\u4F1A\u8BDD",
|
|
206504
|
+
"- `/h` \u5E2E\u52A9",
|
|
206505
|
+
"- `/t` \u6700\u8FD1\u684C\u9762\u4F1A\u8BDD",
|
|
206506
|
+
"- `/t 1` \u63A5\u7BA1\u7B2C 1 \u6761\u4F1A\u8BDD",
|
|
206507
|
+
"- `/n proj1` \u65B0\u5EFA\u4F1A\u8BDD",
|
|
206508
|
+
"- `/his` \u5386\u53F2\u6458\u8981",
|
|
205194
206509
|
"",
|
|
205195
|
-
"\
|
|
205196
|
-
"
|
|
205197
|
-
"
|
|
206510
|
+
"**\u8BBE\u7F6E**",
|
|
206511
|
+
"- `/m` \u67E5\u770B\u6A21\u5F0F\uFF1B\u53EF\u7528 `code | plan | ask`",
|
|
206512
|
+
"- `/r` \u67E5\u770B\u601D\u8003\u7EA7\u522B\uFF1B\u53EF\u7528 `1 | 2 | 3 | 4 | 5`",
|
|
206513
|
+
"- `/t 0` \u4E34\u65F6\u8349\u7A3F\u7EBF\u7A0B",
|
|
206514
|
+
"- `/t 0 reset` \u91CD\u7F6E\u8349\u7A3F\u7EBF\u7A0B",
|
|
206515
|
+
"- `/stop` \u505C\u6B62\u5F53\u524D\u4EFB\u52A1",
|
|
205198
206516
|
"",
|
|
205199
|
-
"\
|
|
205200
|
-
"
|
|
206517
|
+
"**\u5176\u5B83**",
|
|
206518
|
+
"- `/his raw` \u539F\u59CB\u8BB0\u5F55",
|
|
206519
|
+
"- `/perm allow|allow_session|deny <id>` \u6216 `1 / 2 / 3` \u5904\u7406\u6743\u9650"
|
|
205201
206520
|
].join("\n");
|
|
205202
206521
|
break;
|
|
205203
206522
|
default:
|
|
205204
|
-
response = `\u672A\u77E5\u547D\u4EE4\uFF1A${
|
|
205205
|
-
\u53D1\u9001 /help \u67E5\u770B\u53EF\u7528\u547D\u4EE4\u3002`;
|
|
206523
|
+
response = `\u672A\u77E5\u547D\u4EE4\uFF1A${rawCommand}
|
|
206524
|
+
\u53D1\u9001 /h \u6216 /help \u67E5\u770B\u53EF\u7528\u547D\u4EE4\u3002`;
|
|
205206
206525
|
}
|
|
205207
206526
|
if (response) {
|
|
205208
206527
|
await deliver(adapter, {
|
|
205209
206528
|
address: msg.address,
|
|
205210
206529
|
text: response,
|
|
205211
|
-
parseMode:
|
|
206530
|
+
parseMode: responseParseMode,
|
|
205212
206531
|
replyToMessageId: msg.messageId
|
|
205213
206532
|
});
|
|
205214
206533
|
}
|
|
@@ -205224,22 +206543,22 @@ function computeSdkSessionUpdate(sdkSessionId, hasError) {
|
|
|
205224
206543
|
}
|
|
205225
206544
|
|
|
205226
206545
|
// src/store.ts
|
|
205227
|
-
import
|
|
206546
|
+
import fs6 from "node:fs";
|
|
205228
206547
|
import path8 from "node:path";
|
|
205229
|
-
import
|
|
206548
|
+
import crypto9 from "node:crypto";
|
|
205230
206549
|
var DATA_DIR2 = path8.join(CTI_HOME, "data");
|
|
205231
206550
|
var MESSAGES_DIR = path8.join(DATA_DIR2, "messages");
|
|
205232
206551
|
function ensureDir2(dir) {
|
|
205233
|
-
|
|
206552
|
+
fs6.mkdirSync(dir, { recursive: true });
|
|
205234
206553
|
}
|
|
205235
206554
|
function atomicWrite2(filePath, data) {
|
|
205236
206555
|
const tmp = filePath + ".tmp";
|
|
205237
|
-
|
|
205238
|
-
|
|
206556
|
+
fs6.writeFileSync(tmp, data, "utf-8");
|
|
206557
|
+
fs6.renameSync(tmp, filePath);
|
|
205239
206558
|
}
|
|
205240
206559
|
function readJson2(filePath, fallback) {
|
|
205241
206560
|
try {
|
|
205242
|
-
const raw =
|
|
206561
|
+
const raw = fs6.readFileSync(filePath, "utf-8");
|
|
205243
206562
|
return JSON.parse(raw);
|
|
205244
206563
|
} catch {
|
|
205245
206564
|
return fallback;
|
|
@@ -205249,13 +206568,14 @@ function writeJson(filePath, data) {
|
|
|
205249
206568
|
atomicWrite2(filePath, JSON.stringify(data, null, 2));
|
|
205250
206569
|
}
|
|
205251
206570
|
function uuid() {
|
|
205252
|
-
return
|
|
206571
|
+
return crypto9.randomUUID();
|
|
205253
206572
|
}
|
|
205254
206573
|
function now() {
|
|
205255
206574
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
205256
206575
|
}
|
|
205257
206576
|
var JsonFileStore = class {
|
|
205258
206577
|
settings;
|
|
206578
|
+
dynamicSettings;
|
|
205259
206579
|
sessions = /* @__PURE__ */ new Map();
|
|
205260
206580
|
bindings = /* @__PURE__ */ new Map();
|
|
205261
206581
|
messages = /* @__PURE__ */ new Map();
|
|
@@ -205264,8 +206584,9 @@ var JsonFileStore = class {
|
|
|
205264
206584
|
dedupKeys = /* @__PURE__ */ new Map();
|
|
205265
206585
|
locks = /* @__PURE__ */ new Map();
|
|
205266
206586
|
auditLog = [];
|
|
205267
|
-
constructor(settingsMap) {
|
|
206587
|
+
constructor(settingsMap, options) {
|
|
205268
206588
|
this.settings = settingsMap;
|
|
206589
|
+
this.dynamicSettings = options?.dynamicSettings === true;
|
|
205269
206590
|
ensureDir2(DATA_DIR2);
|
|
205270
206591
|
ensureDir2(MESSAGES_DIR);
|
|
205271
206592
|
this.loadAll();
|
|
@@ -205360,7 +206681,19 @@ var JsonFileStore = class {
|
|
|
205360
206681
|
return msgs;
|
|
205361
206682
|
}
|
|
205362
206683
|
// ── Settings ──
|
|
206684
|
+
refreshSettings() {
|
|
206685
|
+
if (!this.dynamicSettings) return;
|
|
206686
|
+
try {
|
|
206687
|
+
const next = configToSettings(loadConfig());
|
|
206688
|
+
this.settings = new Map([
|
|
206689
|
+
...this.settings,
|
|
206690
|
+
...next
|
|
206691
|
+
]);
|
|
206692
|
+
} catch {
|
|
206693
|
+
}
|
|
206694
|
+
}
|
|
205363
206695
|
getSetting(key) {
|
|
206696
|
+
this.refreshSettings();
|
|
205364
206697
|
return this.settings.get(key) ?? null;
|
|
205365
206698
|
}
|
|
205366
206699
|
// ── Channel Bindings ──
|
|
@@ -205379,6 +206712,7 @@ var JsonFileStore = class {
|
|
|
205379
206712
|
sdkSessionId: data.sdkSessionId ?? existing.sdkSessionId,
|
|
205380
206713
|
workingDirectory: data.workingDirectory,
|
|
205381
206714
|
model: data.model,
|
|
206715
|
+
mode: data.mode ?? existing.mode,
|
|
205382
206716
|
updatedAt: now()
|
|
205383
206717
|
};
|
|
205384
206718
|
this.bindings.set(key, updated);
|
|
@@ -205393,7 +206727,7 @@ var JsonFileStore = class {
|
|
|
205393
206727
|
sdkSessionId: data.sdkSessionId ?? "",
|
|
205394
206728
|
workingDirectory: data.workingDirectory,
|
|
205395
206729
|
model: data.model,
|
|
205396
|
-
mode: this.
|
|
206730
|
+
mode: data.mode || this.getSetting("bridge_default_mode") || "code",
|
|
205397
206731
|
active: true,
|
|
205398
206732
|
createdAt: now(),
|
|
205399
206733
|
updatedAt: now()
|
|
@@ -205436,14 +206770,23 @@ var JsonFileStore = class {
|
|
|
205436
206770
|
}
|
|
205437
206771
|
return null;
|
|
205438
206772
|
}
|
|
205439
|
-
createSession(name, model, systemPrompt, cwd,
|
|
206773
|
+
createSession(name, model, systemPrompt, cwd, mode, options) {
|
|
205440
206774
|
this.reloadSessions();
|
|
206775
|
+
const timestamp = now();
|
|
205441
206776
|
const session = {
|
|
205442
206777
|
id: uuid(),
|
|
205443
206778
|
name,
|
|
205444
|
-
working_directory: cwd || this.
|
|
206779
|
+
working_directory: cwd || this.getSetting("bridge_default_work_dir") || process.cwd(),
|
|
205445
206780
|
model,
|
|
205446
|
-
|
|
206781
|
+
preferred_mode: mode,
|
|
206782
|
+
system_prompt: systemPrompt,
|
|
206783
|
+
reasoning_effort: options?.reasoningEffort,
|
|
206784
|
+
session_type: options?.sessionType || "normal",
|
|
206785
|
+
hidden: options?.hidden === true,
|
|
206786
|
+
parent_session_id: options?.parentSessionId,
|
|
206787
|
+
expires_at: options?.expiresAt,
|
|
206788
|
+
created_at: timestamp,
|
|
206789
|
+
updated_at: timestamp
|
|
205447
206790
|
};
|
|
205448
206791
|
this.sessions.set(session.id, session);
|
|
205449
206792
|
this.persistSessions();
|
|
@@ -205454,9 +206797,40 @@ var JsonFileStore = class {
|
|
|
205454
206797
|
const s = this.sessions.get(sessionId);
|
|
205455
206798
|
if (s) {
|
|
205456
206799
|
s.provider_id = providerId;
|
|
206800
|
+
s.updated_at = now();
|
|
205457
206801
|
this.persistSessions();
|
|
205458
206802
|
}
|
|
205459
206803
|
}
|
|
206804
|
+
updateSession(sessionId, updates) {
|
|
206805
|
+
this.reloadSessions();
|
|
206806
|
+
const session = this.sessions.get(sessionId);
|
|
206807
|
+
if (!session) return;
|
|
206808
|
+
const next = {
|
|
206809
|
+
...session,
|
|
206810
|
+
...updates,
|
|
206811
|
+
id: session.id,
|
|
206812
|
+
updated_at: now()
|
|
206813
|
+
};
|
|
206814
|
+
this.sessions.set(sessionId, next);
|
|
206815
|
+
this.persistSessions();
|
|
206816
|
+
}
|
|
206817
|
+
deleteSession(sessionId) {
|
|
206818
|
+
this.reloadSessions();
|
|
206819
|
+
this.reloadBindings();
|
|
206820
|
+
this.sessions.delete(sessionId);
|
|
206821
|
+
for (const [key, binding] of this.bindings) {
|
|
206822
|
+
if (binding.codepilotSessionId === sessionId) {
|
|
206823
|
+
this.bindings.delete(key);
|
|
206824
|
+
}
|
|
206825
|
+
}
|
|
206826
|
+
this.messages.delete(sessionId);
|
|
206827
|
+
try {
|
|
206828
|
+
fs6.rmSync(path8.join(MESSAGES_DIR, `${sessionId}.json`), { force: true });
|
|
206829
|
+
} catch {
|
|
206830
|
+
}
|
|
206831
|
+
this.persistSessions();
|
|
206832
|
+
this.persistBindings();
|
|
206833
|
+
}
|
|
205460
206834
|
// ── Messages ──
|
|
205461
206835
|
addMessage(sessionId, role, content, _usage) {
|
|
205462
206836
|
const msgs = this.loadMessages(sessionId);
|
|
@@ -205496,6 +206870,26 @@ var JsonFileStore = class {
|
|
|
205496
206870
|
}
|
|
205497
206871
|
}
|
|
205498
206872
|
setSessionRuntimeStatus(_sessionId, _status) {
|
|
206873
|
+
this.reloadSessions();
|
|
206874
|
+
const session = this.sessions.get(_sessionId);
|
|
206875
|
+
if (!session) return;
|
|
206876
|
+
const queuedCount = session.queued_count && session.queued_count > 0 ? session.queued_count : 0;
|
|
206877
|
+
let runtimeStatus;
|
|
206878
|
+
if (_status === "running") {
|
|
206879
|
+
runtimeStatus = queuedCount > 0 ? "queued" : "running";
|
|
206880
|
+
} else if (_status === "idle") {
|
|
206881
|
+
runtimeStatus = queuedCount > 0 ? "queued" : "idle";
|
|
206882
|
+
} else {
|
|
206883
|
+
runtimeStatus = session.runtime_status;
|
|
206884
|
+
}
|
|
206885
|
+
const next = {
|
|
206886
|
+
...session,
|
|
206887
|
+
runtime_status: runtimeStatus,
|
|
206888
|
+
last_runtime_update_at: now(),
|
|
206889
|
+
updated_at: now()
|
|
206890
|
+
};
|
|
206891
|
+
this.sessions.set(_sessionId, next);
|
|
206892
|
+
this.persistSessions();
|
|
205499
206893
|
}
|
|
205500
206894
|
// ── SDK Session ──
|
|
205501
206895
|
updateSdkSessionId(sessionId, sdkSessionId) {
|
|
@@ -205504,6 +206898,7 @@ var JsonFileStore = class {
|
|
|
205504
206898
|
const s = this.sessions.get(sessionId);
|
|
205505
206899
|
if (s) {
|
|
205506
206900
|
s.sdk_session_id = sdkSessionId;
|
|
206901
|
+
s.updated_at = now();
|
|
205507
206902
|
this.persistSessions();
|
|
205508
206903
|
}
|
|
205509
206904
|
for (const [key, b] of this.bindings) {
|
|
@@ -205518,6 +206913,7 @@ var JsonFileStore = class {
|
|
|
205518
206913
|
const s = this.sessions.get(sessionId);
|
|
205519
206914
|
if (s) {
|
|
205520
206915
|
s.model = model;
|
|
206916
|
+
s.updated_at = now();
|
|
205521
206917
|
this.persistSessions();
|
|
205522
206918
|
}
|
|
205523
206919
|
}
|
|
@@ -205574,6 +206970,7 @@ var JsonFileStore = class {
|
|
|
205574
206970
|
permissionRequestId: link2.permissionRequestId,
|
|
205575
206971
|
chatId: link2.chatId,
|
|
205576
206972
|
messageId: link2.messageId,
|
|
206973
|
+
sessionId: link2.sessionId,
|
|
205577
206974
|
resolved: false,
|
|
205578
206975
|
suggestions: link2.suggestions
|
|
205579
206976
|
};
|
|
@@ -205611,7 +207008,7 @@ var JsonFileStore = class {
|
|
|
205611
207008
|
|
|
205612
207009
|
// src/llm-provider.ts
|
|
205613
207010
|
init_sse_utils();
|
|
205614
|
-
import
|
|
207011
|
+
import fs7 from "node:fs";
|
|
205615
207012
|
import { execSync } from "node:child_process";
|
|
205616
207013
|
import { query } from "@anthropic-ai/claude-agent-sdk";
|
|
205617
207014
|
var ENV_WHITELIST = /* @__PURE__ */ new Set([
|
|
@@ -205765,7 +207162,7 @@ function preflightCheck(cliPath) {
|
|
|
205765
207162
|
}
|
|
205766
207163
|
function isExecutable(p) {
|
|
205767
207164
|
try {
|
|
205768
|
-
|
|
207165
|
+
fs7.accessSync(p, fs7.constants.X_OK);
|
|
205769
207166
|
return true;
|
|
205770
207167
|
} catch {
|
|
205771
207168
|
return false;
|
|
@@ -206121,7 +207518,7 @@ var PendingPermissions = class {
|
|
|
206121
207518
|
};
|
|
206122
207519
|
|
|
206123
207520
|
// src/logger.ts
|
|
206124
|
-
import
|
|
207521
|
+
import fs8 from "node:fs";
|
|
206125
207522
|
import path9 from "node:path";
|
|
206126
207523
|
var MASK_PATTERNS = [
|
|
206127
207524
|
/(?:token|secret|password|api_key)["']?\s*[:=]\s*["']?([^\s"',]+)/gi,
|
|
@@ -206145,11 +207542,11 @@ var MAX_LOG_SIZE = 10 * 1024 * 1024;
|
|
|
206145
207542
|
var MAX_ROTATED = 3;
|
|
206146
207543
|
var logStream = null;
|
|
206147
207544
|
function openLogStream() {
|
|
206148
|
-
return
|
|
207545
|
+
return fs8.createWriteStream(LOG_PATH, { flags: "a" });
|
|
206149
207546
|
}
|
|
206150
207547
|
function rotateIfNeeded() {
|
|
206151
207548
|
try {
|
|
206152
|
-
const stat =
|
|
207549
|
+
const stat = fs8.statSync(LOG_PATH);
|
|
206153
207550
|
if (stat.size < MAX_LOG_SIZE) return;
|
|
206154
207551
|
} catch {
|
|
206155
207552
|
return;
|
|
@@ -206159,17 +207556,17 @@ function rotateIfNeeded() {
|
|
|
206159
207556
|
logStream = null;
|
|
206160
207557
|
}
|
|
206161
207558
|
const path32 = `${LOG_PATH}.${MAX_ROTATED}`;
|
|
206162
|
-
if (
|
|
207559
|
+
if (fs8.existsSync(path32)) fs8.unlinkSync(path32);
|
|
206163
207560
|
for (let i = MAX_ROTATED - 1; i >= 1; i--) {
|
|
206164
207561
|
const src = `${LOG_PATH}.${i}`;
|
|
206165
207562
|
const dst = `${LOG_PATH}.${i + 1}`;
|
|
206166
|
-
if (
|
|
207563
|
+
if (fs8.existsSync(src)) fs8.renameSync(src, dst);
|
|
206167
207564
|
}
|
|
206168
|
-
|
|
207565
|
+
fs8.renameSync(LOG_PATH, `${LOG_PATH}.1`);
|
|
206169
207566
|
logStream = openLogStream();
|
|
206170
207567
|
}
|
|
206171
207568
|
function setupLogger() {
|
|
206172
|
-
|
|
207569
|
+
fs8.mkdirSync(LOG_DIR, { recursive: true });
|
|
206173
207570
|
logStream = openLogStream();
|
|
206174
207571
|
const write = (level, args) => {
|
|
206175
207572
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -206237,24 +207634,27 @@ async function resolveProvider(config2, pendingPerms) {
|
|
|
206237
207634
|
return new SDKLLMProvider(pendingPerms, cliPath, config2.autoApprove);
|
|
206238
207635
|
}
|
|
206239
207636
|
function writeStatus(info) {
|
|
206240
|
-
|
|
207637
|
+
fs10.mkdirSync(RUNTIME_DIR, { recursive: true });
|
|
206241
207638
|
let existing = {};
|
|
206242
207639
|
try {
|
|
206243
|
-
existing = JSON.parse(
|
|
207640
|
+
existing = JSON.parse(fs10.readFileSync(STATUS_FILE, "utf-8"));
|
|
206244
207641
|
} catch {
|
|
206245
207642
|
}
|
|
206246
207643
|
const merged = { ...existing, ...info };
|
|
206247
207644
|
const tmp = STATUS_FILE + ".tmp";
|
|
206248
|
-
|
|
206249
|
-
|
|
207645
|
+
fs10.writeFileSync(tmp, JSON.stringify(merged, null, 2), "utf-8");
|
|
207646
|
+
fs10.renameSync(tmp, STATUS_FILE);
|
|
207647
|
+
}
|
|
207648
|
+
function getRunningChannels() {
|
|
207649
|
+
return getStatus().adapters.map((adapter) => adapter.channelType).sort();
|
|
206250
207650
|
}
|
|
206251
207651
|
async function main() {
|
|
206252
207652
|
const config2 = loadConfig();
|
|
206253
207653
|
setupLogger();
|
|
206254
|
-
const runId =
|
|
207654
|
+
const runId = crypto10.randomUUID();
|
|
206255
207655
|
console.log(`[codex-to-im] Starting bridge (run_id: ${runId})`);
|
|
206256
207656
|
const settings = configToSettings(config2);
|
|
206257
|
-
const store = new JsonFileStore(settings);
|
|
207657
|
+
const store = new JsonFileStore(settings, { dynamicSettings: true });
|
|
206258
207658
|
const pendingPerms = new PendingPermissions();
|
|
206259
207659
|
const llm = await resolveProvider(config2, pendingPerms);
|
|
206260
207660
|
console.log(`[codex-to-im] Runtime: ${config2.runtime}`);
|
|
@@ -206267,19 +207667,29 @@ async function main() {
|
|
|
206267
207667
|
permissions: gateway,
|
|
206268
207668
|
lifecycle: {
|
|
206269
207669
|
onBridgeStart: () => {
|
|
206270
|
-
|
|
206271
|
-
|
|
207670
|
+
fs10.mkdirSync(RUNTIME_DIR, { recursive: true });
|
|
207671
|
+
fs10.writeFileSync(PID_FILE, String(process.pid), "utf-8");
|
|
207672
|
+
const channels = getRunningChannels();
|
|
206272
207673
|
writeStatus({
|
|
206273
207674
|
running: true,
|
|
206274
207675
|
pid: process.pid,
|
|
206275
207676
|
runId,
|
|
206276
207677
|
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
206277
|
-
channels
|
|
207678
|
+
channels
|
|
207679
|
+
});
|
|
207680
|
+
console.log(`[codex-to-im] Bridge started (PID: ${process.pid}, channels: ${channels.join(", ")})`);
|
|
207681
|
+
},
|
|
207682
|
+
onBridgeAdaptersChanged: (channels) => {
|
|
207683
|
+
writeStatus({
|
|
207684
|
+
running: true,
|
|
207685
|
+
pid: process.pid,
|
|
207686
|
+
runId,
|
|
207687
|
+
channels
|
|
206278
207688
|
});
|
|
206279
|
-
console.log(`[codex-to-im]
|
|
207689
|
+
console.log(`[codex-to-im] Active channels updated: ${channels.join(", ") || "none"}`);
|
|
206280
207690
|
},
|
|
206281
207691
|
onBridgeStop: () => {
|
|
206282
|
-
writeStatus({ running: false });
|
|
207692
|
+
writeStatus({ running: false, channels: [] });
|
|
206283
207693
|
console.log("[codex-to-im] Bridge stopped");
|
|
206284
207694
|
}
|
|
206285
207695
|
}
|