@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.
- package/dist/index.js +88 -7
- 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.
|
|
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.
|
|
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
|
-
|
|
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:
|
|
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
|
-
}
|
|
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.
|
|
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
|
-
}
|
|
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.
|
|
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.
|
|
45
|
+
"@brainervirus/workit-core": "^2.2.1",
|
|
46
46
|
"@modelcontextprotocol/sdk": "1.32.0",
|
|
47
47
|
"zod": "4.6.5"
|
|
48
48
|
},
|