@brainervirus/workit-mcp 2.2.0 → 2.2.1

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 +88 -7
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -19059,7 +19059,7 @@ class TaskStore {
19059
19059
  if (!current.data)
19060
19060
  return failure2("not_found", "workspace not found");
19061
19061
  if (current.data.revision !== expected)
19062
- return this.conflict(expected, current.data.revision);
19062
+ return this.workspaceConflict(expected, current.data.revision);
19063
19063
  const previousBytes = this.snapshotBytes(this.workspacePath);
19064
19064
  if (!previousBytes)
19065
19065
  return failure2("storage_error", "workspace snapshot disappeared during mutation");
@@ -19102,7 +19102,7 @@ class TaskStore {
19102
19102
  if (task.data.revision !== expected)
19103
19103
  return this.conflict(expected, task.data.revision);
19104
19104
  if (workspace.data.revision !== input.expectedWorkspaceRevision)
19105
- return this.conflict(input.expectedWorkspaceRevision, workspace.data.revision);
19105
+ return this.workspaceConflict(input.expectedWorkspaceRevision, workspace.data.revision);
19106
19106
  const previousWorkspaceBytes = this.snapshotBytes(this.workspacePath);
19107
19107
  const previousTaskBytes = this.snapshotBytes(this.taskPath(input.taskId));
19108
19108
  if (!previousWorkspaceBytes || !previousTaskBytes)
@@ -19912,6 +19912,9 @@ class TaskStore {
19912
19912
  actualRevision: actual
19913
19913
  });
19914
19914
  }
19915
+ workspaceConflict(expected, actual) {
19916
+ return failure2("revision_conflict", "workspace revision does not match; omit expectedWorkspaceRevision to use the current record", { expectedWorkspaceRevision: expected, actualWorkspaceRevision: actual });
19917
+ }
19915
19918
  taskPath(taskId) {
19916
19919
  return path4.join(this.tasksDir, `${taskId}.json`);
19917
19920
  }
@@ -22964,6 +22967,29 @@ var applyWorkerLifecycle = (input) => {
22964
22967
  return updated ? success(changed.data.task.revision, changed.data.workspace.revision, updated) : failure2("recovery_required", "worker disappeared during lifecycle observation");
22965
22968
  };
22966
22969
  var refsWithinScope = (refs, scope) => refs.every((ref) => ref.kind !== "file" || bindingCovers(scope, { description: "", paths: [ref.path], exclusions: [] }));
22970
+ var REVISION_RETRY_ATTEMPTS = 8;
22971
+ var retryPause = new Int32Array(new SharedArrayBuffer(4));
22972
+ var filledRevisions = (request) => {
22973
+ const value = typeof request === "object" && request !== null ? request : {};
22974
+ return {
22975
+ task: value.expectedRevision === undefined,
22976
+ workspace: value.expectedWorkspaceRevision === undefined
22977
+ };
22978
+ };
22979
+ var filledConflict = (result, filled) => !result.ok && result.code === "revision_conflict" && (("actualRevision" in result.details) && filled.task || ("actualWorkspaceRevision" in result.details) && filled.workspace);
22980
+ var retryFilledRevisions = (filled, run) => {
22981
+ if (!filled.task && !filled.workspace)
22982
+ return run();
22983
+ let result = run();
22984
+ const deadline = Date.now() + defaultLockTimeout();
22985
+ for (let attempt = 1;filledConflict(result, filled); attempt += 1) {
22986
+ if (attempt >= REVISION_RETRY_ATTEMPTS || Date.now() >= deadline)
22987
+ return failure2("busy", "records kept changing under concurrent writers; retry the call");
22988
+ Atomics.wait(retryPause, 0, 0, Math.floor(Math.random() * 4 * attempt) + 1);
22989
+ result = run();
22990
+ }
22991
+ return result;
22992
+ };
22967
22993
  var trustedNow = (context) => typeof context.now === "function" ? context.now() : context.now;
