@fro.bot/systematic 3.5.8 → 3.5.9

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.
Files changed (2) hide show
  1. package/dist/index.js +86 -18
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -11194,8 +11194,69 @@ function stableSerialize(value, depth = 0, budget = 8192) {
11194
11194
  return;
11195
11195
  return serializeStableRecord(value, depth, budget);
11196
11196
  }
11197
- function argsFingerprint(ledger, args2) {
11198
- const serialized = stableSerialize(args2);
11197
+ function canonicalPatchText(patchText, sessionLocation) {
11198
+ if (patchTextFileTargets(patchText) === undefined)
11199
+ return;
11200
+ const segments = patchText.split(/(\r?\n)/);
11201
+ for (let index = 0;index < segments.length; index += 1) {
11202
+ const line = segments[index];
11203
+ if (line === `
11204
+ ` || line === `\r
11205
+ `)
11206
+ continue;
11207
+ const prefix = PATCH_FILE_PREFIXES.find((candidate) => line.startsWith(candidate));
11208
+ if (!prefix)
11209
+ continue;
11210
+ const filePath = line.slice(prefix.length).trim();
11211
+ if (!filePath)
11212
+ return;
11213
+ segments[index] = `${prefix}${path9.resolve(sessionLocation, filePath)}`;
11214
+ }
11215
+ return segments.join("");
11216
+ }
11217
+ function canonicalHunks(value, sessionLocation) {
11218
+ if (!Array.isArray(value))
11219
+ return;
11220
+ const hunks = [];
11221
+ for (const hunk of value) {
11222
+ if (!isRecord7(hunk) || typeof hunk.path !== "string" || !hunk.path) {
11223
+ return;
11224
+ }
11225
+ const canonical = {
11226
+ ...hunk,
11227
+ path: path9.resolve(sessionLocation, hunk.path)
11228
+ };
11229
+ if (hunk.move_path !== undefined) {
11230
+ if (typeof hunk.move_path !== "string" || !hunk.move_path) {
11231
+ return;
11232
+ }
11233
+ canonical.move_path = path9.resolve(sessionLocation, hunk.move_path);
11234
+ }
11235
+ hunks.push(canonical);
11236
+ }
11237
+ return hunks;
11238
+ }
11239
+ function canonicalOperationArgs(tool, args2, sessionLocation) {
11240
+ if (tool !== "apply_patch" || !isRecord7(args2))
11241
+ return args2;
11242
+ const patchPaths = patchFileTargets(args2);
11243
+ if (patchPaths === undefined)
11244
+ return args2;
11245
+ const patchValue = args2.patchText ?? args2.patch;
11246
+ if (typeof patchValue === "string") {
11247
+ const canonical = canonicalPatchText(patchValue, sessionLocation);
11248
+ if (canonical === undefined)
11249
+ return args2;
11250
+ const patchKey = typeof args2.patchText === "string" ? "patchText" : "patch";
11251
+ return { ...args2, [patchKey]: canonical };
11252
+ }
11253
+ if (patchPaths.length === 0)
11254
+ return args2;
11255
+ const hunks = canonicalHunks(args2.hunks, sessionLocation);
11256
+ return hunks === undefined ? args2 : { ...args2, hunks };
11257
+ }
11258
+ function argsFingerprint(ledger, tool, args2, sessionLocation) {
11259
+ const serialized = stableSerialize(canonicalOperationArgs(tool, args2, sessionLocation));
11199
11260
  return serialized === undefined ? undefined : ledger.digestIdentity("call", serialized);
11200
11261
  }
11201
11262
  function bashCommand(args2) {
@@ -11441,6 +11502,13 @@ function createSessionRuntime(options, operationObservers, recoveredOperationCon
11441
11502
  const pendingQuestionChallenges = new Map;
11442
11503
  const blockedQuestionCalls = new Map;
11443
11504
  const consumedQuestionTargets = new Set;
11505
+ function effectiveTargetContext() {
11506
+ const parentTargetRoot = options.targetDirectory ?? process.cwd();
11507
+ return {
11508
+ parentTargetRoot,
11509
+ sessionLocation: options.sessionLocation ?? parentTargetRoot
11510
+ };
11511
+ }
11444
11512
  function rememberOperationObserver(registration) {
11445
11513
  const existing = operationObservers.get(registration.observer.targetDigest);
11446
11514
  if (existing && existing.targetRoot !== registration.targetRoot)
@@ -12368,7 +12436,8 @@ function createSessionRuntime(options, operationObservers, recoveredOperationCon
12368
12436
  async function prepareOperation(host, args2) {
12369
12437
  if (!options.observer || !isLocalOperationTool(host.tool))
12370
12438
  return;
12371
- const fingerprint = argsFingerprint(ledger, args2);
12439
+ const { parentTargetRoot, sessionLocation } = effectiveTargetContext();
12440
+ const fingerprint = argsFingerprint(ledger, host.tool, args2, sessionLocation);
12372
12441
  if (!fingerprint) {
12373
12442
  markUnavailable();
12374
12443
  return;
@@ -12377,8 +12446,6 @@ function createSessionRuntime(options, operationObservers, recoveredOperationCon
12377
12446
  if (bindCall(callDigest, "operation", `${host.tool}:${fingerprint}`) !== "new") {
12378
12447
  return;
12379
12448
  }
12380
- const parentTargetRoot = options.targetDirectory ?? process.cwd();
12381
- const sessionLocation = options.sessionLocation ?? parentTargetRoot;
12382
12449
  const target = deriveOpencodeOperationTarget(host.tool, args2, {
12383
12450
  parentTargetRoot,
12384
12451
  sessionLocation,
@@ -13108,7 +13175,8 @@ function createSessionRuntime(options, operationObservers, recoveredOperationCon
13108
13175
  if (!options.observer || !isLocalOperationTool(host.tool))
13109
13176
  return;
13110
13177
  const callDigest = digestCall(ledger, host.callID);
13111
- const fingerprint = argsFingerprint(ledger, host.args);
13178
+ const { sessionLocation } = effectiveTargetContext();
13179
+ const fingerprint = argsFingerprint(ledger, host.tool, host.args, sessionLocation);
13112
13180
  if (isSealedOperationReplay(callDigest, host, fingerprint))
13113
13181
  return;
13114
13182
  const pending = takePendingOperation(callDigest, host, fingerprint);
@@ -13119,19 +13187,19 @@ function createSessionRuntime(options, operationObservers, recoveredOperationCon
13119
13187
  markUnavailable();
13120
13188
  return;
13121
13189
  }
13122
- if (result.status === "accepted") {
13123
- const receipt = receiptForOperation(host.callID, result.operation);
13124
- if (receipt) {
13125
- if (localOperation(result.operation)) {
13126
- recoveredOperationContexts.set(receipt.canonical.receiptId, {
13127
- targetIdentity: pending.targetIdentity,
13128
- before: pending.before,
13129
- after: result.after
13130
- });
13131
- }
13132
- mergeReceiptMarker(output, receipt);
13133
- }
13190
+ if (result.status !== "accepted")
13191
+ return;
13192
+ const receipt = receiptForOperation(host.callID, result.operation);
13193
+ if (!receipt)
13194
+ return;
13195
+ if (localOperation(result.operation)) {
13196
+ recoveredOperationContexts.set(receipt.canonical.receiptId, {
13197
+ targetIdentity: pending.targetIdentity,
13198
+ before: pending.before,
13199
+ after: result.after
13200
+ });
13134
13201
  }
13202
+ mergeReceiptMarker(output, receipt);
13135
13203
  }
13136
13204
  async function after(input, output) {
13137
13205
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fro.bot/systematic",
3
- "version": "3.5.8",
3
+ "version": "3.5.9",
4
4
  "description": "Compound-engineering loops for OpenCode, Pi, and Claude Code",
5
5
  "type": "module",
6
6
  "homepage": "https://fro.bot/systematic",
@@ -108,7 +108,7 @@
108
108
  "rimraf": "6.1.3",
109
109
  "semantic-release": "25.0.8",
110
110
  "semantic-release-export-data": "1.2.0",
111
- "typebox": "1.3.8",
111
+ "typebox": "1.3.9",
112
112
  "typescript": "7.0.2"
113
113
  },
114
114
  "dependencies": {