@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.cjs
CHANGED
|
@@ -44,17 +44,17 @@ var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
|
|
|
44
44
|
|
|
45
45
|
// src/server/index.ts
|
|
46
46
|
var import_node_crypto5 = require("crypto");
|
|
47
|
-
var
|
|
47
|
+
var import_node_fs5 = require("fs");
|
|
48
48
|
var import_promises7 = __toESM(require("fs/promises"), 1);
|
|
49
49
|
var import_node_http = __toESM(require("http"), 1);
|
|
50
|
-
var
|
|
50
|
+
var import_node_path8 = __toESM(require("path"), 1);
|
|
51
51
|
var import_node_url2 = require("url");
|
|
52
52
|
var import_ws = require("ws");
|
|
53
53
|
|
|
54
54
|
// src/engine/index.ts
|
|
55
|
-
var
|
|
55
|
+
var import_node_child_process3 = require("child_process");
|
|
56
56
|
var import_node_crypto4 = require("crypto");
|
|
57
|
-
var
|
|
57
|
+
var import_node_fs4 = require("fs");
|
|
58
58
|
var import_format = require("@ai-matrx/kit/format");
|
|
59
59
|
|
|
60
60
|
// src/engine/raw-backup.ts
|
|
@@ -116,8 +116,8 @@ function createRawBackupScheduler(options) {
|
|
|
116
116
|
|
|
117
117
|
// src/engine/index.ts
|
|
118
118
|
var import_promises6 = __toESM(require("fs/promises"), 1);
|
|
119
|
-
var
|
|
120
|
-
var
|
|
119
|
+
var import_node_os5 = __toESM(require("os"), 1);
|
|
120
|
+
var import_node_path7 = __toESM(require("path"), 1);
|
|
121
121
|
var import_node_url = require("url");
|
|
122
122
|
|
|
123
123
|
// src/normalize/claude.ts
|
|
@@ -783,9 +783,177 @@ function describeProblem(provider, problem) {
|
|
|
783
783
|
};
|
|
784
784
|
}
|
|
785
785
|
|
|
786
|
-
// src/engine/
|
|
786
|
+
// src/engine/binaries.ts
|
|
787
|
+
var import_node_child_process = require("child_process");
|
|
788
|
+
var import_node_fs = require("fs");
|
|
787
789
|
var import_node_os = __toESM(require("os"), 1);
|
|
788
790
|
var import_node_path = __toESM(require("path"), 1);
|
|
791
|
+
var SOURCE_LABEL = {
|
|
792
|
+
codex: { "desktop-app": "from ChatGPT app", path: "from PATH", "npm-global": "from npm", configured: "set by host" },
|
|
793
|
+
claude: { "desktop-app": "from Claude app", path: "from PATH", "npm-global": "from npm", configured: "set by host" }
|
|
794
|
+
};
|
|
795
|
+
function sourceLabel(provider, source) {
|
|
796
|
+
return SOURCE_LABEL[provider][source];
|
|
797
|
+
}
|
|
798
|
+
function parseVersion(text) {
|
|
799
|
+
const match = /(\d+)\.(\d+)\.(\d+)(?:[-.][0-9A-Za-z.]+)?/.exec(text ?? "");
|
|
800
|
+
return match ? match[0] : null;
|
|
801
|
+
}
|
|
802
|
+
function compareVersions(a, b) {
|
|
803
|
+
const [aCore = "", aPre] = a.split("-", 2);
|
|
804
|
+
const [bCore = "", bPre] = b.split("-", 2);
|
|
805
|
+
const pa = aCore.split(".").map((n) => Number.parseInt(n, 10) || 0);
|
|
806
|
+
const pb = bCore.split(".").map((n) => Number.parseInt(n, 10) || 0);
|
|
807
|
+
for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
|
|
808
|
+
const d = (pa[i] ?? 0) - (pb[i] ?? 0);
|
|
809
|
+
if (d !== 0) return d < 0 ? -1 : 1;
|
|
810
|
+
}
|
|
811
|
+
if (aPre && !bPre) return -1;
|
|
812
|
+
if (!aPre && bPre) return 1;
|
|
813
|
+
return 0;
|
|
814
|
+
}
|
|
815
|
+
function pickBinary(candidates) {
|
|
816
|
+
let best = null;
|
|
817
|
+
for (const c of candidates) {
|
|
818
|
+
if (!best) {
|
|
819
|
+
best = c;
|
|
820
|
+
continue;
|
|
821
|
+
}
|
|
822
|
+
if (c.version && (!best.version || compareVersions(c.version, best.version) > 0)) best = c;
|
|
823
|
+
}
|
|
824
|
+
return best;
|
|
825
|
+
}
|
|
826
|
+
function executable(file) {
|
|
827
|
+
try {
|
|
828
|
+
(0, import_node_fs.accessSync)(file, import_node_fs.constants.X_OK);
|
|
829
|
+
return true;
|
|
830
|
+
} catch {
|
|
831
|
+
return false;
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
function exeName(name, platform) {
|
|
835
|
+
return platform === "win32" ? [`${name}.exe`, `${name}.cmd`, name] : [name];
|
|
836
|
+
}
|
|
837
|
+
function allOnPath(name, pathValue, platform = process.platform) {
|
|
838
|
+
const found = [];
|
|
839
|
+
for (const dir of pathValue.split(import_node_path.default.delimiter)) {
|
|
840
|
+
if (!dir) continue;
|
|
841
|
+
for (const file of exeName(name, platform)) {
|
|
842
|
+
const candidate = import_node_path.default.join(dir, file);
|
|
843
|
+
if (executable(candidate)) {
|
|
844
|
+
found.push(candidate);
|
|
845
|
+
break;
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
return found;
|
|
850
|
+
}
|
|
851
|
+
function desktopAppCandidates(provider, platform, home, applications) {
|
|
852
|
+
if (platform !== "darwin") return [];
|
|
853
|
+
if (provider === "codex") {
|
|
854
|
+
return applications.map(
|
|
855
|
+
(apps) => import_node_path.default.join(apps, "ChatGPT.app", "Contents", "Resources", "codex-cli", "bin", "codex")
|
|
856
|
+
);
|
|
857
|
+
}
|
|
858
|
+
const root = import_node_path.default.join(home, "Library", "Application Support", "Claude", "claude-code");
|
|
859
|
+
let versions = [];
|
|
860
|
+
try {
|
|
861
|
+
versions = (0, import_node_fs.readdirSync)(root);
|
|
862
|
+
} catch {
|
|
863
|
+
return [];
|
|
864
|
+
}
|
|
865
|
+
return versions.map((v) => import_node_path.default.join(root, v, "claude.app", "Contents", "MacOS", "claude"));
|
|
866
|
+
}
|
|
867
|
+
function npmGlobalPrefix(env) {
|
|
868
|
+
const fromEnv = env.npm_config_prefix ?? env.NPM_CONFIG_PREFIX;
|
|
869
|
+
if (fromEnv) return Promise.resolve(fromEnv);
|
|
870
|
+
const npm = allOnPath("npm", env.PATH ?? "")[0];
|
|
871
|
+
if (!npm) return Promise.resolve(null);
|
|
872
|
+
return new Promise((resolve) => {
|
|
873
|
+
const child = (0, import_node_child_process.execFile)(npm, ["prefix", "-g"], { timeout: 5e3, env }, (error, stdout) => {
|
|
874
|
+
resolve(error ? null : String(stdout).trim() || null);
|
|
875
|
+
});
|
|
876
|
+
child.stdin?.end();
|
|
877
|
+
});
|
|
878
|
+
}
|
|
879
|
+
function declaredVersion(provider, source, file) {
|
|
880
|
+
if (source !== "desktop-app") return null;
|
|
881
|
+
if (provider === "codex") {
|
|
882
|
+
try {
|
|
883
|
+
const pkg = JSON.parse((0, import_node_fs.readFileSync)(import_node_path.default.join(import_node_path.default.dirname(import_node_path.default.dirname(file)), "codex-package.json"), "utf8"));
|
|
884
|
+
return typeof pkg.version === "string" ? parseVersion(pkg.version) : null;
|
|
885
|
+
} catch {
|
|
886
|
+
return null;
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
return parseVersion(import_node_path.default.basename(import_node_path.default.resolve(file, "..", "..", "..", "..")));
|
|
890
|
+
}
|
|
891
|
+
function runVersion(file, env) {
|
|
892
|
+
return new Promise((resolve) => {
|
|
893
|
+
const child = (0, import_node_child_process.execFile)(file, ["--version"], { timeout: 8e3, env }, (error, stdout) => {
|
|
894
|
+
resolve(error ? null : parseVersion(String(stdout)));
|
|
895
|
+
});
|
|
896
|
+
child.stdin?.end();
|
|
897
|
+
});
|
|
898
|
+
}
|
|
899
|
+
async function discoverBinaries(provider, options) {
|
|
900
|
+
const platform = options.platform ?? process.platform;
|
|
901
|
+
const home = options.home ?? options.env.HOME ?? import_node_os.default.homedir();
|
|
902
|
+
const listed2 = [
|
|
903
|
+
...desktopAppCandidates(provider, platform, home, options.applications ?? ["/Applications", import_node_path.default.join(home, "Applications")]).filter(executable).map((p) => ({ path: p, source: "desktop-app" })),
|
|
904
|
+
...allOnPath(provider, options.env.PATH ?? "", platform).map((p) => ({ path: p, source: "path" }))
|
|
905
|
+
];
|
|
906
|
+
const prefix = await npmGlobalPrefix(options.env);
|
|
907
|
+
if (prefix) {
|
|
908
|
+
const dir = platform === "win32" ? prefix : import_node_path.default.join(prefix, "bin");
|
|
909
|
+
for (const file of exeName(provider, platform)) {
|
|
910
|
+
const candidate = import_node_path.default.join(dir, file);
|
|
911
|
+
if (executable(candidate)) {
|
|
912
|
+
listed2.push({ path: candidate, source: "npm-global" });
|
|
913
|
+
break;
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
const seen = /* @__PURE__ */ new Set();
|
|
918
|
+
const unique = listed2.filter((c) => {
|
|
919
|
+
let real = c.path;
|
|
920
|
+
try {
|
|
921
|
+
real = (0, import_node_fs.realpathSync)(c.path);
|
|
922
|
+
} catch {
|
|
923
|
+
}
|
|
924
|
+
if (seen.has(real)) return false;
|
|
925
|
+
seen.add(real);
|
|
926
|
+
return true;
|
|
927
|
+
});
|
|
928
|
+
return Promise.all(
|
|
929
|
+
unique.map(async (c) => ({
|
|
930
|
+
...c,
|
|
931
|
+
version: declaredVersion(provider, c.source, c.path) ?? await runVersion(c.path, options.env)
|
|
932
|
+
}))
|
|
933
|
+
);
|
|
934
|
+
}
|
|
935
|
+
async function resolveBinary(provider, options) {
|
|
936
|
+
const candidates = options.discover === false ? [] : await discoverBinaries(provider, options);
|
|
937
|
+
const best = pickBinary(candidates);
|
|
938
|
+
const inUse = options.forced ? {
|
|
939
|
+
path: options.forced,
|
|
940
|
+
source: "configured",
|
|
941
|
+
version: candidates.find((c) => c.path === options.forced)?.version ?? (options.discover === false ? null : await runVersion(options.forced, options.env))
|
|
942
|
+
} : best;
|
|
943
|
+
if (!inUse) return null;
|
|
944
|
+
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;
|
|
945
|
+
return {
|
|
946
|
+
path: inUse.path,
|
|
947
|
+
version: inUse.version,
|
|
948
|
+
source: inUse.source,
|
|
949
|
+
sourceLabel: sourceLabel(provider, inUse.source),
|
|
950
|
+
newer
|
|
951
|
+
};
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
// src/engine/clean-env.ts
|
|
955
|
+
var import_node_os2 = __toESM(require("os"), 1);
|
|
956
|
+
var import_node_path2 = __toESM(require("path"), 1);
|
|
789
957
|
var ALLOWED_NAMES = /* @__PURE__ */ new Set([
|
|
790
958
|
"HOME",
|
|
791
959
|
"USER",
|
|
@@ -807,11 +975,11 @@ var ALLOWED_NAMES = /* @__PURE__ */ new Set([
|
|
|
807
975
|
var ALLOWED_PREFIXES = ["LC_"];
|
|
808
976
|
function wellKnownBinDirs(home) {
|
|
809
977
|
return [
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
978
|
+
import_node_path2.default.join(home, ".local", "bin"),
|
|
979
|
+
import_node_path2.default.join(home, ".claude", "local"),
|
|
980
|
+
import_node_path2.default.join(home, ".npm-global", "bin"),
|
|
981
|
+
import_node_path2.default.join(home, ".bun", "bin"),
|
|
982
|
+
import_node_path2.default.join(home, ".volta", "bin"),
|
|
815
983
|
"/opt/homebrew/bin",
|
|
816
984
|
"/usr/local/bin",
|
|
817
985
|
"/usr/bin",
|
|
@@ -829,31 +997,31 @@ function buildCleanEnv(hostEnv, extra = {}) {
|
|
|
829
997
|
if (typeof value !== "string") continue;
|
|
830
998
|
if (isAllowedEnvName(name)) out[name] = value;
|
|
831
999
|
}
|
|
832
|
-
const home = out.HOME ??
|
|
1000
|
+
const home = out.HOME ?? import_node_os2.default.homedir();
|
|
833
1001
|
out.HOME = home;
|
|
834
|
-
const hostPath = (hostEnv.PATH ?? "").split(
|
|
1002
|
+
const hostPath = (hostEnv.PATH ?? "").split(import_node_path2.default.delimiter).filter(Boolean);
|
|
835
1003
|
const merged = [];
|
|
836
1004
|
for (const dir of [...hostPath, ...wellKnownBinDirs(home)]) {
|
|
837
1005
|
if (!merged.includes(dir)) merged.push(dir);
|
|
838
1006
|
}
|
|
839
|
-
out.PATH = merged.join(
|
|
1007
|
+
out.PATH = merged.join(import_node_path2.default.delimiter);
|
|
840
1008
|
for (const [name, value] of Object.entries(extra)) out[name] = value;
|
|
841
1009
|
return out;
|
|
842
1010
|
}
|
|
843
1011
|
|
|
844
1012
|
// src/engine/files.ts
|
|
845
|
-
var
|
|
1013
|
+
var import_node_fs2 = require("fs");
|
|
846
1014
|
var import_promises2 = __toESM(require("fs/promises"), 1);
|
|
847
|
-
var
|
|
848
|
-
var
|
|
1015
|
+
var import_node_os3 = __toESM(require("os"), 1);
|
|
1016
|
+
var import_node_path3 = __toESM(require("path"), 1);
|
|
849
1017
|
|
|
850
1018
|
// src/engine/activity.ts
|
|
851
|
-
var
|
|
1019
|
+
var import_node_child_process2 = require("child_process");
|
|
852
1020
|
var RECENT_WRITE_MS = 2 * 60 * 1e3;
|
|
853
1021
|
var OPEN_TOOL_WINDOW_MS = 15 * 60 * 1e3;
|
|
854
1022
|
function listProcesses() {
|
|
855
1023
|
return new Promise((resolve) => {
|
|
856
|
-
(0,
|
|
1024
|
+
(0, import_node_child_process2.execFile)("ps", ["-axww", "-o", "pid=,args="], { maxBuffer: 64 * 1024 * 1024, timeout: 5e3 }, (error, stdout) => {
|
|
857
1025
|
if (error) {
|
|
858
1026
|
resolve([]);
|
|
859
1027
|
return;
|
|
@@ -912,11 +1080,11 @@ function describeActivity(input) {
|
|
|
912
1080
|
}
|
|
913
1081
|
|
|
914
1082
|
// src/engine/files.ts
|
|
915
|
-
function defaultProviderHomes(home =
|
|
1083
|
+
function defaultProviderHomes(home = import_node_os3.default.homedir()) {
|
|
916
1084
|
return {
|
|
917
|
-
claudeProjects:
|
|
918
|
-
codexSessions:
|
|
919
|
-
codexIndex:
|
|
1085
|
+
claudeProjects: import_node_path3.default.join(home, ".claude", "projects"),
|
|
1086
|
+
codexSessions: import_node_path3.default.join(home, ".codex", "sessions"),
|
|
1087
|
+
codexIndex: import_node_path3.default.join(home, ".codex", "session_index.jsonl")
|
|
920
1088
|
};
|
|
921
1089
|
}
|
|
922
1090
|
var UUIDISH = /([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\.jsonl$/i;
|
|
@@ -941,10 +1109,10 @@ async function claudeCandidates(root) {
|
|
|
941
1109
|
const out = [];
|
|
942
1110
|
for (const project of await safeReaddir(root)) {
|
|
943
1111
|
if (!project.isDirectory()) continue;
|
|
944
|
-
const dir =
|
|
1112
|
+
const dir = import_node_path3.default.join(root, project.name);
|
|
945
1113
|
const entries = await safeReaddir(dir);
|
|
946
1114
|
const stats = await Promise.all(
|
|
947
|
-
entries.filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => statCandidate("claude",
|
|
1115
|
+
entries.filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => statCandidate("claude", import_node_path3.default.join(dir, e.name)))
|
|
948
1116
|
);
|
|
949
1117
|
for (const s of stats) if (s) out.push(s);
|
|
950
1118
|
}
|
|
@@ -954,14 +1122,14 @@ async function codexCandidates(root) {
|
|
|
954
1122
|
const out = [];
|
|
955
1123
|
for (const year of await safeReaddir(root)) {
|
|
956
1124
|
if (!year.isDirectory()) continue;
|
|
957
|
-
for (const month of await safeReaddir(
|
|
1125
|
+
for (const month of await safeReaddir(import_node_path3.default.join(root, year.name))) {
|
|
958
1126
|
if (!month.isDirectory()) continue;
|
|
959
|
-
for (const day of await safeReaddir(
|
|
1127
|
+
for (const day of await safeReaddir(import_node_path3.default.join(root, year.name, month.name))) {
|
|
960
1128
|
if (!day.isDirectory()) continue;
|
|
961
|
-
const dir =
|
|
1129
|
+
const dir = import_node_path3.default.join(root, year.name, month.name, day.name);
|
|
962
1130
|
const entries = await safeReaddir(dir);
|
|
963
1131
|
const stats = await Promise.all(
|
|
964
|
-
entries.filter((e) => e.isFile() && e.name.startsWith("rollout-") && e.name.endsWith(".jsonl")).map((e) => statCandidate("codex",
|
|
1132
|
+
entries.filter((e) => e.isFile() && e.name.startsWith("rollout-") && e.name.endsWith(".jsonl")).map((e) => statCandidate("codex", import_node_path3.default.join(dir, e.name)))
|
|
965
1133
|
);
|
|
966
1134
|
for (const s of stats) if (s) out.push(s);
|
|
967
1135
|
}
|
|
@@ -1182,7 +1350,7 @@ async function readSessionFile(provider, file, endOffset, maxBytes = HISTORY_BUD
|
|
|
1182
1350
|
let droppedFirst = start > 0;
|
|
1183
1351
|
let carry = "";
|
|
1184
1352
|
await new Promise((resolve, reject) => {
|
|
1185
|
-
const stream = (0,
|
|
1353
|
+
const stream = (0, import_node_fs2.createReadStream)(file, { start, end: Math.max(start, end - 1), encoding: "utf8" });
|
|
1186
1354
|
stream.on("data", (chunk) => {
|
|
1187
1355
|
const text = carry + String(chunk);
|
|
1188
1356
|
const lines = text.split("\n");
|
|
@@ -1222,7 +1390,7 @@ async function describeSessionFile(candidate, codexNames) {
|
|
|
1222
1390
|
// src/engine/preferences.ts
|
|
1223
1391
|
var import_node_crypto2 = require("crypto");
|
|
1224
1392
|
var import_promises3 = __toESM(require("fs/promises"), 1);
|
|
1225
|
-
var
|
|
1393
|
+
var import_node_path4 = __toESM(require("path"), 1);
|
|
1226
1394
|
var PreferenceStore = class {
|
|
1227
1395
|
constructor(dir) {
|
|
1228
1396
|
this.dir = dir;
|
|
@@ -1231,7 +1399,7 @@ var PreferenceStore = class {
|
|
|
1231
1399
|
data = {};
|
|
1232
1400
|
writing = Promise.resolve();
|
|
1233
1401
|
get file() {
|
|
1234
|
-
return
|
|
1402
|
+
return import_node_path4.default.join(this.dir, "preferences.json");
|
|
1235
1403
|
}
|
|
1236
1404
|
async load() {
|
|
1237
1405
|
try {
|
|
@@ -1286,7 +1454,7 @@ var PreferenceStore = class {
|
|
|
1286
1454
|
};
|
|
1287
1455
|
|
|
1288
1456
|
// src/engine/search.ts
|
|
1289
|
-
var
|
|
1457
|
+
var import_node_fs3 = require("fs");
|
|
1290
1458
|
function findInLine(provider, value, needle) {
|
|
1291
1459
|
const items = provider === "claude" ? createClaudeNormalizer().push(value) : createCodexRolloutNormalizer().push(value);
|
|
1292
1460
|
for (const item of items) {
|
|
@@ -1327,7 +1495,7 @@ async function scanFile(provider, file, needle, raw, deadline) {
|
|
|
1327
1495
|
return new Promise((resolve) => {
|
|
1328
1496
|
let carry = Buffer.alloc(0);
|
|
1329
1497
|
let done = false;
|
|
1330
|
-
const stream = (0,
|
|
1498
|
+
const stream = (0, import_node_fs3.createReadStream)(file, { highWaterMark: 4 * 1024 * 1024 });
|
|
1331
1499
|
const finish = (value) => {
|
|
1332
1500
|
if (done) return;
|
|
1333
1501
|
done = true;
|
|
@@ -1435,7 +1603,7 @@ async function searchLocalChats(query, options = {}) {
|
|
|
1435
1603
|
// src/engine/store.ts
|
|
1436
1604
|
var import_node_crypto3 = require("crypto");
|
|
1437
1605
|
var import_promises4 = __toESM(require("fs/promises"), 1);
|
|
1438
|
-
var
|
|
1606
|
+
var import_node_path5 = __toESM(require("path"), 1);
|
|
1439
1607
|
var MAX_RUNS = 2e3;
|
|
1440
1608
|
var RunIndex = class {
|
|
1441
1609
|
constructor(dir) {
|
|
@@ -1445,7 +1613,7 @@ var RunIndex = class {
|
|
|
1445
1613
|
data = { version: 1, sessions: [], runs: [] };
|
|
1446
1614
|
writing = Promise.resolve();
|
|
1447
1615
|
get file() {
|
|
1448
|
-
return
|
|
1616
|
+
return import_node_path5.default.join(this.dir, "index.json");
|
|
1449
1617
|
}
|
|
1450
1618
|
async load() {
|
|
1451
1619
|
await import_promises4.default.mkdir(this.dir, { recursive: true });
|
|
@@ -1504,7 +1672,7 @@ var RunIndex = class {
|
|
|
1504
1672
|
/** A stable Paperclip agent/company identity for this install, so the
|
|
1505
1673
|
* driver's scratch state is reused rather than growing per run. */
|
|
1506
1674
|
async identity() {
|
|
1507
|
-
const file =
|
|
1675
|
+
const file = import_node_path5.default.join(this.dir, "identity.json");
|
|
1508
1676
|
try {
|
|
1509
1677
|
const parsed = JSON.parse(await import_promises4.default.readFile(file, "utf8"));
|
|
1510
1678
|
if (typeof parsed.companyId === "string" && typeof parsed.agentId === "string") {
|
|
@@ -1520,8 +1688,8 @@ var RunIndex = class {
|
|
|
1520
1688
|
|
|
1521
1689
|
// src/engine/user-defaults.ts
|
|
1522
1690
|
var import_promises5 = __toESM(require("fs/promises"), 1);
|
|
1523
|
-
var
|
|
1524
|
-
var
|
|
1691
|
+
var import_node_os4 = __toESM(require("os"), 1);
|
|
1692
|
+
var import_node_path6 = __toESM(require("path"), 1);
|
|
1525
1693
|
async function readJson(file) {
|
|
1526
1694
|
try {
|
|
1527
1695
|
const parsed = JSON.parse(await import_promises5.default.readFile(file, "utf8"));
|
|
@@ -1533,10 +1701,10 @@ async function readJson(file) {
|
|
|
1533
1701
|
function str3(value) {
|
|
1534
1702
|
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
1535
1703
|
}
|
|
1536
|
-
async function claudeDefaults(cwd, home =
|
|
1704
|
+
async function claudeDefaults(cwd, home = import_node_os4.default.homedir()) {
|
|
1537
1705
|
const files = [
|
|
1538
|
-
...cwd ? [
|
|
1539
|
-
|
|
1706
|
+
...cwd ? [import_node_path6.default.join(cwd, ".claude", "settings.local.json"), import_node_path6.default.join(cwd, ".claude", "settings.json")] : [],
|
|
1707
|
+
import_node_path6.default.join(home, ".claude", "settings.json")
|
|
1540
1708
|
];
|
|
1541
1709
|
let model = null;
|
|
1542
1710
|
let effort = null;
|
|
@@ -1549,10 +1717,10 @@ async function claudeDefaults(cwd, home = import_node_os3.default.homedir()) {
|
|
|
1549
1717
|
}
|
|
1550
1718
|
return { model, effort };
|
|
1551
1719
|
}
|
|
1552
|
-
async function codexDefaults(home =
|
|
1720
|
+
async function codexDefaults(home = import_node_os4.default.homedir()) {
|
|
1553
1721
|
let text;
|
|
1554
1722
|
try {
|
|
1555
|
-
text = await import_promises5.default.readFile(
|
|
1723
|
+
text = await import_promises5.default.readFile(import_node_path6.default.join(home, ".codex", "config.toml"), "utf8");
|
|
1556
1724
|
} catch {
|
|
1557
1725
|
return { model: null, effort: null };
|
|
1558
1726
|
}
|
|
@@ -1576,45 +1744,33 @@ var EFFORT_LEVELS = {
|
|
|
1576
1744
|
// src/engine/index.ts
|
|
1577
1745
|
var RAW_TRANSCRIPT_MAX_BYTES = 200 * 1048576;
|
|
1578
1746
|
function moduleDir() {
|
|
1579
|
-
return
|
|
1747
|
+
return import_node_path7.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl));
|
|
1580
1748
|
}
|
|
1581
1749
|
function resolveWorkerPath() {
|
|
1582
1750
|
const dir = moduleDir();
|
|
1583
1751
|
for (const candidate of [
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1752
|
+
import_node_path7.default.join(dir, "worker.js"),
|
|
1753
|
+
import_node_path7.default.join(dir, "worker.ts"),
|
|
1754
|
+
import_node_path7.default.join(dir, "..", "engine", "worker.js"),
|
|
1755
|
+
import_node_path7.default.join(dir, "..", "engine", "worker.ts")
|
|
1588
1756
|
]) {
|
|
1589
|
-
if ((0,
|
|
1757
|
+
if ((0, import_node_fs4.existsSync)(candidate)) return candidate;
|
|
1590
1758
|
}
|
|
1591
1759
|
throw new Error(`[coding-sessions] The driver worker is missing next to ${dir}.`);
|
|
1592
1760
|
}
|
|
1593
1761
|
async function installShim(dataDir) {
|
|
1594
|
-
const source =
|
|
1595
|
-
if (!(0,
|
|
1762
|
+
const source = import_node_path7.default.resolve(moduleDir(), "..", "..", "bin", "cli-shim.sh");
|
|
1763
|
+
if (!(0, import_node_fs4.existsSync)(source)) throw new Error(`[coding-sessions] The CLI shim is missing at ${source}.`);
|
|
1596
1764
|
const body = await import_promises6.default.readFile(source, "utf8");
|
|
1597
|
-
const target =
|
|
1765
|
+
const target = import_node_path7.default.join(dataDir, "bin", "cli-shim.sh");
|
|
1598
1766
|
const current = await import_promises6.default.readFile(target, "utf8").catch(() => null);
|
|
1599
1767
|
if (current !== body) {
|
|
1600
|
-
await import_promises6.default.mkdir(
|
|
1768
|
+
await import_promises6.default.mkdir(import_node_path7.default.dirname(target), { recursive: true });
|
|
1601
1769
|
await import_promises6.default.writeFile(target, body, { mode: 493 });
|
|
1602
1770
|
}
|
|
1603
1771
|
await import_promises6.default.chmod(target, 493);
|
|
1604
1772
|
return target;
|
|
1605
1773
|
}
|
|
1606
|
-
function whichOnPath(name, pathValue) {
|
|
1607
|
-
for (const dir of pathValue.split(import_node_path6.default.delimiter)) {
|
|
1608
|
-
if (!dir) continue;
|
|
1609
|
-
const candidate = import_node_path6.default.join(dir, name);
|
|
1610
|
-
try {
|
|
1611
|
-
(0, import_node_fs3.accessSync)(candidate, import_node_fs3.constants.X_OK);
|
|
1612
|
-
return candidate;
|
|
1613
|
-
} catch {
|
|
1614
|
-
}
|
|
1615
|
-
}
|
|
1616
|
-
return null;
|
|
1617
|
-
}
|
|
1618
1774
|
function nowIso() {
|
|
1619
1775
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
1620
1776
|
}
|
|
@@ -1653,12 +1809,14 @@ function describeProviderStatus(provider, probe, lastProblem = null, quota = [])
|
|
|
1653
1809
|
function describeAuthStatus(provider, probe) {
|
|
1654
1810
|
const label = PROVIDER_LABEL[provider];
|
|
1655
1811
|
const installed = probe?.installed === true;
|
|
1656
|
-
const
|
|
1812
|
+
const binary = probe?.binary ?? null;
|
|
1813
|
+
const version = binary?.version ?? (typeof probe?.version === "string" ? probe.version : null);
|
|
1657
1814
|
const base = {
|
|
1658
1815
|
provider,
|
|
1659
1816
|
label,
|
|
1660
1817
|
installed,
|
|
1661
1818
|
version,
|
|
1819
|
+
binary,
|
|
1662
1820
|
loggedIn: false,
|
|
1663
1821
|
billing: "unknown",
|
|
1664
1822
|
plan: null,
|
|
@@ -1710,8 +1868,8 @@ function describeAuthStatus(provider, probe) {
|
|
|
1710
1868
|
};
|
|
1711
1869
|
}
|
|
1712
1870
|
async function createCodingSessionsEngine(options = {}) {
|
|
1713
|
-
const dataDir = options.dataDir ??
|
|
1714
|
-
const stateDir =
|
|
1871
|
+
const dataDir = options.dataDir ?? import_node_path7.default.join(import_node_os5.default.homedir(), ".matrx", "coding-sessions");
|
|
1872
|
+
const stateDir = import_node_path7.default.join(dataDir, "paperclip-state");
|
|
1715
1873
|
const homes = options.homes ?? defaultProviderHomes();
|
|
1716
1874
|
const index = new RunIndex(dataDir);
|
|
1717
1875
|
await index.load();
|
|
@@ -1725,7 +1883,7 @@ async function createCodingSessionsEngine(options = {}) {
|
|
|
1725
1883
|
onError: (error) => console.warn("[coding-sessions] raw transcript backup failed:", error)
|
|
1726
1884
|
}) : null;
|
|
1727
1885
|
const discoveredSeen = /* @__PURE__ */ new Map();
|
|
1728
|
-
const healthFile =
|
|
1886
|
+
const healthFile = import_node_path7.default.join(dataDir, "provider-health.json");
|
|
1729
1887
|
let health = {};
|
|
1730
1888
|
try {
|
|
1731
1889
|
health = JSON.parse(await import_promises6.default.readFile(healthFile, "utf8"));
|
|
@@ -1760,7 +1918,24 @@ async function createCodingSessionsEngine(options = {}) {
|
|
|
1760
1918
|
// Marks the forked process as a driver worker (see worker.ts).
|
|
1761
1919
|
MATRX_CODING_SESSIONS_WORKER: "1"
|
|
1762
1920
|
});
|
|
1763
|
-
const
|
|
1921
|
+
const binaryHome = options.hostEnv?.HOME ?? import_node_os5.default.homedir();
|
|
1922
|
+
const binaryCache = /* @__PURE__ */ new Map();
|
|
1923
|
+
function binaryFor(provider, fresh = false) {
|
|
1924
|
+
const cached = binaryCache.get(provider);
|
|
1925
|
+
if (cached && !fresh && Date.now() - cached.at < 5 * 6e4) return cached.value;
|
|
1926
|
+
const forced = options.commands?.[provider];
|
|
1927
|
+
const value = resolveBinary(provider, {
|
|
1928
|
+
env: workerEnv,
|
|
1929
|
+
home: binaryHome,
|
|
1930
|
+
forced,
|
|
1931
|
+
// A forced command needs no discovery to run; the status check still
|
|
1932
|
+
// looks, so it can say when a newer copy exists.
|
|
1933
|
+
discover: !forced || fresh
|
|
1934
|
+
}).catch(() => forced ? { path: forced, version: null, source: "configured", sourceLabel: "set by host", newer: null } : null);
|
|
1935
|
+
if (!forced || !fresh) binaryCache.set(provider, { at: Date.now(), value });
|
|
1936
|
+
return value;
|
|
1937
|
+
}
|
|
1938
|
+
const commandFor = async (provider) => (await binaryFor(provider))?.path ?? null;
|
|
1764
1939
|
const workerPath = resolveWorkerPath();
|
|
1765
1940
|
const shimPath = await installShim(dataDir);
|
|
1766
1941
|
const listeners = /* @__PURE__ */ new Set();
|
|
@@ -1810,7 +1985,7 @@ async function createCodingSessionsEngine(options = {}) {
|
|
|
1810
1985
|
}
|
|
1811
1986
|
}
|
|
1812
1987
|
function forkWorker() {
|
|
1813
|
-
return (0,
|
|
1988
|
+
return (0, import_node_child_process3.fork)(workerPath, [], {
|
|
1814
1989
|
env: workerEnv,
|
|
1815
1990
|
cwd: dataDir,
|
|
1816
1991
|
stdio: ["ignore", "pipe", "pipe", "ipc"],
|
|
@@ -1831,7 +2006,7 @@ async function createCodingSessionsEngine(options = {}) {
|
|
|
1831
2006
|
}
|
|
1832
2007
|
async function startRun(session, prompt) {
|
|
1833
2008
|
const provider = session.provider;
|
|
1834
|
-
const realCommand = commandFor(provider);
|
|
2009
|
+
const realCommand = await commandFor(provider);
|
|
1835
2010
|
const runId = (0, import_node_crypto4.randomUUID)();
|
|
1836
2011
|
const model = session.model ?? (provider === "claude" ? (await userDefaults(provider, session.cwd)).model ?? null : null);
|
|
1837
2012
|
const run = {
|
|
@@ -2063,7 +2238,7 @@ async function createCodingSessionsEngine(options = {}) {
|
|
|
2063
2238
|
}, 3e3);
|
|
2064
2239
|
}
|
|
2065
2240
|
async function pruneDriverScratch() {
|
|
2066
|
-
const runsDir =
|
|
2241
|
+
const runsDir = import_node_path7.default.join(
|
|
2067
2242
|
stateDir,
|
|
2068
2243
|
"instances",
|
|
2069
2244
|
"default",
|
|
@@ -2076,10 +2251,11 @@ async function createCodingSessionsEngine(options = {}) {
|
|
|
2076
2251
|
);
|
|
2077
2252
|
const entries = await import_promises6.default.readdir(runsDir).catch(() => []);
|
|
2078
2253
|
await Promise.all(
|
|
2079
|
-
entries.filter((name) => !live.has(name)).map((name) => import_promises6.default.rm(
|
|
2254
|
+
entries.filter((name) => !live.has(name)).map((name) => import_promises6.default.rm(import_node_path7.default.join(runsDir, name), { recursive: true, force: true }).catch(() => void 0))
|
|
2080
2255
|
);
|
|
2081
2256
|
}
|
|
2082
2257
|
async function probe() {
|
|
2258
|
+
const [claudeBinary, codexBinary] = await Promise.all([binaryFor("claude", true), binaryFor("codex", true)]);
|
|
2083
2259
|
return new Promise((resolve) => {
|
|
2084
2260
|
const child = forkWorker();
|
|
2085
2261
|
let answered = false;
|
|
@@ -2095,8 +2271,8 @@ async function createCodingSessionsEngine(options = {}) {
|
|
|
2095
2271
|
answered = true;
|
|
2096
2272
|
clearTimeout(timer);
|
|
2097
2273
|
resolve({
|
|
2098
|
-
claude: message.claude ?? {},
|
|
2099
|
-
codex: message.codex ?? {}
|
|
2274
|
+
claude: { ...message.claude ?? {}, binary: claudeBinary },
|
|
2275
|
+
codex: { ...message.codex ?? {}, binary: codexBinary }
|
|
2100
2276
|
});
|
|
2101
2277
|
}
|
|
2102
2278
|
});
|
|
@@ -2108,7 +2284,7 @@ async function createCodingSessionsEngine(options = {}) {
|
|
|
2108
2284
|
});
|
|
2109
2285
|
child.send({
|
|
2110
2286
|
kind: "probe",
|
|
2111
|
-
commands: { claude:
|
|
2287
|
+
commands: { claude: claudeBinary?.path ?? null, codex: codexBinary?.path ?? null },
|
|
2112
2288
|
quota: options.quota !== false
|
|
2113
2289
|
});
|
|
2114
2290
|
});
|
|
@@ -2134,7 +2310,7 @@ async function createCodingSessionsEngine(options = {}) {
|
|
|
2134
2310
|
function resolveFolder(raw) {
|
|
2135
2311
|
const trimmed = raw.trim();
|
|
2136
2312
|
if (!trimmed) return null;
|
|
2137
|
-
return
|
|
2313
|
+
return import_node_path7.default.resolve(trimmed.replace(/^~(?=$|\/)/, import_node_os5.default.homedir()));
|
|
2138
2314
|
}
|
|
2139
2315
|
async function checkFolder(raw) {
|
|
2140
2316
|
const target = resolveFolder(raw);
|
|
@@ -2143,7 +2319,7 @@ async function createCodingSessionsEngine(options = {}) {
|
|
|
2143
2319
|
return { path: target, exists: stat !== null, isDirectory: stat?.isDirectory() === true };
|
|
2144
2320
|
}
|
|
2145
2321
|
async function assertFolder(cwd) {
|
|
2146
|
-
const resolved =
|
|
2322
|
+
const resolved = import_node_path7.default.resolve(cwd.replace(/^~(?=$|\/)/, import_node_os5.default.homedir()));
|
|
2147
2323
|
const stat = await import_promises6.default.stat(resolved).catch(() => null);
|
|
2148
2324
|
if (!stat?.isDirectory()) {
|
|
2149
2325
|
throw new Error(`The folder ${resolved} doesn't exist on this computer.`);
|
|
@@ -2297,7 +2473,7 @@ async function createCodingSessionsEngine(options = {}) {
|
|
|
2297
2473
|
};
|
|
2298
2474
|
}
|
|
2299
2475
|
const content = await import_promises6.default.readFile(file, "utf8");
|
|
2300
|
-
return { available: true, fileName:
|
|
2476
|
+
return { available: true, fileName: import_node_path7.default.basename(file), bytes: stat.size, content };
|
|
2301
2477
|
},
|
|
2302
2478
|
async start(input) {
|
|
2303
2479
|
const prompt = input.prompt.trim();
|
|
@@ -2418,7 +2594,7 @@ function openFolderIn(folder, target) {
|
|
|
2418
2594
|
args = ["-a", app.app, folder];
|
|
2419
2595
|
}
|
|
2420
2596
|
return new Promise((resolve, reject) => {
|
|
2421
|
-
(0,
|
|
2597
|
+
(0, import_node_child_process3.execFile)(command, args, { timeout: 1e4 }, (error) => {
|
|
2422
2598
|
if (!error) return resolve();
|
|
2423
2599
|
const label = target === "finder" ? "the folder" : OPEN_APP[target]?.label ?? target;
|
|
2424
2600
|
reject(
|
|
@@ -2495,14 +2671,14 @@ var MIME = {
|
|
|
2495
2671
|
".map": "application/json"
|
|
2496
2672
|
};
|
|
2497
2673
|
function moduleDir2() {
|
|
2498
|
-
return
|
|
2674
|
+
return import_node_path8.default.dirname((0, import_node_url2.fileURLToPath)(importMetaUrl));
|
|
2499
2675
|
}
|
|
2500
2676
|
function defaultUiDir() {
|
|
2501
2677
|
for (const candidate of [
|
|
2502
|
-
|
|
2503
|
-
|
|
2678
|
+
import_node_path8.default.resolve(moduleDir2(), "..", "ui"),
|
|
2679
|
+
import_node_path8.default.resolve(moduleDir2(), "..", "..", "dist", "ui")
|
|
2504
2680
|
]) {
|
|
2505
|
-
if ((0,
|
|
2681
|
+
if ((0, import_node_fs5.existsSync)(import_node_path8.default.join(candidate, "index.html"))) return candidate;
|
|
2506
2682
|
}
|
|
2507
2683
|
return null;
|
|
2508
2684
|
}
|
|
@@ -2525,19 +2701,19 @@ async function serveStatic(uiDir, req, res) {
|
|
|
2525
2701
|
return;
|
|
2526
2702
|
}
|
|
2527
2703
|
const requested = decodeURIComponent(url.pathname);
|
|
2528
|
-
let file =
|
|
2704
|
+
let file = import_node_path8.default.resolve(uiDir, `.${requested}`);
|
|
2529
2705
|
if (!file.startsWith(uiDir)) {
|
|
2530
2706
|
res.writeHead(403).end();
|
|
2531
2707
|
return;
|
|
2532
2708
|
}
|
|
2533
2709
|
const stat = await import_promises7.default.stat(file).catch(() => null);
|
|
2534
|
-
if (!stat || stat.isDirectory()) file =
|
|
2710
|
+
if (!stat || stat.isDirectory()) file = import_node_path8.default.join(uiDir, "index.html");
|
|
2535
2711
|
const body = await import_promises7.default.readFile(file).catch(() => null);
|
|
2536
2712
|
if (!body) {
|
|
2537
2713
|
res.writeHead(404).end();
|
|
2538
2714
|
return;
|
|
2539
2715
|
}
|
|
2540
|
-
const ext =
|
|
2716
|
+
const ext = import_node_path8.default.extname(file);
|
|
2541
2717
|
res.writeHead(200, {
|
|
2542
2718
|
"content-type": MIME[ext] ?? "application/octet-stream",
|
|
2543
2719
|
"cache-control": ext === ".html" ? "no-store" : "public, max-age=31536000, immutable",
|