@fml-inc/fml 0.8.13-rc.1 → 0.8.13-rc.2

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.
@@ -1,6 +1,9 @@
1
1
  import {
2
- canonicalGitHubRepository
3
- } from "./chunk-CSOFP7MT.js";
2
+ GIT_STATE_CACHE_FILENAME,
3
+ canonicalGitHubRepository,
4
+ createGitStateResolver,
5
+ parseGitState
6
+ } from "./chunk-74KOMQZO.js";
4
7
  import {
5
8
  FML_INSTALLATION_ID_FILE,
6
9
  FML_OBSERVER_DIR,
@@ -186,10 +189,10 @@ function setSyncEnabled(settingsFile, enabled) {
186
189
  }
187
190
 
188
191
  // ../../packages/panopticon/src/artifacts.ts
189
- import { createHash as createHash5, randomUUID as randomUUID3 } from "crypto";
190
- import fs9 from "fs";
192
+ import { createHash as createHash4, randomUUID as randomUUID3 } from "crypto";
193
+ import fs8 from "fs";
191
194
  import os3 from "os";
192
- import path20 from "path";
195
+ import path19 from "path";
193
196
 
194
197
  // ../../packages/agent-targets/src/pi-agent-dir.ts
195
198
  import path6 from "path";
@@ -451,14 +454,29 @@ function repositoryObservation(input) {
451
454
  ...commitHash ? { commitHash } : {}
452
455
  };
453
456
  }
457
+ function localGitStateMetadata(states, source = "transcript_discovery") {
458
+ const bounded = [];
459
+ for (const state of states) {
460
+ if (!state || Buffer.byteLength(
461
+ JSON.stringify({ version: 1, source, states: [...bounded, state] }),
462
+ "utf8"
463
+ ) > 4 * 1024)
464
+ continue;
465
+ bounded.push(state);
466
+ }
467
+ return bounded.length ? { localGitStates: { version: 1, source, states: bounded } } : {};
468
+ }
454
469
 
455
470
  // ../../packages/agent-targets/src/artifacts/targets/claude.ts
