@ai-matrx/coding-sessions 0.1.80 → 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 +18 -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 +3 -3
- package/dist/ui/assets/index-B3Ic2ziA.js +0 -69
- package/dist/ui/assets/index-BAkpc01s.css +0 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# @ai-matrx/coding-sessions
|
|
2
2
|
|
|
3
|
+
## 0.1.83
|
|
4
|
+
|
|
5
|
+
Automatic changed-only republish (docs/metadata drift since the last tag — see
|
|
6
|
+
`git diff npm/coding-sessions/v0.1.81..npm/coding-sessions/v0.1.83 -- apps/shared/coding-sessions`).
|
|
7
|
+
No source changes intended and no consumer action required.
|
|
8
|
+
|
|
9
|
+
## 0.1.82
|
|
10
|
+
|
|
11
|
+
Automatic changed-only republish (docs/metadata drift since the last tag — see
|
|
12
|
+
`git diff npm/coding-sessions/v0.1.81..npm/coding-sessions/v0.1.82 -- apps/shared/coding-sessions`).
|
|
13
|
+
No source changes intended and no consumer action required.
|
|
14
|
+
|
|
15
|
+
## 0.1.81
|
|
16
|
+
|
|
17
|
+
Automatic changed-only republish (docs/metadata drift since the last tag — see
|
|
18
|
+
`git diff npm/coding-sessions/v0.1.80..npm/coding-sessions/v0.1.81 -- apps/shared/coding-sessions`).
|
|
19
|
+
No source changes intended and no consumer action required.
|
|
20
|
+
|
|
3
21
|
## 0.1.80
|
|
4
22
|
|
|
5
23
|
Automatic changed-only republish (docs/metadata drift since the last tag — see
|
package/dist/engine/index.cjs
CHANGED
|
@@ -60,9 +60,9 @@ var getImportMetaUrl = () => typeof document === "undefined" ? new URL(`file:${_
|
|
|
60
60
|
var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
|
|
61
61
|
|
|
62
62
|
// src/engine/index.ts
|
|
63
|
-
var
|
|
63
|
+
var import_node_child_process3 = require("child_process");
|
|
64
64
|
var import_node_crypto4 = require("crypto");
|
|
65
|
-
var
|
|
65
|
+
var import_node_fs4 = require("fs");
|
|
66
66
|
var import_format = require("@ai-matrx/kit/format");
|
|
67
67
|
|
|
68
68
|
// src/engine/raw-backup.ts
|
|
@@ -161,8 +161,8 @@ function createAiMatrxRawBackupSink(options) {
|
|
|
161
161
|
|
|
162
162
|
// src/engine/index.ts
|
|
163
163
|
var import_promises6 = __toESM(require("fs/promises"), 1);
|
|
164
|
-
var
|
|
165
|
-
var
|
|
164
|
+
var import_node_os5 = __toESM(require("os"), 1);
|
|
165
|
+
var import_node_path7 = __toESM(require("path"), 1);
|
|
166
166
|
var import_node_url = require("url");
|
|
167
167
|
|
|
168
168
|
// src/normalize/claude.ts
|
|
@@ -828,9 +828,177 @@ function describeProblem(provider, problem) {
|
|
|
828
828
|
};
|
|
829
829
|
}
|
|
830
830
|
|
|
831
|
-
// src/engine/
|
|
831
|
+
// src/engine/binaries.ts
|
|
832
|
+
var import_node_child_process = require("child_process");
|
|
833
|
+
var import_node_fs = require("fs");
|
|
832
834
|
var import_node_os = __toESM(require("os"), 1);
|
|
833
835
|
var import_node_path = __toESM(require("path"), 1);
|
|
836
|
+
var SOURCE_LABEL = {
|
|
837
|
+
codex: { "desktop-app": "from ChatGPT app", path: "from PATH", "npm-global": "from npm", configured: "set by host" },
|
|
838
|
+
claude: { "desktop-app": "from Claude app", path: "from PATH", "npm-global": "from npm", configured: "set by host" }
|
|
839
|
+
};
|
|
840
|
+
function sourceLabel(provider, source) {
|
|
841
|
+
return SOURCE_LABEL[provider][source];
|
|
842
|
+
}
|
|
843
|
+
function parseVersion(text) {
|
|
844
|
+
const match = /(\d+)\.(\d+)\.(\d+)(?:[-.][0-9A-Za-z.]+)?/.exec(text ?? "");
|
|
845
|
+
return match ? match[0] : null;
|
|
846
|
+
}
|
|
847
|
+
function compareVersions(a, b) {
|
|
848
|
+
const [aCore = "", aPre] = a.split("-", 2);
|
|
849
|
+
const [bCore = "", bPre] = b.split("-", 2);
|
|
850
|
+
const pa = aCore.split(".").map((n) => Number.parseInt(n, 10) || 0);
|
|
851
|
+
const pb = bCore.split(".").map((n) => Number.parseInt(n, 10) || 0);
|
|
852
|
+
for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
|
|
853
|
+
const d = (pa[i] ?? 0) - (pb[i] ?? 0);
|
|
854
|
+
if (d !== 0) return d < 0 ? -1 : 1;
|
|
855
|
+
}
|
|
856
|
+
if (aPre && !bPre) return -1;
|
|
857
|
+
if (!aPre && bPre) return 1;
|
|
858
|
+
return 0;
|
|
859
|
+
}
|
|
860
|
+
function pickBinary(candidates) {
|
|
861
|
+
let best = null;
|
|
862
|
+
for (const c of candidates) {
|
|
863
|
+
if (!best) {
|
|
864
|
+
best = c;
|
|
865
|
+
continue;
|
|
866
|
+
}
|
|
867
|
+
if (c.version && (!best.version || compareVersions(c.version, best.version) > 0)) best = c;
|
|
868
|
+
}
|
|
869
|
+
return best;
|
|
870
|
+
}
|
|
871
|
+
function executable(file) {
|
|
872
|
+
try {
|
|
873
|
+
(0, import_node_fs.accessSync)(file, import_node_fs.constants.X_OK);
|
|
874
|
+
return true;
|
|
875
|
+
} catch {
|
|
876
|
+
return false;
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
function exeName(name, platform) {
|
|
880
|
+
return platform === "win32" ? [`${name}.exe`, `${name}.cmd`, name] : [name];
|
|
881
|
+
}
|
|
882
|
+
function allOnPath(name, pathValue, platform = process.platform) {
|
|
883
|
+
const found = [];
|
|
884
|
+
for (const dir of pathValue.split(import_node_path.default.delimiter)) {
|
|
885
|
+
if (!dir) continue;
|
|
886
|
+
for (const file of exeName(name, platform)) {
|
|
887
|
+
const candidate = import_node_path.default.join(dir, file);
|
|
888
|
+
if (executable(candidate)) {
|
|
889
|
+
found.push(candidate);
|
|
890
|
+
break;
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
return found;
|
|
895
|
+
}
|
|
896
|
+
function desktopAppCandidates(provider, platform, home, applications) {
|
|
897
|
+
if (platform !== "darwin") return [];
|
|
898
|
+
if (provider === "codex") {
|
|
899
|
+
return applications.map(
|
|
900
|
+
(apps) => import_node_path.default.join(apps, "ChatGPT.app", "Contents", "Resources", "codex-cli", "bin", "codex")
|
|
901
|
+
);
|
|
902
|
+
}
|
|
903
|
+
const root = import_node_path.default.join(home, "Library", "Application Support", "Claude", "claude-code");
|
|
904
|
+
let versions = [];
|
|
905
|
+
try {
|
|
906
|
+
versions = (0, import_node_fs.readdirSync)(root);
|
|
907
|
+
} catch {
|
|
908
|
+
return [];
|
|
909
|
+
}
|
|
910
|
+
return versions.map((v) => import_node_path.default.join(root, v, "claude.app", "Contents", "MacOS", "claude"));
|
|
911
|
+
}
|
|
912
|
+
function npmGlobalPrefix(env) {
|
|
913
|
+
const fromEnv = env.npm_config_prefix ?? env.NPM_CONFIG_PREFIX;
|
|
914
|
+
if (fromEnv) return Promise.resolve(fromEnv);
|
|
915
|
+
const npm = allOnPath("npm", env.PATH ?? "")[0];
|
|
916
|
+
if (!npm) return Promise.resolve(null);
|
|
917
|
+
return new Promise((resolve) => {
|
|
918
|
+
const child = (0, import_node_child_process.execFile)(npm, ["prefix", "-g"], { timeout: 5e3, env }, (error, stdout) => {
|
|
919
|
+
resolve(error ? null : String(stdout).trim() || null);
|
|
920
|
+
});
|
|
921
|
+
child.stdin?.end();
|
|
922
|
+
});
|
|
923
|
+
}
|
|
924
|
+
function declaredVersion(provider, source, file) {
|
|
925
|
+
if (source !== "desktop-app") return null;
|
|
926
|
+
if (provider === "codex") {
|
|
927
|
+
try {
|
|
928
|
+
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"));
|
|
929
|
+
return typeof pkg.version === "string" ? parseVersion(pkg.version) : null;
|
|
930
|
+
} catch {
|
|
931
|
+
return null;
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
return parseVersion(import_node_path.default.basename(import_node_path.default.resolve(file, "..", "..", "..", "..")));
|
|
935
|
+
}
|
|
936
|
+
function runVersion(file, env) {
|
|
937
|
+
return new Promise((resolve) => {
|
|
938
|
+
const child = (0, import_node_child_process.execFile)(file, ["--version"], { timeout: 8e3, env }, (error, stdout) => {
|
|
939
|
+
resolve(error ? null : parseVersion(String(stdout)));
|
|
940
|
+
});
|
|
941
|
+
child.stdin?.end();
|
|
942
|
+
});
|
|
943
|
+
}
|
|
944
|
+
async function discoverBinaries(provider, options) {
|
|
945
|
+
const platform = options.platform ?? process.platform;
|
|
946
|
+
const home = options.home ?? options.env.HOME ?? import_node_os.default.homedir();
|
|
947
|
+
const listed2 = [
|
|
948
|
+
...desktopAppCandidates(provider, platform, home, options.applications ?? ["/Applications", import_node_path.default.join(home, "Applications")]).filter(executable).map((p) => ({ path: p, source: "desktop-app" })),
|
|
949
|
+
...allOnPath(provider, options.env.PATH ?? "", platform).map((p) => ({ path: p, source: "path" }))
|
|
950
|
+
];
|
|
951
|
+
const prefix = await npmGlobalPrefix(options.env);
|
|
952
|
+
if (prefix) {
|
|
953
|
+
const dir = platform === "win32" ? prefix : import_node_path.default.join(prefix, "bin");
|
|
954
|
+
for (const file of exeName(provider, platform)) {
|
|
955
|
+
const candidate = import_node_path.default.join(dir, file);
|
|
956
|
+
if (executable(candidate)) {
|
|
957
|
+
listed2.push({ path: candidate, source: "npm-global" });
|
|
958
|
+
break;
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
const seen = /* @__PURE__ */ new Set();
|
|
963
|
+
const unique = listed2.filter((c) => {
|
|
964
|
+
let real = c.path;
|
|
965
|
+
try {
|
|
966
|
+
real = (0, import_node_fs.realpathSync)(c.path);
|
|
967
|
+
} catch {
|
|
968
|
+
}
|
|
969
|
+
if (seen.has(real)) return false;
|
|
970
|
+
seen.add(real);
|
|
971
|
+
return true;
|
|
972
|
+
});
|
|
973
|
+
return Promise.all(
|
|
974
|
+
unique.map(async (c) => ({
|
|
975
|
+
...c,
|
|
976
|
+
version: declaredVersion(provider, c.source, c.path) ?? await runVersion(c.path, options.env)
|
|
977
|
+
}))
|
|
978
|
+
);
|
|
979
|
+
}
|
|
980
|
+
async function resolveBinary(provider, options) {
|
|
981
|
+
const candidates = options.discover === false ? [] : await discoverBinaries(provider, options);
|
|
982
|
+
const best = pickBinary(candidates);
|
|
983
|
+
const inUse = options.forced ? {
|
|
984
|
+
path: options.forced,
|
|
985
|
+
source: "configured",
|
|
986
|
+
version: candidates.find((c) => c.path === options.forced)?.version ?? (options.discover === false ? null : await runVersion(options.forced, options.env))
|
|
987
|
+
} : best;
|
|
988
|
+
if (!inUse) return null;
|
|
989
|
+
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;
|
|
990
|
+
return {
|
|
991
|
+
path: inUse.path,
|
|
992
|
+
version: inUse.version,
|
|
993
|
+
source: inUse.source,
|
|
994
|
+
sourceLabel: sourceLabel(provider, inUse.source),
|
|
995
|
+
newer
|
|
996
|
+
};
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
// src/engine/clean-env.ts
|
|
1000
|
+
var import_node_os2 = __toESM(require("os"), 1);
|
|
1001
|
+
var import_node_path2 = __toESM(require("path"), 1);
|
|
834
1002
|
var ALLOWED_NAMES = /* @__PURE__ */ new Set([
|
|
835
1003
|
"HOME",
|
|
836
1004
|
"USER",
|
|
@@ -852,11 +1020,11 @@ var ALLOWED_NAMES = /* @__PURE__ */ new Set([
|
|
|
852
1020
|
var ALLOWED_PREFIXES = ["LC_"];
|
|
853
1021
|
function wellKnownBinDirs(home) {
|
|
854
1022
|
return [
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
1023
|
+
import_node_path2.default.join(home, ".local", "bin"),
|
|
1024
|
+
import_node_path2.default.join(home, ".claude", "local"),
|
|
1025
|
+
import_node_path2.default.join(home, ".npm-global", "bin"),
|
|
1026
|
+
import_node_path2.default.join(home, ".bun", "bin"),
|
|
1027
|
+
import_node_path2.default.join(home, ".volta", "bin"),
|
|
860
1028
|
"/opt/homebrew/bin",
|
|
861
1029
|
"/usr/local/bin",
|
|
862
1030
|
"/usr/bin",
|
|
@@ -874,31 +1042,31 @@ function buildCleanEnv(hostEnv, extra = {}) {
|
|
|
874
1042
|
if (typeof value !== "string") continue;
|
|
875
1043
|
if (isAllowedEnvName(name)) out[name] = value;
|
|
876
1044
|
}
|
|
877
|
-
const home = out.HOME ??
|
|
1045
|
+
const home = out.HOME ?? import_node_os2.default.homedir();
|
|
878
1046
|
out.HOME = home;
|
|
879
|
-
const hostPath = (hostEnv.PATH ?? "").split(
|
|
1047
|
+
const hostPath = (hostEnv.PATH ?? "").split(import_node_path2.default.delimiter).filter(Boolean);
|
|
880
1048
|
const merged = [];
|
|
881
1049
|
for (const dir of [...hostPath, ...wellKnownBinDirs(home)]) {
|
|
882
1050
|
if (!merged.includes(dir)) merged.push(dir);
|
|
883
1051
|
}
|
|
884
|
-
out.PATH = merged.join(
|
|
1052
|
+
out.PATH = merged.join(import_node_path2.default.delimiter);
|
|
885
1053
|
for (const [name, value] of Object.entries(extra)) out[name] = value;
|
|
886
1054
|
return out;
|
|
887
1055
|
}
|
|
888
1056
|
|
|
889
1057
|
// src/engine/files.ts
|
|
890
|
-
var
|
|
1058
|
+
var import_node_fs2 = require("fs");
|
|
891
1059
|
var import_promises2 = __toESM(require("fs/promises"), 1);
|
|
892
|
-
var
|
|
893
|
-
var
|
|
1060
|
+
var import_node_os3 = __toESM(require("os"), 1);
|
|
1061
|
+
var import_node_path3 = __toESM(require("path"), 1);
|
|
894
1062
|
|
|
895
1063
|
// src/engine/activity.ts
|
|
896
|
-
var
|
|
1064
|
+
var import_node_child_process2 = require("child_process");
|
|
897
1065
|
var RECENT_WRITE_MS = 2 * 60 * 1e3;
|
|
898
1066
|
var OPEN_TOOL_WINDOW_MS = 15 * 60 * 1e3;
|
|
899
1067
|
function listProcesses() {
|
|
900
1068
|
return new Promise((resolve) => {
|
|
901
|
-
(0,
|
|
1069
|
+
(0, import_node_child_process2.execFile)("ps", ["-axww", "-o", "pid=,args="], { maxBuffer: 64 * 1024 * 1024, timeout: 5e3 }, (error, stdout) => {
|
|
902
1070
|
if (error) {
|
|
903
1071
|
resolve([]);
|
|
904
1072
|
return;
|
|
@@ -957,11 +1125,11 @@ function describeActivity(input) {
|
|
|
957
1125
|
}
|
|
958
1126
|
|
|
959
1127
|
// src/engine/files.ts
|
|
960
|
-
function defaultProviderHomes(home =
|
|
1128
|
+
function defaultProviderHomes(home = import_node_os3.default.homedir()) {
|
|
961
1129
|
return {
|
|
962
|
-
claudeProjects:
|
|
963
|
-
codexSessions:
|
|
964
|
-
codexIndex:
|
|
1130
|
+
claudeProjects: import_node_path3.default.join(home, ".claude", "projects"),
|
|
1131
|
+
codexSessions: import_node_path3.default.join(home, ".codex", "sessions"),
|
|
1132
|
+
codexIndex: import_node_path3.default.join(home, ".codex", "session_index.jsonl")
|
|
965
1133
|
};
|
|
966
1134
|
}
|
|
967
1135
|
var UUIDISH = /([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\.jsonl$/i;
|
|
@@ -986,10 +1154,10 @@ async function claudeCandidates(root) {
|
|
|
986
1154
|
const out = [];
|
|
987
1155
|
for (const project of await safeReaddir(root)) {
|
|
988
1156
|
if (!project.isDirectory()) continue;
|
|
989
|
-
const dir =
|
|
1157
|
+
const dir = import_node_path3.default.join(root, project.name);
|
|
990
1158
|
const entries = await safeReaddir(dir);
|
|
991
1159
|
const stats = await Promise.all(
|
|
992
|
-
entries.filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => statCandidate("claude",
|
|
1160
|
+
entries.filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => statCandidate("claude", import_node_path3.default.join(dir, e.name)))
|
|
993
1161
|
);
|
|
994
1162
|
for (const s of stats) if (s) out.push(s);
|
|
995
1163
|
}
|
|
@@ -999,14 +1167,14 @@ async function codexCandidates(root) {
|
|
|
999
1167
|
const out = [];
|
|
1000
1168
|
for (const year of await safeReaddir(root)) {
|
|
1001
1169
|
if (!year.isDirectory()) continue;
|
|
1002
|
-
for (const month of await safeReaddir(
|
|
1170
|
+
for (const month of await safeReaddir(import_node_path3.default.join(root, year.name))) {
|
|
1003
1171
|
if (!month.isDirectory()) continue;
|
|
1004
|
-
for (const day of await safeReaddir(
|
|
1172
|
+
for (const day of await safeReaddir(import_node_path3.default.join(root, year.name, month.name))) {
|
|
1005
1173
|
if (!day.isDirectory()) continue;
|
|
1006
|
-
const dir =
|
|
1174
|
+
const dir = import_node_path3.default.join(root, year.name, month.name, day.name);
|
|
1007
1175
|
const entries = await safeReaddir(dir);
|
|
1008
1176
|
const stats = await Promise.all(
|
|
1009
|
-
entries.filter((e) => e.isFile() && e.name.startsWith("rollout-") && e.name.endsWith(".jsonl")).map((e) => statCandidate("codex",
|
|
1177
|
+
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)))
|
|
1010
1178
|
);
|
|
1011
1179
|
for (const s of stats) if (s) out.push(s);
|
|
1012
1180
|
}
|
|
@@ -1227,7 +1395,7 @@ async function readSessionFile(provider, file, endOffset, maxBytes = HISTORY_BUD
|
|
|
1227
1395
|
let droppedFirst = start > 0;
|
|
1228
1396
|
let carry = "";
|
|
1229
1397
|
await new Promise((resolve, reject) => {
|
|
1230
|
-
const stream = (0,
|
|
1398
|
+
const stream = (0, import_node_fs2.createReadStream)(file, { start, end: Math.max(start, end - 1), encoding: "utf8" });
|
|
1231
1399
|
stream.on("data", (chunk) => {
|
|
1232
1400
|
const text = carry + String(chunk);
|
|
1233
1401
|
const lines = text.split("\n");
|
|
@@ -1267,7 +1435,7 @@ async function describeSessionFile(candidate, codexNames) {
|
|
|
1267
1435
|
// src/engine/preferences.ts
|
|
1268
1436
|
var import_node_crypto2 = require("crypto");
|
|
1269
1437
|
var import_promises3 = __toESM(require("fs/promises"), 1);
|
|
1270
|
-
var
|
|
1438
|
+
var import_node_path4 = __toESM(require("path"), 1);
|
|
1271
1439
|
var PreferenceStore = class {
|
|
1272
1440
|
constructor(dir) {
|
|
1273
1441
|
this.dir = dir;
|
|
@@ -1276,7 +1444,7 @@ var PreferenceStore = class {
|
|
|
1276
1444
|
data = {};
|
|
1277
1445
|
writing = Promise.resolve();
|
|
1278
1446
|
get file() {
|
|
1279
|
-
return
|
|
1447
|
+
return import_node_path4.default.join(this.dir, "preferences.json");
|
|
1280
1448
|
}
|
|
1281
1449
|
async load() {
|
|
1282
1450
|
try {
|
|
@@ -1331,7 +1499,7 @@ var PreferenceStore = class {
|
|
|
1331
1499
|
};
|
|
1332
1500
|
|
|
1333
1501
|
// src/engine/search.ts
|
|
1334
|
-
var
|
|
1502
|
+
var import_node_fs3 = require("fs");
|
|
1335
1503
|
function findInLine(provider, value, needle) {
|
|
1336
1504
|
const items = provider === "claude" ? createClaudeNormalizer().push(value) : createCodexRolloutNormalizer().push(value);
|
|
1337
1505
|
for (const item of items) {
|
|
@@ -1372,7 +1540,7 @@ async function scanFile(provider, file, needle, raw, deadline) {
|
|
|
1372
1540
|
return new Promise((resolve) => {
|
|
1373
1541
|
let carry = Buffer.alloc(0);
|
|
1374
1542
|
let done = false;
|
|
1375
|
-
const stream = (0,
|
|
1543
|
+
const stream = (0, import_node_fs3.createReadStream)(file, { highWaterMark: 4 * 1024 * 1024 });
|
|
1376
1544
|
const finish = (value) => {
|
|
1377
1545
|
if (done) return;
|
|
1378
1546
|
done = true;
|
|
@@ -1480,7 +1648,7 @@ async function searchLocalChats(query, options = {}) {
|
|
|
1480
1648
|
// src/engine/store.ts
|
|
1481
1649
|
var import_node_crypto3 = require("crypto");
|
|
1482
1650
|
var import_promises4 = __toESM(require("fs/promises"), 1);
|
|
1483
|
-
var
|
|
1651
|
+
var import_node_path5 = __toESM(require("path"), 1);
|
|
1484
1652
|
var MAX_RUNS = 2e3;
|
|
1485
1653
|
var RunIndex = class {
|
|
1486
1654
|
constructor(dir) {
|
|
@@ -1490,7 +1658,7 @@ var RunIndex = class {
|
|
|
1490
1658
|
data = { version: 1, sessions: [], runs: [] };
|
|
1491
1659
|
writing = Promise.resolve();
|
|
1492
1660
|
get file() {
|
|
1493
|
-
return
|
|
1661
|
+
return import_node_path5.default.join(this.dir, "index.json");
|
|
1494
1662
|
}
|
|
1495
1663
|
async load() {
|
|
1496
1664
|
await import_promises4.default.mkdir(this.dir, { recursive: true });
|
|
@@ -1549,7 +1717,7 @@ var RunIndex = class {
|
|
|
1549
1717
|
/** A stable Paperclip agent/company identity for this install, so the
|
|
1550
1718
|
* driver's scratch state is reused rather than growing per run. */
|
|
1551
1719
|
async identity() {
|
|
1552
|
-
const file =
|
|
1720
|
+
const file = import_node_path5.default.join(this.dir, "identity.json");
|
|
1553
1721
|
try {
|
|
1554
1722
|
const parsed = JSON.parse(await import_promises4.default.readFile(file, "utf8"));
|
|
1555
1723
|
if (typeof parsed.companyId === "string" && typeof parsed.agentId === "string") {
|
|
@@ -1565,8 +1733,8 @@ var RunIndex = class {
|
|
|
1565
1733
|
|
|
1566
1734
|
// src/engine/user-defaults.ts
|
|
1567
1735
|
var import_promises5 = __toESM(require("fs/promises"), 1);
|
|
1568
|
-
var
|
|
1569
|
-
var
|
|
1736
|
+
var import_node_os4 = __toESM(require("os"), 1);
|
|
1737
|
+
var import_node_path6 = __toESM(require("path"), 1);
|
|
1570
1738
|
async function readJson(file) {
|
|
1571
1739
|
try {
|
|
1572
1740
|
const parsed = JSON.parse(await import_promises5.default.readFile(file, "utf8"));
|
|
@@ -1578,10 +1746,10 @@ async function readJson(file) {
|
|
|
1578
1746
|
function str3(value) {
|
|
1579
1747
|
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
1580
1748
|
}
|
|
1581
|
-
async function claudeDefaults(cwd, home =
|
|
1749
|
+
async function claudeDefaults(cwd, home = import_node_os4.default.homedir()) {
|
|
1582
1750
|
const files = [
|
|
1583
|
-
...cwd ? [
|
|
1584
|
-
|
|
1751
|
+
...cwd ? [import_node_path6.default.join(cwd, ".claude", "settings.local.json"), import_node_path6.default.join(cwd, ".claude", "settings.json")] : [],
|
|
1752
|
+
import_node_path6.default.join(home, ".claude", "settings.json")
|
|
1585
1753
|
];
|
|
1586
1754
|
let model = null;
|
|
1587
1755
|
let effort = null;
|
|
@@ -1594,10 +1762,10 @@ async function claudeDefaults(cwd, home = import_node_os3.default.homedir()) {
|
|
|
1594
1762
|
}
|
|
1595
1763
|
return { model, effort };
|
|
1596
1764
|
}
|
|
1597
|
-
async function codexDefaults(home =
|
|
1765
|
+
async function codexDefaults(home = import_node_os4.default.homedir()) {
|
|
1598
1766
|
let text;
|
|
1599
1767
|
try {
|
|
1600
|
-
text = await import_promises5.default.readFile(
|
|
1768
|
+
text = await import_promises5.default.readFile(import_node_path6.default.join(home, ".codex", "config.toml"), "utf8");
|
|
1601
1769
|
} catch {
|
|
1602
1770
|
return { model: null, effort: null };
|
|
1603
1771
|
}
|
|
@@ -1621,45 +1789,33 @@ var EFFORT_LEVELS = {
|
|
|
1621
1789
|
// src/engine/index.ts
|
|
1622
1790
|
var RAW_TRANSCRIPT_MAX_BYTES = 200 * 1048576;
|
|
1623
1791
|
function moduleDir() {
|
|
1624
|
-
return
|
|
1792
|
+
return import_node_path7.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl));
|
|
1625
1793
|
}
|
|
1626
1794
|
function resolveWorkerPath() {
|
|
1627
1795
|
const dir = moduleDir();
|
|
1628
1796
|
for (const candidate of [
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1797
|
+
import_node_path7.default.join(dir, "worker.js"),
|
|
1798
|
+
import_node_path7.default.join(dir, "worker.ts"),
|
|
1799
|
+
import_node_path7.default.join(dir, "..", "engine", "worker.js"),
|
|
1800
|
+
import_node_path7.default.join(dir, "..", "engine", "worker.ts")
|
|
1633
1801
|
]) {
|
|
1634
|
-
if ((0,
|
|
1802
|
+
if ((0, import_node_fs4.existsSync)(candidate)) return candidate;
|
|
1635
1803
|
}
|
|
1636
1804
|
throw new Error(`[coding-sessions] The driver worker is missing next to ${dir}.`);
|
|
1637
1805
|
}
|
|
1638
1806
|
async function installShim(dataDir) {
|
|
1639
|
-
const source =
|
|
1640
|
-
if (!(0,
|
|
1807
|
+
const source = import_node_path7.default.resolve(moduleDir(), "..", "..", "bin", "cli-shim.sh");
|
|
1808
|
+
if (!(0, import_node_fs4.existsSync)(source)) throw new Error(`[coding-sessions] The CLI shim is missing at ${source}.`);
|
|
1641
1809
|
const body = await import_promises6.default.readFile(source, "utf8");
|
|
1642
|
-
const target =
|
|
1810
|
+
const target = import_node_path7.default.join(dataDir, "bin", "cli-shim.sh");
|
|
1643
1811
|
const current = await import_promises6.default.readFile(target, "utf8").catch(() => null);
|
|
1644
1812
|
if (current !== body) {
|
|
1645
|
-
await import_promises6.default.mkdir(
|
|
1813
|
+
await import_promises6.default.mkdir(import_node_path7.default.dirname(target), { recursive: true });
|
|
1646
1814
|
await import_promises6.default.writeFile(target, body, { mode: 493 });
|
|
1647
1815
|
}
|
|
1648
1816
|
await import_promises6.default.chmod(target, 493);
|
|
1649
1817
|
return target;
|
|
1650
1818
|
}
|
|
1651
|
-
function whichOnPath(name, pathValue) {
|
|
1652
|
-
for (const dir of pathValue.split(import_node_path6.default.delimiter)) {
|
|
1653
|
-
if (!dir) continue;
|
|
1654
|
-
const candidate = import_node_path6.default.join(dir, name);
|
|
1655
|
-
try {
|
|
1656
|
-
(0, import_node_fs3.accessSync)(candidate, import_node_fs3.constants.X_OK);
|
|
1657
|
-
return candidate;
|
|
1658
|
-
} catch {
|
|
1659
|
-
}
|
|
1660
|
-
}
|
|
1661
|
-
return null;
|
|
1662
|
-
}
|
|
1663
1819
|
function nowIso() {
|
|
1664
1820
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
1665
1821
|
}
|
|
@@ -1698,12 +1854,14 @@ function describeProviderStatus(provider, probe, lastProblem = null, quota = [])
|
|
|
1698
1854
|
function describeAuthStatus(provider, probe) {
|
|
1699
1855
|
const label = PROVIDER_LABEL[provider];
|
|
1700
1856
|
const installed = probe?.installed === true;
|
|
1701
|
-
const
|
|
1857
|
+
const binary = probe?.binary ?? null;
|
|
1858
|
+
const version = binary?.version ?? (typeof probe?.version === "string" ? probe.version : null);
|
|
1702
1859
|
const base = {
|
|
1703
1860
|
provider,
|
|
1704
1861
|
label,
|
|
1705
1862
|
installed,
|
|
1706
1863
|
version,
|
|
1864
|
+
binary,
|
|
1707
1865
|
loggedIn: false,
|
|
1708
1866
|
billing: "unknown",
|
|
1709
1867
|
plan: null,
|
|
@@ -1755,8 +1913,8 @@ function describeAuthStatus(provider, probe) {
|
|
|
1755
1913
|
};
|
|
1756
1914
|
}
|
|
1757
1915
|
async function createCodingSessionsEngine(options = {}) {
|
|
1758
|
-
const dataDir = options.dataDir ??
|
|
1759
|
-
const stateDir =
|
|
1916
|
+
const dataDir = options.dataDir ?? import_node_path7.default.join(import_node_os5.default.homedir(), ".matrx", "coding-sessions");
|
|
1917
|
+
const stateDir = import_node_path7.default.join(dataDir, "paperclip-state");
|
|
1760
1918
|
const homes = options.homes ?? defaultProviderHomes();
|
|
1761
1919
|
const index = new RunIndex(dataDir);
|
|
1762
1920
|
await index.load();
|
|
@@ -1770,7 +1928,7 @@ async function createCodingSessionsEngine(options = {}) {
|
|
|
1770
1928
|
onError: (error) => console.warn("[coding-sessions] raw transcript backup failed:", error)
|
|
1771
1929
|
}) : null;
|
|
1772
1930
|
const discoveredSeen = /* @__PURE__ */ new Map();
|
|
1773
|
-
const healthFile =
|
|
1931
|
+
const healthFile = import_node_path7.default.join(dataDir, "provider-health.json");
|
|
1774
1932
|
let health = {};
|
|
1775
1933
|
try {
|
|
1776
1934
|
health = JSON.parse(await import_promises6.default.readFile(healthFile, "utf8"));
|
|
@@ -1805,7 +1963,24 @@ async function createCodingSessionsEngine(options = {}) {
|
|
|
1805
1963
|
// Marks the forked process as a driver worker (see worker.ts).
|
|
1806
1964
|
MATRX_CODING_SESSIONS_WORKER: "1"
|
|
1807
1965
|
});
|
|
1808
|
-
const
|
|
1966
|
+
const binaryHome = options.hostEnv?.HOME ?? import_node_os5.default.homedir();
|
|
1967
|
+
const binaryCache = /* @__PURE__ */ new Map();
|
|
1968
|
+
function binaryFor(provider, fresh = false) {
|
|
1969
|
+
const cached = binaryCache.get(provider);
|
|
1970
|
+
if (cached && !fresh && Date.now() - cached.at < 5 * 6e4) return cached.value;
|
|
1971
|
+
const forced = options.commands?.[provider];
|
|
1972
|
+
const value = resolveBinary(provider, {
|
|
1973
|
+
env: workerEnv,
|
|
1974
|
+
home: binaryHome,
|
|
1975
|
+
forced,
|
|
1976
|
+
// A forced command needs no discovery to run; the status check still
|
|
1977
|
+
// looks, so it can say when a newer copy exists.
|
|
1978
|
+
discover: !forced || fresh
|
|
1979
|
+
}).catch(() => forced ? { path: forced, version: null, source: "configured", sourceLabel: "set by host", newer: null } : null);
|
|
1980
|
+
if (!forced || !fresh) binaryCache.set(provider, { at: Date.now(), value });
|
|
1981
|
+
return value;
|
|
1982
|
+
}
|
|
1983
|
+
const commandFor = async (provider) => (await binaryFor(provider))?.path ?? null;
|
|
1809
1984
|
const workerPath = resolveWorkerPath();
|
|
1810
1985
|
const shimPath = await installShim(dataDir);
|
|
1811
1986
|
const listeners = /* @__PURE__ */ new Set();
|
|
@@ -1855,7 +2030,7 @@ async function createCodingSessionsEngine(options = {}) {
|
|
|
1855
2030
|
}
|
|
1856
2031
|
}
|
|
1857
2032
|
function forkWorker() {
|
|
1858
|
-
return (0,
|
|
2033
|
+
return (0, import_node_child_process3.fork)(workerPath, [], {
|
|
1859
2034
|
env: workerEnv,
|
|
1860
2035
|
cwd: dataDir,
|
|
1861
2036
|
stdio: ["ignore", "pipe", "pipe", "ipc"],
|
|
@@ -1876,7 +2051,7 @@ async function createCodingSessionsEngine(options = {}) {
|
|
|
1876
2051
|
}
|
|
1877
2052
|
async function startRun(session, prompt) {
|
|
1878
2053
|
const provider = session.provider;
|
|
1879
|
-
const realCommand = commandFor(provider);
|
|
2054
|
+
const realCommand = await commandFor(provider);
|
|
1880
2055
|
const runId = (0, import_node_crypto4.randomUUID)();
|
|
1881
2056
|
const model = session.model ?? (provider === "claude" ? (await userDefaults(provider, session.cwd)).model ?? null : null);
|
|
1882
2057
|
const run = {
|
|
@@ -2108,7 +2283,7 @@ async function createCodingSessionsEngine(options = {}) {
|
|
|
2108
2283
|
}, 3e3);
|
|
2109
2284
|
}
|
|
2110
2285
|
async function pruneDriverScratch() {
|
|
2111
|
-
const runsDir =
|
|
2286
|
+
const runsDir = import_node_path7.default.join(
|
|
2112
2287
|
stateDir,
|
|
2113
2288
|
"instances",
|
|
2114
2289
|
"default",
|
|
@@ -2121,10 +2296,11 @@ async function createCodingSessionsEngine(options = {}) {
|
|
|
2121
2296
|
);
|
|
2122
2297
|
const entries = await import_promises6.default.readdir(runsDir).catch(() => []);
|
|
2123
2298
|
await Promise.all(
|
|
2124
|
-
entries.filter((name) => !live.has(name)).map((name) => import_promises6.default.rm(
|
|
2299
|
+
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))
|
|
2125
2300
|
);
|
|
2126
2301
|
}
|
|
2127
2302
|
async function probe() {
|
|
2303
|
+
const [claudeBinary, codexBinary] = await Promise.all([binaryFor("claude", true), binaryFor("codex", true)]);
|
|
2128
2304
|
return new Promise((resolve) => {
|
|
2129
2305
|
const child = forkWorker();
|
|
2130
2306
|
let answered = false;
|
|
@@ -2140,8 +2316,8 @@ async function createCodingSessionsEngine(options = {}) {
|
|
|
2140
2316
|
answered = true;
|
|
2141
2317
|
clearTimeout(timer);
|
|
2142
2318
|
resolve({
|
|
2143
|
-
claude: message.claude ?? {},
|
|
2144
|
-
codex: message.codex ?? {}
|
|
2319
|
+
claude: { ...message.claude ?? {}, binary: claudeBinary },
|
|
2320
|
+
codex: { ...message.codex ?? {}, binary: codexBinary }
|
|
2145
2321
|
});
|
|
2146
2322
|
}
|
|
2147
2323
|
});
|
|
@@ -2153,7 +2329,7 @@ async function createCodingSessionsEngine(options = {}) {
|
|
|
2153
2329
|
});
|
|
2154
2330
|
child.send({
|
|
2155
2331
|
kind: "probe",
|
|
2156
|
-
commands: { claude:
|
|
2332
|
+
commands: { claude: claudeBinary?.path ?? null, codex: codexBinary?.path ?? null },
|
|
2157
2333
|
quota: options.quota !== false
|
|
2158
2334
|
});
|
|
2159
2335
|
});
|
|
@@ -2179,7 +2355,7 @@ async function createCodingSessionsEngine(options = {}) {
|
|
|
2179
2355
|
function resolveFolder(raw) {
|
|
2180
2356
|
const trimmed = raw.trim();
|
|
2181
2357
|
if (!trimmed) return null;
|
|
2182
|
-
return
|
|
2358
|
+
return import_node_path7.default.resolve(trimmed.replace(/^~(?=$|\/)/, import_node_os5.default.homedir()));
|
|
2183
2359
|
}
|
|
2184
2360
|
async function checkFolder(raw) {
|
|
2185
2361
|
const target = resolveFolder(raw);
|
|
@@ -2188,7 +2364,7 @@ async function createCodingSessionsEngine(options = {}) {
|
|
|
2188
2364
|
return { path: target, exists: stat !== null, isDirectory: stat?.isDirectory() === true };
|
|
2189
2365
|
}
|
|
2190
2366
|
async function assertFolder(cwd) {
|
|
2191
|
-
const resolved =
|
|
2367
|
+
const resolved = import_node_path7.default.resolve(cwd.replace(/^~(?=$|\/)/, import_node_os5.default.homedir()));
|
|
2192
2368
|
const stat = await import_promises6.default.stat(resolved).catch(() => null);
|
|
2193
2369
|
if (!stat?.isDirectory()) {
|
|
2194
2370
|
throw new Error(`The folder ${resolved} doesn't exist on this computer.`);
|
|
@@ -2342,7 +2518,7 @@ async function createCodingSessionsEngine(options = {}) {
|
|
|
2342
2518
|
};
|
|
2343
2519
|
}
|
|
2344
2520
|
const content = await import_promises6.default.readFile(file, "utf8");
|
|
2345
|
-
return { available: true, fileName:
|
|
2521
|
+
return { available: true, fileName: import_node_path7.default.basename(file), bytes: stat.size, content };
|
|
2346
2522
|
},
|
|
2347
2523
|
async start(input) {
|
|
2348
2524
|
const prompt = input.prompt.trim();
|
|
@@ -2463,7 +2639,7 @@ function openFolderIn(folder, target) {
|
|
|
2463
2639
|
args = ["-a", app.app, folder];
|
|
2464
2640
|
}
|
|
2465
2641
|
return new Promise((resolve, reject) => {
|
|
2466
|
-
(0,
|
|
2642
|
+
(0, import_node_child_process3.execFile)(command, args, { timeout: 1e4 }, (error) => {
|
|
2467
2643
|
if (!error) return resolve();
|
|
2468
2644
|
const label = target === "finder" ? "the folder" : OPEN_APP[target]?.label ?? target;
|
|
2469
2645
|
reject(
|