@fml-inc/fml 0.8.10-dev.1 → 0.8.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +114 -3
- package/agent-assets/mini-swe-agent/FML_WORKFLOW.md +62 -0
- package/agent-assets/mini-swe-agent/fml_mini_agent.py +483 -0
- package/agent-assets/mini-swe-agent/fml_mini_bootstrap.py +141 -0
- package/bin/fml +18 -4
- package/dist/{chunk-2DGHAVVR.js → chunk-OUXFHL3I.js} +1 -1
- package/dist/{chunk-JPHN4VKM.js → chunk-PTDADW47.js} +197 -94
- package/dist/{chunk-5SI6S4HW.js → chunk-U4BM27VN.js} +1 -1
- package/dist/{chunk-5PEFBQNX.js → chunk-XB7EIDWY.js} +17 -4
- package/dist/cli.js +4600 -3882
- package/dist/hook-handler.js +39 -11
- package/dist/mcp/server.js +5 -5
- package/dist/observer-server.js +5 -5
- package/dist/pi/extension.js +17 -4
- package/dist/sync-cycle.js +2 -2
- package/package.json +1 -1
|
@@ -184,9 +184,9 @@ function setSyncEnabled(settingsFile, enabled) {
|
|
|
184
184
|
|
|
185
185
|
// ../../packages/panopticon/src/artifacts.ts
|
|
186
186
|
import { createHash as createHash5, randomUUID as randomUUID3 } from "crypto";
|
|
187
|
-
import
|
|
187
|
+
import fs9 from "fs";
|
|
188
188
|
import os3 from "os";
|
|
189
|
-
import
|
|
189
|
+
import path19 from "path";
|
|
190
190
|
|
|
191
191
|
// ../../packages/agent-targets/src/artifacts/targets/claude.ts
|
|
192
192
|
import path8 from "path";
|
|
@@ -755,8 +755,100 @@ var grokArtifactDiscovery = Object.freeze({
|
|
|
755
755
|
)
|
|
756
756
|
});
|
|
757
757
|
|
|
758
|
-
// ../../packages/agent-targets/src/artifacts/targets/
|
|
758
|
+
// ../../packages/agent-targets/src/artifacts/targets/mini-swe-agent.ts
|
|
759
|
+
import fs6 from "fs";
|
|
759
760
|
import path15 from "path";
|
|
761
|
+
var SESSION_ID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
762
|
+
function dataDirectory({ homeDir, env }) {
|
|
763
|
+
if (env.FML_DATA_DIR?.trim()) {
|
|
764
|
+
if (!path15.isAbsolute(env.FML_DATA_DIR)) {
|
|
765
|
+
throw new Error("FML_DATA_DIR must be an absolute path");
|
|
766
|
+
}
|
|
767
|
+
return path15.normalize(env.FML_DATA_DIR);
|
|
768
|
+
}
|
|
769
|
+
if (process.platform === "darwin") {
|
|
770
|
+
return path15.join(homeDir, "Library", "Application Support", "fml");
|
|
771
|
+
}
|
|
772
|
+
if (process.platform === "win32") {
|
|
773
|
+
const roaming = env.APPDATA && path15.isAbsolute(env.APPDATA) ? env.APPDATA : path15.join(homeDir, "AppData", "Roaming");
|
|
774
|
+
return path15.join(roaming, "fml");
|
|
775
|
+
}
|
|
776
|
+
const xdgDataHome = env.XDG_DATA_HOME && path15.isAbsolute(env.XDG_DATA_HOME) ? env.XDG_DATA_HOME : path15.join(homeDir, ".local", "share");
|
|
777
|
+
return path15.join(xdgDataHome, "fml");
|
|
778
|
+
}
|
|
779
|
+
function snapshotCandidate(sourcePath, context) {
|
|
780
|
+
let file;
|
|
781
|
+
try {
|
|
782
|
+
file = fs6.openSync(sourcePath, "r");
|
|
783
|
+
} catch {
|
|
784
|
+
return null;
|
|
785
|
+
}
|
|
786
|
+
try {
|
|
787
|
+
const stat = fs6.fstatSync(file);
|
|
788
|
+
if (!stat.isFile()) return null;
|
|
789
|
+
if (context.maxFileBytes !== void 0 && stat.size > context.maxFileBytes) {
|
|
790
|
+
return transcriptCandidate({ targetId: "mini-swe-agent", sourcePath });
|
|
791
|
+
}
|
|
792
|
+
const bytes = Buffer.allocUnsafe(stat.size);
|
|
793
|
+
let offset = 0;
|
|
794
|
+
while (offset < bytes.length) {
|
|
795
|
+
const read = fs6.readSync(
|
|
796
|
+
file,
|
|
797
|
+
bytes,
|
|
798
|
+
offset,
|
|
799
|
+
bytes.length - offset,
|
|
800
|
+
offset
|
|
801
|
+
);
|
|
802
|
+
if (read <= 0) return null;
|
|
803
|
+
offset += read;
|
|
804
|
+
}
|
|
805
|
+
if (fs6.fstatSync(file).size !== stat.size) return null;
|
|
806
|
+
const value = JSON.parse(bytes.toString("utf8"));
|
|
807
|
+
if (typeof value !== "object" || value === null || !("fml" in value)) {
|
|
808
|
+
return null;
|
|
809
|
+
}
|
|
810
|
+
const metadata = value.fml;
|
|
811
|
+
if (typeof metadata !== "object" || metadata === null || !("version" in metadata) || metadata.version !== 1 || !("session_id" in metadata) || typeof metadata.session_id !== "string" || !SESSION_ID_PATTERN.test(metadata.session_id)) {
|
|
812
|
+
return null;
|
|
813
|
+
}
|
|
814
|
+
const cwd = "cwd" in metadata && typeof metadata.cwd === "string" ? metadata.cwd : void 0;
|
|
815
|
+
const origin = cwd ? context.resolveGitHubOrigin?.(cwd) : null;
|
|
816
|
+
return transcriptCandidate({
|
|
817
|
+
targetId: "mini-swe-agent",
|
|
818
|
+
sourcePath,
|
|
819
|
+
sessionId: metadata.session_id,
|
|
820
|
+
metadata: { store: "managed_snapshots" },
|
|
821
|
+
repositoryObservations: origin ? [
|
|
822
|
+
repositoryObservation({
|
|
823
|
+
repository: origin.repository,
|
|
824
|
+
source: "git_origin",
|
|
825
|
+
observedAtMs: (context.nowMs ?? Date.now)(),
|
|
826
|
+
cwd,
|
|
827
|
+
branch: origin.branch,
|
|
828
|
+
commitHash: origin.commitHash
|
|
829
|
+
})
|
|
830
|
+
] : []
|
|
831
|
+
});
|
|
832
|
+
} catch {
|
|
833
|
+
return null;
|
|
834
|
+
} finally {
|
|
835
|
+
fs6.closeSync(file);
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
var miniSweAgentArtifactDiscovery = Object.freeze({
|
|
839
|
+
targetId: "mini-swe-agent",
|
|
840
|
+
discover: (context) => walkFiles({
|
|
841
|
+
root: path15.join(dataDirectory(context), "mini-swe-agent", "trajectories"),
|
|
842
|
+
maxDepth: 0,
|
|
843
|
+
includeFile: (filePath) => filePath.endsWith(".traj.json")
|
|
844
|
+
}).flatMap((sourcePath) => {
|
|
845
|
+
const candidate = snapshotCandidate(sourcePath, context);
|
|
846
|
+
return candidate ? [candidate] : [];
|
|
847
|
+
})
|
|
848
|
+
});
|
|
849
|
+
|
|
850
|
+
// ../../packages/agent-targets/src/artifacts/targets/pi.ts
|
|
851
|
+
import path16 from "path";
|
|
760
852
|
var PI_SKIP_DIRS = /* @__PURE__ */ new Set(["subagent-artifacts"]);
|
|
761
853
|
function piTranscriptCandidate(sourcePath, context) {
|
|
762
854
|
const fallbackObservedAtMs = (context.nowMs ?? Date.now)();
|
|
@@ -794,7 +886,7 @@ var piArtifactDiscovery = Object.freeze({
|
|
|
794
886
|
discover: (context) => {
|
|
795
887
|
const { homeDir } = context;
|
|
796
888
|
return walkFiles({
|
|
797
|
-
root:
|
|
889
|
+
root: path16.join(homeDir, ".pi", "agent", "sessions"),
|
|
798
890
|
maxDepth: 8,
|
|
799
891
|
includeFile: (filePath) => filePath.endsWith(".jsonl"),
|
|
800
892
|
skipDirs: PI_SKIP_DIRS
|
|
@@ -809,6 +901,7 @@ var ARTIFACT_DISCOVERY_CAPABILITIES = Object.freeze([
|
|
|
809
901
|
geminiArtifactDiscovery,
|
|
810
902
|
grokArtifactDiscovery,
|
|
811
903
|
piArtifactDiscovery,
|
|
904
|
+
miniSweAgentArtifactDiscovery,
|
|
812
905
|
cursorArtifactDiscovery,
|
|
813
906
|
copilotCliArtifactDiscovery,
|
|
814
907
|
factoryDroidArtifactDiscovery
|
|
@@ -826,13 +919,13 @@ function discoverTargetArtifactCandidates(context) {
|
|
|
826
919
|
|
|
827
920
|
// ../../packages/agent-targets/src/artifacts/materialize.ts
|
|
828
921
|
import { createHash as createHash3 } from "crypto";
|
|
829
|
-
import
|
|
830
|
-
import
|
|
922
|
+
import fs7 from "fs";
|
|
923
|
+
import path17 from "path";
|
|
831
924
|
import zlib from "zlib";
|
|
832
925
|
var MAX_MATERIALIZED_ARTIFACT_BYTES = 100 * 1024 * 1024;
|
|
833
926
|
var DEFAULT_MATERIALIZED_CACHE_BYTES = 2 * 1024 * 1024 * 1024;
|
|
834
927
|
function cacheEntryName(sourcePath, stat) {
|
|
835
|
-
const identity = `${
|
|
928
|
+
const identity = `${path17.resolve(sourcePath)}\0${stat.size}\0${Math.floor(
|
|
836
929
|
stat.mtimeMs
|
|
837
930
|
)}`;
|
|
838
931
|
const digest = createHash3("sha256").update(identity).digest("hex");
|
|
@@ -845,7 +938,7 @@ function decodeZstd(sourcePath, maxOutputBytes) {
|
|
|
845
938
|
const decompress = zlib.zstdDecompressSync;
|
|
846
939
|
if (typeof decompress !== "function") return null;
|
|
847
940
|
try {
|
|
848
|
-
return decompress(
|
|
941
|
+
return decompress(fs7.readFileSync(sourcePath), {
|
|
849
942
|
maxOutputLength: maxOutputBytes
|
|
850
943
|
});
|
|
851
944
|
} catch {
|
|
@@ -854,9 +947,9 @@ function decodeZstd(sourcePath, maxOutputBytes) {
|
|
|
854
947
|
}
|
|
855
948
|
function materializedArtifactPath(input) {
|
|
856
949
|
try {
|
|
857
|
-
const stat =
|
|
950
|
+
const stat = fs7.statSync(input.sourcePath);
|
|
858
951
|
if (!stat.isFile() || stat.size === 0) return null;
|
|
859
|
-
return
|
|
952
|
+
return path17.join(input.cacheDir, cacheEntryName(input.sourcePath, stat));
|
|
860
953
|
} catch {
|
|
861
954
|
return null;
|
|
862
955
|
}
|
|
@@ -864,20 +957,20 @@ function materializedArtifactPath(input) {
|
|
|
864
957
|
function materializeCompressedArtifact(input) {
|
|
865
958
|
let stat;
|
|
866
959
|
try {
|
|
867
|
-
stat =
|
|
960
|
+
stat = fs7.statSync(input.sourcePath);
|
|
868
961
|
} catch {
|
|
869
962
|
return null;
|
|
870
963
|
}
|
|
871
964
|
if (!stat.isFile() || stat.size === 0) return null;
|
|
872
|
-
const cachePath =
|
|
965
|
+
const cachePath = path17.join(
|
|
873
966
|
input.cacheDir,
|
|
874
967
|
cacheEntryName(input.sourcePath, stat)
|
|
875
968
|
);
|
|
876
969
|
try {
|
|
877
|
-
if (
|
|
970
|
+
if (fs7.statSync(cachePath).isFile()) {
|
|
878
971
|
const now = /* @__PURE__ */ new Date();
|
|
879
972
|
try {
|
|
880
|
-
|
|
973
|
+
fs7.utimesSync(cachePath, now, now);
|
|
881
974
|
} catch {
|
|
882
975
|
}
|
|
883
976
|
return cachePath;
|
|
@@ -890,10 +983,10 @@ function materializeCompressedArtifact(input) {
|
|
|
890
983
|
);
|
|
891
984
|
if (!decoded) return null;
|
|
892
985
|
try {
|
|
893
|
-
|
|
986
|
+
fs7.mkdirSync(input.cacheDir, { recursive: true, mode: 448 });
|
|
894
987
|
const tempPath = `${cachePath}.${process.pid}.tmp`;
|
|
895
|
-
|
|
896
|
-
|
|
988
|
+
fs7.writeFileSync(tempPath, decoded, { mode: 384 });
|
|
989
|
+
fs7.renameSync(tempPath, cachePath);
|
|
897
990
|
return cachePath;
|
|
898
991
|
} catch {
|
|
899
992
|
return null;
|
|
@@ -903,16 +996,16 @@ function pruneMaterializedCache(input) {
|
|
|
903
996
|
const maxTotalBytes = input.maxTotalBytes ?? DEFAULT_MATERIALIZED_CACHE_BYTES;
|
|
904
997
|
let entries;
|
|
905
998
|
try {
|
|
906
|
-
entries =
|
|
999
|
+
entries = fs7.readdirSync(input.cacheDir, { withFileTypes: true });
|
|
907
1000
|
} catch {
|
|
908
1001
|
return { removed: 0, retainedBytes: 0 };
|
|
909
1002
|
}
|
|
910
1003
|
const files = [];
|
|
911
1004
|
for (const entry of entries) {
|
|
912
1005
|
if (!entry.isFile()) continue;
|
|
913
|
-
const filePath =
|
|
1006
|
+
const filePath = path17.join(input.cacheDir, entry.name);
|
|
914
1007
|
try {
|
|
915
|
-
const stat =
|
|
1008
|
+
const stat = fs7.statSync(filePath);
|
|
916
1009
|
files.push({ path: filePath, size: stat.size, atimeMs: stat.atimeMs });
|
|
917
1010
|
} catch {
|
|
918
1011
|
}
|
|
@@ -927,7 +1020,7 @@ function pruneMaterializedCache(input) {
|
|
|
927
1020
|
continue;
|
|
928
1021
|
}
|
|
929
1022
|
try {
|
|
930
|
-
|
|
1023
|
+
fs7.rmSync(file.path);
|
|
931
1024
|
removed += 1;
|
|
932
1025
|
} catch {
|
|
933
1026
|
retainedBytes += file.size;
|
|
@@ -939,8 +1032,8 @@ function pruneMaterializedCache(input) {
|
|
|
939
1032
|
// ../../packages/panopticon/src/repository-context.ts
|
|
940
1033
|
import { execFileSync } from "child_process";
|
|
941
1034
|
import { createHash as createHash4 } from "crypto";
|
|
942
|
-
import
|
|
943
|
-
import
|
|
1035
|
+
import fs8 from "fs";
|
|
1036
|
+
import path18 from "path";
|
|
944
1037
|
var MAX_CWD_BYTES2 = 4096;
|
|
945
1038
|
var GIT_OUTPUT_BYTES = 16 * 1024;
|
|
946
1039
|
var GIT_CONFIG_OUTPUT_BYTES = 4 * 1024 * 1024;
|
|
@@ -1080,7 +1173,7 @@ var PERSISTENT_ORIGIN_CACHE_SCHEMA_VERSION = 2;
|
|
|
1080
1173
|
var DEFAULT_PERSISTENT_ORIGIN_CACHE_MAX_ENTRIES = 512;
|
|
1081
1174
|
function fileContentIdentity(filePath) {
|
|
1082
1175
|
try {
|
|
1083
|
-
const contents =
|
|
1176
|
+
const contents = fs8.readFileSync(filePath);
|
|
1084
1177
|
return `sha256:${createHash4("sha256").update(contents).digest("hex")}`;
|
|
1085
1178
|
} catch (error) {
|
|
1086
1179
|
const code = error && typeof error === "object" && "code" in error ? error.code : void 0;
|
|
@@ -1089,7 +1182,7 @@ function fileContentIdentity(filePath) {
|
|
|
1089
1182
|
}
|
|
1090
1183
|
function packedRefsIdentity(filePath) {
|
|
1091
1184
|
try {
|
|
1092
|
-
const stat =
|
|
1185
|
+
const stat = fs8.statSync(filePath, { bigint: true });
|
|
1093
1186
|
if (!stat.isFile() || stat.ino === 0n) return null;
|
|
1094
1187
|
return [stat.dev, stat.ino, stat.size, stat.mtimeNs, stat.ctimeNs].join(
|
|
1095
1188
|
":"
|
|
@@ -1118,18 +1211,18 @@ function effectiveConfigIdentity(cwd) {
|
|
|
1118
1211
|
}
|
|
1119
1212
|
function readSmallText(filePath) {
|
|
1120
1213
|
try {
|
|
1121
|
-
return
|
|
1214
|
+
return fs8.readFileSync(filePath, "utf8").trim();
|
|
1122
1215
|
} catch {
|
|
1123
1216
|
return null;
|
|
1124
1217
|
}
|
|
1125
1218
|
}
|
|
1126
1219
|
function findGitDirectory(cwd) {
|
|
1127
|
-
let current =
|
|
1220
|
+
let current = path18.resolve(cwd);
|
|
1128
1221
|
for (; ; ) {
|
|
1129
|
-
const candidate =
|
|
1222
|
+
const candidate = path18.join(current, ".git");
|
|
1130
1223
|
let stat;
|
|
1131
1224
|
try {
|
|
1132
|
-
stat =
|
|
1225
|
+
stat = fs8.statSync(candidate);
|
|
1133
1226
|
} catch {
|
|
1134
1227
|
stat = void 0;
|
|
1135
1228
|
}
|
|
@@ -1140,20 +1233,20 @@ function findGitDirectory(cwd) {
|
|
|
1140
1233
|
const pointer = readSmallText(candidate);
|
|
1141
1234
|
const match = pointer ? /^gitdir:\s*(.+)$/u.exec(pointer) : null;
|
|
1142
1235
|
if (!match?.[1]) return null;
|
|
1143
|
-
const gitDir =
|
|
1144
|
-
const common = readSmallText(
|
|
1236
|
+
const gitDir = path18.resolve(current, match[1]);
|
|
1237
|
+
const common = readSmallText(path18.join(gitDir, "commondir"));
|
|
1145
1238
|
return {
|
|
1146
1239
|
gitDir,
|
|
1147
|
-
commonDir: common ?
|
|
1240
|
+
commonDir: common ? path18.resolve(gitDir, common) : gitDir
|
|
1148
1241
|
};
|
|
1149
1242
|
}
|
|
1150
|
-
const parent =
|
|
1243
|
+
const parent = path18.dirname(current);
|
|
1151
1244
|
if (parent === current) return null;
|
|
1152
1245
|
current = parent;
|
|
1153
1246
|
}
|
|
1154
1247
|
}
|
|
1155
1248
|
function checkoutSignature(layout, cwd) {
|
|
1156
|
-
const headPath =
|
|
1249
|
+
const headPath = path18.join(layout.gitDir, "HEAD");
|
|
1157
1250
|
const head = readSmallText(headPath);
|
|
1158
1251
|
const configIdentity = effectiveConfigIdentity(cwd);
|
|
1159
1252
|
if (head === null || configIdentity === null) {
|
|
@@ -1162,14 +1255,14 @@ function checkoutSignature(layout, cwd) {
|
|
|
1162
1255
|
const parts = [layout.gitDir, head, configIdentity];
|
|
1163
1256
|
const ref = /^ref:\s*(.+)$/u.exec(head)?.[1];
|
|
1164
1257
|
if (ref) {
|
|
1165
|
-
const looseRefPath =
|
|
1258
|
+
const looseRefPath = path18.join(layout.commonDir, ref);
|
|
1166
1259
|
if (/^ref:/u.test(readSmallText(looseRefPath) ?? "")) return null;
|
|
1167
1260
|
const looseRefIdentity = fileContentIdentity(looseRefPath);
|
|
1168
1261
|
const packedIdentity = packedRefsIdentity(
|
|
1169
|
-
|
|
1262
|
+
path18.join(layout.commonDir, "packed-refs")
|
|
1170
1263
|
);
|
|
1171
1264
|
const reftableIdentity = fileContentIdentity(
|
|
1172
|
-
|
|
1265
|
+
path18.join(layout.commonDir, "reftable", "tables.list")
|
|
1173
1266
|
);
|
|
1174
1267
|
if (!looseRefIdentity || !packedIdentity || !reftableIdentity || looseRefIdentity === "missing" && packedIdentity === "missing" && reftableIdentity === "missing") {
|
|
1175
1268
|
return null;
|
|
@@ -1180,7 +1273,7 @@ function checkoutSignature(layout, cwd) {
|
|
|
1180
1273
|
}
|
|
1181
1274
|
function readPersistentOriginCache(cacheFile) {
|
|
1182
1275
|
try {
|
|
1183
|
-
const parsed = JSON.parse(
|
|
1276
|
+
const parsed = JSON.parse(fs8.readFileSync(cacheFile, "utf8"));
|
|
1184
1277
|
if (parsed && typeof parsed === "object" && parsed.schemaVersion === PERSISTENT_ORIGIN_CACHE_SCHEMA_VERSION && parsed.entries && typeof parsed.entries === "object") {
|
|
1185
1278
|
return parsed;
|
|
1186
1279
|
}
|
|
@@ -1191,13 +1284,13 @@ function readPersistentOriginCache(cacheFile) {
|
|
|
1191
1284
|
function writePersistentOriginCache(cacheFile, cache) {
|
|
1192
1285
|
const temporary = `${cacheFile}.${process.pid}.tmp`;
|
|
1193
1286
|
try {
|
|
1194
|
-
|
|
1195
|
-
|
|
1287
|
+
fs8.mkdirSync(path18.dirname(cacheFile), { recursive: true, mode: 448 });
|
|
1288
|
+
fs8.writeFileSync(temporary, `${JSON.stringify(cache)}
|
|
1196
1289
|
`, { mode: 384 });
|
|
1197
|
-
|
|
1290
|
+
fs8.renameSync(temporary, cacheFile);
|
|
1198
1291
|
} catch {
|
|
1199
1292
|
try {
|
|
1200
|
-
|
|
1293
|
+
fs8.rmSync(temporary, { force: true });
|
|
1201
1294
|
} catch {
|
|
1202
1295
|
}
|
|
1203
1296
|
}
|
|
@@ -1285,20 +1378,20 @@ function isAbortError(error) {
|
|
|
1285
1378
|
}
|
|
1286
1379
|
function safeStat(filePath) {
|
|
1287
1380
|
try {
|
|
1288
|
-
return
|
|
1381
|
+
return fs9.statSync(filePath);
|
|
1289
1382
|
} catch {
|
|
1290
1383
|
return null;
|
|
1291
1384
|
}
|
|
1292
1385
|
}
|
|
1293
1386
|
function normalizeFilePath2(filePath) {
|
|
1294
|
-
return
|
|
1387
|
+
return path19.resolve(filePath);
|
|
1295
1388
|
}
|
|
1296
1389
|
function artifactReadPath(artifact) {
|
|
1297
1390
|
return normalizeFilePath2(artifact.readPath ?? artifact.sourcePath);
|
|
1298
1391
|
}
|
|
1299
1392
|
function statCandidateSource(sourcePath, transientStatErrors) {
|
|
1300
1393
|
try {
|
|
1301
|
-
return
|
|
1394
|
+
return fs9.statSync(sourcePath);
|
|
1302
1395
|
} catch (error) {
|
|
1303
1396
|
if (error.code === "ENOENT") return null;
|
|
1304
1397
|
if (transientStatErrors === "throw") throw error;
|
|
@@ -1306,7 +1399,7 @@ function statCandidateSource(sourcePath, transientStatErrors) {
|
|
|
1306
1399
|
}
|
|
1307
1400
|
}
|
|
1308
1401
|
function contentTypeForPath(filePath) {
|
|
1309
|
-
const ext =
|
|
1402
|
+
const ext = path19.extname(filePath).toLowerCase();
|
|
1310
1403
|
if (ext === ".json" || ext === ".jsonl") return "application/json";
|
|
1311
1404
|
if (ext === ".md") return "text/markdown";
|
|
1312
1405
|
if (ext === ".toml") return "application/toml";
|
|
@@ -1349,13 +1442,14 @@ function discoverArtifacts(options = {}) {
|
|
|
1349
1442
|
};
|
|
1350
1443
|
}
|
|
1351
1444
|
const homeDir = normalizeFilePath2(homeDirInput);
|
|
1445
|
+
const maxBytes = options.maxFileBytes ?? DEFAULT_MAX_ARTIFACT_BYTES;
|
|
1352
1446
|
const candidates = discoverTargetArtifactCandidates({
|
|
1353
1447
|
homeDir,
|
|
1354
1448
|
env,
|
|
1449
|
+
maxFileBytes: maxBytes,
|
|
1355
1450
|
resolveGitHubOrigin: repositoryResolution.resolve,
|
|
1356
1451
|
...options.materializeArtifact ? { materializeArtifact: options.materializeArtifact } : {}
|
|
1357
1452
|
});
|
|
1358
|
-
const maxBytes = options.maxFileBytes ?? DEFAULT_MAX_ARTIFACT_BYTES;
|
|
1359
1453
|
const byKey = /* @__PURE__ */ new Map();
|
|
1360
1454
|
const oversizedByKey = /* @__PURE__ */ new Map();
|
|
1361
1455
|
for (const candidate of candidates) {
|
|
@@ -1418,7 +1512,7 @@ function readUploadThrottles(value) {
|
|
|
1418
1512
|
}
|
|
1419
1513
|
function readArtifactQueue(queueFile) {
|
|
1420
1514
|
try {
|
|
1421
|
-
const parsed = JSON.parse(
|
|
1515
|
+
const parsed = JSON.parse(fs9.readFileSync(queueFile, "utf8"));
|
|
1422
1516
|
if (!parsed || typeof parsed !== "object") return emptyQueue();
|
|
1423
1517
|
const record = parsed;
|
|
1424
1518
|
if (record.schemaVersion !== RAW_ARTIFACT_SCHEMA_VERSION) {
|
|
@@ -1435,15 +1529,15 @@ function readArtifactQueue(queueFile) {
|
|
|
1435
1529
|
}
|
|
1436
1530
|
}
|
|
1437
1531
|
function writeArtifactQueue(queueFile, queue) {
|
|
1438
|
-
|
|
1532
|
+
fs9.mkdirSync(path19.dirname(queueFile), { recursive: true, mode: 448 });
|
|
1439
1533
|
const tempFile = `${queueFile}.${process.pid}.${Date.now()}.tmp`;
|
|
1440
|
-
|
|
1534
|
+
fs9.writeFileSync(tempFile, `${JSON.stringify(queue, null, 2)}
|
|
1441
1535
|
`, {
|
|
1442
1536
|
mode: 384
|
|
1443
1537
|
});
|
|
1444
|
-
|
|
1538
|
+
fs9.renameSync(tempFile, queueFile);
|
|
1445
1539
|
try {
|
|
1446
|
-
|
|
1540
|
+
fs9.chmodSync(queueFile, 384);
|
|
1447
1541
|
} catch {
|
|
1448
1542
|
}
|
|
1449
1543
|
}
|
|
@@ -1460,11 +1554,20 @@ function nextGenerationStartedAtMs(nowMs, existing) {
|
|
|
1460
1554
|
return existing ? Math.max(nowMs, existing.generationStartedAtMs + 1) : nowMs;
|
|
1461
1555
|
}
|
|
1462
1556
|
function shouldStartNewGeneration(input) {
|
|
1557
|
+
if (input.existing.source === "mini-swe-agent") {
|
|
1558
|
+
if (input.existing.contentSha256) {
|
|
1559
|
+
try {
|
|
1560
|
+
return createHash5("sha256").update(fs9.readFileSync(input.nextReadPath)).digest("hex") !== input.existing.contentSha256;
|
|
1561
|
+
} catch {
|
|
1562
|
+
}
|
|
1563
|
+
}
|
|
1564
|
+
return input.nextSizeBytes !== input.existing.sizeBytes || input.nextMtimeMs !== input.existing.mtimeMs;
|
|
1565
|
+
}
|
|
1463
1566
|
if (input.nextSizeBytes < input.existing.uploadedSizeBytes) return true;
|
|
1464
1567
|
if (input.nextSizeBytes < input.existing.sizeBytes) return true;
|
|
1465
1568
|
if ((input.nextReadPath !== artifactReadPath(input.existing) || input.existing.readPath !== void 0) && input.nextSizeBytes === input.existing.sizeBytes && input.existing.uploadedSizeBytes >= input.nextSizeBytes && input.existing.contentSha256) {
|
|
1466
1569
|
try {
|
|
1467
|
-
const contentSha256 = createHash5("sha256").update(
|
|
1570
|
+
const contentSha256 = createHash5("sha256").update(fs9.readFileSync(input.nextReadPath)).digest("hex");
|
|
1468
1571
|
if (contentSha256 === input.existing.contentSha256) return false;
|
|
1469
1572
|
} catch {
|
|
1470
1573
|
}
|
|
@@ -1583,7 +1686,7 @@ function metadataForGeneration(input) {
|
|
|
1583
1686
|
...repositoryContext ? { repositoryContext } : {}
|
|
1584
1687
|
};
|
|
1585
1688
|
}
|
|
1586
|
-
function
|
|
1689
|
+
function snapshotCandidate2(candidate, existing, nowMs, maxFileBytes, transientStatErrors = "ignore", observerIdentity) {
|
|
1587
1690
|
const sourcePath = normalizeFilePath2(candidate.sourcePath);
|
|
1588
1691
|
const readPath = artifactReadPath(candidate);
|
|
1589
1692
|
const stat = statCandidateSource(readPath, transientStatErrors);
|
|
@@ -1727,7 +1830,7 @@ function snapshotArtifactsLocked(options, lock) {
|
|
|
1727
1830
|
throw new Error("artifact queue lock ownership was lost");
|
|
1728
1831
|
}
|
|
1729
1832
|
const existing = (candidate.identityKey ? entriesByIdentityKey.get(candidate.identityKey) : void 0) ?? entriesByKey.get(buildArtifactKey(candidate));
|
|
1730
|
-
const snapshot =
|
|
1833
|
+
const snapshot = snapshotCandidate2(
|
|
1731
1834
|
candidate,
|
|
1732
1835
|
existing,
|
|
1733
1836
|
nowMs,
|
|
@@ -1798,7 +1901,7 @@ function sameSourceRevision(left, right) {
|
|
|
1798
1901
|
}
|
|
1799
1902
|
function safeSourceRevision(filePath) {
|
|
1800
1903
|
try {
|
|
1801
|
-
const stat =
|
|
1904
|
+
const stat = fs9.statSync(filePath, { bigint: true });
|
|
1802
1905
|
return stat.isFile() ? sourceRevisionFromStat(stat) : null;
|
|
1803
1906
|
} catch {
|
|
1804
1907
|
return null;
|
|
@@ -1810,7 +1913,7 @@ function readExactRange(fd, startByte, endByte) {
|
|
|
1810
1913
|
const buffer = Buffer.alloc(sizeBytes);
|
|
1811
1914
|
let offset = 0;
|
|
1812
1915
|
while (offset < sizeBytes) {
|
|
1813
|
-
const bytesRead =
|
|
1916
|
+
const bytesRead = fs9.readSync(
|
|
1814
1917
|
fd,
|
|
1815
1918
|
buffer,
|
|
1816
1919
|
offset,
|
|
@@ -1829,19 +1932,19 @@ function readFileRangeAtRevision(filePath, startByte, endByte, expectedRevision)
|
|
|
1829
1932
|
}
|
|
1830
1933
|
let fd;
|
|
1831
1934
|
try {
|
|
1832
|
-
fd =
|
|
1935
|
+
fd = fs9.openSync(filePath, "r");
|
|
1833
1936
|
} catch {
|
|
1834
1937
|
return null;
|
|
1835
1938
|
}
|
|
1836
1939
|
try {
|
|
1837
1940
|
const openedRevision = sourceRevisionFromStat(
|
|
1838
|
-
|
|
1941
|
+
fs9.fstatSync(fd, { bigint: true })
|
|
1839
1942
|
);
|
|
1840
1943
|
if (!sameSourceRevision(pathRevisionBefore, openedRevision)) return null;
|
|
1841
1944
|
const bytes = readExactRange(fd, startByte, endByte);
|
|
1842
1945
|
if (!bytes) return null;
|
|
1843
1946
|
const revisionAfterRead = sourceRevisionFromStat(
|
|
1844
|
-
|
|
1947
|
+
fs9.fstatSync(fd, { bigint: true })
|
|
1845
1948
|
);
|
|
1846
1949
|
const pathRevisionAfter = safeSourceRevision(filePath);
|
|
1847
1950
|
if (!sameSourceRevision(openedRevision, revisionAfterRead) || !pathRevisionAfter || !sameSourceRevision(openedRevision, pathRevisionAfter)) {
|
|
@@ -1851,7 +1954,7 @@ function readFileRangeAtRevision(filePath, startByte, endByte, expectedRevision)
|
|
|
1851
1954
|
} catch {
|
|
1852
1955
|
return null;
|
|
1853
1956
|
} finally {
|
|
1854
|
-
|
|
1957
|
+
fs9.closeSync(fd);
|
|
1855
1958
|
}
|
|
1856
1959
|
}
|
|
1857
1960
|
function uploadMetadata(input) {
|
|
@@ -1983,13 +2086,13 @@ function validateCheckpointPrefix(input) {
|
|
|
1983
2086
|
}
|
|
1984
2087
|
let fd;
|
|
1985
2088
|
try {
|
|
1986
|
-
fd =
|
|
2089
|
+
fd = fs9.openSync(input.sourcePath, "r");
|
|
1987
2090
|
} catch {
|
|
1988
2091
|
return { status: "changed" };
|
|
1989
2092
|
}
|
|
1990
2093
|
try {
|
|
1991
2094
|
const openedRevision = sourceRevisionFromStat(
|
|
1992
|
-
|
|
2095
|
+
fs9.fstatSync(fd, { bigint: true })
|
|
1993
2096
|
);
|
|
1994
2097
|
if (!sameSourceRevision(pathRevisionBefore, openedRevision)) {
|
|
1995
2098
|
return { status: "changed" };
|
|
@@ -2009,7 +2112,7 @@ function validateCheckpointPrefix(input) {
|
|
|
2009
2112
|
contentHash.update(chunk);
|
|
2010
2113
|
}
|
|
2011
2114
|
const revisionAfterRead = sourceRevisionFromStat(
|
|
2012
|
-
|
|
2115
|
+
fs9.fstatSync(fd, { bigint: true })
|
|
2013
2116
|
);
|
|
2014
2117
|
const pathRevisionAfter = safeSourceRevision(input.sourcePath);
|
|
2015
2118
|
if (!sameSourceRevision(openedRevision, revisionAfterRead) || !pathRevisionAfter || !sameSourceRevision(openedRevision, pathRevisionAfter)) {
|
|
@@ -2024,7 +2127,7 @@ function validateCheckpointPrefix(input) {
|
|
|
2024
2127
|
} catch {
|
|
2025
2128
|
return { status: "changed" };
|
|
2026
2129
|
} finally {
|
|
2027
|
-
|
|
2130
|
+
fs9.closeSync(fd);
|
|
2028
2131
|
}
|
|
2029
2132
|
}
|
|
2030
2133
|
function validatedPrefixStillApplies(prefix, entry, uploadDestinationId, revision) {
|
|
@@ -2158,14 +2261,14 @@ function defaultIsPidAlive(pid) {
|
|
|
2158
2261
|
}
|
|
2159
2262
|
function readQueueLockHolder(lockFile) {
|
|
2160
2263
|
try {
|
|
2161
|
-
const parsed = JSON.parse(
|
|
2264
|
+
const parsed = JSON.parse(fs9.readFileSync(lockFile, "utf8"));
|
|
2162
2265
|
if (!parsed || typeof parsed !== "object") return null;
|
|
2163
2266
|
const record = parsed;
|
|
2164
2267
|
if (typeof record.pid !== "number" || typeof record.timestampMs !== "number") {
|
|
2165
2268
|
return null;
|
|
2166
2269
|
}
|
|
2167
2270
|
const ownerToken = typeof record.ownerToken === "string" ? record.ownerToken : void 0;
|
|
2168
|
-
const timestampMs = ownerToken ? Math.max(record.timestampMs,
|
|
2271
|
+
const timestampMs = ownerToken ? Math.max(record.timestampMs, fs9.statSync(lockFile).mtimeMs) : record.timestampMs;
|
|
2169
2272
|
return { pid: record.pid, timestampMs, ownerToken };
|
|
2170
2273
|
} catch {
|
|
2171
2274
|
return null;
|
|
@@ -2173,8 +2276,8 @@ function readQueueLockHolder(lockFile) {
|
|
|
2173
2276
|
}
|
|
2174
2277
|
function queueLockFileMatchesOwner(lockFile, fd, ownerToken) {
|
|
2175
2278
|
try {
|
|
2176
|
-
const openStat =
|
|
2177
|
-
const pathStat =
|
|
2279
|
+
const openStat = fs9.fstatSync(fd);
|
|
2280
|
+
const pathStat = fs9.statSync(lockFile);
|
|
2178
2281
|
if (openStat.dev !== pathStat.dev || openStat.ino !== pathStat.ino) {
|
|
2179
2282
|
return false;
|
|
2180
2283
|
}
|
|
@@ -2185,14 +2288,14 @@ function queueLockFileMatchesOwner(lockFile, fd, ownerToken) {
|
|
|
2185
2288
|
}
|
|
2186
2289
|
function acquireQueueLock(queueFile, deps) {
|
|
2187
2290
|
const lockFile = queueLockFile(queueFile);
|
|
2188
|
-
|
|
2291
|
+
fs9.mkdirSync(path19.dirname(lockFile), { recursive: true, mode: 448 });
|
|
2189
2292
|
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
2190
2293
|
try {
|
|
2191
|
-
const fd =
|
|
2294
|
+
const fd = fs9.openSync(lockFile, "wx+", 384);
|
|
2192
2295
|
const ownerToken = randomUUID3();
|
|
2193
2296
|
let released = false;
|
|
2194
2297
|
try {
|
|
2195
|
-
|
|
2298
|
+
fs9.writeSync(
|
|
2196
2299
|
fd,
|
|
2197
2300
|
`${JSON.stringify({
|
|
2198
2301
|
pid: process.pid,
|
|
@@ -2202,11 +2305,11 @@ function acquireQueueLock(queueFile, deps) {
|
|
|
2202
2305
|
`
|
|
2203
2306
|
);
|
|
2204
2307
|
const heartbeatAt = new Date(deps.nowMs());
|
|
2205
|
-
|
|
2308
|
+
fs9.futimesSync(fd, heartbeatAt, heartbeatAt);
|
|
2206
2309
|
} catch (error) {
|
|
2207
|
-
|
|
2310
|
+
fs9.closeSync(fd);
|
|
2208
2311
|
try {
|
|
2209
|
-
|
|
2312
|
+
fs9.unlinkSync(lockFile);
|
|
2210
2313
|
} catch {
|
|
2211
2314
|
}
|
|
2212
2315
|
throw error;
|
|
@@ -2214,7 +2317,7 @@ function acquireQueueLock(queueFile, deps) {
|
|
|
2214
2317
|
const close = () => {
|
|
2215
2318
|
if (released) return;
|
|
2216
2319
|
released = true;
|
|
2217
|
-
|
|
2320
|
+
fs9.closeSync(fd);
|
|
2218
2321
|
};
|
|
2219
2322
|
return {
|
|
2220
2323
|
heartbeat() {
|
|
@@ -2223,7 +2326,7 @@ function acquireQueueLock(queueFile, deps) {
|
|
|
2223
2326
|
return false;
|
|
2224
2327
|
try {
|
|
2225
2328
|
const heartbeatAt = new Date(deps.nowMs());
|
|
2226
|
-
|
|
2329
|
+
fs9.futimesSync(fd, heartbeatAt, heartbeatAt);
|
|
2227
2330
|
return true;
|
|
2228
2331
|
} catch {
|
|
2229
2332
|
return false;
|
|
@@ -2233,7 +2336,7 @@ function acquireQueueLock(queueFile, deps) {
|
|
|
2233
2336
|
if (released) return;
|
|
2234
2337
|
if (queueLockFileMatchesOwner(lockFile, fd, ownerToken)) {
|
|
2235
2338
|
try {
|
|
2236
|
-
|
|
2339
|
+
fs9.unlinkSync(lockFile);
|
|
2237
2340
|
} catch {
|
|
2238
2341
|
}
|
|
2239
2342
|
}
|
|
@@ -2246,7 +2349,7 @@ function acquireQueueLock(queueFile, deps) {
|
|
|
2246
2349
|
const stale = !holder || !deps.isPidAlive(holder.pid) || deps.nowMs() - holder.timestampMs > QUEUE_LOCK_STALE_MS;
|
|
2247
2350
|
if (!stale) return null;
|
|
2248
2351
|
try {
|
|
2249
|
-
|
|
2352
|
+
fs9.unlinkSync(lockFile);
|
|
2250
2353
|
} catch {
|
|
2251
2354
|
}
|
|
2252
2355
|
}
|
|
@@ -2304,7 +2407,7 @@ async function postRawArtifact(url, metadata, content, headers, fetchImpl = fetc
|
|
|
2304
2407
|
form.append(
|
|
2305
2408
|
"file",
|
|
2306
2409
|
new Blob([new Uint8Array(content)], { type: metadata.contentType }),
|
|
2307
|
-
|
|
2410
|
+
path19.basename(metadata.sourcePath) || "raw-artifact"
|
|
2308
2411
|
);
|
|
2309
2412
|
const abort = new AbortController();
|
|
2310
2413
|
const timeout = setTimeout(() => abort.abort(), timeoutMs);
|
|
@@ -2663,7 +2766,7 @@ async function uploadPendingArtifactsLocked(options, run) {
|
|
|
2663
2766
|
let sourceRefreshesThisAttempt = 0;
|
|
2664
2767
|
let validatedPrefix;
|
|
2665
2768
|
const refreshSourceSnapshot = () => {
|
|
2666
|
-
const snapshot =
|
|
2769
|
+
const snapshot = snapshotCandidate2(
|
|
2667
2770
|
{
|
|
2668
2771
|
artifactType: current.artifactType,
|
|
2669
2772
|
source: current.source,
|
|
@@ -3193,11 +3296,11 @@ async function uploadPendingArtifactsLocked(options, run) {
|
|
|
3193
3296
|
}
|
|
3194
3297
|
|
|
3195
3298
|
// ../../packages/panopticon/src/raw-sync.ts
|
|
3196
|
-
import
|
|
3197
|
-
import
|
|
3299
|
+
import fs11 from "fs";
|
|
3300
|
+
import path20 from "path";
|
|
3198
3301
|
|
|
3199
3302
|
// ../../packages/panopticon/src/artifact-materializer.ts
|
|
3200
|
-
import
|
|
3303
|
+
import fs10 from "fs";
|
|
3201
3304
|
function entryNeedsBytes(entry, amendmentPending) {
|
|
3202
3305
|
if (entry.uploadedSizeBytes < entry.sizeBytes) return true;
|
|
3203
3306
|
return amendmentPending(entry);
|
|
@@ -3212,7 +3315,7 @@ function createArtifactMaterializer(input) {
|
|
|
3212
3315
|
const unsupportedReason = (input.supportsCompression ?? supportsCompressedArtifacts)() ? void 0 : `compressed artifacts need Node 22.15 or newer (running ${process.version})`;
|
|
3213
3316
|
const chargeExisting = (cachePath) => {
|
|
3214
3317
|
try {
|
|
3215
|
-
const stat =
|
|
3318
|
+
const stat = fs10.statSync(cachePath);
|
|
3216
3319
|
if (!stat.isFile()) return false;
|
|
3217
3320
|
if (!retained.has(cachePath)) {
|
|
3218
3321
|
retained.add(cachePath);
|
|
@@ -3260,20 +3363,20 @@ function getRawArtifactSyncPaths(stateDir) {
|
|
|
3260
3363
|
if (stateDir.length === 0) {
|
|
3261
3364
|
throw new Error("raw artifact sync state directory must not be empty");
|
|
3262
3365
|
}
|
|
3263
|
-
const root =
|
|
3366
|
+
const root = path20.resolve(stateDir);
|
|
3264
3367
|
const managed = getManagedClientPaths({ PANOPTICON_HOME: root });
|
|
3265
3368
|
return {
|
|
3266
3369
|
root,
|
|
3267
3370
|
settingsFile: managed.syncSettingsFile,
|
|
3268
3371
|
queueFile: managed.artifactQueue,
|
|
3269
3372
|
artifactCacheDir: managed.artifactCache,
|
|
3270
|
-
discoveryCacheFile:
|
|
3271
|
-
githubOriginCacheFile:
|
|
3373
|
+
discoveryCacheFile: path20.join(root, "discovery.cache.json"),
|
|
3374
|
+
githubOriginCacheFile: path20.join(root, "github-origins.cache.json")
|
|
3272
3375
|
};
|
|
3273
3376
|
}
|
|
3274
3377
|
function invalidateRawArtifactDiscoveryCache(stateDir) {
|
|
3275
3378
|
try {
|
|
3276
|
-
|
|
3379
|
+
fs11.rmSync(getRawArtifactSyncPaths(stateDir).discoveryCacheFile, {
|
|
3277
3380
|
force: true
|
|
3278
3381
|
});
|
|
3279
3382
|
} catch {
|
|
@@ -3382,7 +3485,7 @@ function createRawArtifactSync(options) {
|
|
|
3382
3485
|
if (reuseMs <= 0) return null;
|
|
3383
3486
|
try {
|
|
3384
3487
|
const parsed = JSON.parse(
|
|
3385
|
-
|
|
3488
|
+
fs11.readFileSync(paths.discoveryCacheFile, "utf8")
|
|
3386
3489
|
);
|
|
3387
3490
|
if (parsed.schemaVersion !== DISCOVERY_CACHE_SCHEMA_VERSION || typeof parsed.createdAtMs !== "number" || parsed.inputs !== discoveryInputs() || !parsed.discovery || typeof parsed.discovery !== "object") {
|
|
3388
3491
|
return null;
|
|
@@ -3398,11 +3501,11 @@ function createRawArtifactSync(options) {
|
|
|
3398
3501
|
if ((options.discoveryReuseMs ?? 0) <= 0) return;
|
|
3399
3502
|
const temporary = `${paths.discoveryCacheFile}.${process.pid}.tmp`;
|
|
3400
3503
|
try {
|
|
3401
|
-
|
|
3504
|
+
fs11.mkdirSync(path20.dirname(paths.discoveryCacheFile), {
|
|
3402
3505
|
recursive: true,
|
|
3403
3506
|
mode: 448
|
|
3404
3507
|
});
|
|
3405
|
-
|
|
3508
|
+
fs11.writeFileSync(
|
|
3406
3509
|
temporary,
|
|
3407
3510
|
`${JSON.stringify({
|
|
3408
3511
|
schemaVersion: DISCOVERY_CACHE_SCHEMA_VERSION,
|
|
@@ -3413,10 +3516,10 @@ function createRawArtifactSync(options) {
|
|
|
3413
3516
|
`,
|
|
3414
3517
|
{ mode: 384 }
|
|
3415
3518
|
);
|
|
3416
|
-
|
|
3519
|
+
fs11.renameSync(temporary, paths.discoveryCacheFile);
|
|
3417
3520
|
} catch {
|
|
3418
3521
|
try {
|
|
3419
|
-
|
|
3522
|
+
fs11.rmSync(temporary, { force: true });
|
|
3420
3523
|
} catch {
|
|
3421
3524
|
}
|
|
3422
3525
|
}
|