456
471
  function claudeTranscriptCandidate(sourcePath, context, harnessInstallId) {
457
472
  const fallbackObservedAtMs = (context.nowMs ?? Date.now)();
473
+ const states = /* @__PURE__ */ new Map();
458
474
  const observations = /* @__PURE__ */ new Map();
459
475
  for (const record of readJsonlContextRecords(sourcePath)) {
460
476
  if (typeof record.cwd !== "string" || !record.cwd.trim()) continue;
461
477
  const origin = context.resolveGitHubOrigin?.(record.cwd);
478
+ const state = origin?.gitState ?? context.resolveGitState?.(record.cwd);
479
+ if (state) states.set(state.worktreeRoot, state);
462
480
  if (!origin) continue;
463
481
  const observation = repositoryObservation({
464
482
  repository: origin.repository,
@@ -473,7 +491,10 @@ function claudeTranscriptCandidate(sourcePath, context, harnessInstallId) {
473
491
  return transcriptCandidate({
474
492
  targetId: "claude",
475
493
  sourcePath,
476
- metadata: harnessInstallId ? { harnessInstallId } : void 0,
494
+ metadata: {
495
+ ...harnessInstallId ? { harnessInstallId } : {},
496
+ ...localGitStateMetadata([...states.values()])
497
+ },
477
498
  repositoryObservations: [...observations.values()]
478
499
  });
479
500
  }
@@ -513,6 +534,7 @@ function codexTranscriptCandidate(sourcePath, readPath, store, context, harnessI
513
534
  const git = recordValue(payload.git);
514
535
  const nativeRepository = typeof git?.repository_url === "string" ? canonicalGitHubRepository(git.repository_url) : null;
515
536
  const origin = cwd ? context.resolveGitHubOrigin?.(cwd) : null;
537
+ const state = origin?.gitState ?? (cwd ? context.resolveGitState?.(cwd) : null);
516
538
  const observations = [];
517
539
  if (nativeRepository) {
518
540
  observations.push(
@@ -547,7 +569,11 @@ function codexTranscriptCandidate(sourcePath, readPath, store, context, harnessI
547
569
  identityKey,
548
570
  readPath,
549
571
  sessionId,
550
- metadata: { store, ...identityMetadata },
572
+ metadata: {
573
+ store,
574
+ ...identityMetadata,
575
+ ...localGitStateMetadata([state])
576
+ },
551
577
  repositoryObservations: observations
552
578
  });
553
579
  }
@@ -827,6 +853,12 @@ var PI_REPOSITORY_ORIGIN_ENTRY_TYPE = "fml-repository-origin";
827
853
  var RepositorySlugSchema = z.string().regex(/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/u).transform((slug) => canonicalGitHubRepository(`https://github.com/${slug}`)).pipe(z.string());
828
854
  var PiRepositoryOriginDataSchema = z.object({
829
855
  version: z.literal(1),
856
+ gitState: z.unknown().transform((value, ctx) => {
857
+ const state = parseGitState(value);
858
+ if (state) return state;
859
+ ctx.addIssue({ code: "custom", message: "Invalid Git state snapshot" });
860
+ return z.NEVER;
861
+ }).nullable().optional(),
830
862
  repository: RepositorySlugSchema.nullable(),
831
863
  cwd: z.string().min(1).refine(
832
864
  (cwd) => cwd.trim().length > 0 && !new RegExp("\\p{Cc}", "u").test(cwd) && Buffer.byteLength(cwd, "utf8") <= 4096
@@ -868,12 +900,15 @@ function piTranscriptCandidate(sourcePath) {
868
900
  targetId: "pi",
869
901
  sourcePath,
870
902
  sessionId,
903
+ metadata: localGitStateMetadata([snapshot?.gitState], "pi_origin"),
871
904
  repositoryObservations: snapshot?.repository ? [
872
905
  repositoryObservation({
873
906
  repository: snapshot.repository,
874
907
  source: "git_origin",
875
908
  observedAtMs: snapshot.observedAtMs,
876
- cwd: snapshot.cwd
909
+ cwd: snapshot.cwd,
910
+ branch: snapshot.gitState?.branch,
911
+ commitHash: snapshot.gitState?.commitHash
877
912
  })
878
913
  ] : []
879
914
  });
@@ -1026,78 +1061,18 @@ function pruneMaterializedCache(input) {
1026
1061
  }
1027
1062
 
1028
1063
  // ../../packages/panopticon/src/repository-context.ts
1029
- import { execFileSync } from "child_process";
1030
- import { createHash as createHash4 } from "crypto";
1031
- import fs8 from "fs";
1032
- import path19 from "path";
1033
- var MAX_CWD_BYTES2 = 4096;
1034
- var GIT_OUTPUT_BYTES = 16 * 1024;
1035
- var GIT_CONFIG_OUTPUT_BYTES = 4 * 1024 * 1024;
1036
- var GIT_TIMEOUT_MS = 1e3;
1037
1064
  var DEFAULT_GITHUB_ORIGIN_CACHE_MAX_ENTRIES = 512;
1038
- var ReadOnlyGitCommandError = class extends Error {
1039
- constructor() {
1040
- super("read-only git command failed");
1041
- }
1042
- };
1043
- function validCwd(cwd) {
1044
- const trimmed = cwd.trim();
1045
- return trimmed === cwd && trimmed.length > 0 && !new RegExp("\\p{Cc}", "u").test(trimmed) && Buffer.byteLength(trimmed, "utf8") <= MAX_CWD_BYTES2;
1046
- }
1047
- function runReadOnlyGit(cwd, args, maxBuffer = GIT_OUTPUT_BYTES) {
1048
- if (!validCwd(cwd)) return null;
1049
- try {
1050
- return execFileSync("git", ["-C", cwd, ...args], {
1051
- encoding: "utf8",
1052
- maxBuffer,
1053
- timeout: GIT_TIMEOUT_MS,
1054
- stdio: ["ignore", "pipe", "ignore"],
1055
- windowsHide: true
1056
- }).trim() || null;
1057
- } catch (error) {
1058
- const status = error && typeof error === "object" && "status" in error ? error.status : void 0;
1059
- if (status === 2 && args.length === 3 && args[0] === "remote" && args[1] === "get-url" && args[2] === "origin") {
1060
- return null;
1061
- }
1062
- throw new ReadOnlyGitCommandError();
1063
- }
1064
- }
1065
- function resolveGitHubOriginResult(cwd, runGit = runReadOnlyGit) {
1066
- let remote;
1067
- try {
1068
- remote = runGit(cwd, ["remote", "get-url", "origin"]);
1069
- } catch {
1070
- return { origin: null, definitive: false };
1071
- }
1072
- const repository = remote ? canonicalGitHubRepository(remote) : null;
1073
- if (!repository) return { origin: null, definitive: true };
1074
- let branchResult;
1075
- try {
1076
- branchResult = runGit(cwd, ["rev-parse", "--abbrev-ref", "HEAD"]);
1077
- } catch {
1078
- return { origin: { repository }, definitive: false };
1079
- }
1080
- const branch = branchResult === "HEAD" ? null : branchResult;
1081
- let commitHash;
1082
- try {
1083
- commitHash = runGit(cwd, ["rev-parse", "HEAD"]);
1084
- } catch {
1085
- return {
1086
- origin: { repository, ...branch ? { branch } : {} },
1087
- definitive: false
1088
- };
1089
- }
1090
- return {
1091
- origin: {
1092
- repository,
1093
- ...branch ? { branch } : {},
1094
- ...commitHash ? { commitHash } : {}
1095
- },
1096
- definitive: true
1097
- };
1098
- }
1099
- function resolveGitHubOrigin(cwd, runGit = runReadOnlyGit) {
1100
- return resolveGitHubOriginResult(cwd, runGit).origin;
1065
+ var DEFAULT_RESOLVER = createGitStateResolver();
1066
+ function gitStateOrigin(state) {
1067
+ return state?.repository ? {
1068
+ repository: state.repository,
1069
+ ...state.branch ? { branch: state.branch } : {},
1070
+ ...state.commitHash ? { commitHash: state.commitHash } : {},
1071
+ gitState: state
1072
+ } : null;
1073
+ }
1074
+ function resolveGitHubOrigin(cwd) {
1075
+ return gitStateOrigin(DEFAULT_RESOLVER.resolve(cwd));
1101
1076
  }
1102
1077
  function createMeasuredGitHubOriginResolver(resolve = (cwd) => resolveGitHubOrigin(cwd), nowMs = () => performance.now(), options = {}) {
1103
1078
  const cache = /* @__PURE__ */ new Map();
@@ -1165,173 +1140,29 @@ function createMeasuredGitHubOriginResolver(resolve = (cwd) => resolveGitHubOrig
1165
1140
  })
1166
1141
  };
1167
1142
  }
1168
- var PERSISTENT_ORIGIN_CACHE_SCHEMA_VERSION = 2;
1169
- var DEFAULT_PERSISTENT_ORIGIN_CACHE_MAX_ENTRIES = 512;
1170
- function fileContentIdentity(filePath) {
1171
- try {
1172
- const contents = fs8.readFileSync(filePath);
1173
- return `sha256:${createHash4("sha256").update(contents).digest("hex")}`;
1174
- } catch (error) {
1175
- const code = error && typeof error === "object" && "code" in error ? error.code : void 0;
1176
- return code === "ENOENT" || code === "ENOTDIR" ? "missing" : null;
1177
- }
1178
- }
1179
- function packedRefsIdentity(filePath) {
1180
- try {
1181
- const stat = fs8.statSync(filePath, { bigint: true });
1182
- if (!stat.isFile() || stat.ino === 0n) return null;
1183
- return [stat.dev, stat.ino, stat.size, stat.mtimeNs, stat.ctimeNs].join(
1184
- ":"
1185
- );
1186
- } catch (error) {
1187
- const code = error && typeof error === "object" && "code" in error ? error.code : void 0;
1188
- return code === "ENOENT" || code === "ENOTDIR" ? "missing" : null;
1189
- }
1190
- }
1191
- function effectiveConfigIdentity(cwd) {
1192
- if (["GIT_CONFIG", "GIT_DIR", "GIT_COMMON_DIR", "GIT_WORK_TREE"].some(
1193
- (name) => process.env[name] !== void 0
1194
- )) {
1195
- return null;
1196
- }
1197
- try {
1198
- const config = runReadOnlyGit(
1199
- cwd,
1200
- ["config", "--includes", "--null", "--list"],
1201
- GIT_CONFIG_OUTPUT_BYTES
1202
- );
1203
- return createHash4("sha256").update(config ?? "").digest("hex");
1204
- } catch {
1205
- return null;
1206
- }
1207
- }
1208
- function readSmallText(filePath) {
1209
- try {
1210
- return fs8.readFileSync(filePath, "utf8").trim();
1211
- } catch {
1212
- return null;
1213
- }
1214
- }
1215
- function findGitDirectory(cwd) {
1216
- let current = path19.resolve(cwd);
1217
- for (; ; ) {
1218
- const candidate = path19.join(current, ".git");
1219
- let stat;
1220
- try {
1221
- stat = fs8.statSync(candidate);
1222
- } catch {
1223
- stat = void 0;
1224
- }
1225
- if (stat?.isDirectory()) {
1226
- return { gitDir: candidate, commonDir: candidate };
1227
- }
1228
- if (stat?.isFile()) {
1229
- const pointer = readSmallText(candidate);
1230
- const match = pointer ? /^gitdir:\s*(.+)$/u.exec(pointer) : null;
1231
- if (!match?.[1]) return null;
1232
- const gitDir = path19.resolve(current, match[1]);
1233
- const common = readSmallText(path19.join(gitDir, "commondir"));
1234
- return {
1235
- gitDir,
1236
- commonDir: common ? path19.resolve(gitDir, common) : gitDir
1237
- };
1238
- }
1239
- const parent = path19.dirname(current);
1240
- if (parent === current) return null;
1241
- current = parent;
1242
- }
1243
- }
1244
- function checkoutSignature(layout, cwd) {
1245
- const headPath = path19.join(layout.gitDir, "HEAD");
1246
- const head = readSmallText(headPath);
1247
- const configIdentity = effectiveConfigIdentity(cwd);
1248
- if (head === null || configIdentity === null) {
1249
- return null;
1250
- }
1251
- const parts = [layout.gitDir, head, configIdentity];
1252
- const ref = /^ref:\s*(.+)$/u.exec(head)?.[1];
1253
- if (ref) {
1254
- const looseRefPath = path19.join(layout.commonDir, ref);
1255
- if (/^ref:/u.test(readSmallText(looseRefPath) ?? "")) return null;
1256
- const looseRefIdentity = fileContentIdentity(looseRefPath);
1257
- const packedIdentity = packedRefsIdentity(
1258
- path19.join(layout.commonDir, "packed-refs")
1259
- );
1260
- const reftableIdentity = fileContentIdentity(
1261
- path19.join(layout.commonDir, "reftable", "tables.list")
1262
- );
1263
- if (!looseRefIdentity || !packedIdentity || !reftableIdentity || looseRefIdentity === "missing" && packedIdentity === "missing" && reftableIdentity === "missing") {
1264
- return null;
1265
- }
1266
- parts.push(looseRefIdentity, packedIdentity, reftableIdentity);
1267
- }
1268
- return parts.join("\0");
1269
- }
1270
- function readPersistentOriginCache(cacheFile) {
1271
- try {
1272
- const parsed = JSON.parse(fs8.readFileSync(cacheFile, "utf8"));
1273
- if (parsed && typeof parsed === "object" && parsed.schemaVersion === PERSISTENT_ORIGIN_CACHE_SCHEMA_VERSION && parsed.entries && typeof parsed.entries === "object") {
1274
- return parsed;
1275
- }
1276
- } catch {
1277
- }
1278
- return { schemaVersion: PERSISTENT_ORIGIN_CACHE_SCHEMA_VERSION, entries: {} };
1279
- }
1280
- function writePersistentOriginCache(cacheFile, cache) {
1281
- const temporary = `${cacheFile}.${process.pid}.tmp`;
1282
- try {
1283
- fs8.mkdirSync(path19.dirname(cacheFile), { recursive: true, mode: 448 });
1284
- fs8.writeFileSync(temporary, `${JSON.stringify(cache)}
1285
- `, { mode: 384 });
1286
- fs8.renameSync(temporary, cacheFile);
1287
- } catch {
1288
- try {
1289
- fs8.rmSync(temporary, { force: true });
1290
- } catch {
1291
- }
1292
- }
1293
- }
1294
- function createPersistentGitHubOriginResolver(options) {
1295
- const maxEntries = options.maxEntries ?? DEFAULT_PERSISTENT_ORIGIN_CACHE_MAX_ENTRIES;
1296
- const cache = readPersistentOriginCache(options.cacheFile);
1297
- const entries = new Map(Object.entries(cache.entries));
1298
- const remember = (cwd, entry) => {
1299
- entries.delete(cwd);
1300
- entries.set(cwd, entry);
1301
- while (entries.size > maxEntries) {
1302
- const oldest = entries.keys().next().value;
1143
+ function createArtifactDiscoveryGitHubOriginResolver(options = {}) {
1144
+ const resolver = createGitStateResolver(options);
1145
+ const states = /* @__PURE__ */ new Map();
1146
+ const measured = createMeasuredGitHubOriginResolver((cwd) => {
1147
+ const state = resolver.resolve(cwd);
1148
+ states.delete(cwd);
1149
+ states.set(cwd, state);
1150
+ while (states.size > DEFAULT_GITHUB_ORIGIN_CACHE_MAX_ENTRIES) {
1151
+ const oldest = states.keys().next().value;
1303
1152
  if (oldest === void 0) break;
1304
- entries.delete(oldest);
1305
- }
1306
- writePersistentOriginCache(options.cacheFile, {
1307
- schemaVersion: PERSISTENT_ORIGIN_CACHE_SCHEMA_VERSION,
1308
- entries: Object.fromEntries(entries)
1309
- });
1310
- };
1311
- return (cwd) => {
1312
- if (!validCwd(cwd)) return null;
1313
- const layout = findGitDirectory(cwd);
1314
- if (!layout) return null;
1315
- const signature = checkoutSignature(layout, cwd);
1316
- const cached = entries.get(cwd);
1317
- if (signature !== null && cached && cached.signature === signature) {
1318
- return cached.origin;
1153
+ states.delete(oldest);
1319
1154
  }
1320
- try {
1321
- const result = options.resolve ? { origin: options.resolve(cwd), definitive: true } : resolveGitHubOriginResult(cwd);
1322
- if (signature !== null && result.definitive) {
1323
- remember(cwd, { signature, origin: result.origin });
1324
- }
1325
- return result.origin;
1326
- } catch {
1327
- return null;
1155
+ return gitStateOrigin(state);
1156
+ });
1157
+ return {
1158
+ ...measured,
1159
+ resolveState: (cwd) => {
1160
+ if (states.has(cwd)) return states.get(cwd) ?? null;
1161
+ const origin = measured.resolve(cwd);
1162
+ return origin?.gitState ?? (states.has(cwd) ? states.get(cwd) ?? null : resolver.resolve(cwd));
1328
1163
  }
1329
1164
  };
1330
1165
  }
1331
- function createArtifactDiscoveryGitHubOriginResolver(options = {}) {
1332
- const resolve = options.cacheFile ? createPersistentGitHubOriginResolver({ cacheFile: options.cacheFile }) : (cwd) => resolveGitHubOrigin(cwd);
1333
- return createMeasuredGitHubOriginResolver(resolve, () => performance.now());
1334
- }
1335
1166
 
1336
1167
  // ../../packages/panopticon/src/artifacts.ts
1337
1168
  var RAW_ARTIFACT_ENDPOINT = "/v1/ingest/raw-artifact";
@@ -1374,20 +1205,20 @@ function isAbortError(error) {
1374
1205
  }
1375
1206
  function safeStat(filePath) {
1376
1207
  try {
1377
- return fs9.statSync(filePath);
1208
+ return fs8.statSync(filePath);
1378
1209
  } catch {
1379
1210
  return null;
1380
1211
  }
1381
1212
  }
1382
1213
  function normalizeFilePath2(filePath) {
1383
- return path20.resolve(filePath);
1214
+ return path19.resolve(filePath);
1384
1215
  }
1385
1216
  function artifactReadPath(artifact) {
1386
1217
  return normalizeFilePath2(artifact.readPath ?? artifact.sourcePath);
1387
1218
  }
1388
1219
  function statCandidateSource(sourcePath, transientStatErrors) {
1389
1220
  try {
1390
- return fs9.statSync(sourcePath);
1221
+ return fs8.statSync(sourcePath);
1391
1222
  } catch (error) {
1392
1223
  if (error.code === "ENOENT") return null;
1393
1224
  if (transientStatErrors === "throw") throw error;
@@ -1395,7 +1226,7 @@ function statCandidateSource(sourcePath, transientStatErrors) {
1395
1226
  }
1396
1227
  }
1397
1228
  function contentTypeForPath(filePath) {
1398
- const ext = path20.extname(filePath).toLowerCase();
1229
+ const ext = path19.extname(filePath).toLowerCase();
1399
1230
  if (ext === ".json" || ext === ".jsonl") return "application/json";
1400
1231
  if (ext === ".md") return "text/markdown";
1401
1232
  if (ext === ".toml") return "application/toml";
@@ -1444,6 +1275,7 @@ function discoverArtifacts(options = {}) {
1444
1275
  env,
1445
1276
  maxFileBytes: maxBytes,
1446
1277
  resolveGitHubOrigin: repositoryResolution.resolve,
1278
+ resolveGitState: repositoryResolution.resolveState,
1447
1279
  ...options.materializeArtifact ? { materializeArtifact: options.materializeArtifact } : {}
1448
1280
  });
1449
1281
  const byKey = /* @__PURE__ */ new Map();
@@ -1508,7 +1340,7 @@ function readUploadThrottles(value) {
1508
1340
  }
1509
1341
  function readArtifactQueue(queueFile) {
1510
1342
  try {
1511
- const parsed = JSON.parse(fs9.readFileSync(queueFile, "utf8"));
1343
+ const parsed = JSON.parse(fs8.readFileSync(queueFile, "utf8"));
1512
1344
  if (!parsed || typeof parsed !== "object") return emptyQueue();
1513
1345
  const record = parsed;
1514
1346
  if (record.schemaVersion !== RAW_ARTIFACT_SCHEMA_VERSION) {
@@ -1524,16 +1356,52 @@ function readArtifactQueue(queueFile) {
1524
1356
  return emptyQueue();
1525
1357
  }
1526
1358
  }
1359
+ var QUEUE_WRITE_SLICE_ENTRIES = 256;
1360
+ function writeQueuePiece(fd, piece) {
1361
+ const buffer = Buffer.from(piece, "utf8");
1362
+ let offset = 0;
1363
+ while (offset < buffer.length) {
1364
+ const written = fs8.writeSync(fd, buffer, offset);
1365
+ if (written === 0) {
1366
+ throw new Error("artifact queue write made no progress");
1367
+ }
1368
+ offset += written;
1369
+ }
1370
+ }
1527
1371
  function writeArtifactQueue(queueFile, queue) {
1528
- fs9.mkdirSync(path20.dirname(queueFile), { recursive: true, mode: 448 });
1372
+ fs8.mkdirSync(path19.dirname(queueFile), { recursive: true, mode: 448 });
1529
1373
  const tempFile = `${queueFile}.${process.pid}.${Date.now()}.tmp`;
1530
- fs9.writeFileSync(tempFile, `${JSON.stringify(queue, null, 2)}
1531
- `, {
1532
- mode: 384
1533
- });
1534
- fs9.renameSync(tempFile, queueFile);
1374
+ const fd = fs8.openSync(tempFile, "w", 384);
1375
+ try {
1376
+ writeQueuePiece(
1377
+ fd,
1378
+ `{"schemaVersion":${JSON.stringify(queue.schemaVersion)}`
1379
+ );
1380
+ if (queue.uploadThrottles !== void 0) {
1381
+ writeQueuePiece(
1382
+ fd,
1383
+ `,"uploadThrottles":${JSON.stringify(queue.uploadThrottles)}`
1384
+ );
1385
+ }
1386
+ writeQueuePiece(fd, ',"artifacts":[');
1387
+ const artifacts = queue.artifacts;
1388
+ for (let start = 0; start < artifacts.length; start += QUEUE_WRITE_SLICE_ENTRIES) {
1389
+ const slice = artifacts.slice(start, start + QUEUE_WRITE_SLICE_ENTRIES).map((entry) => JSON.stringify(entry)).join(",");
1390
+ writeQueuePiece(fd, start === 0 ? slice : `,${slice}`);
1391
+ }
1392
+ writeQueuePiece(fd, "]}\n");
1393
+ } catch (error) {
1394
+ fs8.closeSync(fd);
1395
+ try {
1396
+ fs8.rmSync(tempFile, { force: true });
1397
+ } catch {
1398
+ }
1399
+ throw error;
1400
+ }
1401
+ fs8.closeSync(fd);
1402
+ fs8.renameSync(tempFile, queueFile);
1535
1403
  try {
1536
- fs9.chmodSync(queueFile, 384);
1404
+ fs8.chmodSync(queueFile, 384);
1537
1405
  } catch {
1538
1406
  }
1539
1407
  }
@@ -1553,7 +1421,7 @@ function shouldStartNewGeneration(input) {
1553
1421
  if (input.existing.source === "mini-swe-agent") {
1554
1422
  if (input.existing.contentSha256) {
1555
1423
  try {
1556
- return createHash5("sha256").update(fs9.readFileSync(input.nextReadPath)).digest("hex") !== input.existing.contentSha256;
1424
+ return createHash4("sha256").update(fs8.readFileSync(input.nextReadPath)).digest("hex") !== input.existing.contentSha256;
1557
1425
  } catch {
1558
1426
  }
1559
1427
  }
@@ -1563,7 +1431,7 @@ function shouldStartNewGeneration(input) {
1563
1431
  if (input.nextSizeBytes < input.existing.sizeBytes) return true;
1564
1432
  if ((input.nextReadPath !== artifactReadPath(input.existing) || input.existing.readPath !== void 0) && input.nextSizeBytes === input.existing.sizeBytes && input.existing.uploadedSizeBytes >= input.nextSizeBytes && input.existing.contentSha256) {
1565
1433
  try {
1566
- const contentSha256 = createHash5("sha256").update(fs9.readFileSync(input.nextReadPath)).digest("hex");
1434
+ const contentSha256 = createHash4("sha256").update(fs8.readFileSync(input.nextReadPath)).digest("hex");
1567
1435
  if (contentSha256 === input.existing.contentSha256) return false;
1568
1436
  } catch {
1569
1437
  }
@@ -1674,13 +1542,24 @@ function metadataForGeneration(input) {
1674
1542
  observations: input.candidateObservations,
1675
1543
  metadataWithoutContext
1676
1544
  });
1677
- return {
1545
+ const metadata = {
1678
1546
  ...metadataWithoutContext,
1679
1547
  ...hasInstallIdentity ? {
1680
1548
  installIdentitySchemaVersion: RAW_ARTIFACT_IDENTITY_SCHEMA_VERSION
1681
1549
  } : {},
1682
1550
  ...repositoryContext ? { repositoryContext } : {}
1683
1551
  };
1552
+ const rawGitStates = metadata.localGitStates;
1553
+ const statesValue = Array.isArray(rawGitStates) ? rawGitStates : rawGitStates !== null && typeof rawGitStates === "object" && "version" in rawGitStates && rawGitStates.version === 1 && "states" in rawGitStates ? rawGitStates.states : void 0;
1554
+ if (Array.isArray(statesValue) && rawGitStates && typeof rawGitStates === "object") {
1555
+ const states = [...statesValue];
1556
+ metadata.localGitStates = Array.isArray(rawGitStates) ? states : { ...rawGitStates, states };
1557
+ while (states.length && Buffer.byteLength(JSON.stringify(metadata), "utf8") > MAX_RAW_ARTIFACT_NESTED_METADATA_BYTES)
1558
+ states.pop();
1559
+ if (!states.length && Buffer.byteLength(JSON.stringify(metadata), "utf8") > MAX_RAW_ARTIFACT_NESTED_METADATA_BYTES)
1560
+ delete metadata.localGitStates;
1561
+ }
1562
+ return metadata;
1684
1563
  }
1685
1564
  function snapshotCandidate2(candidate, existing, nowMs, maxFileBytes, transientStatErrors = "ignore", observerIdentity) {
1686
1565
  const sourcePath = normalizeFilePath2(candidate.sourcePath);
@@ -1897,7 +1776,7 @@ function sameSourceRevision(left, right) {
1897
1776
  }
1898
1777
  function safeSourceRevision(filePath) {
1899
1778
  try {
1900
- const stat = fs9.statSync(filePath, { bigint: true });
1779
+ const stat = fs8.statSync(filePath, { bigint: true });
1901
1780
  return stat.isFile() ? sourceRevisionFromStat(stat) : null;
1902
1781
  } catch {
1903
1782
  return null;
@@ -1909,7 +1788,7 @@ function readExactRange(fd, startByte, endByte) {
1909
1788
  const buffer = Buffer.alloc(sizeBytes);
1910
1789
  let offset = 0;
1911
1790
  while (offset < sizeBytes) {
1912
- const bytesRead = fs9.readSync(
1791
+ const bytesRead = fs8.readSync(
1913
1792
  fd,
1914
1793
  buffer,
1915
1794
  offset,
@@ -1928,19 +1807,19 @@ function readFileRangeAtRevision(filePath, startByte, endByte, expectedRevision)
1928
1807
  }
1929
1808
  let fd;
1930
1809
  try {
1931
- fd = fs9.openSync(filePath, "r");
1810
+ fd = fs8.openSync(filePath, "r");
1932
1811
  } catch {
1933
1812
  return null;
1934
1813
  }
1935
1814
  try {
1936
1815
  const openedRevision = sourceRevisionFromStat(
1937
- fs9.fstatSync(fd, { bigint: true })
1816
+ fs8.fstatSync(fd, { bigint: true })
1938
1817
  );
1939
1818
  if (!sameSourceRevision(pathRevisionBefore, openedRevision)) return null;
1940
1819
  const bytes = readExactRange(fd, startByte, endByte);
1941
1820
  if (!bytes) return null;
1942
1821
  const revisionAfterRead = sourceRevisionFromStat(
1943
- fs9.fstatSync(fd, { bigint: true })
1822
+ fs8.fstatSync(fd, { bigint: true })
1944
1823
  );
1945
1824
  const pathRevisionAfter = safeSourceRevision(filePath);
1946
1825
  if (!sameSourceRevision(openedRevision, revisionAfterRead) || !pathRevisionAfter || !sameSourceRevision(openedRevision, pathRevisionAfter)) {
@@ -1950,7 +1829,7 @@ function readFileRangeAtRevision(filePath, startByte, endByte, expectedRevision)
1950
1829
  } catch {
1951
1830
  return null;
1952
1831
  } finally {
1953
- fs9.closeSync(fd);
1832
+ fs8.closeSync(fd);
1954
1833
  }
1955
1834
  }
1956
1835
  function uploadMetadata(input) {
@@ -2082,18 +1961,18 @@ function validateCheckpointPrefix(input) {
2082
1961
  }
2083
1962
  let fd;
2084
1963
  try {
2085
- fd = fs9.openSync(input.sourcePath, "r");
1964
+ fd = fs8.openSync(input.sourcePath, "r");
2086
1965
  } catch {
2087
1966
  return { status: "changed" };
2088
1967
  }
2089
1968
  try {
2090
1969
  const openedRevision = sourceRevisionFromStat(
2091
- fs9.fstatSync(fd, { bigint: true })
1970
+ fs8.fstatSync(fd, { bigint: true })
2092
1971
  );
2093
1972
  if (!sameSourceRevision(pathRevisionBefore, openedRevision)) {
2094
1973
  return { status: "changed" };
2095
1974
  }
2096
- const contentHash = createHash5("sha256");
1975
+ const contentHash = createHash4("sha256");
2097
1976
  let checkpointMismatch = false;
2098
1977
  for (const checkpoint of checkpoints) {
2099
1978
  const chunk = readExactRange(
@@ -2108,7 +1987,7 @@ function validateCheckpointPrefix(input) {
2108
1987
  contentHash.update(chunk);
2109
1988
  }
2110
1989
  const revisionAfterRead = sourceRevisionFromStat(
2111
- fs9.fstatSync(fd, { bigint: true })
1990
+ fs8.fstatSync(fd, { bigint: true })
2112
1991
  );
2113
1992
  const pathRevisionAfter = safeSourceRevision(input.sourcePath);
2114
1993
  if (!sameSourceRevision(openedRevision, revisionAfterRead) || !pathRevisionAfter || !sameSourceRevision(openedRevision, pathRevisionAfter)) {
@@ -2123,7 +2002,7 @@ function validateCheckpointPrefix(input) {
2123
2002
  } catch {
2124
2003
  return { status: "changed" };
2125
2004
  } finally {
2126
- fs9.closeSync(fd);
2005
+ fs8.closeSync(fd);
2127
2006
  }
2128
2007
  }
2129
2008
  function validatedPrefixStillApplies(prefix, entry, uploadDestinationId, revision) {
@@ -2257,14 +2136,14 @@ function defaultIsPidAlive(pid) {
2257
2136
  }
2258
2137
  function readQueueLockHolder(lockFile) {
2259
2138
  try {
2260
- const parsed = JSON.parse(fs9.readFileSync(lockFile, "utf8"));
2139
+ const parsed = JSON.parse(fs8.readFileSync(lockFile, "utf8"));
2261
2140
  if (!parsed || typeof parsed !== "object") return null;
2262
2141
  const record = parsed;
2263
2142
  if (typeof record.pid !== "number" || typeof record.timestampMs !== "number") {
2264
2143
  return null;
2265
2144
  }
2266
2145
  const ownerToken = typeof record.ownerToken === "string" ? record.ownerToken : void 0;
2267
- const timestampMs = ownerToken ? Math.max(record.timestampMs, fs9.statSync(lockFile).mtimeMs) : record.timestampMs;
2146
+ const timestampMs = ownerToken ? Math.max(record.timestampMs, fs8.statSync(lockFile).mtimeMs) : record.timestampMs;
2268
2147
  return { pid: record.pid, timestampMs, ownerToken };
2269
2148
  } catch {
2270
2149
  return null;
@@ -2272,8 +2151,8 @@ function readQueueLockHolder(lockFile) {
2272
2151
  }
2273
2152
  function queueLockFileMatchesOwner(lockFile, fd, ownerToken) {
2274
2153
  try {
2275
- const openStat = fs9.fstatSync(fd);
2276
- const pathStat = fs9.statSync(lockFile);
2154
+ const openStat = fs8.fstatSync(fd);
2155
+ const pathStat = fs8.statSync(lockFile);
2277
2156
  if (openStat.dev !== pathStat.dev || openStat.ino !== pathStat.ino) {
2278
2157
  return false;
2279
2158
  }
@@ -2284,14 +2163,14 @@ function queueLockFileMatchesOwner(lockFile, fd, ownerToken) {
2284
2163
  }
2285
2164
  function acquireQueueLock(queueFile, deps) {
2286
2165
  const lockFile = queueLockFile(queueFile);
2287
- fs9.mkdirSync(path20.dirname(lockFile), { recursive: true, mode: 448 });
2166
+ fs8.mkdirSync(path19.dirname(lockFile), { recursive: true, mode: 448 });
2288
2167
  for (let attempt = 0; attempt < 2; attempt += 1) {
2289
2168
  try {
2290
- const fd = fs9.openSync(lockFile, "wx+", 384);
2169
+ const fd = fs8.openSync(lockFile, "wx+", 384);
2291
2170
  const ownerToken = randomUUID3();
2292
2171
  let released = false;
2293
2172
  try {
2294
- fs9.writeSync(
2173
+ fs8.writeSync(
2295
2174
  fd,
2296
2175
  `${JSON.stringify({
2297
2176
  pid: process.pid,
@@ -2301,11 +2180,11 @@ function acquireQueueLock(queueFile, deps) {
2301
2180
  `
2302
2181
  );
2303
2182
  const heartbeatAt = new Date(deps.nowMs());
2304
- fs9.futimesSync(fd, heartbeatAt, heartbeatAt);
2183
+ fs8.futimesSync(fd, heartbeatAt, heartbeatAt);
2305
2184
  } catch (error) {
2306
- fs9.closeSync(fd);
2185
+ fs8.closeSync(fd);
2307
2186
  try {
2308
- fs9.unlinkSync(lockFile);
2187
+ fs8.unlinkSync(lockFile);
2309
2188
  } catch {
2310
2189
  }
2311
2190
  throw error;
@@ -2313,7 +2192,7 @@ function acquireQueueLock(queueFile, deps) {
2313
2192
  const close = () => {
2314
2193
  if (released) return;
2315
2194
  released = true;
2316
- fs9.closeSync(fd);
2195
+ fs8.closeSync(fd);
2317
2196
  };
2318
2197
  return {
2319
2198
  heartbeat() {
@@ -2322,7 +2201,7 @@ function acquireQueueLock(queueFile, deps) {
2322
2201
  return false;
2323
2202
  try {
2324
2203
  const heartbeatAt = new Date(deps.nowMs());
2325
- fs9.futimesSync(fd, heartbeatAt, heartbeatAt);
2204
+ fs8.futimesSync(fd, heartbeatAt, heartbeatAt);
2326
2205
  return true;
2327
2206
  } catch {
2328
2207
  return false;
@@ -2332,7 +2211,7 @@ function acquireQueueLock(queueFile, deps) {
2332
2211
  if (released) return;
2333
2212
  if (queueLockFileMatchesOwner(lockFile, fd, ownerToken)) {
2334
2213
  try {
2335
- fs9.unlinkSync(lockFile);
2214
+ fs8.unlinkSync(lockFile);
2336
2215
  } catch {
2337
2216
  }
2338
2217
  }
@@ -2345,7 +2224,7 @@ function acquireQueueLock(queueFile, deps) {
2345
2224
  const stale = !holder || !deps.isPidAlive(holder.pid) || deps.nowMs() - holder.timestampMs > QUEUE_LOCK_STALE_MS;
2346
2225
  if (!stale) return null;
2347
2226
  try {
2348
- fs9.unlinkSync(lockFile);
2227
+ fs8.unlinkSync(lockFile);
2349
2228
  } catch {
2350
2229
  }
2351
2230
  }
@@ -2403,7 +2282,7 @@ async function postRawArtifact(url, metadata, content, headers, fetchImpl = fetc
2403
2282
  form.append(
2404
2283
  "file",
2405
2284
  new Blob([new Uint8Array(content)], { type: metadata.contentType }),
2406
- path20.basename(metadata.sourcePath) || "raw-artifact"
2285
+ path19.basename(metadata.sourcePath) || "raw-artifact"
2407
2286
  );
2408
2287
  const abort = new AbortController();
2409
2288
  const timeout = setTimeout(() => abort.abort(), timeoutMs);
@@ -2684,14 +2563,15 @@ async function syncArtifacts(options) {
2684
2563
  }
2685
2564
  const upload = await uploadPendingArtifactsLocked(
2686
2565
  options,
2687
- resolveUploadRun(options, lock)
2566
+ resolveUploadRun(options, lock),
2567
+ snapshot.queue
2688
2568
  );
2689
2569
  return { snapshot, upload };
2690
2570
  } finally {
2691
2571
  lock.release();
2692
2572
  }
2693
2573
  }
2694
- async function uploadPendingArtifactsLocked(options, run) {
2574
+ async function uploadPendingArtifactsLocked(options, run, currentQueue) {
2695
2575
  const {
2696
2576
  nowMs,
2697
2577
  limit,
@@ -2703,7 +2583,7 @@ async function uploadPendingArtifactsLocked(options, run) {
2703
2583
  retryExhausted,
2704
2584
  lock
2705
2585
  } = run;
2706
- const queue = readArtifactQueue(options.queueFile);
2586
+ const queue = currentQueue ?? readArtifactQueue(options.queueFile);
2707
2587
  const entries = queue.artifacts.filter((entry) => artifactSourceEnabled(entry.source)).map(
2708
2588
  (entry) => activateUploadDestination(entry, uploadDestinationId, targetName)
2709
2589
  );
@@ -3255,7 +3135,11 @@ async function uploadPendingArtifactsLocked(options, run) {
3255
3135
  persist();
3256
3136
  }
3257
3137
  }
3258
- const nextQueue = readArtifactQueue(options.queueFile);
3138
+ const nextQueue = {
3139
+ schemaVersion: RAW_ARTIFACT_SCHEMA_VERSION,
3140
+ artifacts: entries,
3141
+ uploadThrottles: Object.keys(uploadThrottles).length > 0 ? uploadThrottles : void 0
3142
+ };
3259
3143
  const completedAtMs = nowMs();
3260
3144
  const exhausted = nextQueue.artifacts.filter(
3261
3145
  (entry) => isExhaustedForDestination(entry, uploadDestinationId, retryExhausted)
@@ -3292,12 +3176,12 @@ async function uploadPendingArtifactsLocked(options, run) {
3292
3176
  }
3293
3177
 
3294
3178
  // ../../packages/panopticon/src/raw-sync.ts
3295
- import fs11 from "fs";
3296
- import path21 from "path";
3179
+ import fs10 from "fs";
3180
+ import path20 from "path";
3297
3181
  import os4 from "os";
3298
3182
 
3299
3183
  // ../../packages/panopticon/src/artifact-materializer.ts
3300
- import fs10 from "fs";
3184
+ import fs9 from "fs";
3301
3185
  function entryNeedsBytes(entry, amendmentPending) {
3302
3186
  if (entry.uploadedSizeBytes < entry.sizeBytes) return true;
3303
3187
  return amendmentPending(entry);
@@ -3312,7 +3196,7 @@ function createArtifactMaterializer(input) {
3312
3196
  const unsupportedReason = (input.supportsCompression ?? supportsCompressedArtifacts)() ? void 0 : `compressed artifacts need Node 22.15 or newer (running ${process.version})`;
3313
3197
  const chargeExisting = (cachePath) => {
3314
3198
  try {
3315
- const stat = fs10.statSync(cachePath);
3199
+ const stat = fs9.statSync(cachePath);
3316
3200
  if (!stat.isFile()) return false;
3317
3201
  if (!retained.has(cachePath)) {
3318
3202
  retained.add(cachePath);
@@ -3360,20 +3244,20 @@ function getRawArtifactSyncPaths(stateDir) {
3360
3244
  if (stateDir.length === 0) {
3361
3245
  throw new Error("raw artifact sync state directory must not be empty");
3362
3246
  }
3363
- const root = path21.resolve(stateDir);
3247
+ const root = path20.resolve(stateDir);
3364
3248
  const managed = getManagedClientPaths({ PANOPTICON_HOME: root });
3365
3249
  return {
3366
3250
  root,
3367
3251
  settingsFile: managed.syncSettingsFile,
3368
3252
  queueFile: managed.artifactQueue,
3369
3253
  artifactCacheDir: managed.artifactCache,
3370
- discoveryCacheFile: path21.join(root, "discovery.cache.json"),
3371
- githubOriginCacheFile: path21.join(root, "github-origins.cache.json")
3254
+ discoveryCacheFile: path20.join(root, "discovery.cache.json"),
3255
+ githubOriginCacheFile: path20.join(root, GIT_STATE_CACHE_FILENAME)
3372
3256
  };
3373
3257
  }
3374
3258
  function invalidateRawArtifactDiscoveryCache(stateDir) {
3375
3259
  try {
3376
- fs11.rmSync(getRawArtifactSyncPaths(stateDir).discoveryCacheFile, {
3260
+ fs10.rmSync(getRawArtifactSyncPaths(stateDir).discoveryCacheFile, {
3377
3261
  force: true
3378
3262
  });
3379
3263
  } catch {
@@ -3476,9 +3360,9 @@ function createRawArtifactSync(options) {
3476
3360
  options.homeDir ?? null,
3477
3361
  options.projectRoots ?? null,
3478
3362
  options.maxFileBytes ?? null,
3479
- path21.resolve(
3363
+ path20.resolve(
3480
3364
  resolvePiAgentDir({
3481
- homeDir: path21.resolve(
3365
+ homeDir: path20.resolve(
3482
3366
  options.homeDir ?? process.env.HOME ?? os4.homedir()
3483
3367
  ),
3484
3368
  env: process.env
@@ -3491,7 +3375,7 @@ function createRawArtifactSync(options) {
3491
3375
  if (reuseMs <= 0) return null;
3492
3376
  try {
3493
3377
  const parsed = JSON.parse(
3494
- fs11.readFileSync(paths.discoveryCacheFile, "utf8")
3378
+ fs10.readFileSync(paths.discoveryCacheFile, "utf8")
3495
3379
  );
3496
3380
  if (parsed.schemaVersion !== DISCOVERY_CACHE_SCHEMA_VERSION || typeof parsed.createdAtMs !== "number" || parsed.inputs !== discoveryInputs() || !parsed.discovery || typeof parsed.discovery !== "object") {
3497
3381
  return null;
@@ -3507,11 +3391,11 @@ function createRawArtifactSync(options) {
3507
3391
  if ((options.discoveryReuseMs ?? 0) <= 0) return;
3508
3392
  const temporary = `${paths.discoveryCacheFile}.${process.pid}.tmp`;
3509
3393
  try {
3510
- fs11.mkdirSync(path21.dirname(paths.discoveryCacheFile), {
3394
+ fs10.mkdirSync(path20.dirname(paths.discoveryCacheFile), {
3511
3395
  recursive: true,
3512
3396
  mode: 448
3513
3397
  });
3514
- fs11.writeFileSync(
3398
+ fs10.writeFileSync(
3515
3399
  temporary,
3516
3400
  `${JSON.stringify({
3517
3401
  schemaVersion: DISCOVERY_CACHE_SCHEMA_VERSION,
@@ -3522,10 +3406,10 @@ function createRawArtifactSync(options) {
3522
3406
  `,
3523
3407
  { mode: 384 }
3524
3408
  );
3525
- fs11.renameSync(temporary, paths.discoveryCacheFile);
3409
+ fs10.renameSync(temporary, paths.discoveryCacheFile);
3526
3410
  } catch {
3527
3411
  try {
3528
- fs11.rmSync(temporary, { force: true });
3412
+ fs10.rmSync(temporary, { force: true });
3529
3413
  } catch {
3530
3414
  }
3531
3415
  }