@brainervirus/workit-cli 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.
Files changed (2) hide show
  1. package/dist/index.js +87 -9
  2. package/package.json +4 -4
package/dist/index.js CHANGED
@@ -9822,7 +9822,7 @@ class TaskStore {
9822
9822
  if (!current.data)
9823
9823
  return failure2("not_found", "workspace not found");
9824
9824
  if (current.data.revision !== expected)
9825
- return this.conflict(expected, current.data.revision);
9825
+ return this.workspaceConflict(expected, current.data.revision);
9826
9826
  const previousBytes = this.snapshotBytes(this.workspacePath);
9827
9827
  if (!previousBytes)
9828
9828
  return failure2("storage_error", "workspace snapshot disappeared during mutation");
@@ -9865,7 +9865,7 @@ class TaskStore {
9865
9865
  if (task.data.revision !== expected)
9866
9866
  return this.conflict(expected, task.data.revision);
9867
9867
  if (workspace.data.revision !== input.expectedWorkspaceRevision)
9868
- return this.conflict(input.expectedWorkspaceRevision, workspace.data.revision);
9868
+ return this.workspaceConflict(input.expectedWorkspaceRevision, workspace.data.revision);
9869
9869
  const previousWorkspaceBytes = this.snapshotBytes(this.workspacePath);
9870
9870
  const previousTaskBytes = this.snapshotBytes(this.taskPath(input.taskId));
9871
9871
  if (!previousWorkspaceBytes || !previousTaskBytes)
@@ -10675,6 +10675,9 @@ class TaskStore {
10675
10675
  actualRevision: actual
10676
10676
  });
10677
10677
  }
10678
+ workspaceConflict(expected, actual) {
10679
+ return failure2("revision_conflict", "workspace revision does not match; omit expectedWorkspaceRevision to use the current record", { expectedWorkspaceRevision: expected, actualWorkspaceRevision: actual });
10680
+ }
10678
10681
  taskPath(taskId) {
10679
10682
  return path5.join(this.tasksDir, `${taskId}.json`);
10680
10683
  }
@@ -14756,6 +14759,9 @@ class WorkitCore {
14756
14759
  if (input.expectedWorkspaceRevision === undefined)
14757
14760
  input.expectedWorkspaceRevision = workspace ? workspace.revision : null;
14758
14761
  }
14762
+ retryOmittedRevisions(request, run) {
14763
+ return retryFilledRevisions(filledRevisions(request), run);
14764
+ }
14759
14765
  helperEntry(task, requireSession = false, requireActive = false) {
14760
14766
  const workerId = this.context.workerId ?? null;
14761
14767
  if (workerId === null)
@@ -14787,6 +14793,9 @@ class WorkitCore {
14787
14793
  return null;
14788
14794
  }
14789
14795
  state(request) {
14796
+ return request?.action === "import" ? this.retryOmittedRevisions(request, () => this.stateOnce(request)) : this.stateOnce(request);
14797
+ }
14798
+ stateOnce(request) {
14790
14799
  const root = this.contextRootError();
14791
14800
  if (!root.ok)
14792
14801
  return root;
@@ -14888,6 +14897,9 @@ class WorkitCore {
14888
14897
  });
14889
14898
  }
14890
14899
  task(request) {
14900
+ return this.retryOmittedRevisions(request, () => this.taskOnce(request));
14901
+ }
14902
+ taskOnce(request) {
14891
14903
  const root = this.contextRootError();
14892
14904
  if (!root.ok)
14893
14905
  return root;
@@ -14987,6 +14999,9 @@ class WorkitCore {
14987
14999
  }
14988
15000
  }
