@ai-matrx/coding-sessions 0.1.81 → 0.1.83
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/CHANGELOG.md +12 -0
- package/dist/engine/index.cjs +257 -81
- package/dist/engine/index.cjs.map +1 -1
- package/dist/engine/index.d.cts +1 -1
- package/dist/engine/index.d.ts +1 -1
- package/dist/engine/index.js +250 -74
- package/dist/engine/index.js.map +1 -1
- package/dist/engine/worker.js +13 -1
- package/dist/engine/worker.js.map +1 -1
- package/dist/{index-RYOb-YZT.d.cts → index-DQ0teQvw.d.cts} +18 -0
- package/dist/{index-RYOb-YZT.d.ts → index-DQ0teQvw.d.ts} +18 -0
- package/dist/index.cjs +21 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +19 -1
- package/dist/index.d.ts +19 -1
- package/dist/index.js +21 -3
- package/dist/index.js.map +1 -1
- package/dist/react/index.cjs +62 -8
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +18 -0
- package/dist/react/index.d.ts +18 -0
- package/dist/react/index.js +62 -8
- package/dist/react/index.js.map +1 -1
- package/dist/server/index.cjs +266 -90
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.d.cts +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +258 -82
- package/dist/server/index.js.map +1 -1
- package/dist/ui/assets/index-C-_1qjy9.css +2 -0
- package/dist/ui/assets/index-CmFgFvLa.js +69 -0
- package/dist/ui/index.html +2 -2
- package/package.json +1 -1
- package/dist/ui/assets/index-B3Ic2ziA.js +0 -69
- package/dist/ui/assets/index-BAkpc01s.css +0 -2
package/dist/server/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { C as CodingSessionsMethod, a as CodingSessionsApi, b as CodingEvent, c as CodingSessionsEngine, d as CodingSessionsEngineOptions } from '../index-
|
|
1
|
+
import { C as CodingSessionsMethod, a as CodingSessionsApi, b as CodingEvent, c as CodingSessionsEngine, d as CodingSessionsEngineOptions } from '../index-DQ0teQvw.cjs';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* THE HOST BRIDGE — the one seam between the engine and any transport.
|
package/dist/server/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { C as CodingSessionsMethod, a as CodingSessionsApi, b as CodingEvent, c as CodingSessionsEngine, d as CodingSessionsEngineOptions } from '../index-
|
|
1
|
+
import { C as CodingSessionsMethod, a as CodingSessionsApi, b as CodingEvent, c as CodingSessionsEngine, d as CodingSessionsEngineOptions } from '../index-DQ0teQvw.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* THE HOST BRIDGE — the one seam between the engine and any transport.
|
package/dist/server/index.js
CHANGED
|
@@ -3,14 +3,14 @@ import { randomBytes, timingSafeEqual } from "crypto";
|
|
|
3
3
|
import { existsSync as existsSync2 } from "fs";
|
|
4
4
|
import fs7 from "fs/promises";
|
|
5
5
|
import http from "http";
|
|
6
|
-
import
|
|
6
|
+
import path8 from "path";
|
|
7
7
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
8
8
|
import { WebSocketServer } from "ws";
|
|
9
9
|
|
|
10
10
|
// src/engine/index.ts
|
|
11
|
-
import { execFile as
|
|
11
|
+
import { execFile as execFile3, fork } from "child_process";
|
|
12
12
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
13
|
-
import {
|
|
13
|
+
import { existsSync } from "fs";
|
|
14
14
|
import { formatFileSize } from "@ai-matrx/kit/format";
|
|
15
15
|
|
|
16
16
|
// src/engine/raw-backup.ts
|
|
@@ -72,8 +72,8 @@ function createRawBackupScheduler(options) {
|
|
|
72
72
|
|
|
73
73
|
// src/engine/index.ts
|
|
74
74
|
import fs6 from "fs/promises";
|
|
75
|
-
import
|
|
76
|
-
import
|
|
75
|
+
import os5 from "os";
|
|
76
|
+
import path7 from "path";
|
|
77
77
|
import { fileURLToPath } from "url";
|
|
78
78
|
|
|
79
79
|
// src/normalize/claude.ts
|
|
@@ -739,9 +739,177 @@ function describeProblem(provider, problem) {
|
|
|
739
739
|
};
|
|
740
740
|
}
|
|
741
741
|
|
|
742
|
-
// src/engine/
|
|
742
|
+
// src/engine/binaries.ts
|
|
743
|
+
import { execFile } from "child_process";
|
|
744
|
+
import { accessSync, constants as fsConstants, readdirSync, readFileSync, realpathSync } from "fs";
|
|
743
745
|
import os from "os";
|
|
744
746
|
import path from "path";
|
|
747
|
+
var SOURCE_LABEL = {
|
|
748
|
+
codex: { "desktop-app": "from ChatGPT app", path: "from PATH", "npm-global": "from npm", configured: "set by host" },
|
|
749
|
+
claude: { "desktop-app": "from Claude app", path: "from PATH", "npm-global": "from npm", configured: "set by host" }
|
|
750
|
+
};
|
|
751
|
+
function sourceLabel(provider, source) {
|
|
752
|
+
return SOURCE_LABEL[provider][source];
|
|
753
|
+
}
|
|
754
|
+
function parseVersion(text) {
|
|
755
|
+
const match = /(\d+)\.(\d+)\.(\d+)(?:[-.][0-9A-Za-z.]+)?/.exec(text ?? "");
|
|
756
|
+
return match ? match[0] : null;
|
|
757
|
+
}
|
|
758
|
+
function compareVersions(a, b) {
|
|
759
|
+
const [aCore = "", aPre] = a.split("-", 2);
|
|
760
|
+
const [bCore = "", bPre] = b.split("-", 2);
|
|
761
|
+
const pa = aCore.split(".").map((n) => Number.parseInt(n, 10) || 0);
|
|
762
|
+
const pb = bCore.split(".").map((n) => Number.parseInt(n, 10) || 0);
|
|
763
|
+
for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
|
|
764
|
+
const d = (pa[i] ?? 0) - (pb[i] ?? 0);
|
|
765
|
+
if (d !== 0) return d < 0 ? -1 : 1;
|
|
766
|
+
}
|
|
767
|
+
if (aPre && !bPre) return -1;
|
|
768
|
+
if (!aPre && bPre) return 1;
|
|
769
|
+
return 0;
|
|
770
|
+
}
|
|
771
|
+
function pickBinary(candidates) {
|
|
772
|
+
let best = null;
|
|
773
|
+
for (const c of candidates) {
|
|
774
|
+
if (!best) {
|
|
775
|
+
best = c;
|
|
776
|
+
continue;
|
|
777
|
+
}
|
|
778
|
+
if (c.version && (!best.version || compareVersions(c.version, best.version) > 0)) best = c;
|
|
779
|
+
}
|
|
780
|
+
return best;
|
|
781
|
+
}
|
|
782
|
+
function executable(file) {
|
|
783
|
+
try {
|
|
784
|
+
accessSync(file, fsConstants.X_OK);
|
|
785
|
+
return true;
|
|
786
|
+
} catch {
|
|
787
|
+
return false;
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
function exeName(name, platform) {
|
|
791
|
+
return platform === "win32" ? [`${name}.exe`, `${name}.cmd`, name] : [name];
|
|
792
|
+
}
|
|
793
|
+
function allOnPath(name, pathValue, platform = process.platform) {
|
|
794
|
+
const found = [];
|
|
795
|
+
for (const dir of pathValue.split(path.delimiter)) {
|
|
796
|
+
if (!dir) continue;
|
|
797
|
+
for (const file of exeName(name, platform)) {
|
|
798
|
+
const candidate = path.join(dir, file);
|
|
799
|
+
if (executable(candidate)) {
|
|
800
|
+
found.push(candidate);
|
|
801
|
+
break;
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
return found;
|
|
806
|
+
}
|
|
807
|
+
function desktopAppCandidates(provider, platform, home, applications) {
|
|
808
|
+
if (platform !== "darwin") return [];
|
|
809
|
+
if (provider === "codex") {
|
|
810
|
+
return applications.map(
|
|
811
|
+
(apps) => path.join(apps, "ChatGPT.app", "Contents", "Resources", "codex-cli", "bin", "codex")
|
|
812
|
+
);
|
|
813
|
+
}
|
|
814
|
+
const root = path.join(home, "Library", "Application Support", "Claude", "claude-code");
|
|
815
|
+
let versions = [];
|
|
816
|
+
try {
|
|
817
|
+
versions = readdirSync(root);
|
|
818
|
+
} catch {
|
|
819
|
+
return [];
|
|
820
|
+
}
|
|
821
|
+
return versions.map((v) => path.join(root, v, "claude.app", "Contents", "MacOS", "claude"));
|
|
822
|
+
}
|
|
823
|
+
function npmGlobalPrefix(env) {
|
|
824
|
+
const fromEnv = env.npm_config_prefix ?? env.NPM_CONFIG_PREFIX;
|
|
825
|
+
if (fromEnv) return Promise.resolve(fromEnv);
|
|
826
|
+
const npm = allOnPath("npm", env.PATH ?? "")[0];
|
|
827
|
+
if (!npm) return Promise.resolve(null);
|
|
828
|
+
return new Promise((resolve) => {
|
|
829
|
+
const child = execFile(npm, ["prefix", "-g"], { timeout: 5e3, env }, (error, stdout) => {
|
|
830
|
+
resolve(error ? null : String(stdout).trim() || null);
|
|
831
|
+
});
|
|
832
|
+
child.stdin?.end();
|
|
833
|
+
});
|
|
834
|
+
}
|
|
835
|
+
function declaredVersion(provider, source, file) {
|
|
836
|
+
if (source !== "desktop-app") return null;
|
|
837
|
+
if (provider === "codex") {
|
|
838
|
+
try {
|
|
839
|
+
const pkg = JSON.parse(readFileSync(path.join(path.dirname(path.dirname(file)), "codex-package.json"), "utf8"));
|
|
840
|
+
return typeof pkg.version === "string" ? parseVersion(pkg.version) : null;
|
|
841
|
+
} catch {
|
|
842
|
+
return null;
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
return parseVersion(path.basename(path.resolve(file, "..", "..", "..", "..")));
|
|
846
|
+
}
|
|
847
|
+
function runVersion(file, env) {
|
|
848
|
+
return new Promise((resolve) => {
|
|
849
|
+
const child = execFile(file, ["--version"], { timeout: 8e3, env }, (error, stdout) => {
|
|
850
|
+
resolve(error ? null : parseVersion(String(stdout)));
|
|
851
|
+
});
|
|
852
|
+
child.stdin?.end();
|
|
853
|
+
});
|
|
854
|
+
}
|
|
855
|
+
async function discoverBinaries(provider, options) {
|
|
856
|
+
const platform = options.platform ?? process.platform;
|
|
857
|
+
const home = options.home ?? options.env.HOME ?? os.homedir();
|
|
858
|
+
const listed2 = [
|
|
859
|
+
...desktopAppCandidates(provider, platform, home, options.applications ?? ["/Applications", path.join(home, "Applications")]).filter(executable).map((p) => ({ path: p, source: "desktop-app" })),
|
|
860
|
+
...allOnPath(provider, options.env.PATH ?? "", platform).map((p) => ({ path: p, source: "path" }))
|
|
861
|
+
];
|
|
862
|
+
const prefix = await npmGlobalPrefix(options.env);
|
|
863
|
+
if (prefix) {
|
|
864
|
+
const dir = platform === "win32" ? prefix : path.join(prefix, "bin");
|
|
865
|
+
for (const file of exeName(provider, platform)) {
|
|
866
|
+
const candidate = path.join(dir, file);
|
|
867
|
+
if (executable(candidate)) {
|
|
868
|
+
listed2.push({ path: candidate, source: "npm-global" });
|
|
869
|
+
break;
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
const seen = /* @__PURE__ */ new Set();
|
|
874
|
+
const unique = listed2.filter((c) => {
|
|
875
|
+
let real = c.path;
|
|
876
|
+
try {
|
|
877
|
+
real = realpathSync(c.path);
|
|
878
|
+
} catch {
|
|
879
|
+
}
|
|
880
|
+
if (seen.has(real)) return false;
|
|
881
|
+
seen.add(real);
|
|
882
|
+
return true;
|
|
883
|
+
});
|
|
884
|
+
return Promise.all(
|
|
885
|
+
unique.map(async (c) => ({
|
|
886
|
+
...c,
|
|
887
|
+
version: declaredVersion(provider, c.source, c.path) ?? await runVersion(c.path, options.env)
|
|
888
|
+
}))
|
|
889
|
+
);
|
|
890
|
+
}
|
|
891
|
+
async function resolveBinary(provider, options) {
|
|
892
|
+
const candidates = options.discover === false ? [] : await discoverBinaries(provider, options);
|
|
893
|
+
const best = pickBinary(candidates);
|
|
894
|
+
const inUse = options.forced ? {
|
|
895
|
+
path: options.forced,
|
|
896
|
+
source: "configured",
|
|
897
|
+
version: candidates.find((c) => c.path === options.forced)?.version ?? (options.discover === false ? null : await runVersion(options.forced, options.env))
|
|
898
|
+
} : best;
|
|
899
|
+
if (!inUse) return null;
|
|
900
|
+
const newer = best && best.path !== inUse.path && best.version && (!inUse.version || compareVersions(best.version, inUse.version) > 0) ? { path: best.path, version: best.version, sourceLabel: sourceLabel(provider, best.source) } : null;
|
|
901
|
+
return {
|
|
902
|
+
path: inUse.path,
|
|
903
|
+
version: inUse.version,
|
|
904
|
+
source: inUse.source,
|
|
905
|
+
sourceLabel: sourceLabel(provider, inUse.source),
|
|
906
|
+
newer
|
|
907
|
+
};
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
// src/engine/clean-env.ts
|
|
911
|
+
import os2 from "os";
|
|
912
|
+
import path2 from "path";
|
|
745
913
|
var ALLOWED_NAMES = /* @__PURE__ */ new Set([
|
|
746
914
|
"HOME",
|
|
747
915
|
"USER",
|
|
@@ -763,11 +931,11 @@ var ALLOWED_NAMES = /* @__PURE__ */ new Set([
|
|
|
763
931
|
var ALLOWED_PREFIXES = ["LC_"];
|
|
764
932
|
function wellKnownBinDirs(home) {
|
|
765
933
|
return [
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
934
|
+
path2.join(home, ".local", "bin"),
|
|
935
|
+
path2.join(home, ".claude", "local"),
|
|
936
|
+
path2.join(home, ".npm-global", "bin"),
|
|
937
|
+
path2.join(home, ".bun", "bin"),
|
|
938
|
+
path2.join(home, ".volta", "bin"),
|
|
771
939
|
"/opt/homebrew/bin",
|
|
772
940
|
"/usr/local/bin",
|
|
773
941
|
"/usr/bin",
|
|
@@ -785,14 +953,14 @@ function buildCleanEnv(hostEnv, extra = {}) {
|
|
|
785
953
|
if (typeof value !== "string") continue;
|
|
786
954
|
if (isAllowedEnvName(name)) out[name] = value;
|
|
787
955
|
}
|
|
788
|
-
const home = out.HOME ??
|
|
956
|
+
const home = out.HOME ?? os2.homedir();
|
|
789
957
|
out.HOME = home;
|
|
790
|
-
const hostPath = (hostEnv.PATH ?? "").split(
|
|
958
|
+
const hostPath = (hostEnv.PATH ?? "").split(path2.delimiter).filter(Boolean);
|
|
791
959
|
const merged = [];
|
|
792
960
|
for (const dir of [...hostPath, ...wellKnownBinDirs(home)]) {
|
|
793
961
|
if (!merged.includes(dir)) merged.push(dir);
|
|
794
962
|
}
|
|
795
|
-
out.PATH = merged.join(
|
|
963
|
+
out.PATH = merged.join(path2.delimiter);
|
|
796
964
|
for (const [name, value] of Object.entries(extra)) out[name] = value;
|
|
797
965
|
return out;
|
|
798
966
|
}
|
|
@@ -800,16 +968,16 @@ function buildCleanEnv(hostEnv, extra = {}) {
|
|
|
800
968
|
// src/engine/files.ts
|
|
801
969
|
import { createReadStream } from "fs";
|
|
802
970
|
import fs2 from "fs/promises";
|
|
803
|
-
import
|
|
804
|
-
import
|
|
971
|
+
import os3 from "os";
|
|
972
|
+
import path3 from "path";
|
|
805
973
|
|
|
806
974
|
// src/engine/activity.ts
|
|
807
|
-
import { execFile } from "child_process";
|
|
975
|
+
import { execFile as execFile2 } from "child_process";
|
|
808
976
|
var RECENT_WRITE_MS = 2 * 60 * 1e3;
|
|
809
977
|
var OPEN_TOOL_WINDOW_MS = 15 * 60 * 1e3;
|
|
810
978
|
function listProcesses() {
|
|
811
979
|
return new Promise((resolve) => {
|
|
812
|
-
|
|
980
|
+
execFile2("ps", ["-axww", "-o", "pid=,args="], { maxBuffer: 64 * 1024 * 1024, timeout: 5e3 }, (error, stdout) => {
|
|
813
981
|
if (error) {
|
|
814
982
|
resolve([]);
|
|
815
983
|
return;
|
|
@@ -868,11 +1036,11 @@ function describeActivity(input) {
|
|
|
868
1036
|
}
|
|
869
1037
|
|
|
870
1038
|
// src/engine/files.ts
|
|
871
|
-
function defaultProviderHomes(home =
|
|
1039
|
+
function defaultProviderHomes(home = os3.homedir()) {
|
|
872
1040
|
return {
|
|
873
|
-
claudeProjects:
|
|
874
|
-
codexSessions:
|
|
875
|
-
codexIndex:
|
|
1041
|
+
claudeProjects: path3.join(home, ".claude", "projects"),
|
|
1042
|
+
codexSessions: path3.join(home, ".codex", "sessions"),
|
|
1043
|
+
codexIndex: path3.join(home, ".codex", "session_index.jsonl")
|
|
876
1044
|
};
|
|
877
1045
|
}
|
|
878
1046
|
var UUIDISH = /([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\.jsonl$/i;
|
|
@@ -897,10 +1065,10 @@ async function claudeCandidates(root) {
|
|
|
897
1065
|
const out = [];
|
|
898
1066
|
for (const project of await safeReaddir(root)) {
|
|
899
1067
|
if (!project.isDirectory()) continue;
|
|
900
|
-
const dir =
|
|
1068
|
+
const dir = path3.join(root, project.name);
|
|
901
1069
|
const entries = await safeReaddir(dir);
|
|
902
1070
|
const stats = await Promise.all(
|
|
903
|
-
entries.filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => statCandidate("claude",
|
|
1071
|
+
entries.filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => statCandidate("claude", path3.join(dir, e.name)))
|
|
904
1072
|
);
|
|
905
1073
|
for (const s of stats) if (s) out.push(s);
|
|
906
1074
|
}
|
|
@@ -910,14 +1078,14 @@ async function codexCandidates(root) {
|
|
|
910
1078
|
const out = [];
|
|
911
1079
|
for (const year of await safeReaddir(root)) {
|
|
912
1080
|
if (!year.isDirectory()) continue;
|
|
913
|
-
for (const month of await safeReaddir(
|
|
1081
|
+
for (const month of await safeReaddir(path3.join(root, year.name))) {
|
|
914
1082
|
if (!month.isDirectory()) continue;
|
|
915
|
-
for (const day of await safeReaddir(
|
|
1083
|
+
for (const day of await safeReaddir(path3.join(root, year.name, month.name))) {
|
|
916
1084
|
if (!day.isDirectory()) continue;
|
|
917
|
-
const dir =
|
|
1085
|
+
const dir = path3.join(root, year.name, month.name, day.name);
|
|
918
1086
|
const entries = await safeReaddir(dir);
|
|
919
1087
|
const stats = await Promise.all(
|
|
920
|
-
entries.filter((e) => e.isFile() && e.name.startsWith("rollout-") && e.name.endsWith(".jsonl")).map((e) => statCandidate("codex",
|
|
1088
|
+
entries.filter((e) => e.isFile() && e.name.startsWith("rollout-") && e.name.endsWith(".jsonl")).map((e) => statCandidate("codex", path3.join(dir, e.name)))
|
|
921
1089
|
);
|
|
922
1090
|
for (const s of stats) if (s) out.push(s);
|
|
923
1091
|
}
|
|
@@ -1178,7 +1346,7 @@ async function describeSessionFile(candidate, codexNames) {
|
|
|
1178
1346
|
// src/engine/preferences.ts
|
|
1179
1347
|
import { randomUUID } from "crypto";
|
|
1180
1348
|
import fs3 from "fs/promises";
|
|
1181
|
-
import
|
|
1349
|
+
import path4 from "path";
|
|
1182
1350
|
var PreferenceStore = class {
|
|
1183
1351
|
constructor(dir) {
|
|
1184
1352
|
this.dir = dir;
|
|
@@ -1187,7 +1355,7 @@ var PreferenceStore = class {
|
|
|
1187
1355
|
data = {};
|
|
1188
1356
|
writing = Promise.resolve();
|
|
1189
1357
|
get file() {
|
|
1190
|
-
return
|
|
1358
|
+
return path4.join(this.dir, "preferences.json");
|
|
1191
1359
|
}
|
|
1192
1360
|
async load() {
|
|
1193
1361
|
try {
|
|
@@ -1391,7 +1559,7 @@ async function searchLocalChats(query, options = {}) {
|
|
|
1391
1559
|
// src/engine/store.ts
|
|
1392
1560
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
1393
1561
|
import fs4 from "fs/promises";
|
|
1394
|
-
import
|
|
1562
|
+
import path5 from "path";
|
|
1395
1563
|
var MAX_RUNS = 2e3;
|
|
1396
1564
|
var RunIndex = class {
|
|
1397
1565
|
constructor(dir) {
|
|
@@ -1401,7 +1569,7 @@ var RunIndex = class {
|
|
|
1401
1569
|
data = { version: 1, sessions: [], runs: [] };
|
|
1402
1570
|
writing = Promise.resolve();
|
|
1403
1571
|
get file() {
|
|
1404
|
-
return
|
|
1572
|
+
return path5.join(this.dir, "index.json");
|
|
1405
1573
|
}
|
|
1406
1574
|
async load() {
|
|
1407
1575
|
await fs4.mkdir(this.dir, { recursive: true });
|
|
@@ -1460,7 +1628,7 @@ var RunIndex = class {
|
|
|
1460
1628
|
/** A stable Paperclip agent/company identity for this install, so the
|
|
1461
1629
|
* driver's scratch state is reused rather than growing per run. */
|
|
1462
1630
|
async identity() {
|
|
1463
|
-
const file =
|
|
1631
|
+
const file = path5.join(this.dir, "identity.json");
|
|
1464
1632
|
try {
|
|
1465
1633
|
const parsed = JSON.parse(await fs4.readFile(file, "utf8"));
|
|
1466
1634
|
if (typeof parsed.companyId === "string" && typeof parsed.agentId === "string") {
|
|
@@ -1476,8 +1644,8 @@ var RunIndex = class {
|
|
|
1476
1644
|
|
|
1477
1645
|
// src/engine/user-defaults.ts
|
|
1478
1646
|
import fs5 from "fs/promises";
|
|
1479
|
-
import
|
|
1480
|
-
import
|
|
1647
|
+
import os4 from "os";
|
|
1648
|
+
import path6 from "path";
|
|
1481
1649
|
async function readJson(file) {
|
|
1482
1650
|
try {
|
|
1483
1651
|
const parsed = JSON.parse(await fs5.readFile(file, "utf8"));
|
|
@@ -1489,10 +1657,10 @@ async function readJson(file) {
|
|
|
1489
1657
|
function str3(value) {
|
|
1490
1658
|
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
1491
1659
|
}
|
|
1492
|
-
async function claudeDefaults(cwd, home =
|
|
1660
|
+
async function claudeDefaults(cwd, home = os4.homedir()) {
|
|
1493
1661
|
const files = [
|
|
1494
|
-
...cwd ? [
|
|
1495
|
-
|
|
1662
|
+
...cwd ? [path6.join(cwd, ".claude", "settings.local.json"), path6.join(cwd, ".claude", "settings.json")] : [],
|
|
1663
|
+
path6.join(home, ".claude", "settings.json")
|
|
1496
1664
|
];
|
|
1497
1665
|
let model = null;
|
|
1498
1666
|
let effort = null;
|
|
@@ -1505,10 +1673,10 @@ async function claudeDefaults(cwd, home = os3.homedir()) {
|
|
|
1505
1673
|
}
|
|
1506
1674
|
return { model, effort };
|
|
1507
1675
|
}
|
|
1508
|
-
async function codexDefaults(home =
|
|
1676
|
+
async function codexDefaults(home = os4.homedir()) {
|
|
1509
1677
|
let text;
|
|
1510
1678
|
try {
|
|
1511
|
-
text = await fs5.readFile(
|
|
1679
|
+
text = await fs5.readFile(path6.join(home, ".codex", "config.toml"), "utf8");
|
|
1512
1680
|
} catch {
|
|
1513
1681
|
return { model: null, effort: null };
|
|
1514
1682
|
}
|
|
@@ -1532,45 +1700,33 @@ var EFFORT_LEVELS = {
|
|
|
1532
1700
|
// src/engine/index.ts
|
|
1533
1701
|
var RAW_TRANSCRIPT_MAX_BYTES = 200 * 1048576;
|
|
1534
1702
|
function moduleDir() {
|
|
1535
|
-
return
|
|
1703
|
+
return path7.dirname(fileURLToPath(import.meta.url));
|
|
1536
1704
|
}
|
|
1537
1705
|
function resolveWorkerPath() {
|
|
1538
1706
|
const dir = moduleDir();
|
|
1539
1707
|
for (const candidate of [
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1708
|
+
path7.join(dir, "worker.js"),
|
|
1709
|
+
path7.join(dir, "worker.ts"),
|
|
1710
|
+
path7.join(dir, "..", "engine", "worker.js"),
|
|
1711
|
+
path7.join(dir, "..", "engine", "worker.ts")
|
|
1544
1712
|
]) {
|
|
1545
1713
|
if (existsSync(candidate)) return candidate;
|
|
1546
1714
|
}
|
|
1547
1715
|
throw new Error(`[coding-sessions] The driver worker is missing next to ${dir}.`);
|
|
1548
1716
|
}
|
|
1549
1717
|
async function installShim(dataDir) {
|
|
1550
|
-
const source =
|
|
1718
|
+
const source = path7.resolve(moduleDir(), "..", "..", "bin", "cli-shim.sh");
|
|
1551
1719
|
if (!existsSync(source)) throw new Error(`[coding-sessions] The CLI shim is missing at ${source}.`);
|
|
1552
1720
|
const body = await fs6.readFile(source, "utf8");
|
|
1553
|
-
const target =
|
|
1721
|
+
const target = path7.join(dataDir, "bin", "cli-shim.sh");
|
|
1554
1722
|
const current = await fs6.readFile(target, "utf8").catch(() => null);
|
|
1555
1723
|
if (current !== body) {
|
|
1556
|
-
await fs6.mkdir(
|
|
1724
|
+
await fs6.mkdir(path7.dirname(target), { recursive: true });
|
|
1557
1725
|
await fs6.writeFile(target, body, { mode: 493 });
|
|
1558
1726
|
}
|
|
1559
1727
|
await fs6.chmod(target, 493);
|
|
1560
1728
|
return target;
|
|
1561
1729
|
}
|
|
1562
|
-
function whichOnPath(name, pathValue) {
|
|
1563
|
-
for (const dir of pathValue.split(path6.delimiter)) {
|
|
1564
|
-
if (!dir) continue;
|
|
1565
|
-
const candidate = path6.join(dir, name);
|
|
1566
|
-
try {
|
|
1567
|
-
accessSync(candidate, fsConstants.X_OK);
|
|
1568
|
-
return candidate;
|
|
1569
|
-
} catch {
|
|
1570
|
-
}
|
|
1571
|
-
}
|
|
1572
|
-
return null;
|
|
1573
|
-
}
|
|
1574
1730
|
function nowIso() {
|
|
1575
1731
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
1576
1732
|
}
|
|
@@ -1609,12 +1765,14 @@ function describeProviderStatus(provider, probe, lastProblem = null, quota = [])
|
|
|
1609
1765
|
function describeAuthStatus(provider, probe) {
|
|
1610
1766
|
const label = PROVIDER_LABEL[provider];
|
|
1611
1767
|
const installed = probe?.installed === true;
|
|
1612
|
-
const
|
|
1768
|
+
const binary = probe?.binary ?? null;
|
|
1769
|
+
const version = binary?.version ?? (typeof probe?.version === "string" ? probe.version : null);
|
|
1613
1770
|
const base = {
|
|
1614
1771
|
provider,
|
|
1615
1772
|
label,
|
|
1616
1773
|
installed,
|
|
1617
1774
|
version,
|
|
1775
|
+
binary,
|
|
1618
1776
|
loggedIn: false,
|
|
1619
1777
|
billing: "unknown",
|
|
1620
1778
|
plan: null,
|
|
@@ -1666,8 +1824,8 @@ function describeAuthStatus(provider, probe) {
|
|
|
1666
1824
|
};
|
|
1667
1825
|
}
|
|
1668
1826
|
async function createCodingSessionsEngine(options = {}) {
|
|
1669
|
-
const dataDir = options.dataDir ??
|
|
1670
|
-
const stateDir =
|
|
1827
|
+
const dataDir = options.dataDir ?? path7.join(os5.homedir(), ".matrx", "coding-sessions");
|
|
1828
|
+
const stateDir = path7.join(dataDir, "paperclip-state");
|
|
1671
1829
|
const homes = options.homes ?? defaultProviderHomes();
|
|
1672
1830
|
const index = new RunIndex(dataDir);
|
|
1673
1831
|
await index.load();
|
|
@@ -1681,7 +1839,7 @@ async function createCodingSessionsEngine(options = {}) {
|
|
|
1681
1839
|
onError: (error) => console.warn("[coding-sessions] raw transcript backup failed:", error)
|
|
1682
1840
|
}) : null;
|
|
1683
1841
|
const discoveredSeen = /* @__PURE__ */ new Map();
|
|
1684
|
-
const healthFile =
|
|
1842
|
+
const healthFile = path7.join(dataDir, "provider-health.json");
|
|
1685
1843
|
let health = {};
|
|
1686
1844
|
try {
|
|
1687
1845
|
health = JSON.parse(await fs6.readFile(healthFile, "utf8"));
|
|
@@ -1716,7 +1874,24 @@ async function createCodingSessionsEngine(options = {}) {
|
|
|
1716
1874
|
// Marks the forked process as a driver worker (see worker.ts).
|
|
1717
1875
|
MATRX_CODING_SESSIONS_WORKER: "1"
|
|
1718
1876
|
});
|
|
1719
|
-
const
|
|
1877
|
+
const binaryHome = options.hostEnv?.HOME ?? os5.homedir();
|
|
1878
|
+
const binaryCache = /* @__PURE__ */ new Map();
|
|
1879
|
+
function binaryFor(provider, fresh = false) {
|
|
1880
|
+
const cached = binaryCache.get(provider);
|
|
1881
|
+
if (cached && !fresh && Date.now() - cached.at < 5 * 6e4) return cached.value;
|
|
1882
|
+
const forced = options.commands?.[provider];
|
|
1883
|
+
const value = resolveBinary(provider, {
|
|
1884
|
+
env: workerEnv,
|
|
1885
|
+
home: binaryHome,
|
|
1886
|
+
forced,
|
|
1887
|
+
// A forced command needs no discovery to run; the status check still
|
|
1888
|
+
// looks, so it can say when a newer copy exists.
|
|
1889
|
+
discover: !forced || fresh
|
|
1890
|
+
}).catch(() => forced ? { path: forced, version: null, source: "configured", sourceLabel: "set by host", newer: null } : null);
|
|
1891
|
+
if (!forced || !fresh) binaryCache.set(provider, { at: Date.now(), value });
|
|
1892
|
+
return value;
|
|
1893
|
+
}
|
|
1894
|
+
const commandFor = async (provider) => (await binaryFor(provider))?.path ?? null;
|
|
1720
1895
|
const workerPath = resolveWorkerPath();
|
|
1721
1896
|
const shimPath = await installShim(dataDir);
|
|
1722
1897
|
const listeners = /* @__PURE__ */ new Set();
|
|
@@ -1787,7 +1962,7 @@ async function createCodingSessionsEngine(options = {}) {
|
|
|
1787
1962
|
}
|
|
1788
1963
|
async function startRun(session, prompt) {
|
|
1789
1964
|
const provider = session.provider;
|
|
1790
|
-
const realCommand = commandFor(provider);
|
|
1965
|
+
const realCommand = await commandFor(provider);
|
|
1791
1966
|
const runId = randomUUID3();
|
|
1792
1967
|
const model = session.model ?? (provider === "claude" ? (await userDefaults(provider, session.cwd)).model ?? null : null);
|
|
1793
1968
|
const run = {
|
|
@@ -2019,7 +2194,7 @@ async function createCodingSessionsEngine(options = {}) {
|
|
|
2019
2194
|
}, 3e3);
|
|
2020
2195
|
}
|
|
2021
2196
|
async function pruneDriverScratch() {
|
|
2022
|
-
const runsDir =
|
|
2197
|
+
const runsDir = path7.join(
|
|
2023
2198
|
stateDir,
|
|
2024
2199
|
"instances",
|
|
2025
2200
|
"default",
|
|
@@ -2032,10 +2207,11 @@ async function createCodingSessionsEngine(options = {}) {
|
|
|
2032
2207
|
);
|
|
2033
2208
|
const entries = await fs6.readdir(runsDir).catch(() => []);
|
|
2034
2209
|
await Promise.all(
|
|
2035
|
-
entries.filter((name) => !live.has(name)).map((name) => fs6.rm(
|
|
2210
|
+
entries.filter((name) => !live.has(name)).map((name) => fs6.rm(path7.join(runsDir, name), { recursive: true, force: true }).catch(() => void 0))
|
|
2036
2211
|
);
|
|
2037
2212
|
}
|
|
2038
2213
|
async function probe() {
|
|
2214
|
+
const [claudeBinary, codexBinary] = await Promise.all([binaryFor("claude", true), binaryFor("codex", true)]);
|
|
2039
2215
|
return new Promise((resolve) => {
|
|
2040
2216
|
const child = forkWorker();
|
|
2041
2217
|
let answered = false;
|
|
@@ -2051,8 +2227,8 @@ async function createCodingSessionsEngine(options = {}) {
|
|
|
2051
2227
|
answered = true;
|
|
2052
2228
|
clearTimeout(timer);
|
|
2053
2229
|
resolve({
|
|
2054
|
-
claude: message.claude ?? {},
|
|
2055
|
-
codex: message.codex ?? {}
|
|
2230
|
+
claude: { ...message.claude ?? {}, binary: claudeBinary },
|
|
2231
|
+
codex: { ...message.codex ?? {}, binary: codexBinary }
|
|
2056
2232
|
});
|
|
2057
2233
|
}
|
|
2058
2234
|
});
|
|
@@ -2064,7 +2240,7 @@ async function createCodingSessionsEngine(options = {}) {
|
|
|
2064
2240
|
});
|
|
2065
2241
|
child.send({
|
|
2066
2242
|
kind: "probe",
|
|
2067
|
-
commands: { claude:
|
|
2243
|
+
commands: { claude: claudeBinary?.path ?? null, codex: codexBinary?.path ?? null },
|
|
2068
2244
|
quota: options.quota !== false
|
|
2069
2245
|
});
|
|
2070
2246
|
});
|
|
@@ -2090,7 +2266,7 @@ async function createCodingSessionsEngine(options = {}) {
|
|
|
2090
2266
|
function resolveFolder(raw) {
|
|
2091
2267
|
const trimmed = raw.trim();
|
|
2092
2268
|
if (!trimmed) return null;
|
|
2093
|
-
return
|
|
2269
|
+
return path7.resolve(trimmed.replace(/^~(?=$|\/)/, os5.homedir()));
|
|
2094
2270
|
}
|
|
2095
2271
|
async function checkFolder(raw) {
|
|
2096
2272
|
const target = resolveFolder(raw);
|
|
@@ -2099,7 +2275,7 @@ async function createCodingSessionsEngine(options = {}) {
|
|
|
2099
2275
|
return { path: target, exists: stat !== null, isDirectory: stat?.isDirectory() === true };
|
|
2100
2276
|
}
|
|
2101
2277
|
async function assertFolder(cwd) {
|
|
2102
|
-
const resolved =
|
|
2278
|
+
const resolved = path7.resolve(cwd.replace(/^~(?=$|\/)/, os5.homedir()));
|
|
2103
2279
|
const stat = await fs6.stat(resolved).catch(() => null);
|
|
2104
2280
|
if (!stat?.isDirectory()) {
|
|
2105
2281
|
throw new Error(`The folder ${resolved} doesn't exist on this computer.`);
|
|
@@ -2253,7 +2429,7 @@ async function createCodingSessionsEngine(options = {}) {
|
|
|
2253
2429
|
};
|
|
2254
2430
|
}
|
|
2255
2431
|
const content = await fs6.readFile(file, "utf8");
|
|
2256
|
-
return { available: true, fileName:
|
|
2432
|
+
return { available: true, fileName: path7.basename(file), bytes: stat.size, content };
|
|
2257
2433
|
},
|
|
2258
2434
|
async start(input) {
|
|
2259
2435
|
const prompt = input.prompt.trim();
|
|
@@ -2374,7 +2550,7 @@ function openFolderIn(folder, target) {
|
|
|
2374
2550
|
args = ["-a", app.app, folder];
|
|
2375
2551
|
}
|
|
2376
2552
|
return new Promise((resolve, reject) => {
|
|
2377
|
-
|
|
2553
|
+
execFile3(command, args, { timeout: 1e4 }, (error) => {
|
|
2378
2554
|
if (!error) return resolve();
|
|
2379
2555
|
const label = target === "finder" ? "the folder" : OPEN_APP[target]?.label ?? target;
|
|
2380
2556
|
reject(
|
|
@@ -2451,14 +2627,14 @@ var MIME = {
|
|
|
2451
2627
|
".map": "application/json"
|
|
2452
2628
|
};
|
|
2453
2629
|
function moduleDir2() {
|
|
2454
|
-
return
|
|
2630
|
+
return path8.dirname(fileURLToPath2(import.meta.url));
|
|
2455
2631
|
}
|
|
2456
2632
|
function defaultUiDir() {
|
|
2457
2633
|
for (const candidate of [
|
|
2458
|
-
|
|
2459
|
-
|
|
2634
|
+
path8.resolve(moduleDir2(), "..", "ui"),
|
|
2635
|
+
path8.resolve(moduleDir2(), "..", "..", "dist", "ui")
|
|
2460
2636
|
]) {
|
|
2461
|
-
if (existsSync2(
|
|
2637
|
+
if (existsSync2(path8.join(candidate, "index.html"))) return candidate;
|
|
2462
2638
|
}
|
|
2463
2639
|
return null;
|
|
2464
2640
|
}
|
|
@@ -2481,19 +2657,19 @@ async function serveStatic(uiDir, req, res) {
|
|
|
2481
2657
|
return;
|
|
2482
2658
|
}
|
|
2483
2659
|
const requested = decodeURIComponent(url.pathname);
|
|
2484
|
-
let file =
|
|
2660
|
+
let file = path8.resolve(uiDir, `.${requested}`);
|
|
2485
2661
|
if (!file.startsWith(uiDir)) {
|
|
2486
2662
|
res.writeHead(403).end();
|
|
2487
2663
|
return;
|
|
2488
2664
|
}
|
|
2489
2665
|
const stat = await fs7.stat(file).catch(() => null);
|
|
2490
|
-
if (!stat || stat.isDirectory()) file =
|
|
2666
|
+
if (!stat || stat.isDirectory()) file = path8.join(uiDir, "index.html");
|
|
2491
2667
|
const body = await fs7.readFile(file).catch(() => null);
|
|
2492
2668
|
if (!body) {
|
|
2493
2669
|
res.writeHead(404).end();
|
|
2494
2670
|
return;
|
|
2495
2671
|
}
|
|
2496
|
-
const ext =
|
|
2672
|
+
const ext = path8.extname(file);
|
|
2497
2673
|
res.writeHead(200, {
|
|
2498
2674
|
"content-type": MIME[ext] ?? "application/octet-stream",
|
|
2499
2675
|
"cache-control": ext === ".html" ? "no-store" : "public, max-age=31536000, immutable",
|