22968
22994
  var mapRef = (ref, ids) => {
22969
22995
  if (ref.kind !== "record")
@@ -23211,6 +23237,9 @@ class WorkitCore {
23211
23237
  if (input.expectedWorkspaceRevision === undefined)
23212
23238
  input.expectedWorkspaceRevision = workspace ? workspace.revision : null;
23213
23239
  }
23240
+ retryOmittedRevisions(request, run) {
23241
+ return retryFilledRevisions(filledRevisions(request), run);
23242
+ }
23214
23243
  helperEntry(task, requireSession = false, requireActive = false) {
23215
23244
  const workerId = this.context.workerId ?? null;
23216
23245
  if (workerId === null)
@@ -23242,6 +23271,9 @@ class WorkitCore {
23242
23271
  return null;
23243
23272
  }
23244
23273
  state(request) {
23274
+ return request?.action === "import" ? this.retryOmittedRevisions(request, () => this.stateOnce(request)) : this.stateOnce(request);
23275
+ }
23276
+ stateOnce(request) {
23245
23277
  const root = this.contextRootError();
23246
23278
  if (!root.ok)
23247
23279
  return root;
@@ -23343,6 +23375,9 @@ class WorkitCore {
23343
23375
  });
23344
23376
  }
23345
23377
  task(request) {
23378
+ return this.retryOmittedRevisions(request, () => this.taskOnce(request));
23379
+ }
23380
+ taskOnce(request) {
23346
23381
  const root = this.contextRootError();
23347
23382
  if (!root.ok)
23348
23383
  return root;
@@ -23442,6 +23477,9 @@ class WorkitCore {
23442
23477
  }
23443
23478
  }
23444
23479
  policy(request) {
23480
+ return this.retryOmittedRevisions(request, () => this.policyOnce(request));
23481
+ }
23482
+ policyOnce(request) {
23445
23483
  const root = this.contextRootError();
23446
23484
  if (!root.ok)
23447
23485
  return root;
@@ -23488,6 +23526,9 @@ class WorkitCore {
23488
23526
  return success(changed.data.revision, null, changed.data.policy);
23489
23527
  }
23490
23528
  evidence(request) {
23529
+ return this.retryOmittedRevisions(request, () => this.evidenceOnce(request));
23530
+ }
23531
+ evidenceOnce(request) {
23491
23532
  const root = this.contextRootError();
23492
23533
  if (!root.ok)
23493
23534
  return root;
@@ -23572,6 +23613,23 @@ class WorkitCore {
23572
23613
  observeStandingDecision(request) {
23573
23614
  return this.recordDecision(request, undefined, true, true);
23574
23615
  }
23616
+ commitTask(taskId, expected, filled, recheck, update) {
23617
+ let revision = expected;
23618
+ let first = true;
23619
+ return retryFilledRevisions({ task: filled, workspace: false }, () => {
23620
+ if (!first) {
23621
+ const fresh = this.store.readTask(taskId);
23622
+ if (!fresh.ok)
23623
+ return fresh;
23624
+ const checked = recheck(fresh.data);
23625
+ if (!checked.ok)
23626
+ return checked;
23627
+ revision = fresh.data.revision;
23628
+ }
23629
+ first = false;
23630
+ return this.store.mutateTask(taskId, revision, update, trustedNow(this.context));
23631
+ });
23632
+ }
23575
23633
  recordDecision(request, nativeObservation, nativeRequired = false, standing = false) {
23576
23634
  const root = this.contextRootError();
23577
23635
  if (!root.ok)
@@ -23596,6 +23654,7 @@ class WorkitCore {
23596
23654
  return task;
23597
23655
  if ((this.context.workerId ?? null) !== null)
23598
23656
  return failure2("permission_denied", "helpers cannot record or revoke decisions");
23657
+ const filled = input.expectedRevision === undefined;
23599
23658
  this.fillRevisions(input, task.data);
23600
23659
  if (input.action === "record") {
23601
23660
  if (task.data.status === "closed")
@@ -23644,7 +23703,20 @@ class WorkitCore {
23644
23703
  const nativeProvenance = native?.ok ? retireNativeAuthority(native.data) : null;
23645
23704
  if (native?.ok && !nativeProvenance)
23646
23705
  return failure2("permission_denied", "native decision authority was retired");
23647
- const changed = this.store.mutateTask(task.data.id, input.expectedRevision, (current, mutation) => {
23706
+ let standingProvenance = standingApproval?.ok === true ? standingApproval.data : null;
23707
+ const recheck = (fresh) => {
23708
+ if (fresh.status === "closed")
23709
+ return failure2("invalid_transition", "closed task cannot record a decision");
23710
+ if (!standingProvenance)
23711
+ return success(null, null, null);
23712
+ const again = verifyStandingApproval(this.store.root, fresh, this.context.caller, input.binding);
23713
+ if (again.ok)
23714
+ standingProvenance = again.data;
23715
+ return again;
23716
+ };
23717
+ const changed = this.commitTask(task.data.id, input.expectedRevision, filled, recheck, (current, mutation) => {
23718
+ if (current.status === "closed")
23719
+ return failure2("invalid_transition", "closed task cannot record a decision");
23648
23720
  const latestContent = verifyDecisionContent(this.store, input.binding);
23649
23721
  if (!latestContent.ok)
23650
23722
  return latestContent;
@@ -23656,14 +23728,14 @@ class WorkitCore {
23656
23728
  const entry = {
23657
23729
  id: newId(),
23658
23730
  recordedAt: mutation.now,
23659
- provenance: standingApproval?.ok === true ? standingApproval.data : nativeProvenance ?? provenance(this.context, "agent_reported"),
23731
+ provenance: standingProvenance ?? nativeProvenance ?? provenance(this.context, "agent_reported"),
23660
23732
  data
23661
23733
  };
23662
23734
  return success(mutation.revision, null, {
23663
23735
  ...current,
23664
23736
  decisions: [...current.decisions, entry]
23665
23737
  });
23666
- }, trustedNow(this.context));
23738
+ });
23667
23739
  if (!changed.ok)
23668
23740
  return changed;
23669
23741
  return success(changed.data.revision, null, changed.data.decisions.at(-1));
@@ -23677,7 +23749,7 @@ class WorkitCore {
23677
23749
  return failure2("invalid_transition", "decision is already revoked");
23678
23750
  if (decision.data.consumption)
23679
23751
  return failure2("permission_denied", "consumed decision cannot be revoked");
23680
- const changed = this.store.mutateTask(task.data.id, input.expectedRevision, (current, mutation) => {
23752
+ const changed = this.commitTask(task.data.id, input.expectedRevision, filled, () => success(null, null, null), (current, mutation) => {
23681
23753
  const entry = current.decisions.find((candidate) => candidate.id === input.decisionId);
23682
23754
  if (!entry)
23683
23755
  return failure2("not_found", "decision not found");
@@ -23694,13 +23766,16 @@ class WorkitCore {
23694
23766
  ...current,
23695
23767
  decisions: current.decisions.map((candidate) => candidate.id === input.decisionId ? updated : candidate)
23696
23768
  });
23697
- }, trustedNow(this.context));
23769
+ });
23698
23770
  if (!changed.ok)
23699
23771
  return changed;
23700
23772
  const entry = changed.data.decisions.find((candidate) => candidate.id === input.decisionId);
23701
23773
  return entry ? success(changed.data.revision, null, entry) : failure2("recovery_required", "decision disappeared");
23702
23774
  }
23703
23775
  finding(request) {
23776
+ return this.retryOmittedRevisions(request, () => this.findingOnce(request));
23777
+ }
23778
+ findingOnce(request) {
23704
23779
  const root = this.contextRootError();
23705
23780
  if (!root.ok)
23706
23781
  return root;
@@ -23824,6 +23899,9 @@ class WorkitCore {
23824
23899
  return entry ? success(changed.data.revision, null, entry) : failure2("recovery_required", "finding disappeared");
23825
23900
  }
23826
23901
  worker(request) {
23902
+ return this.retryOmittedRevisions(request, () => this.workerOnce(request));
23903
+ }
23904
+ workerOnce(request) {
23827
23905
  const root = this.contextRootError();
23828
23906
  if (!root.ok)
23829
23907
  return root;
@@ -24171,6 +24249,9 @@ class WorkitCore {
24171
24249
  return applied;
24172
24250
  }
24173
24251
  writer(request) {
24252
+ return this.retryOmittedRevisions(request, () => this.writerOnce(request));
24253
+ }
24254
+ writerOnce(request) {
24174
24255
  const root = this.contextRootError();
24175
24256
  if (!root.ok)
24176
24257
  return root;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brainervirus/workit-mcp",
3
- "version": "2.2.0",
3
+ "version": "2.2.1",
4
4
  "private": false,
5
5
  "description": "Workit shared MCP transport for the eight task and policy operation families",
6
6
  "keywords": [
@@ -42,7 +42,7 @@
42
42
  "build": "bun scripts/build.ts"
43
43
  },
44
44
  "dependencies": {
45
- "@brainervirus/workit-core": "^2.2.0",
45
+ "@brainervirus/workit-core": "^2.2.1",
46
46
  "@modelcontextprotocol/sdk": "1.32.0",
47
47
  "zod": "4.6.5"
48
48
  },