@essentialai/cogent-plugin 3.19.2 → 3.20.0
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/.claude-plugin/plugin.json +1 -1
- package/bridge/cogent-bridge.mjs +428 -88
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cogent",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.20.0",
|
|
4
4
|
"description": "Inter-session communication bridge for Claude Code with Slack integration. Enables CC agents and Slack team members to communicate in real time.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Essential AI Solutions",
|
package/bridge/cogent-bridge.mjs
CHANGED
|
@@ -1259,8 +1259,8 @@ var init_parseUtil = __esm({
|
|
|
1259
1259
|
init_errors();
|
|
1260
1260
|
init_en();
|
|
1261
1261
|
makeIssue = (params) => {
|
|
1262
|
-
const { data, path:
|
|
1263
|
-
const fullPath = [...
|
|
1262
|
+
const { data, path: path18, errorMaps, issueData } = params;
|
|
1263
|
+
const fullPath = [...path18, ...issueData.path || []];
|
|
1264
1264
|
const fullIssue = {
|
|
1265
1265
|
...issueData,
|
|
1266
1266
|
path: fullPath
|
|
@@ -1540,11 +1540,11 @@ var init_types = __esm({
|
|
|
1540
1540
|
init_parseUtil();
|
|
1541
1541
|
init_util();
|
|
1542
1542
|
ParseInputLazyPath = class {
|
|
1543
|
-
constructor(parent, value,
|
|
1543
|
+
constructor(parent, value, path18, key) {
|
|
1544
1544
|
this._cachedPath = [];
|
|
1545
1545
|
this.parent = parent;
|
|
1546
1546
|
this.data = value;
|
|
1547
|
-
this._path =
|
|
1547
|
+
this._path = path18;
|
|
1548
1548
|
this._key = key;
|
|
1549
1549
|
}
|
|
1550
1550
|
get path() {
|
|
@@ -4996,10 +4996,10 @@ function assignProp(target, prop, value) {
|
|
|
4996
4996
|
configurable: true
|
|
4997
4997
|
});
|
|
4998
4998
|
}
|
|
4999
|
-
function getElementAtPath(obj,
|
|
5000
|
-
if (!
|
|
4999
|
+
function getElementAtPath(obj, path18) {
|
|
5000
|
+
if (!path18)
|
|
5001
5001
|
return obj;
|
|
5002
|
-
return
|
|
5002
|
+
return path18.reduce((acc, key) => acc?.[key], obj);
|
|
5003
5003
|
}
|
|
5004
5004
|
function promiseAllObject(promisesObj) {
|
|
5005
5005
|
const keys = Object.keys(promisesObj);
|
|
@@ -5248,11 +5248,11 @@ function aborted(x, startIndex = 0) {
|
|
|
5248
5248
|
}
|
|
5249
5249
|
return false;
|
|
5250
5250
|
}
|
|
5251
|
-
function prefixIssues(
|
|
5251
|
+
function prefixIssues(path18, issues) {
|
|
5252
5252
|
return issues.map((iss) => {
|
|
5253
5253
|
var _a;
|
|
5254
5254
|
(_a = iss).path ?? (_a.path = []);
|
|
5255
|
-
iss.path.unshift(
|
|
5255
|
+
iss.path.unshift(path18);
|
|
5256
5256
|
return iss;
|
|
5257
5257
|
});
|
|
5258
5258
|
}
|
|
@@ -17058,8 +17058,8 @@ var require_utils = __commonJS({
|
|
|
17058
17058
|
}
|
|
17059
17059
|
return ind;
|
|
17060
17060
|
}
|
|
17061
|
-
function removeDotSegments(
|
|
17062
|
-
let input =
|
|
17061
|
+
function removeDotSegments(path18) {
|
|
17062
|
+
let input = path18;
|
|
17063
17063
|
const output = [];
|
|
17064
17064
|
let nextSlash = -1;
|
|
17065
17065
|
let len = 0;
|
|
@@ -17258,8 +17258,8 @@ var require_schemes = __commonJS({
|
|
|
17258
17258
|
wsComponent.secure = void 0;
|
|
17259
17259
|
}
|
|
17260
17260
|
if (wsComponent.resourceName) {
|
|
17261
|
-
const [
|
|
17262
|
-
wsComponent.path =
|
|
17261
|
+
const [path18, query] = wsComponent.resourceName.split("?");
|
|
17262
|
+
wsComponent.path = path18 && path18 !== "/" ? path18 : void 0;
|
|
17263
17263
|
wsComponent.query = query;
|
|
17264
17264
|
wsComponent.resourceName = void 0;
|
|
17265
17265
|
}
|
|
@@ -20612,12 +20612,12 @@ var require_dist = __commonJS({
|
|
|
20612
20612
|
throw new Error(`Unknown format "${name}"`);
|
|
20613
20613
|
return f;
|
|
20614
20614
|
};
|
|
20615
|
-
function addFormats(ajv, list,
|
|
20615
|
+
function addFormats(ajv, list, fs16, exportName) {
|
|
20616
20616
|
var _a;
|
|
20617
20617
|
var _b;
|
|
20618
20618
|
(_a = (_b = ajv.opts.code).formats) !== null && _a !== void 0 ? _a : _b.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
|
|
20619
20619
|
for (const f of list)
|
|
20620
|
-
ajv.addFormat(f,
|
|
20620
|
+
ajv.addFormat(f, fs16[f]);
|
|
20621
20621
|
}
|
|
20622
20622
|
module.exports = exports = formatsPlugin;
|
|
20623
20623
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -21729,8 +21729,8 @@ var require_parseUtil = __commonJS({
|
|
|
21729
21729
|
var errors_js_1 = require_errors2();
|
|
21730
21730
|
var en_js_1 = __importDefault(require_en());
|
|
21731
21731
|
var makeIssue2 = (params) => {
|
|
21732
|
-
const { data, path:
|
|
21733
|
-
const fullPath = [...
|
|
21732
|
+
const { data, path: path18, errorMaps, issueData } = params;
|
|
21733
|
+
const fullPath = [...path18, ...issueData.path || []];
|
|
21734
21734
|
const fullIssue = {
|
|
21735
21735
|
...issueData,
|
|
21736
21736
|
path: fullPath
|
|
@@ -21884,11 +21884,11 @@ var require_types2 = __commonJS({
|
|
|
21884
21884
|
var parseUtil_js_1 = require_parseUtil();
|
|
21885
21885
|
var util_js_1 = require_util2();
|
|
21886
21886
|
var ParseInputLazyPath2 = class {
|
|
21887
|
-
constructor(parent, value,
|
|
21887
|
+
constructor(parent, value, path18, key) {
|
|
21888
21888
|
this._cachedPath = [];
|
|
21889
21889
|
this.parent = parent;
|
|
21890
21890
|
this.data = value;
|
|
21891
|
-
this._path =
|
|
21891
|
+
this._path = path18;
|
|
21892
21892
|
this._key = key;
|
|
21893
21893
|
}
|
|
21894
21894
|
get path() {
|
|
@@ -26389,8 +26389,8 @@ var init_stdio2 = __esm({
|
|
|
26389
26389
|
// src/constants.ts
|
|
26390
26390
|
import { createRequire } from "node:module";
|
|
26391
26391
|
function resolveVersion() {
|
|
26392
|
-
if ("3.
|
|
26393
|
-
return "3.
|
|
26392
|
+
if ("3.20.0") {
|
|
26393
|
+
return "3.20.0";
|
|
26394
26394
|
}
|
|
26395
26395
|
try {
|
|
26396
26396
|
const require2 = createRequire(import.meta.url);
|
|
@@ -26610,6 +26610,18 @@ var init_config = __esm({
|
|
|
26610
26610
|
COGENT_PLATFORM: import_zod2.z.enum(["cc", "codex", "slack", "gchat", "web"]).default("cc"),
|
|
26611
26611
|
COGENT_CODEX_PATH: import_zod2.z.string().default("codex"),
|
|
26612
26612
|
COGENT_CODEX_SANDBOX: import_zod2.z.enum(["full-auto", "read-only", "workspace-write", "danger-full-access", "bypass"]).default("full-auto"),
|
|
26613
|
+
// Codex real-time-wake rail selector. codex >=0.145 has a SINGLE-WRITER
|
|
26614
|
+
// thread-store: a codex agent running in an interactive TUI holds an exclusive
|
|
26615
|
+
// writer on its own thread, so the current rail (`exec-resume` =
|
|
26616
|
+
// `codex exec resume <same id>`) fast-fails `-32600 already has an active
|
|
26617
|
+
// writer` and the peer never gets a real-time reply. The `app-server` rail
|
|
26618
|
+
// injects the peer's message as a turn THROUGH codex's app-server daemon (the
|
|
26619
|
+
// daemon is the single writer; the human's `codex --remote` TUI and the bridge
|
|
26620
|
+
// are both just clients → no conflict). DEFAULT stays `exec-resume` so this is
|
|
26621
|
+
// purely additive/opt-in: nothing changes for any agent until a codex user
|
|
26622
|
+
// launches via the daemon (see bin/cogent-codex) and sets this to `app-server`.
|
|
26623
|
+
// Only affects COGENT_PLATFORM=codex; claude/gemini/mail rails never read it.
|
|
26624
|
+
COGENT_CODEX_WAKE: import_zod2.z.enum(["exec-resume", "app-server"]).default("exec-resume"),
|
|
26613
26625
|
// Auto-recovery for a blocked Codex sandbox. On a host where the OS sandbox
|
|
26614
26626
|
// can't initialize (unprivileged user namespaces blocked — Ubuntu 24.04's
|
|
26615
26627
|
// apparmor_restrict_unprivileged_userns, containers, hardened kernels),
|
|
@@ -27589,7 +27601,7 @@ var init_http_backend = __esm({
|
|
|
27589
27601
|
* in cloud mode we ignore it and use this.sessionId (the cloud session).
|
|
27590
27602
|
*/
|
|
27591
27603
|
async registerPeer(peerId, _sessionId, cwd, label, clientVersion, mode, _channelSessionId, capabilities, workspaceId, threadId) {
|
|
27592
|
-
const
|
|
27604
|
+
const path18 = PATHS.peers.replace(":sessionId", this.sessionId);
|
|
27593
27605
|
const body = {
|
|
27594
27606
|
peerId,
|
|
27595
27607
|
cwd,
|
|
@@ -27617,7 +27629,7 @@ var init_http_backend = __esm({
|
|
|
27617
27629
|
body.role = roleCap.slice("role:".length);
|
|
27618
27630
|
}
|
|
27619
27631
|
}
|
|
27620
|
-
return this.http.post(
|
|
27632
|
+
return this.http.post(path18, body);
|
|
27621
27633
|
}
|
|
27622
27634
|
/**
|
|
27623
27635
|
* Deregister a peer from the cloud session.
|
|
@@ -27629,9 +27641,9 @@ var init_http_backend = __esm({
|
|
|
27629
27641
|
* local mail creds. A 404 (peer not found) resolves to `{ removed: false, ... }`, not a throw.
|
|
27630
27642
|
*/
|
|
27631
27643
|
async deregisterPeer(peerId) {
|
|
27632
|
-
const
|
|
27644
|
+
const path18 = PATHS.peer.replace(":sessionId", this.sessionId).replace(":peerId", peerId);
|
|
27633
27645
|
try {
|
|
27634
|
-
const headers = await this.http.delete(
|
|
27646
|
+
const headers = await this.http.delete(path18, {});
|
|
27635
27647
|
const mailboxDeprovisioned = headers.get(MAILBOX_DEPROVISIONED_HEADER) === "true";
|
|
27636
27648
|
return { removed: true, mailboxDeprovisioned };
|
|
27637
27649
|
} catch {
|
|
@@ -27652,8 +27664,8 @@ var init_http_backend = __esm({
|
|
|
27652
27664
|
* GET /api/sessions/:sessionId/peers
|
|
27653
27665
|
*/
|
|
27654
27666
|
async listPeers() {
|
|
27655
|
-
const
|
|
27656
|
-
const result = await this.http.get(
|
|
27667
|
+
const path18 = PATHS.peers.replace(":sessionId", this.sessionId);
|
|
27668
|
+
const result = await this.http.get(path18);
|
|
27657
27669
|
return result.peers;
|
|
27658
27670
|
}
|
|
27659
27671
|
/**
|
|
@@ -27661,8 +27673,8 @@ var init_http_backend = __esm({
|
|
|
27661
27673
|
* Calls the lightweight heartbeat endpoint on the cloud relay server.
|
|
27662
27674
|
*/
|
|
27663
27675
|
async updateLastSeen(peerId) {
|
|
27664
|
-
const
|
|
27665
|
-
await this.http.post(
|
|
27676
|
+
const path18 = PATHS.heartbeat.replace(":sessionId", this.sessionId);
|
|
27677
|
+
await this.http.post(path18, { peerId });
|
|
27666
27678
|
}
|
|
27667
27679
|
/**
|
|
27668
27680
|
* Record a message in the cloud session.
|
|
@@ -27673,7 +27685,7 @@ var init_http_backend = __esm({
|
|
|
27673
27685
|
* the input record to construct a full MessageRecord.
|
|
27674
27686
|
*/
|
|
27675
27687
|
async recordMessage(record2) {
|
|
27676
|
-
const
|
|
27688
|
+
const path18 = PATHS.messages.replace(":sessionId", this.sessionId);
|
|
27677
27689
|
const body = {
|
|
27678
27690
|
fromPeerId: record2.fromPeerId,
|
|
27679
27691
|
toPeerId: record2.toPeerId,
|
|
@@ -27685,7 +27697,7 @@ var init_http_backend = __esm({
|
|
|
27685
27697
|
if (record2.attachments && record2.attachments.length > 0) {
|
|
27686
27698
|
body.attachments = record2.attachments;
|
|
27687
27699
|
}
|
|
27688
|
-
const resp = await this.http.post(
|
|
27700
|
+
const resp = await this.http.post(path18, body);
|
|
27689
27701
|
return {
|
|
27690
27702
|
...record2,
|
|
27691
27703
|
id: resp.id,
|
|
@@ -27699,7 +27711,7 @@ var init_http_backend = __esm({
|
|
|
27699
27711
|
* Supports optional peerId filter and limit (default 300).
|
|
27700
27712
|
*/
|
|
27701
27713
|
async getHistory(peerId, limit, includeRelayEchoes, metadataOnly, dedupInferredEchoes) {
|
|
27702
|
-
const
|
|
27714
|
+
const path18 = PATHS.messages.replace(":sessionId", this.sessionId);
|
|
27703
27715
|
const query = {};
|
|
27704
27716
|
if (peerId) {
|
|
27705
27717
|
query.peerId = peerId;
|
|
@@ -27714,7 +27726,7 @@ var init_http_backend = __esm({
|
|
|
27714
27726
|
if (dedupInferredEchoes) {
|
|
27715
27727
|
query.dedupInferredEchoes = "true";
|
|
27716
27728
|
}
|
|
27717
|
-
const result = await this.http.get(
|
|
27729
|
+
const result = await this.http.get(path18, query);
|
|
27718
27730
|
return result.messages;
|
|
27719
27731
|
}
|
|
27720
27732
|
/**
|
|
@@ -27725,12 +27737,12 @@ var init_http_backend = __esm({
|
|
|
27725
27737
|
* so that get-history shows the actual response (not null).
|
|
27726
27738
|
*/
|
|
27727
27739
|
async updateMessageResponse(messageId, response, durationMs, pending) {
|
|
27728
|
-
const
|
|
27740
|
+
const path18 = PATHS.message.replace(":sessionId", this.sessionId).replace(":messageId", messageId);
|
|
27729
27741
|
const body = { response, durationMs };
|
|
27730
27742
|
if (pending === true) {
|
|
27731
27743
|
body.pending = true;
|
|
27732
27744
|
}
|
|
27733
|
-
await this.http.patch(
|
|
27745
|
+
await this.http.patch(path18, body);
|
|
27734
27746
|
}
|
|
27735
27747
|
/**
|
|
27736
27748
|
* Validate a session.
|
|
@@ -27872,8 +27884,8 @@ var init_http_client = __esm({
|
|
|
27872
27884
|
* Perform an authenticated GET request.
|
|
27873
27885
|
* Appends query parameters to the URL if provided.
|
|
27874
27886
|
*/
|
|
27875
|
-
async get(
|
|
27876
|
-
const url = new URL(
|
|
27887
|
+
async get(path18, query) {
|
|
27888
|
+
const url = new URL(path18, this.baseUrl);
|
|
27877
27889
|
if (query) {
|
|
27878
27890
|
for (const [k, v] of Object.entries(query)) {
|
|
27879
27891
|
url.searchParams.set(k, v);
|
|
@@ -27888,8 +27900,8 @@ var init_http_client = __esm({
|
|
|
27888
27900
|
/**
|
|
27889
27901
|
* Perform an authenticated POST request with a JSON body.
|
|
27890
27902
|
*/
|
|
27891
|
-
async post(
|
|
27892
|
-
const url = new URL(
|
|
27903
|
+
async post(path18, body) {
|
|
27904
|
+
const url = new URL(path18, this.baseUrl);
|
|
27893
27905
|
const resp = await this.fetchWithTimeout(url, {
|
|
27894
27906
|
method: "POST",
|
|
27895
27907
|
headers: this.headers(),
|
|
@@ -27907,8 +27919,8 @@ var init_http_client = __esm({
|
|
|
27907
27919
|
* Perform an authenticated PATCH request with a JSON body.
|
|
27908
27920
|
* Used to update existing resources (e.g., message response fields).
|
|
27909
27921
|
*/
|
|
27910
|
-
async patch(
|
|
27911
|
-
const url = new URL(
|
|
27922
|
+
async patch(path18, body) {
|
|
27923
|
+
const url = new URL(path18, this.baseUrl);
|
|
27912
27924
|
const resp = await this.fetchWithTimeout(url, {
|
|
27913
27925
|
method: "PATCH",
|
|
27914
27926
|
headers: this.headers(),
|
|
@@ -27933,8 +27945,8 @@ var init_http_client = __esm({
|
|
|
27933
27945
|
* "Malformed JSON in request body" 400 from cogent-server <=3.1.2 when
|
|
27934
27946
|
* any client (including third-party tools) DELETEd a peer without a body.
|
|
27935
27947
|
*/
|
|
27936
|
-
async delete(
|
|
27937
|
-
const url = new URL(
|
|
27948
|
+
async delete(path18, body) {
|
|
27949
|
+
const url = new URL(path18, this.baseUrl);
|
|
27938
27950
|
const headers = {
|
|
27939
27951
|
"Authorization": `Bearer ${this.token}`
|
|
27940
27952
|
};
|
|
@@ -32117,14 +32129,14 @@ var init_ws_client = __esm({
|
|
|
32117
32129
|
if (this.pollTimer) return;
|
|
32118
32130
|
const poll = async () => {
|
|
32119
32131
|
try {
|
|
32120
|
-
const
|
|
32132
|
+
const path18 = `/api/sessions/${this.opts.sessionId}/poll`;
|
|
32121
32133
|
const query = {
|
|
32122
32134
|
peerId: this.opts.peerId
|
|
32123
32135
|
};
|
|
32124
32136
|
if (this.lastMessageId) {
|
|
32125
32137
|
query.lastMessageId = this.lastMessageId;
|
|
32126
32138
|
}
|
|
32127
|
-
const result = await this.opts.http.get(
|
|
32139
|
+
const result = await this.opts.http.get(path18, query);
|
|
32128
32140
|
if (result.messages && result.messages.length > 0) {
|
|
32129
32141
|
this.opts.onMessages(result.messages);
|
|
32130
32142
|
this.lastMessageId = result.messages[result.messages.length - 1].id;
|
|
@@ -32278,11 +32290,13 @@ function execCodex(sessionId, message, cwd, timeoutMs) {
|
|
|
32278
32290
|
if (code !== 0) {
|
|
32279
32291
|
await cleanupFile();
|
|
32280
32292
|
const sandboxBlocked = SANDBOX_FAILURE_RE.test(stderr);
|
|
32293
|
+
const codexLiveSession = ACTIVE_WRITER_RE.test(stderr);
|
|
32281
32294
|
safeResolve({
|
|
32282
32295
|
stdout: "",
|
|
32283
32296
|
stderr: `CLI_EXEC_FAILED: codex exited with code ${code}. stderr: ${stderr}`,
|
|
32284
32297
|
exitCode: code,
|
|
32285
|
-
...sandboxBlocked ? { sandboxBlocked: true } : {}
|
|
32298
|
+
...sandboxBlocked ? { sandboxBlocked: true } : {},
|
|
32299
|
+
...codexLiveSession ? { codexLiveSession: true } : {}
|
|
32286
32300
|
});
|
|
32287
32301
|
return;
|
|
32288
32302
|
}
|
|
@@ -32412,7 +32426,7 @@ async function validateCodexSession(sessionId) {
|
|
|
32412
32426
|
return false;
|
|
32413
32427
|
}
|
|
32414
32428
|
}
|
|
32415
|
-
var sandboxOverride, SANDBOX_FAILURE_RE;
|
|
32429
|
+
var sandboxOverride, SANDBOX_FAILURE_RE, ACTIVE_WRITER_RE;
|
|
32416
32430
|
var init_codex_cli = __esm({
|
|
32417
32431
|
"src/services/codex-cli.ts"() {
|
|
32418
32432
|
"use strict";
|
|
@@ -32420,14 +32434,329 @@ var init_codex_cli = __esm({
|
|
|
32420
32434
|
init_agent_config();
|
|
32421
32435
|
sandboxOverride = null;
|
|
32422
32436
|
SANDBOX_FAILURE_RE = /bwrap:|setting up uid ?map|\/proc\/self\/(uid|gid)_map|newuidmap|user namespaces?|RTM_NEWADDR|unshare[^\n]*(Operation not permitted|Permission denied)|clone3?[^\n]*(EPERM|not permitted)/i;
|
|
32437
|
+
ACTIVE_WRITER_RE = /already has an active writer|thread-store conflict|-32600/i;
|
|
32438
|
+
}
|
|
32439
|
+
});
|
|
32440
|
+
|
|
32441
|
+
// src/services/codex-app-server.ts
|
|
32442
|
+
import path12 from "node:path";
|
|
32443
|
+
import fs11 from "node:fs/promises";
|
|
32444
|
+
import { spawn as spawn3 } from "node:child_process";
|
|
32445
|
+
function appServerSocketPath(codexHome = codexHomeDir()) {
|
|
32446
|
+
return path12.join(codexHome, "app-server-control", "app-server-control.sock");
|
|
32447
|
+
}
|
|
32448
|
+
function rpcUrl(sock) {
|
|
32449
|
+
return `ws+unix://${sock}:/rpc`;
|
|
32450
|
+
}
|
|
32451
|
+
async function ensureDaemon(codexHome = codexHomeDir(), deps = {}) {
|
|
32452
|
+
if (ensuredSock) return ensuredSock;
|
|
32453
|
+
const run = deps.run ?? defaultRun;
|
|
32454
|
+
const socketExists = deps.socketExists ?? defaultSocketExists;
|
|
32455
|
+
const waitMs = deps.waitMs ?? 8e3;
|
|
32456
|
+
const pollMs = deps.pollMs ?? 150;
|
|
32457
|
+
const codexPath = getConfig().COGENT_CODEX_PATH;
|
|
32458
|
+
const env = { ...process.env, CODEX_HOME: codexHome };
|
|
32459
|
+
const res = await run(codexPath, ["app-server", "daemon", "start"], env);
|
|
32460
|
+
if (/managed standalone Codex install not found/i.test(`${res.stdout}
|
|
32461
|
+
${res.stderr}`)) {
|
|
32462
|
+
throw new Error(
|
|
32463
|
+
"MANAGED_CODEX_REQUIRED: the codex app-server daemon needs the managed-standalone codex install, which the npm/Homebrew @openai/codex package does not provide. Install it with: curl -fsSL https://chatgpt.com/codex/install.sh | sh then relaunch via cogent-codex. (Until then, codex answers at its next turn, not in real time.)"
|
|
32464
|
+
);
|
|
32465
|
+
}
|
|
32466
|
+
let sock = appServerSocketPath(codexHome);
|
|
32467
|
+
try {
|
|
32468
|
+
const parsed = JSON.parse(res.stdout.trim());
|
|
32469
|
+
if (parsed && typeof parsed.socketPath === "string") sock = parsed.socketPath;
|
|
32470
|
+
} catch {
|
|
32471
|
+
}
|
|
32472
|
+
const deadline = Date.now() + waitMs;
|
|
32473
|
+
while (!await socketExists(sock)) {
|
|
32474
|
+
if (Date.now() >= deadline) {
|
|
32475
|
+
throw new Error(
|
|
32476
|
+
`app-server daemon socket did not appear at ${sock} within ${waitMs}ms (stderr: ${res.stderr.trim() || "none"})`
|
|
32477
|
+
);
|
|
32478
|
+
}
|
|
32479
|
+
await sleep2(pollMs);
|
|
32480
|
+
}
|
|
32481
|
+
ensuredSock = sock;
|
|
32482
|
+
return sock;
|
|
32483
|
+
}
|
|
32484
|
+
function isAgentMessage(item) {
|
|
32485
|
+
return typeof item?.type === "string" && /^agent[_-]?message$/i.test(item.type);
|
|
32486
|
+
}
|
|
32487
|
+
function itemText(item) {
|
|
32488
|
+
if (typeof item?.text === "string") return item.text;
|
|
32489
|
+
if (Array.isArray(item?.content)) {
|
|
32490
|
+
return item.content.filter((c2) => typeof c2?.text === "string").map((c2) => c2.text).join("");
|
|
32491
|
+
}
|
|
32492
|
+
return "";
|
|
32493
|
+
}
|
|
32494
|
+
function extractAgentMessageText(notes) {
|
|
32495
|
+
const fromCompleted = [];
|
|
32496
|
+
const fromStream = [];
|
|
32497
|
+
for (const n of notes) {
|
|
32498
|
+
if (n.method === "turn/completed") {
|
|
32499
|
+
const items = n.params?.items ?? n.params?.turn?.items ?? [];
|
|
32500
|
+
for (const it of items) if (isAgentMessage(it)) fromCompleted.push(itemText(it));
|
|
32501
|
+
} else if (n.method === "item/completed") {
|
|
32502
|
+
const it = n.params?.item;
|
|
32503
|
+
if (isAgentMessage(it)) fromStream.push(itemText(it));
|
|
32504
|
+
}
|
|
32505
|
+
}
|
|
32506
|
+
const chosen = fromCompleted.length > 0 ? fromCompleted : fromStream;
|
|
32507
|
+
return chosen.join("").trim();
|
|
32508
|
+
}
|
|
32509
|
+
function sandboxPolicyFor(mode, cwd) {
|
|
32510
|
+
switch (mode) {
|
|
32511
|
+
case "read-only":
|
|
32512
|
+
return { type: "readOnly", networkAccess: false };
|
|
32513
|
+
case "danger-full-access":
|
|
32514
|
+
case "bypass":
|
|
32515
|
+
return { type: "dangerFullAccess" };
|
|
32516
|
+
case "workspace-write":
|
|
32517
|
+
case "full-auto":
|
|
32518
|
+
default:
|
|
32519
|
+
return {
|
|
32520
|
+
type: "workspaceWrite",
|
|
32521
|
+
writableRoots: [cwd],
|
|
32522
|
+
networkAccess: false,
|
|
32523
|
+
excludeTmpdirEnvVar: false,
|
|
32524
|
+
excludeSlashTmp: false
|
|
32525
|
+
};
|
|
32526
|
+
}
|
|
32527
|
+
}
|
|
32528
|
+
function execCodexViaAppServer(threadId, message, cwd, timeoutMs, deps = {}) {
|
|
32529
|
+
const key = deps.idempotencyKey ? `${threadId}::${deps.idempotencyKey}` : null;
|
|
32530
|
+
if (!key) return _injectTurn(threadId, message, cwd, timeoutMs, deps);
|
|
32531
|
+
const existing = idempotencyCache.get(key);
|
|
32532
|
+
if (existing) {
|
|
32533
|
+
return existing.done ? Promise.resolve(existing.done.result) : existing.promise;
|
|
32534
|
+
}
|
|
32535
|
+
const promise = _injectTurn(threadId, message, cwd, timeoutMs, deps);
|
|
32536
|
+
const entry = { promise };
|
|
32537
|
+
idempotencyCache.set(key, entry);
|
|
32538
|
+
void promise.then((result) => {
|
|
32539
|
+
entry.done = { result, at: Date.now() };
|
|
32540
|
+
const t = setTimeout(() => idempotencyCache.delete(key), IDEMPOTENCY_TTL_MS);
|
|
32541
|
+
if (typeof t.unref === "function") t.unref();
|
|
32542
|
+
});
|
|
32543
|
+
return promise;
|
|
32544
|
+
}
|
|
32545
|
+
async function _injectTurn(threadId, message, cwd, timeoutMs, deps = {}) {
|
|
32546
|
+
const config2 = getConfig();
|
|
32547
|
+
const effectiveTimeout = timeoutMs ?? config2.COGENT_TIMEOUT_MS;
|
|
32548
|
+
const truncated = config2.COGENT_CHAR_LIMIT > 0 && message.length > config2.COGENT_CHAR_LIMIT ? message.slice(0, config2.COGENT_CHAR_LIMIT) + "\n...[truncated]" : message;
|
|
32549
|
+
const sock = deps.socketPath ?? appServerSocketPath();
|
|
32550
|
+
const wsFactory = deps.wsFactory ?? defaultWsFactory;
|
|
32551
|
+
let client;
|
|
32552
|
+
try {
|
|
32553
|
+
const ws = wsFactory(rpcUrl(sock), { perMessageDeflate: false, headers: { Host: "localhost" } });
|
|
32554
|
+
client = new AppServerClient(ws);
|
|
32555
|
+
await client.waitOpen();
|
|
32556
|
+
await client.request("initialize", {
|
|
32557
|
+
clientInfo: { name: "cogent-bridge", version: "1" },
|
|
32558
|
+
capabilities: { experimentalApi: true }
|
|
32559
|
+
});
|
|
32560
|
+
} catch (err) {
|
|
32561
|
+
return {
|
|
32562
|
+
stdout: "",
|
|
32563
|
+
stderr: `APP_SERVER_UNAVAILABLE: ${err.message}`,
|
|
32564
|
+
exitCode: 1,
|
|
32565
|
+
appServerUnavailable: true
|
|
32566
|
+
};
|
|
32567
|
+
}
|
|
32568
|
+
try {
|
|
32569
|
+
await client.request("thread/resume", { threadId, cwd });
|
|
32570
|
+
const buffered = [];
|
|
32571
|
+
let myTurnId;
|
|
32572
|
+
const isMine = (msg) => msg.method === "turn/completed" && (myTurnId !== void 0 ? msg.params?.turn?.id === myTurnId : msg.params?.threadId === threadId);
|
|
32573
|
+
let deliver = null;
|
|
32574
|
+
const off = client.onNotification((msg) => {
|
|
32575
|
+
if (msg.method !== "turn/completed") return;
|
|
32576
|
+
if (myTurnId === void 0) {
|
|
32577
|
+
buffered.push(msg);
|
|
32578
|
+
return;
|
|
32579
|
+
}
|
|
32580
|
+
if (isMine(msg) && deliver) {
|
|
32581
|
+
const d = deliver;
|
|
32582
|
+
deliver = null;
|
|
32583
|
+
d(msg);
|
|
32584
|
+
}
|
|
32585
|
+
});
|
|
32586
|
+
const startResult = await client.request("turn/start", {
|
|
32587
|
+
threadId,
|
|
32588
|
+
input: [{ type: "text", text: truncated }],
|
|
32589
|
+
// Bound the injected peer turn by the CONFIGURED sandbox (not the human
|
|
32590
|
+
// session's privilege). See sandboxPolicyFor.
|
|
32591
|
+
sandboxPolicy: sandboxPolicyFor(config2.COGENT_CODEX_SANDBOX, cwd),
|
|
32592
|
+
// Native correlation id (daemon does NOT auto-dedupe on it — our own
|
|
32593
|
+
// idempotency guard does; this is for daemon-side correlation/telemetry).
|
|
32594
|
+
...deps.idempotencyKey ? { clientUserMessageId: deps.idempotencyKey } : {}
|
|
32595
|
+
});
|
|
32596
|
+
myTurnId = startResult?.turn?.id;
|
|
32597
|
+
const turnCompleted = await new Promise((resolve) => {
|
|
32598
|
+
deliver = resolve;
|
|
32599
|
+
const early = buffered.find(isMine);
|
|
32600
|
+
if (early) {
|
|
32601
|
+
deliver = null;
|
|
32602
|
+
resolve(early);
|
|
32603
|
+
return;
|
|
32604
|
+
}
|
|
32605
|
+
setTimeout(() => {
|
|
32606
|
+
if (deliver) {
|
|
32607
|
+
deliver = null;
|
|
32608
|
+
resolve(null);
|
|
32609
|
+
}
|
|
32610
|
+
}, effectiveTimeout);
|
|
32611
|
+
});
|
|
32612
|
+
off();
|
|
32613
|
+
if (!turnCompleted) {
|
|
32614
|
+
return {
|
|
32615
|
+
stdout: "",
|
|
32616
|
+
stderr: `CLI_TIMEOUT: app-server turn did not complete within ${effectiveTimeout}ms`,
|
|
32617
|
+
exitCode: null
|
|
32618
|
+
};
|
|
32619
|
+
}
|
|
32620
|
+
const text = extractAgentMessageText([turnCompleted]);
|
|
32621
|
+
return {
|
|
32622
|
+
stdout: text,
|
|
32623
|
+
stderr: "",
|
|
32624
|
+
exitCode: 0,
|
|
32625
|
+
captureContract: "event_stream",
|
|
32626
|
+
stable: true
|
|
32627
|
+
};
|
|
32628
|
+
} catch (err) {
|
|
32629
|
+
return {
|
|
32630
|
+
stdout: "",
|
|
32631
|
+
stderr: `CLI_EXEC_FAILED: app-server turn failed: ${err.message}`,
|
|
32632
|
+
exitCode: 1
|
|
32633
|
+
};
|
|
32634
|
+
} finally {
|
|
32635
|
+
client.close();
|
|
32636
|
+
}
|
|
32637
|
+
}
|
|
32638
|
+
var defaultWsFactory, ensuredSock, defaultRun, defaultSocketExists, sleep2, AppServerClient, idempotencyCache, IDEMPOTENCY_TTL_MS;
|
|
32639
|
+
var init_codex_app_server = __esm({
|
|
32640
|
+
"src/services/codex-app-server.ts"() {
|
|
32641
|
+
"use strict";
|
|
32642
|
+
init_wrapper();
|
|
32643
|
+
init_config();
|
|
32644
|
+
init_agent_config();
|
|
32645
|
+
defaultWsFactory = (url, opts) => new wrapper_default(url, opts);
|
|
32646
|
+
ensuredSock = null;
|
|
32647
|
+
defaultRun = (cmd, args, env) => new Promise((resolve) => {
|
|
32648
|
+
const child = spawn3(cmd, args, { env, stdio: ["ignore", "pipe", "pipe"] });
|
|
32649
|
+
let stdout = "";
|
|
32650
|
+
let stderr = "";
|
|
32651
|
+
child.stdout.on("data", (c2) => stdout += c2.toString());
|
|
32652
|
+
child.stderr.on("data", (c2) => stderr += c2.toString());
|
|
32653
|
+
child.on("error", (err) => resolve({ stdout, stderr: stderr + String(err), code: 127 }));
|
|
32654
|
+
child.on("close", (code) => resolve({ stdout, stderr, code }));
|
|
32655
|
+
});
|
|
32656
|
+
defaultSocketExists = async (p) => {
|
|
32657
|
+
try {
|
|
32658
|
+
await fs11.stat(p);
|
|
32659
|
+
return true;
|
|
32660
|
+
} catch {
|
|
32661
|
+
return false;
|
|
32662
|
+
}
|
|
32663
|
+
};
|
|
32664
|
+
sleep2 = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
32665
|
+
AppServerClient = class {
|
|
32666
|
+
ws;
|
|
32667
|
+
nextId = 1;
|
|
32668
|
+
pending = /* @__PURE__ */ new Map();
|
|
32669
|
+
notifyListeners = /* @__PURE__ */ new Set();
|
|
32670
|
+
opened;
|
|
32671
|
+
openResolved = false;
|
|
32672
|
+
constructor(ws) {
|
|
32673
|
+
this.ws = ws;
|
|
32674
|
+
this.opened = new Promise((resolve, reject) => {
|
|
32675
|
+
ws.on("open", () => {
|
|
32676
|
+
this.openResolved = true;
|
|
32677
|
+
resolve();
|
|
32678
|
+
});
|
|
32679
|
+
ws.on("unexpected-response", (_req, res) => {
|
|
32680
|
+
if (!this.openResolved) reject(new Error(`app-server ws upgrade rejected: HTTP ${res?.statusCode}`));
|
|
32681
|
+
});
|
|
32682
|
+
ws.on("error", (err) => {
|
|
32683
|
+
if (!this.openResolved) reject(err);
|
|
32684
|
+
else this._failAll(err);
|
|
32685
|
+
});
|
|
32686
|
+
ws.on("close", () => {
|
|
32687
|
+
if (this.openResolved) this._failAll(new Error("app-server ws closed"));
|
|
32688
|
+
});
|
|
32689
|
+
});
|
|
32690
|
+
ws.on("message", (data) => this._onMessage(data));
|
|
32691
|
+
}
|
|
32692
|
+
/** Await the open handshake. Rejects (before open) on connect/upgrade errors. */
|
|
32693
|
+
waitOpen() {
|
|
32694
|
+
return this.opened;
|
|
32695
|
+
}
|
|
32696
|
+
_failAll(err) {
|
|
32697
|
+
for (const [, p] of this.pending) p.reject(err);
|
|
32698
|
+
this.pending.clear();
|
|
32699
|
+
}
|
|
32700
|
+
_onMessage(data) {
|
|
32701
|
+
let msg;
|
|
32702
|
+
try {
|
|
32703
|
+
msg = JSON.parse(data.toString());
|
|
32704
|
+
} catch {
|
|
32705
|
+
return;
|
|
32706
|
+
}
|
|
32707
|
+
if (typeof msg.id === "number" && this.pending.has(msg.id)) {
|
|
32708
|
+
const p = this.pending.get(msg.id);
|
|
32709
|
+
this.pending.delete(msg.id);
|
|
32710
|
+
if (msg.error) p.reject(Object.assign(new Error(msg.error.message ?? "rpc error"), { rpcError: msg.error }));
|
|
32711
|
+
else p.resolve(msg.result);
|
|
32712
|
+
return;
|
|
32713
|
+
}
|
|
32714
|
+
if (typeof msg.method === "string") {
|
|
32715
|
+
for (const cb of this.notifyListeners) cb(msg);
|
|
32716
|
+
}
|
|
32717
|
+
}
|
|
32718
|
+
/** Issue a JSON-RPC request and resolve with its result (rejects on rpc error). */
|
|
32719
|
+
request(method, params) {
|
|
32720
|
+
const id = this.nextId++;
|
|
32721
|
+
const p = new Promise((resolve, reject) => {
|
|
32722
|
+
this.pending.set(id, { resolve, reject });
|
|
32723
|
+
});
|
|
32724
|
+
this.ws.send(JSON.stringify({ jsonrpc: "2.0", id, method, params }));
|
|
32725
|
+
return p;
|
|
32726
|
+
}
|
|
32727
|
+
/** Subscribe to server notifications; returns an unsubscribe fn. */
|
|
32728
|
+
onNotification(cb) {
|
|
32729
|
+
this.notifyListeners.add(cb);
|
|
32730
|
+
return () => this.notifyListeners.delete(cb);
|
|
32731
|
+
}
|
|
32732
|
+
close() {
|
|
32733
|
+
try {
|
|
32734
|
+
this.ws.close();
|
|
32735
|
+
} catch {
|
|
32736
|
+
}
|
|
32737
|
+
}
|
|
32738
|
+
};
|
|
32739
|
+
idempotencyCache = /* @__PURE__ */ new Map();
|
|
32740
|
+
IDEMPOTENCY_TTL_MS = 3e5;
|
|
32423
32741
|
}
|
|
32424
32742
|
});
|
|
32425
32743
|
|
|
32426
32744
|
// src/services/exec-remote.ts
|
|
32427
|
-
function
|
|
32745
|
+
async function execCodexWake(sessionId, message, cwd, timeoutMs, idempotencyKey) {
|
|
32746
|
+
if (getConfig().COGENT_CODEX_WAKE === "app-server") {
|
|
32747
|
+
try {
|
|
32748
|
+
const sock = await ensureDaemon();
|
|
32749
|
+
const result = await execCodexViaAppServer(sessionId, message, cwd, timeoutMs, { socketPath: sock, idempotencyKey });
|
|
32750
|
+
if (!result.appServerUnavailable) return result;
|
|
32751
|
+
} catch {
|
|
32752
|
+
}
|
|
32753
|
+
}
|
|
32754
|
+
return execCodex(sessionId, message, cwd, timeoutMs);
|
|
32755
|
+
}
|
|
32756
|
+
function execRemote(platform, sessionId, message, cwd, timeoutMs, opts) {
|
|
32428
32757
|
switch (platform) {
|
|
32429
32758
|
case "codex":
|
|
32430
|
-
return
|
|
32759
|
+
return execCodexWake(sessionId, message, cwd, timeoutMs, opts?.idempotencyKey);
|
|
32431
32760
|
case "cc":
|
|
32432
32761
|
default:
|
|
32433
32762
|
return execClaude(sessionId, message, cwd, timeoutMs);
|
|
@@ -32463,8 +32792,10 @@ function validateSessionFor(platform, sessionId, cwd) {
|
|
|
32463
32792
|
var init_exec_remote = __esm({
|
|
32464
32793
|
"src/services/exec-remote.ts"() {
|
|
32465
32794
|
"use strict";
|
|
32795
|
+
init_config();
|
|
32466
32796
|
init_cc_cli();
|
|
32467
32797
|
init_codex_cli();
|
|
32798
|
+
init_codex_app_server();
|
|
32468
32799
|
}
|
|
32469
32800
|
});
|
|
32470
32801
|
|
|
@@ -33172,7 +33503,12 @@ var init_auto_relay = __esm({
|
|
|
33172
33503
|
getConfig().COGENT_PLATFORM,
|
|
33173
33504
|
this.localSessionId,
|
|
33174
33505
|
formatted,
|
|
33175
|
-
this.localCwd
|
|
33506
|
+
this.localCwd,
|
|
33507
|
+
void 0,
|
|
33508
|
+
// Idempotency: the codex app-server rail runs turns on the daemon
|
|
33509
|
+
// independent of our client, so a redelivery of this same message must
|
|
33510
|
+
// not start a second turn. Keyed by the stable relay message id.
|
|
33511
|
+
{ idempotencyKey: msg.id }
|
|
33176
33512
|
);
|
|
33177
33513
|
const durationMs = Date.now() - startMs;
|
|
33178
33514
|
if (result.exitCode === 0 && result.stdout) {
|
|
@@ -33221,7 +33557,7 @@ var init_auto_relay = __esm({
|
|
|
33221
33557
|
if (freshId && freshId !== this.localSessionId) {
|
|
33222
33558
|
logger.info(`Auto-relay: retry with rotated session ${this.localSessionId} -> ${freshId}`);
|
|
33223
33559
|
this.localSessionId = freshId;
|
|
33224
|
-
const retry = await execRemote(getConfig().COGENT_PLATFORM, this.localSessionId, formatted, this.localCwd);
|
|
33560
|
+
const retry = await execRemote(getConfig().COGENT_PLATFORM, this.localSessionId, formatted, this.localCwd, void 0, { idempotencyKey: msg.id });
|
|
33225
33561
|
if (retry.exitCode === 0 && retry.stdout) {
|
|
33226
33562
|
await this._relayCapturedReply(msg, retry, traceId, Date.now() - startMs, true);
|
|
33227
33563
|
replied = true;
|
|
@@ -33231,7 +33567,9 @@ var init_auto_relay = __esm({
|
|
|
33231
33567
|
}
|
|
33232
33568
|
}
|
|
33233
33569
|
if (!replied) {
|
|
33234
|
-
await this._recordNoReplyFailure(msg, traceId, Date.now() - startMs
|
|
33570
|
+
await this._recordNoReplyFailure(msg, traceId, Date.now() - startMs, {
|
|
33571
|
+
codexLiveSession: result.codexLiveSession === true
|
|
33572
|
+
});
|
|
33235
33573
|
}
|
|
33236
33574
|
} catch (err) {
|
|
33237
33575
|
const durationMs = Date.now() - startMs;
|
|
@@ -33252,16 +33590,18 @@ var init_auto_relay = __esm({
|
|
|
33252
33590
|
* at the next turn boundary. Refusal (AMBIGUOUS_SESSION) and sandbox-blocked
|
|
33253
33591
|
* paths record their own failure and return before this, so no double-record.
|
|
33254
33592
|
*/
|
|
33255
|
-
async _recordNoReplyFailure(msg, traceId, durationMs) {
|
|
33593
|
+
async _recordNoReplyFailure(msg, traceId, durationMs, opts) {
|
|
33594
|
+
const codexLive = opts?.codexLiveSession === true;
|
|
33595
|
+
const message = codexLive ? `\u{1F4E8} Queued for "${this.localPeerId}": it's live in an interactive Codex session, so Cogent can't resume it in real time \u2014 it will see this at its next turn. For real-time replies, launch it via \`cogent-codex\` (COGENT_CODEX_WAKE=app-server). (trace ${traceId})` : `\u26A0\uFE0F Cogent could not capture a reply from "${this.localPeerId}" (it may have been busy, or the resume produced no output). Manual response required \u2014 the target agent must reply in its own session. (trace ${traceId})`;
|
|
33256
33596
|
try {
|
|
33257
33597
|
await getBackend().recordMessage({
|
|
33258
33598
|
fromPeerId: this.localPeerId,
|
|
33259
33599
|
toPeerId: msg.fromPeerId,
|
|
33260
|
-
message
|
|
33600
|
+
message,
|
|
33261
33601
|
response: null,
|
|
33262
33602
|
durationMs,
|
|
33263
33603
|
success: false,
|
|
33264
|
-
error: "NO_REPLY_CAPTURED",
|
|
33604
|
+
error: codexLive ? "CODEX_LIVE_SESSION" : "NO_REPLY_CAPTURED",
|
|
33265
33605
|
isRelayEcho: true,
|
|
33266
33606
|
traceId
|
|
33267
33607
|
});
|
|
@@ -33624,14 +33964,14 @@ __export(startup_exports, {
|
|
|
33624
33964
|
triggerReRegistration: () => triggerReRegistration
|
|
33625
33965
|
});
|
|
33626
33966
|
import os6 from "node:os";
|
|
33627
|
-
import
|
|
33628
|
-
import
|
|
33967
|
+
import path13 from "node:path";
|
|
33968
|
+
import fs12 from "node:fs/promises";
|
|
33629
33969
|
import readline2 from "node:readline";
|
|
33630
33970
|
import { execFile as execFile5 } from "node:child_process";
|
|
33631
33971
|
import { promisify as promisify4 } from "node:util";
|
|
33632
33972
|
async function loadPersistedConfig() {
|
|
33633
33973
|
try {
|
|
33634
|
-
const raw = await
|
|
33974
|
+
const raw = await fs12.readFile(PERSIST_PATH, "utf-8");
|
|
33635
33975
|
return JSON.parse(raw);
|
|
33636
33976
|
} catch {
|
|
33637
33977
|
return {};
|
|
@@ -33639,7 +33979,7 @@ async function loadPersistedConfig() {
|
|
|
33639
33979
|
}
|
|
33640
33980
|
async function savePersistedConfig(config2) {
|
|
33641
33981
|
try {
|
|
33642
|
-
await
|
|
33982
|
+
await fs12.writeFile(PERSIST_PATH, JSON.stringify(config2, null, 2) + "\n", "utf-8");
|
|
33643
33983
|
} catch (err) {
|
|
33644
33984
|
const msg = err instanceof Error ? err.message : String(err);
|
|
33645
33985
|
logger.warn(`Could not save config to ${PERSIST_PATH}: ${msg}`);
|
|
@@ -33674,11 +34014,11 @@ First run detected. Where should cogent-bridge store its data?
|
|
|
33674
34014
|
});
|
|
33675
34015
|
}
|
|
33676
34016
|
async function validateStateDir(statePath) {
|
|
33677
|
-
await
|
|
33678
|
-
const testFile =
|
|
34017
|
+
await fs12.mkdir(statePath, { recursive: true });
|
|
34018
|
+
const testFile = path13.join(statePath, ".write-test");
|
|
33679
34019
|
try {
|
|
33680
|
-
await
|
|
33681
|
-
await
|
|
34020
|
+
await fs12.writeFile(testFile, "test", "utf-8");
|
|
34021
|
+
await fs12.unlink(testFile);
|
|
33682
34022
|
} catch {
|
|
33683
34023
|
throw new BridgeError(
|
|
33684
34024
|
"STARTUP_FAILED" /* STARTUP_FAILED */,
|
|
@@ -33824,10 +34164,10 @@ async function runStartup() {
|
|
|
33824
34164
|
if (envStatePath) {
|
|
33825
34165
|
statePath = envStatePath;
|
|
33826
34166
|
} else {
|
|
33827
|
-
const defaultPath =
|
|
34167
|
+
const defaultPath = path13.join(os6.homedir(), ".cogent");
|
|
33828
34168
|
statePath = await firstRunPrompt(defaultPath);
|
|
33829
34169
|
}
|
|
33830
|
-
if (!envStatePath && statePath !==
|
|
34170
|
+
if (!envStatePath && statePath !== path13.join(os6.homedir(), ".cogent")) {
|
|
33831
34171
|
process.env.COGENT_STATE_PATH = statePath;
|
|
33832
34172
|
} else if (!envStatePath) {
|
|
33833
34173
|
process.env.COGENT_STATE_PATH = statePath;
|
|
@@ -33905,7 +34245,7 @@ async function runStartup() {
|
|
|
33905
34245
|
}
|
|
33906
34246
|
initLogger(
|
|
33907
34247
|
config2.COGENT_LOG_LEVEL,
|
|
33908
|
-
|
|
34248
|
+
path13.join(config2.COGENT_STATE_PATH, "logs")
|
|
33909
34249
|
);
|
|
33910
34250
|
if (isCloud && effectiveSessionId && effectiveToken) {
|
|
33911
34251
|
cloudInbox = new MessageInbox();
|
|
@@ -33965,7 +34305,7 @@ var init_startup = __esm({
|
|
|
33965
34305
|
init_auto_relay();
|
|
33966
34306
|
UUID_V4_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
33967
34307
|
execFileAsync3 = promisify4(execFile5);
|
|
33968
|
-
PERSIST_PATH =
|
|
34308
|
+
PERSIST_PATH = path13.join(os6.homedir(), ".cogent-config.json");
|
|
33969
34309
|
legacyWarnEmitted = false;
|
|
33970
34310
|
cloudWsClient = null;
|
|
33971
34311
|
cloudInbox = null;
|
|
@@ -33976,12 +34316,12 @@ var init_startup = __esm({
|
|
|
33976
34316
|
|
|
33977
34317
|
// src/cloud/mail-credential-store.ts
|
|
33978
34318
|
import crypto3 from "node:crypto";
|
|
33979
|
-
import
|
|
33980
|
-
import
|
|
34319
|
+
import fs13 from "node:fs/promises";
|
|
34320
|
+
import path14 from "node:path";
|
|
33981
34321
|
import os7 from "node:os";
|
|
33982
34322
|
function defaultMailCredentialPath(cwd = process.cwd()) {
|
|
33983
|
-
const hash = crypto3.createHash("sha256").update(
|
|
33984
|
-
return
|
|
34323
|
+
const hash = crypto3.createHash("sha256").update(path14.resolve(cwd)).digest("hex").slice(0, 16);
|
|
34324
|
+
return path14.join(os7.homedir(), ".cogent", "mail-credentials", `${hash}.json`);
|
|
33985
34325
|
}
|
|
33986
34326
|
function resolveMailCredentialPath(credentialPath) {
|
|
33987
34327
|
if (credentialPath) return credentialPath;
|
|
@@ -33992,16 +34332,16 @@ function resolveMailCredentialPath(credentialPath) {
|
|
|
33992
34332
|
async function loadMailCredentials(credentialPath) {
|
|
33993
34333
|
const filePath = resolveMailCredentialPath(credentialPath);
|
|
33994
34334
|
try {
|
|
33995
|
-
return JSON.parse(await
|
|
34335
|
+
return JSON.parse(await fs13.readFile(filePath, "utf-8"));
|
|
33996
34336
|
} catch {
|
|
33997
34337
|
return null;
|
|
33998
34338
|
}
|
|
33999
34339
|
}
|
|
34000
34340
|
async function saveMailCredentials(creds, credentialPath) {
|
|
34001
34341
|
const filePath = resolveMailCredentialPath(credentialPath);
|
|
34002
|
-
await
|
|
34003
|
-
await
|
|
34004
|
-
await
|
|
34342
|
+
await fs13.mkdir(path14.dirname(filePath), { recursive: true, mode: 448 });
|
|
34343
|
+
await fs13.writeFile(filePath, JSON.stringify(creds, null, 2) + "\n", { encoding: "utf-8", mode: 384 });
|
|
34344
|
+
await fs13.chmod(filePath, 384);
|
|
34005
34345
|
}
|
|
34006
34346
|
async function persistProvisionedMailbox(mailbox, credentialPath) {
|
|
34007
34347
|
if (!mailbox?.address || !mailbox.password) return false;
|
|
@@ -34022,7 +34362,7 @@ async function persistProvisionedMailbox(mailbox, credentialPath) {
|
|
|
34022
34362
|
async function clearMailCredentials(credentialPath) {
|
|
34023
34363
|
const filePath = resolveMailCredentialPath(credentialPath);
|
|
34024
34364
|
try {
|
|
34025
|
-
await
|
|
34365
|
+
await fs13.unlink(filePath);
|
|
34026
34366
|
} catch (err) {
|
|
34027
34367
|
if (err.code !== "ENOENT") throw err;
|
|
34028
34368
|
}
|
|
@@ -35708,13 +36048,13 @@ var init_setup_mail = __esm({
|
|
|
35708
36048
|
});
|
|
35709
36049
|
|
|
35710
36050
|
// src/mail/mail-sender.ts
|
|
35711
|
-
import
|
|
35712
|
-
import
|
|
36051
|
+
import fs14 from "node:fs/promises";
|
|
36052
|
+
import path15 from "node:path";
|
|
35713
36053
|
async function buildAndSendMail(sender, creds, params) {
|
|
35714
36054
|
const attachments = [];
|
|
35715
36055
|
for (const p of params.attachmentPaths ?? []) {
|
|
35716
|
-
const content = await
|
|
35717
|
-
attachments.push({ filename:
|
|
36056
|
+
const content = await fs14.readFile(p);
|
|
36057
|
+
attachments.push({ filename: path15.basename(p), content });
|
|
35718
36058
|
}
|
|
35719
36059
|
const { messageId } = await sender.send({
|
|
35720
36060
|
from: creds.address,
|
|
@@ -35842,16 +36182,16 @@ var init_send_mail = __esm({
|
|
|
35842
36182
|
});
|
|
35843
36183
|
|
|
35844
36184
|
// src/mail/mail-fetcher.ts
|
|
35845
|
-
import
|
|
35846
|
-
import
|
|
36185
|
+
import fs15 from "node:fs/promises";
|
|
36186
|
+
import path16 from "node:path";
|
|
35847
36187
|
async function saveAttachments(attachments, downloadDir) {
|
|
35848
36188
|
if (attachments.length === 0) return [];
|
|
35849
|
-
await
|
|
36189
|
+
await fs15.mkdir(downloadDir, { recursive: true });
|
|
35850
36190
|
const saved = [];
|
|
35851
36191
|
for (const a of attachments) {
|
|
35852
|
-
const name =
|
|
35853
|
-
const savedPath =
|
|
35854
|
-
await
|
|
36192
|
+
const name = path16.basename(a.filename) || "attachment";
|
|
36193
|
+
const savedPath = path16.join(downloadDir, name);
|
|
36194
|
+
await fs15.writeFile(savedPath, a.content);
|
|
35855
36195
|
saved.push({ filename: name, savedPath, size: a.content.length });
|
|
35856
36196
|
}
|
|
35857
36197
|
return saved;
|
|
@@ -35983,7 +36323,7 @@ var init_mail_fetcher = __esm({
|
|
|
35983
36323
|
|
|
35984
36324
|
// src/tools/fetch-mail.ts
|
|
35985
36325
|
import os8 from "node:os";
|
|
35986
|
-
import
|
|
36326
|
+
import path17 from "node:path";
|
|
35987
36327
|
function registerFetchMailTool(server, deps = {}) {
|
|
35988
36328
|
const makeFetcher = deps.fetcherFactory ?? ((creds) => new ImapflowMailFetcher(creds));
|
|
35989
36329
|
server.registerTool(
|
|
@@ -36045,7 +36385,7 @@ var init_fetch_mail = __esm({
|
|
|
36045
36385
|
init_mail_fetcher();
|
|
36046
36386
|
init_auth_error();
|
|
36047
36387
|
init_validate();
|
|
36048
|
-
DEFAULT_DOWNLOAD_DIR =
|
|
36388
|
+
DEFAULT_DOWNLOAD_DIR = path17.join(os8.homedir(), ".cogent", "mail-downloads");
|
|
36049
36389
|
}
|
|
36050
36390
|
});
|
|
36051
36391
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@essentialai/cogent-plugin",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.20.0",
|
|
4
4
|
"description": "Cogent — Claude Code plugin (skills + slash-commands + MCP server) for the cross-agent comms fabric.",
|
|
5
5
|
"author": { "name": "Essential AI Solutions Ltd.", "url": "https://essentialai.uk" },
|
|
6
6
|
"homepage": "https://cogent.tools",
|