@brainervirus/workit-opencode 2.2.0 → 2.2.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.
- package/dist/plugin.js +92 -9
- package/package.json +2 -2
package/dist/plugin.js
CHANGED
|
@@ -10038,7 +10038,7 @@ class TaskStore {
|
|
|
10038
10038
|
if (!current.data)
|
|
10039
10039
|
return failure2("not_found", "workspace not found");
|
|
10040
10040
|
if (current.data.revision !== expected)
|
|
10041
|
-
return this.
|
|
10041
|
+
return this.workspaceConflict(expected, current.data.revision);
|
|
10042
10042
|
const previousBytes = this.snapshotBytes(this.workspacePath);
|
|
10043
10043
|
if (!previousBytes)
|
|
10044
10044
|
return failure2("storage_error", "workspace snapshot disappeared during mutation");
|
|
@@ -10081,7 +10081,7 @@ class TaskStore {
|
|
|
10081
10081
|
if (task.data.revision !== expected)
|
|
10082
10082
|
return this.conflict(expected, task.data.revision);
|
|
10083
10083
|
if (workspace.data.revision !== input.expectedWorkspaceRevision)
|
|
10084
|
-
return this.
|
|
10084
|
+
return this.workspaceConflict(input.expectedWorkspaceRevision, workspace.data.revision);
|
|
10085
10085
|
const previousWorkspaceBytes = this.snapshotBytes(this.workspacePath);
|
|
10086
10086
|
const previousTaskBytes = this.snapshotBytes(this.taskPath(input.taskId));
|
|
10087
10087
|
if (!previousWorkspaceBytes || !previousTaskBytes)
|
|
@@ -10891,6 +10891,9 @@ class TaskStore {
|
|
|
10891
10891
|
actualRevision: actual
|
|
10892
10892
|
});
|
|
10893
10893
|
}
|
|
10894
|
+
workspaceConflict(expected, actual) {
|
|
10895
|
+
return failure2("revision_conflict", "workspace revision does not match; omit expectedWorkspaceRevision to use the current record", { expectedWorkspaceRevision: expected, actualWorkspaceRevision: actual });
|
|
10896
|
+
}
|
|
10894
10897
|
taskPath(taskId) {
|
|
10895
10898
|
return path4.join(this.tasksDir, `${taskId}.json`);
|
|
10896
10899
|
}
|
|
@@ -13312,8 +13315,10 @@ values are still concurrency-checked, so never copy revisions between calls.
|
|
|
13312
13315
|
A busy result means another live Workit call holds the checkout lock: retry the
|
|
13313
13316
|
same call; it is not a recovery condition. A lock left by a dead process is
|
|
13314
13317
|
reclaimed on the next write, and \`workit doctor --fix-lock\` clears it on demand.
|
|
13315
|
-
|
|
13316
|
-
|
|
13318
|
+
An omitted revision absorbs a concurrent write: Workit re-reads, re-checks
|
|
13319
|
+
policy, and reapplies the call, returning busy under persistent contention. A
|
|
13320
|
+
revision_conflict means a revision you passed is stale: re-read the record
|
|
13321
|
+
before deciding whether to retry.
|
|
13317
13322
|
A solo edit does not need writer acquisition; use it when concurrent checkout
|
|
13318
13323
|
writers need coordination. Record only observed facts and checks. Evidence can
|
|
13319
13324
|
become stale when its bound candidate changes; reconcile findings against the
|
|
@@ -14126,6 +14131,29 @@ var applyWorkerLifecycle = (input) => {
|
|
|
14126
14131
|
return updated ? success(changed.data.task.revision, changed.data.workspace.revision, updated) : failure2("recovery_required", "worker disappeared during lifecycle observation");
|
|
14127
14132
|
};
|
|
14128
14133
|
var refsWithinScope = (refs, scope) => refs.every((ref) => ref.kind !== "file" || bindingCovers(scope, { description: "", paths: [ref.path], exclusions: [] }));
|
|
14134
|
+
var REVISION_RETRY_ATTEMPTS = 8;
|
|
14135
|
+
var retryPause = new Int32Array(new SharedArrayBuffer(4));
|
|
14136
|
+
var filledRevisions = (request) => {
|
|
14137
|
+
const value = typeof request === "object" && request !== null ? request : {};
|
|
14138
|
+
return {
|
|
14139
|
+
task: value.expectedRevision === undefined,
|
|
14140
|
+
workspace: value.expectedWorkspaceRevision === undefined
|
|
14141
|
+
};
|
|
14142
|
+
};
|
|
14143
|
+
var filledConflict = (result, filled) => !result.ok && result.code === "revision_conflict" && (("actualRevision" in result.details) && filled.task || ("actualWorkspaceRevision" in result.details) && filled.workspace);
|
|
14144
|
+
var retryFilledRevisions = (filled, run) => {
|
|
14145
|
+
if (!filled.task && !filled.workspace)
|
|
14146
|
+
return run();
|
|
14147
|
+
let result = run();
|
|
14148
|
+
const deadline = Date.now() + defaultLockTimeout();
|
|
14149
|
+
for (let attempt = 1;filledConflict(result, filled); attempt += 1) {
|
|
14150
|
+
if (attempt >= REVISION_RETRY_ATTEMPTS || Date.now() >= deadline)
|
|
14151
|
+
return failure2("busy", "records kept changing under concurrent writers; retry the call");
|
|
14152
|
+
Atomics.wait(retryPause, 0, 0, Math.floor(Math.random() * 4 * attempt) + 1);
|
|
14153
|
+
result = run();
|
|
14154
|
+
}
|
|
14155
|
+
return result;
|
|
14156
|
+
};
|
|
14129
14157
|
var trustedNow = (context) => typeof context.now === "function" ? context.now() : context.now;
|
|
14130
14158
|
var mapRef = (ref, ids) => {
|
|
14131
14159
|
if (ref.kind !== "record")
|
|
@@ -14373,6 +14401,9 @@ class WorkitCore {
|
|
|
14373
14401
|
if (input.expectedWorkspaceRevision === undefined)
|
|
14374
14402
|
input.expectedWorkspaceRevision = workspace ? workspace.revision : null;
|
|
14375
14403
|
}
|
|
14404
|
+
retryOmittedRevisions(request, run) {
|
|
14405
|
+
return retryFilledRevisions(filledRevisions(request), run);
|
|
14406
|
+
}
|
|
14376
14407
|
helperEntry(task, requireSession = false, requireActive = false) {
|
|
14377
14408
|
const workerId = this.context.workerId ?? null;
|
|
14378
14409
|
if (workerId === null)
|
|
@@ -14404,6 +14435,9 @@ class WorkitCore {
|
|
|
14404
14435
|
return null;
|
|
14405
14436
|
}
|
|
14406
14437
|
state(request) {
|
|
14438
|
+
return request?.action === "import" ? this.retryOmittedRevisions(request, () => this.stateOnce(request)) : this.stateOnce(request);
|
|
14439
|
+
}
|
|
14440
|
+
stateOnce(request) {
|
|
14407
14441
|
const root = this.contextRootError();
|
|
14408
14442
|
if (!root.ok)
|
|
14409
14443
|
return root;
|
|
@@ -14505,6 +14539,9 @@ class WorkitCore {
|
|
|
14505
14539
|
});
|
|
14506
14540
|
}
|
|
14507
14541
|
task(request) {
|
|
14542
|
+
return this.retryOmittedRevisions(request, () => this.taskOnce(request));
|
|
14543
|
+
}
|
|
14544
|
+
taskOnce(request) {
|
|
14508
14545
|
const root = this.contextRootError();
|
|
14509
14546
|
if (!root.ok)
|
|
14510
14547
|
return root;
|
|
@@ -14604,6 +14641,9 @@ class WorkitCore {
|
|
|
14604
14641
|
}
|
|
14605
14642
|
}
|
|
14606
14643
|
policy(request) {
|
|
14644
|
+
return this.retryOmittedRevisions(request, () => this.policyOnce(request));
|
|
14645
|
+
}
|
|
14646
|
+
policyOnce(request) {
|
|
14607
14647
|
const root = this.contextRootError();
|
|
14608
14648
|
if (!root.ok)
|
|
14609
14649
|
return root;
|
|
@@ -14650,6 +14690,9 @@ class WorkitCore {
|
|
|
14650
14690
|
return success(changed.data.revision, null, changed.data.policy);
|
|
14651
14691
|
}
|
|
14652
14692
|
evidence(request) {
|
|
14693
|
+
return this.retryOmittedRevisions(request, () => this.evidenceOnce(request));
|
|
14694
|
+
}
|
|
14695
|
+
evidenceOnce(request) {
|
|
14653
14696
|
const root = this.contextRootError();
|
|
14654
14697
|
if (!root.ok)
|
|
14655
14698
|
return root;
|
|
@@ -14734,6 +14777,23 @@ class WorkitCore {
|
|
|
14734
14777
|
observeStandingDecision(request) {
|
|
14735
14778
|
return this.recordDecision(request, undefined, true, true);
|
|
14736
14779
|
}
|
|
14780
|
+
commitTask(taskId, expected, filled, recheck, update) {
|
|
14781
|
+
let revision = expected;
|
|
14782
|
+
let first = true;
|
|
14783
|
+
return retryFilledRevisions({ task: filled, workspace: false }, () => {
|
|
14784
|
+
if (!first) {
|
|
14785
|
+
const fresh = this.store.readTask(taskId);
|
|
14786
|
+
if (!fresh.ok)
|
|
14787
|
+
return fresh;
|
|
14788
|
+
const checked = recheck(fresh.data);
|
|
14789
|
+
if (!checked.ok)
|
|
14790
|
+
return checked;
|
|
14791
|
+
revision = fresh.data.revision;
|
|
14792
|
+
}
|
|
14793
|
+
first = false;
|
|
14794
|
+
return this.store.mutateTask(taskId, revision, update, trustedNow(this.context));
|
|
14795
|
+
});
|
|
14796
|
+
}
|
|
14737
14797
|
recordDecision(request, nativeObservation, nativeRequired = false, standing = false) {
|
|
14738
14798
|
const root = this.contextRootError();
|
|
14739
14799
|
if (!root.ok)
|
|
@@ -14758,6 +14818,7 @@ class WorkitCore {
|
|
|
14758
14818
|
return task;
|
|
14759
14819
|
if ((this.context.workerId ?? null) !== null)
|
|
14760
14820
|
return failure2("permission_denied", "helpers cannot record or revoke decisions");
|
|
14821
|
+
const filled = input.expectedRevision === undefined;
|
|
14761
14822
|
this.fillRevisions(input, task.data);
|
|
14762
14823
|
if (input.action === "record") {
|
|
14763
14824
|
if (task.data.status === "closed")
|
|
@@ -14806,7 +14867,20 @@ class WorkitCore {
|
|
|
14806
14867
|
const nativeProvenance = native?.ok ? retireNativeAuthority(native.data) : null;
|
|
14807
14868
|
if (native?.ok && !nativeProvenance)
|
|
14808
14869
|
return failure2("permission_denied", "native decision authority was retired");
|
|
14809
|
-
|
|
14870
|
+
let standingProvenance = standingApproval?.ok === true ? standingApproval.data : null;
|
|
14871
|
+
const recheck = (fresh) => {
|
|
14872
|
+
if (fresh.status === "closed")
|
|
14873
|
+
return failure2("invalid_transition", "closed task cannot record a decision");
|
|
14874
|
+
if (!standingProvenance)
|
|
14875
|
+
return success(null, null, null);
|
|
14876
|
+
const again = verifyStandingApproval(this.store.root, fresh, this.context.caller, input.binding);
|
|
14877
|
+
if (again.ok)
|
|
14878
|
+
standingProvenance = again.data;
|
|
14879
|
+
return again;
|
|
14880
|
+
};
|
|
14881
|
+
const changed = this.commitTask(task.data.id, input.expectedRevision, filled, recheck, (current, mutation) => {
|
|
14882
|
+
if (current.status === "closed")
|
|
14883
|
+
return failure2("invalid_transition", "closed task cannot record a decision");
|
|
14810
14884
|
const latestContent = verifyDecisionContent(this.store, input.binding);
|
|
14811
14885
|
if (!latestContent.ok)
|
|
14812
14886
|
return latestContent;
|
|
@@ -14818,14 +14892,14 @@ class WorkitCore {
|
|
|
14818
14892
|
const entry = {
|
|
14819
14893
|
id: newId(),
|
|
14820
14894
|
recordedAt: mutation.now,
|
|
14821
|
-
provenance:
|
|
14895
|
+
provenance: standingProvenance ?? nativeProvenance ?? provenance(this.context, "agent_reported"),
|
|
14822
14896
|
data
|
|
14823
14897
|
};
|
|
14824
14898
|
return success(mutation.revision, null, {
|
|
14825
14899
|
...current,
|
|
14826
14900
|
decisions: [...current.decisions, entry]
|
|
14827
14901
|
});
|
|
14828
|
-
}
|
|
14902
|
+
});
|
|
14829
14903
|
if (!changed.ok)
|
|
14830
14904
|
return changed;
|
|
14831
14905
|
return success(changed.data.revision, null, changed.data.decisions.at(-1));
|
|
@@ -14839,7 +14913,7 @@ class WorkitCore {
|
|
|
14839
14913
|
return failure2("invalid_transition", "decision is already revoked");
|
|
14840
14914
|
if (decision.data.consumption)
|
|
14841
14915
|
return failure2("permission_denied", "consumed decision cannot be revoked");
|
|
14842
|
-
const changed = this.
|
|
14916
|
+
const changed = this.commitTask(task.data.id, input.expectedRevision, filled, () => success(null, null, null), (current, mutation) => {
|
|
14843
14917
|
const entry = current.decisions.find((candidate) => candidate.id === input.decisionId);
|
|
14844
14918
|
if (!entry)
|
|
14845
14919
|
return failure2("not_found", "decision not found");
|
|
@@ -14856,13 +14930,16 @@ class WorkitCore {
|
|
|
14856
14930
|
...current,
|
|
14857
14931
|
decisions: current.decisions.map((candidate) => candidate.id === input.decisionId ? updated : candidate)
|
|
14858
14932
|
});
|
|
14859
|
-
}
|
|
14933
|
+
});
|
|
14860
14934
|
if (!changed.ok)
|
|
14861
14935
|
return changed;
|
|
14862
14936
|
const entry = changed.data.decisions.find((candidate) => candidate.id === input.decisionId);
|
|
14863
14937
|
return entry ? success(changed.data.revision, null, entry) : failure2("recovery_required", "decision disappeared");
|
|
14864
14938
|
}
|
|
14865
14939
|
finding(request) {
|
|
14940
|
+
return this.retryOmittedRevisions(request, () => this.findingOnce(request));
|
|
14941
|
+
}
|
|
14942
|
+
findingOnce(request) {
|
|
14866
14943
|
const root = this.contextRootError();
|
|
14867
14944
|
if (!root.ok)
|
|
14868
14945
|
return root;
|
|
@@ -14986,6 +15063,9 @@ class WorkitCore {
|
|
|
14986
15063
|
return entry ? success(changed.data.revision, null, entry) : failure2("recovery_required", "finding disappeared");
|
|
14987
15064
|
}
|
|
14988
15065
|
worker(request) {
|
|
15066
|
+
return this.retryOmittedRevisions(request, () => this.workerOnce(request));
|
|
15067
|
+
}
|
|
15068
|
+
workerOnce(request) {
|
|
14989
15069
|
const root = this.contextRootError();
|
|
14990
15070
|
if (!root.ok)
|
|
14991
15071
|
return root;
|
|
@@ -15333,6 +15413,9 @@ class WorkitCore {
|
|
|
15333
15413
|
return applied;
|
|
15334
15414
|
}
|
|
15335
15415
|
writer(request) {
|
|
15416
|
+
return this.retryOmittedRevisions(request, () => this.writerOnce(request));
|
|
15417
|
+
}
|
|
15418
|
+
writerOnce(request) {
|
|
15336
15419
|
const root = this.contextRootError();
|
|
15337
15420
|
if (!root.ok)
|
|
15338
15421
|
return root;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@brainervirus/workit-opencode",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Workit OpenCode plugin — native tools, adaptive policy, and fourteen method skills",
|
|
6
6
|
"keywords": [
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"typecheck": "tsc --noEmit"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@brainervirus/workit-core": "^2.2.
|
|
42
|
+
"@brainervirus/workit-core": "^2.2.2"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"@opencode-ai/plugin": "1.18.34",
|