14989
15001
  policy(request) {
15002
+ return this.retryOmittedRevisions(request, () => this.policyOnce(request));
15003
+ }
15004
+ policyOnce(request) {
14990
15005
  const root = this.contextRootError();
14991
15006
  if (!root.ok)
14992
15007
  return root;
@@ -15033,6 +15048,9 @@ class WorkitCore {
15033
15048
  return success(changed.data.revision, null, changed.data.policy);
15034
15049
  }
15035
15050
  evidence(request) {
15051
+ return this.retryOmittedRevisions(request, () => this.evidenceOnce(request));
15052
+ }
15053
+ evidenceOnce(request) {
15036
15054
  const root = this.contextRootError();
15037
15055
  if (!root.ok)
15038
15056
  return root;
@@ -15117,6 +15135,23 @@ class WorkitCore {
15117
15135
  observeStandingDecision(request) {
15118
15136
  return this.recordDecision(request, undefined, true, true);
15119
15137
  }
15138
+ commitTask(taskId, expected, filled, recheck, update) {
15139
+ let revision = expected;
15140
+ let first = true;
15141
+ return retryFilledRevisions({ task: filled, workspace: false }, () => {
15142
+ if (!first) {
15143
+ const fresh = this.store.readTask(taskId);
15144
+ if (!fresh.ok)
15145
+ return fresh;
15146
+ const checked = recheck(fresh.data);
15147
+ if (!checked.ok)
15148
+ return checked;
15149
+ revision = fresh.data.revision;
15150
+ }
15151
+ first = false;
15152
+ return this.store.mutateTask(taskId, revision, update, trustedNow(this.context));
15153
+ });
15154
+ }
15120
15155
  recordDecision(request, nativeObservation, nativeRequired = false, standing = false) {
15121
15156
  const root = this.contextRootError();
15122
15157
  if (!root.ok)
@@ -15141,6 +15176,7 @@ class WorkitCore {
15141
15176
  return task;
15142
15177
  if ((this.context.workerId ?? null) !== null)
15143
15178
  return failure2("permission_denied", "helpers cannot record or revoke decisions");
15179
+ const filled = input.expectedRevision === undefined;
15144
15180
  this.fillRevisions(input, task.data);
15145
15181
  if (input.action === "record") {
15146
15182
  if (task.data.status === "closed")
@@ -15189,7 +15225,20 @@ class WorkitCore {
15189
15225
  const nativeProvenance = native?.ok ? retireNativeAuthority(native.data) : null;
15190
15226
  if (native?.ok && !nativeProvenance)
15191
15227
  return failure2("permission_denied", "native decision authority was retired");
15192
- const changed = this.store.mutateTask(task.data.id, input.expectedRevision, (current, mutation) => {
15228
+ let standingProvenance = standingApproval?.ok === true ? standingApproval.data : null;
15229
+ const recheck = (fresh) => {
15230
+ if (fresh.status === "closed")
15231
+ return failure2("invalid_transition", "closed task cannot record a decision");
15232
+ if (!standingProvenance)
15233
+ return success(null, null, null);
15234
+ const again = verifyStandingApproval(this.store.root, fresh, this.context.caller, input.binding);
15235
+ if (again.ok)
15236
+ standingProvenance = again.data;
15237
+ return again;
15238
+ };
15239
+ const changed = this.commitTask(task.data.id, input.expectedRevision, filled, recheck, (current, mutation) => {
15240
+ if (current.status === "closed")
15241
+ return failure2("invalid_transition", "closed task cannot record a decision");
15193
15242
  const latestContent = verifyDecisionContent(this.store, input.binding);
15194
15243
  if (!latestContent.ok)
15195
15244
  return latestContent;
@@ -15201,14 +15250,14 @@ class WorkitCore {
15201
15250
  const entry = {
15202
15251
  id: newId(),
15203
15252
  recordedAt: mutation.now,
15204
- provenance: standingApproval?.ok === true ? standingApproval.data : nativeProvenance ?? provenance(this.context, "agent_reported"),
15253
+ provenance: standingProvenance ?? nativeProvenance ?? provenance(this.context, "agent_reported"),
15205
15254
  data
15206
15255
  };
15207
15256
  return success(mutation.revision, null, {
15208
15257
  ...current,
15209
15258
  decisions: [...current.decisions, entry]
15210
15259
  });
15211
- }, trustedNow(this.context));
15260
+ });
15212
15261
  if (!changed.ok)
15213
15262
  return changed;
15214
15263
  return success(changed.data.revision, null, changed.data.decisions.at(-1));
@@ -15222,7 +15271,7 @@ class WorkitCore {
15222
15271
  return failure2("invalid_transition", "decision is already revoked");
15223
15272
  if (decision.data.consumption)
15224
15273
  return failure2("permission_denied", "consumed decision cannot be revoked");
15225
- const changed = this.store.mutateTask(task.data.id, input.expectedRevision, (current, mutation) => {
15274
+ const changed = this.commitTask(task.data.id, input.expectedRevision, filled, () => success(null, null, null), (current, mutation) => {
15226
15275
  const entry = current.decisions.find((candidate) => candidate.id === input.decisionId);
15227
15276
  if (!entry)
15228
15277
  return failure2("not_found", "decision not found");
@@ -15239,13 +15288,16 @@ class WorkitCore {
15239
15288
  ...current,
15240
15289
  decisions: current.decisions.map((candidate) => candidate.id === input.decisionId ? updated : candidate)
15241
15290
  });
15242
- }, trustedNow(this.context));
15291
+ });
15243
15292
  if (!changed.ok)
15244
15293
  return changed;
15245
15294
  const entry = changed.data.decisions.find((candidate) => candidate.id === input.decisionId);
15246
15295
  return entry ? success(changed.data.revision, null, entry) : failure2("recovery_required", "decision disappeared");
15247
15296
  }
15248
15297
  finding(request) {
15298
+ return this.retryOmittedRevisions(request, () => this.findingOnce(request));
15299
+ }
15300
+ findingOnce(request) {
15249
15301
  const root = this.contextRootError();
15250
15302
  if (!root.ok)
15251
15303
  return root;
@@ -15369,6 +15421,9 @@ class WorkitCore {
15369
15421
  return entry ? success(changed.data.revision, null, entry) : failure2("recovery_required", "finding disappeared");
15370
15422
  }
15371
15423
  worker(request) {
15424
+ return this.retryOmittedRevisions(request, () => this.workerOnce(request));
15425
+ }
15426
+ workerOnce(request) {
15372
15427
  const root = this.contextRootError();
15373
15428
  if (!root.ok)
15374
15429
  return root;
@@ -15716,6 +15771,9 @@ class WorkitCore {
15716
15771
  return applied;
15717
15772
  }
15718
15773
  writer(request) {
15774
+ return this.retryOmittedRevisions(request, () => this.writerOnce(request));
15775
+ }
15776
+ writerOnce(request) {
15719
15777
  const root = this.contextRootError();
15720
15778
  if (!root.ok)
15721
15779
  return root;
@@ -16474,7 +16532,25 @@ var provenance = (context, kind = context.provenanceKind ?? "host_observed") =>
16474
16532
  return changed;
16475
16533
  const updated = changed.data.task.workers.find((candidate) => candidate.id === input.workerId);
16476
16534
  return updated ? success(changed.data.task.revision, changed.data.workspace.revision, updated) : failure2("recovery_required", "worker disappeared during lifecycle observation");
16477
- }, refsWithinScope = (refs, scope) => refs.every((ref) => ref.kind !== "file" || bindingCovers(scope, { description: "", paths: [ref.path], exclusions: [] })), trustedNow = (context) => typeof context.now === "function" ? context.now() : context.now, mapRef = (ref, ids) => {
16535
+ }, refsWithinScope = (refs, scope) => refs.every((ref) => ref.kind !== "file" || bindingCovers(scope, { description: "", paths: [ref.path], exclusions: [] })), REVISION_RETRY_ATTEMPTS = 8, retryPause, filledRevisions = (request) => {
16536
+ const value = typeof request === "object" && request !== null ? request : {};
16537
+ return {
16538
+ task: value.expectedRevision === undefined,
16539
+ workspace: value.expectedWorkspaceRevision === undefined
16540
+ };
16541
+ }, filledConflict = (result, filled) => !result.ok && result.code === "revision_conflict" && (("actualRevision" in result.details) && filled.task || ("actualWorkspaceRevision" in result.details) && filled.workspace), retryFilledRevisions = (filled, run) => {
16542
+ if (!filled.task && !filled.workspace)
16543
+ return run();
16544
+ let result = run();
16545
+ const deadline = Date.now() + defaultLockTimeout();
16546
+ for (let attempt = 1;filledConflict(result, filled); attempt += 1) {
16547
+ if (attempt >= REVISION_RETRY_ATTEMPTS || Date.now() >= deadline)
16548
+ return failure2("busy", "records kept changing under concurrent writers; retry the call");
16549
+ Atomics.wait(retryPause, 0, 0, Math.floor(Math.random() * 4 * attempt) + 1);
16550
+ result = run();
16551
+ }
16552
+ return result;
16553
+ }, trustedNow = (context) => typeof context.now === "function" ? context.now() : context.now, mapRef = (ref, ids) => {
16478
16554
  if (ref.kind !== "record")
16479
16555
  return ref;
16480
16556
  return { ...ref, id: ids.get(ref.id) ?? ref.id };
@@ -16685,11 +16761,13 @@ var init_task_engine = __esm(() => {
16685
16761
  init_authority();
16686
16762
  init_policy_resolver();
16687
16763
  init_auto_approval();
16764
+ init_store_lock();
16688
16765
  init_task_context();
16689
16766
  init_workers();
16690
16767
  init_task_evaluation();
16691
16768
  verifiedWorkers = new WeakMap;
16692
16769
  dispatchReservations = new WeakMap;
16770
+ retryPause = new Int32Array(new SharedArrayBuffer(4));
16693
16771
  });
16694
16772
 
16695
16773
  // packages/workit-core/src/core.ts
@@ -73026,7 +73104,7 @@ import path34 from "node:path";
73026
73104
  // packages/workit-cli/package.json
73027
73105
  var package_default = {
73028
73106
  name: "@brainervirus/workit-cli",
73029
- version: "2.1.5",
73107
+ version: "2.2.1",
73030
73108
  private: false,
73031
73109
  description: "Workit CLI — setup wizard, doctor, and task control for agentic coding workflows",
73032
73110
  keywords: [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brainervirus/workit-cli",
3
- "version": "2.2.0",
3
+ "version": "2.2.2",
4
4
  "private": false,
5
5
  "description": "Workit CLI — setup wizard, doctor, and task control for agentic coding workflows",
6
6
  "keywords": [
@@ -37,9 +37,9 @@
37
37
  "typecheck": "tsc --noEmit"
38
38
  },
39
39
  "dependencies": {
40
- "@brainervirus/workit-core": "^2.2.0",
41
- "@brainervirus/workit-cursor": "^2.2.0",
42
- "@brainervirus/workit-opencode": "^2.2.0",
40
+ "@brainervirus/workit-core": "^2.2.2",
41
+ "@brainervirus/workit-cursor": "^2.2.2",
42
+ "@brainervirus/workit-opencode": "^2.2.2",
43
43
  "@inkjs/ui": "2.0.0",
44
44
  "ink": "7.1.1",
45
45
  "react": "19.2.8"