@brainervirus/workit-cursor 1.0.8 → 1.0.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.
@@ -2,7 +2,7 @@
2
2
  "name": "workit",
3
3
  "displayName": "Workit",
4
4
  "description": "Adaptive Workit workflow with shared MCP tools and native Cursor hooks",
5
- "version": "1.0.8",
5
+ "version": "1.0.9",
6
6
  "author": {
7
7
  "name": "Cristhofer Pincetti"
8
8
  },
@@ -7832,7 +7832,7 @@ var init_task_contract = __esm(() => {
7832
7832
  }).strict();
7833
7833
  workerSchema = object({
7834
7834
  assignment: assignmentSchema,
7835
- state: _enum(["assigned", "running", "cancelling", "stopped", "unknown"]),
7835
+ state: _enum(["assigned", "dispatching", "running", "cancelling", "stopped", "unknown"]),
7836
7836
  session: refSchema.nullable(),
7837
7837
  report: workerReportSchema.nullable()
7838
7838
  }).strict();
@@ -10478,6 +10478,95 @@ var init_task_evaluation = __esm(() => {
10478
10478
  scopeCovers2 = scopeCovers;
10479
10479
  });
10480
10480
 
10481
+ // packages/workit-core/src/core/methods.ts
10482
+ function selectMethods(policy, capabilities) {
10483
+ return Object.entries(METHODS).flatMap(([id, definition]) => {
10484
+ const requirements = policy.requirements.filter((requirement) => methodMatches(id, definition, requirement));
10485
+ if (requirements.length === 0)
10486
+ return [];
10487
+ const capability = assuranceFor(id, definition, capabilities);
10488
+ const reasons = [
10489
+ ...new Set(requirements.map((requirement) => requirement.reason)),
10490
+ ...capability.reasons
10491
+ ];
10492
+ if (capability.assurance === "unavailable")
10493
+ reasons.unshift("required capability is unavailable");
10494
+ return [{ id, reason: reasons.join("; "), assurance: capability.assurance }];
10495
+ });
10496
+ }
10497
+ var METHODS, methodMatches = (id, definition, requirement) => definition.dimensions?.includes(requirement.dimension) === true && !(id === "workit-review" && requirement.ruleId === "self-review") || definition.ruleIds?.includes(requirement.ruleId) === true, assuranceFor = (id, definition, capabilities) => {
10498
+ const keys = new Set([
10499
+ id,
10500
+ ...definition.dimensions ?? [],
10501
+ ...definition.ruleIds ?? []
10502
+ ]);
10503
+ const matches = capabilities.filter((capability) => keys.has(capability.name) || keys.has(capability.surface));
10504
+ if (id === "workit-review" && matches.length === 0)
10505
+ return { assurance: "unavailable", reasons: ["independent review capability is unavailable"] };
10506
+ if (matches.some((capability) => capability.assurance === "unavailable"))
10507
+ return {
10508
+ assurance: "unavailable",
10509
+ reasons: matches.filter((capability) => capability.assurance === "unavailable").map((capability) => capability.reason)
10510
+ };
10511
+ if (matches.some((capability) => capability.assurance === "enforced"))
10512
+ return { assurance: "enforced", reasons: matches.map((capability) => capability.reason) };
10513
+ return { assurance: "agent_guided", reasons: matches.map((capability) => capability.reason) };
10514
+ }, invariantBootstrap = () => `
10515
+ Workit keeps one accountable lead and one shared task state. Inspect current task
10516
+ state before acting. An empty task.list means no session yet, not permission to
10517
+ skip Workit; for user-requested product, debug, or behavior work with no active
10518
+ or paused task, run task.start then policy.assess before other product mutations.
10519
+ Omitted expectedRevision, expectedWorkspaceRevision, and writer workerId default
10520
+ to the current records; explicit values are still concurrency-checked, so never
10521
+ copy revisions between calls. Happy path: task.list, task.start {intent} with no
10522
+ revisions, policy.assess {assessment: {facts, signals, consequences,
10523
+ verification}} where facts are inferred or observed with file refs,
10524
+ writer.acquire {taskId} before product writes, evidence.record {evidence} where
10525
+ check and review kinds auto-bind the current tree and need no digests. Record
10526
+ self-review requirements with kind review and reviewContext matching your own
10527
+ host session; the lead may also record checks. Fresh-context review requires a
10528
+ session distinct from the task creator and every other evidence recorder. Record
10529
+ verification evidence last: later evidence or commits can reopen fixed findings
10530
+ for re-verification, so verify, resolve, then close with nothing in between.
10531
+ decision.record {binding with taskId/workspaceId from inspect plus presented and
10532
+ approvedContent} only through a native approval question asked receipt-shaped:
10533
+ header Workit decision: <purpose>, the same label repeated in the question
10534
+ text (some host UIs do not render headers), exactly two options approved and
10535
+ rejected; ask once, never re-ask to mint a receipt. task.close {outcome,
10536
+ summary, decisionIds}. A completed native subagent run stops its bound worker
10537
+ by itself; if a worker strands in cancelling with its run verifiably over,
10538
+ repeat worker.cancel {reason} to confirm the stop. Check and review evidence
10539
+ without a bound candidate goes stale; findings close only as fixed with passing
10540
+ verification, dismissed with supporting evidence, or deferred under an approved
10541
+ limitation. Use only the
10542
+ shared operations for task, policy, evidence, finding, decision, worker, writer,
10543
+ and state changes. Authority is bounded by the requested scope, current
10544
+ revision, caller/session provenance, and observed capabilities. Never claim host
10545
+ enforcement or evidence that the host cannot provide. Shell-executed writes are
10546
+ unattested agent-guided work even when a writer is held. Preserve unresolved
10547
+ requirements, gaps, and uncertain workers. Skill routing: slash aliases /wk-*
10548
+ always load on demand. Model-invoked: new instructions, interruptions, or
10549
+ forgotten items mid-task → load workit-steer before responding; about to open
10550
+ a PR or fresh from implementing → load workit-deslop; CI red → load
10551
+ workit-green-run; small-looking change before close or merge → load
10552
+ workit-blast-radius; ambiguous, consequential, or disputed proposal before
10553
+ recommending → load workit-challenge; spec or plan needs a flow diagram →
10554
+ load workit-diagram, a UI sketch → load workit-mockup. Load the skill; never
10555
+ act from memory of it.
10556
+ `.trim();
10557
+ var init_methods = __esm(() => {
10558
+ METHODS = {
10559
+ "workit-challenge": { dimensions: ["challenge", "decisions"] },
10560
+ "workit-behavioral-tdd": { dimensions: ["testing"] },
10561
+ "workit-review": { dimensions: ["review"] },
10562
+ "workit-plan": { dimensions: ["artifacts", "continuity"] },
10563
+ "workit-implement": { dimensions: ["delegation"] },
10564
+ "workit-debug": { ruleIds: ["root-cause-investigation"] },
10565
+ "workit-handoff": { ruleIds: ["durable-handoff"] },
10566
+ "workit-deslop": { ruleIds: ["pre-pr-cleanup"] }
10567
+ };
10568
+ });
10569
+
10481
10570
  // packages/workit-core/src/core/task-context.ts
10482
10571
  function reconcileResume(view, observations = []) {
10483
10572
  if (observations.length > 0)
@@ -10487,7 +10576,7 @@ function reconcileResume(view, observations = []) {
10487
10576
  return candidate;
10488
10577
  const staleEvidenceIds = evaluateEvidence(view.task, candidate.data).filter((entry) => entry.status === "stale").map((entry) => entry.evidenceId);
10489
10578
  const blockers = [...view.task.progress.blockers];
10490
- if (view.task.workers.some((entry) => ["running", "cancelling", "unknown"].includes(entry.data.state)))
10579
+ if (view.task.workers.some((entry) => ["dispatching", "running", "cancelling", "unknown"].includes(entry.data.state)))
10491
10580
  blockers.push({
10492
10581
  reason: "worker state requires reconciliation",
10493
10582
  dependentAction: "resume",
@@ -10509,6 +10598,11 @@ function compactTaskContext(view) {
10509
10598
  digest: entry.data.digest,
10510
10599
  references: entry.data.binding.contentRefs.slice(0, 1).map(compactReference)
10511
10600
  }));
10601
+ const methods = view.task.policy ? selectMethods(view.task.policy, view.capabilities).map((method) => ({
10602
+ id: method.id,
10603
+ assurance: method.assurance,
10604
+ reason: compactText(method.reason, COMPACT_TEXT_BYTES) ?? ""
10605
+ })) : [];
10512
10606
  const gaps = Array.from(new Set([
10513
10607
  ...view.evidence.filter((entry) => entry.status === "stale").map((entry) => `stale evidence: ${entry.evidenceId}`),
10514
10608
  ...view.requirements.filter((entry) => entry.status !== "satisfied").map((entry) => entry.reason),
@@ -10518,15 +10612,18 @@ function compactTaskContext(view) {
10518
10612
  objective: compactText(view.task.intent.data.objective, COMPACT_TEXT_BYTES) ?? "",
10519
10613
  status: view.task.status,
10520
10614
  decisions,
10615
+ methods,
10521
10616
  gaps,
10522
10617
  nextAction: compactText(view.task.progress.nextAction, COMPACT_TEXT_BYTES)
10523
10618
  };
10524
10619
  let encoded = JSON.stringify(context);
10525
- while (compactBytes(encoded) > COMPACT_MAX_BYTES && (context.decisions.length || context.gaps.length)) {
10620
+ while (compactBytes(encoded) > COMPACT_MAX_BYTES && (context.decisions.length || context.methods.length || context.gaps.length)) {
10526
10621
  if (context.gaps.length)
10527
10622
  context.gaps.pop();
10528
- else
10623
+ else if (context.decisions.length)
10529
10624
  context.decisions.pop();
10625
+ else
10626
+ context.methods.pop();
10530
10627
  encoded = JSON.stringify(context);
10531
10628
  }
10532
10629
  if (compactBytes(encoded) > COMPACT_MAX_BYTES) {
@@ -10564,56 +10661,14 @@ var COMPACT_MAX_BYTES = 4096, COMPACT_MAX_ITEMS = 8, COMPACT_TEXT_BYTES = 128, s
10564
10661
  var init_task_context = __esm(() => {
10565
10662
  init_task_contract();
10566
10663
  init_task_evaluation();
10664
+ init_methods();
10567
10665
  sensitiveUrl = /\bhttps?:\/\/[^/\s:@]+:[^@\s]+@/gi;
10568
10666
  sensitiveValue = /(?:token|secret|password|passwd|api[-_ ]?key|private[-_ ]?key|authorization)\s*[:=]\s*(?:bearer\s+)?\S+|\bbearer\s+\S+/gi;
10569
10667
  privateKey = /-----BEGIN [^-]*PRIVATE KEY-----[\s\S]*?-----END [^-]*PRIVATE KEY-----/gi;
10570
10668
  });
10571
10669
 
10572
- // packages/workit-core/src/core/methods.ts
10573
- var invariantBootstrap = () => `
10574
- Workit keeps one accountable lead and one shared task state. Inspect current task
10575
- state before acting. An empty task.list means no session yet, not permission to
10576
- skip Workit; for user-requested product, debug, or behavior work with no active
10577
- or paused task, run task.start then policy.assess before other product mutations.
10578
- Omitted expectedRevision, expectedWorkspaceRevision, and writer workerId default
10579
- to the current records; explicit values are still concurrency-checked, so never
10580
- copy revisions between calls. Happy path: task.list, task.start {intent} with no
10581
- revisions, policy.assess {assessment: {facts, signals, consequences,
10582
- verification}} where facts are inferred or observed with file refs,
10583
- writer.acquire {taskId} before product writes, evidence.record {evidence} where
10584
- check and review kinds auto-bind the current tree and need no digests. Record
10585
- self-review requirements with kind review and reviewContext matching your own
10586
- host session; the lead may also record checks. Fresh-context review requires a
10587
- session distinct from the task creator and every other evidence recorder. Record
10588
- verification evidence last: later evidence or commits can reopen fixed findings
10589
- for re-verification, so verify, resolve, then close with nothing in between.
10590
- decision.record {binding with taskId/workspaceId from inspect plus presented and
10591
- approvedContent} only through a native approval question asked receipt-shaped:
10592
- header Workit decision: <purpose>, the same label repeated in the question
10593
- text (some host UIs do not render headers), exactly two options approved and
10594
- rejected; ask once, never re-ask to mint a receipt. task.close {outcome,
10595
- summary, decisionIds}. A completed native subagent run stops its bound worker
10596
- by itself; if a worker strands in cancelling with its run verifiably over,
10597
- repeat worker.cancel {reason} to confirm the stop. Check and review evidence
10598
- without a bound candidate goes stale; findings close only as fixed with passing
10599
- verification, dismissed with supporting evidence, or deferred under an approved
10600
- limitation. Use only the
10601
- shared operations for task, policy, evidence, finding, decision, worker, writer,
10602
- and state changes. Authority is bounded by the requested scope, current
10603
- revision, caller/session provenance, and observed capabilities. Never claim host
10604
- enforcement or evidence that the host cannot provide. Shell-executed writes are
10605
- unattested agent-guided work even when a writer is held. Preserve unresolved
10606
- requirements, gaps, and uncertain workers. Skill routing: slash aliases /wk-*
10607
- always load on demand. Model-invoked: new instructions, interruptions, or
10608
- forgotten items mid-task → load workit-steer before responding; about to open
10609
- a PR or fresh from implementing → load workit-deslop; CI red → load
10610
- workit-green-run; small-looking change before close or merge → load
10611
- workit-blast-radius; ambiguous, consequential, or disputed proposal before
10612
- recommending → load workit-challenge; spec or plan needs a flow diagram →
10613
- load workit-diagram, a UI sketch → load workit-mockup. Load the skill; never
10614
- act from memory of it.
10615
- `.trim();
10616
- var init_methods = () => {};
10670
+ // packages/workit-core/src/core/route-intent.ts
10671
+ var init_route_intent = () => {};
10617
10672
 
10618
10673
  // packages/workit-core/src/core/external-action.ts
10619
10674
  var externalActionSchema;
@@ -11140,7 +11195,7 @@ class WorkitCore {
11140
11195
  activeWorkerBlocker(task, workspace) {
11141
11196
  if (workspace.writer)
11142
11197
  return failure("recovery_required", "writer ownership must be released first");
11143
- if (task.workers.some((entry) => ["running", "cancelling", "unknown"].includes(entry.data.state)))
11198
+ if (task.workers.some((entry) => ["dispatching", "running", "cancelling", "unknown"].includes(entry.data.state)))
11144
11199
  return failure("recovery_required", "worker state requires reconciliation");
11145
11200
  return null;
11146
11201
  }
@@ -11904,7 +11959,12 @@ class WorkitCore {
11904
11959
  return failure("invalid_transition", "worker is not awaiting dispatch");
11905
11960
  return success(mutation.revision, null, {
11906
11961
  ...current,
11907
- workers: current.workers.map((item) => item.id === input.workerId ? { ...item, recordedAt: mutation.now, provenance: attested.data } : item)
11962
+ workers: current.workers.map((item) => item.id === input.workerId ? {
11963
+ ...item,
11964
+ recordedAt: mutation.now,
11965
+ provenance: attested.data,
11966
+ data: { ...item.data, state: "dispatching" }
11967
+ } : item)
11908
11968
  });
11909
11969
  }
11910
11970
  });
@@ -12373,7 +12433,7 @@ class WorkitCore {
12373
12433
  const base = reconcileResume(effectiveView);
12374
12434
  if (!base.ok)
12375
12435
  return base;
12376
- const needsReconciliation = view.task.workers.some((entry) => ["running", "cancelling", "unknown"].includes(observedStates.get(entry.id) ?? entry.data.state));
12436
+ const needsReconciliation = view.task.workers.some((entry) => ["dispatching", "running", "cancelling", "unknown"].includes(observedStates.get(entry.id) ?? entry.data.state));
12377
12437
  const blockers = [...base.data.blockers];
12378
12438
  if (needsReconciliation && !blockers.some((entry) => entry.reason === "worker state requires reconciliation"))
12379
12439
  blockers.push({
@@ -12664,10 +12724,10 @@ var provenance = (context, kind = context.provenanceKind ?? "host_observed") =>
12664
12724
  const notStarted = input.dispatch === true;
12665
12725
  if (notStarted && (input.state !== "stopped" || input.session !== null))
12666
12726
  return failure("invalid_input", "a never-dispatched worker stops with no session");
12667
- if (notStarted && (entry.data.state === "stopped" || entry.data.state === "unknown"))
12668
- return failure("invalid_transition", "worker is no longer awaiting dispatch");
12669
- if (notStarted && (entry.data.session !== null || entry.data.state === "running"))
12727
+ if (notStarted && entry.data.session !== null)
12670
12728
  return failure("invalid_transition", "worker already has an observed session");
12729
+ if (notStarted && !["dispatching", "cancelling"].includes(entry.data.state))
12730
+ return failure("invalid_transition", "worker launch was not claimed");
12671
12731
  if ((input.state === "running" || input.state === "cancelling" || input.state === "stopped" && !notStarted) && !input.session)
12672
12732
  return failure("invalid_input", "running worker observations require a session");
12673
12733
  if (entry.data.session && !sameValue(entry.data.session, input.session))
@@ -13002,6 +13062,7 @@ var init_core3 = __esm(() => {
13002
13062
  init_task_store();
13003
13063
  init_task_context();
13004
13064
  init_methods();
13065
+ init_route_intent();
13005
13066
  init_authority();
13006
13067
  init_external_action();
13007
13068
  init_external_action();
@@ -20310,7 +20310,7 @@ var workerReportSchema = object4({
20310
20310
  }).strict();
20311
20311
  var workerSchema = object4({
20312
20312
  assignment: assignmentSchema,
20313
- state: _enum2(["assigned", "running", "cancelling", "stopped", "unknown"]),
20313
+ state: _enum2(["assigned", "dispatching", "running", "cancelling", "stopped", "unknown"]),
20314
20314
  session: refSchema.nullable(),
20315
20315
  report: workerReportSchema.nullable()
20316
20316
  }).strict();
@@ -23144,7 +23144,7 @@ function reconcileResume(view, observations = []) {
23144
23144
  return candidate;
23145
23145
  const staleEvidenceIds = evaluateEvidence(view.task, candidate.data).filter((entry) => entry.status === "stale").map((entry) => entry.evidenceId);
23146
23146
  const blockers = [...view.task.progress.blockers];
23147
- if (view.task.workers.some((entry) => ["running", "cancelling", "unknown"].includes(entry.data.state)))
23147
+ if (view.task.workers.some((entry) => ["dispatching", "running", "cancelling", "unknown"].includes(entry.data.state)))
23148
23148
  blockers.push({
23149
23149
  reason: "worker state requires reconciliation",
23150
23150
  dependentAction: "resume",
@@ -23752,10 +23752,10 @@ var applyWorkerLifecycle = (input) => {
23752
23752
  const notStarted = input.dispatch === true;
23753
23753
  if (notStarted && (input.state !== "stopped" || input.session !== null))
23754
23754
  return failure("invalid_input", "a never-dispatched worker stops with no session");
23755
- if (notStarted && (entry.data.state === "stopped" || entry.data.state === "unknown"))
23756
- return failure("invalid_transition", "worker is no longer awaiting dispatch");
23757
- if (notStarted && (entry.data.session !== null || entry.data.state === "running"))
23755
+ if (notStarted && entry.data.session !== null)
23758
23756
  return failure("invalid_transition", "worker already has an observed session");
23757
+ if (notStarted && !["dispatching", "cancelling"].includes(entry.data.state))
23758
+ return failure("invalid_transition", "worker launch was not claimed");
23759
23759
  if ((input.state === "running" || input.state === "cancelling" || input.state === "stopped" && !notStarted) && !input.session)
23760
23760
  return failure("invalid_input", "running worker observations require a session");
23761
23761
  if (entry.data.session && !sameValue(entry.data.session, input.session))
@@ -24142,7 +24142,7 @@ class WorkitCore {
24142
24142
  activeWorkerBlocker(task, workspace) {
24143
24143
  if (workspace.writer)
24144
24144
  return failure("recovery_required", "writer ownership must be released first");
24145
- if (task.workers.some((entry) => ["running", "cancelling", "unknown"].includes(entry.data.state)))
24145
+ if (task.workers.some((entry) => ["dispatching", "running", "cancelling", "unknown"].includes(entry.data.state)))
24146
24146
  return failure("recovery_required", "worker state requires reconciliation");
24147
24147
  return null;
24148
24148
  }
@@ -24906,7 +24906,12 @@ class WorkitCore {
24906
24906
  return failure("invalid_transition", "worker is not awaiting dispatch");
24907
24907
  return success(mutation.revision, null, {
24908
24908
  ...current,
24909
- workers: current.workers.map((item) => item.id === input.workerId ? { ...item, recordedAt: mutation.now, provenance: attested.data } : item)
24909
+ workers: current.workers.map((item) => item.id === input.workerId ? {
24910
+ ...item,
24911
+ recordedAt: mutation.now,
24912
+ provenance: attested.data,
24913
+ data: { ...item.data, state: "dispatching" }
24914
+ } : item)
24910
24915
  });
24911
24916
  }
24912
24917
  });
@@ -25375,7 +25380,7 @@ class WorkitCore {
25375
25380
  const base = reconcileResume(effectiveView);
25376
25381
  if (!base.ok)
25377
25382
  return base;
25378
- const needsReconciliation = view.task.workers.some((entry) => ["running", "cancelling", "unknown"].includes(observedStates.get(entry.id) ?? entry.data.state));
25383
+ const needsReconciliation = view.task.workers.some((entry) => ["dispatching", "running", "cancelling", "unknown"].includes(observedStates.get(entry.id) ?? entry.data.state));
25379
25384
  const blockers = [...base.data.blockers];
25380
25385
  if (needsReconciliation && !blockers.some((entry) => entry.reason === "worker state requires reconciliation"))
25381
25386
  blockers.push({
@@ -7611,7 +7611,7 @@ var workerReportSchema = object({
7611
7611
  }).strict();
7612
7612
  var workerSchema = object({
7613
7613
  assignment: assignmentSchema,
7614
- state: _enum(["assigned", "running", "cancelling", "stopped", "unknown"]),
7614
+ state: _enum(["assigned", "dispatching", "running", "cancelling", "stopped", "unknown"]),
7615
7615
  session: refSchema.nullable(),
7616
7616
  report: workerReportSchema.nullable()
7617
7617
  }).strict();
@@ -10380,6 +10380,95 @@ function evaluateClosure(requestedOutcome, view) {
10380
10380
  });
10381
10381
  }
10382
10382
 
10383
+ // packages/workit-core/src/core/methods.ts
10384
+ var METHODS = {
10385
+ "workit-challenge": { dimensions: ["challenge", "decisions"] },
10386
+ "workit-behavioral-tdd": { dimensions: ["testing"] },
10387
+ "workit-review": { dimensions: ["review"] },
10388
+ "workit-plan": { dimensions: ["artifacts", "continuity"] },
10389
+ "workit-implement": { dimensions: ["delegation"] },
10390
+ "workit-debug": { ruleIds: ["root-cause-investigation"] },
10391
+ "workit-handoff": { ruleIds: ["durable-handoff"] },
10392
+ "workit-deslop": { ruleIds: ["pre-pr-cleanup"] }
10393
+ };
10394
+ var methodMatches = (id, definition, requirement) => definition.dimensions?.includes(requirement.dimension) === true && !(id === "workit-review" && requirement.ruleId === "self-review") || definition.ruleIds?.includes(requirement.ruleId) === true;
10395
+ var assuranceFor = (id, definition, capabilities) => {
10396
+ const keys = new Set([
10397
+ id,
10398
+ ...definition.dimensions ?? [],
10399
+ ...definition.ruleIds ?? []
10400
+ ]);
10401
+ const matches = capabilities.filter((capability) => keys.has(capability.name) || keys.has(capability.surface));
10402
+ if (id === "workit-review" && matches.length === 0)
10403
+ return { assurance: "unavailable", reasons: ["independent review capability is unavailable"] };
10404
+ if (matches.some((capability) => capability.assurance === "unavailable"))
10405
+ return {
10406
+ assurance: "unavailable",
10407
+ reasons: matches.filter((capability) => capability.assurance === "unavailable").map((capability) => capability.reason)
10408
+ };
10409
+ if (matches.some((capability) => capability.assurance === "enforced"))
10410
+ return { assurance: "enforced", reasons: matches.map((capability) => capability.reason) };
10411
+ return { assurance: "agent_guided", reasons: matches.map((capability) => capability.reason) };
10412
+ };
10413
+ function selectMethods(policy, capabilities) {
10414
+ return Object.entries(METHODS).flatMap(([id, definition]) => {
10415
+ const requirements = policy.requirements.filter((requirement) => methodMatches(id, definition, requirement));
10416
+ if (requirements.length === 0)
10417
+ return [];
10418
+ const capability = assuranceFor(id, definition, capabilities);
10419
+ const reasons = [
10420
+ ...new Set(requirements.map((requirement) => requirement.reason)),
10421
+ ...capability.reasons
10422
+ ];
10423
+ if (capability.assurance === "unavailable")
10424
+ reasons.unshift("required capability is unavailable");
10425
+ return [{ id, reason: reasons.join("; "), assurance: capability.assurance }];
10426
+ });
10427
+ }
10428
+ var invariantBootstrap = () => `
10429
+ Workit keeps one accountable lead and one shared task state. Inspect current task
10430
+ state before acting. An empty task.list means no session yet, not permission to
10431
+ skip Workit; for user-requested product, debug, or behavior work with no active
10432
+ or paused task, run task.start then policy.assess before other product mutations.
10433
+ Omitted expectedRevision, expectedWorkspaceRevision, and writer workerId default
10434
+ to the current records; explicit values are still concurrency-checked, so never
10435
+ copy revisions between calls. Happy path: task.list, task.start {intent} with no
10436
+ revisions, policy.assess {assessment: {facts, signals, consequences,
10437
+ verification}} where facts are inferred or observed with file refs,
10438
+ writer.acquire {taskId} before product writes, evidence.record {evidence} where
10439
+ check and review kinds auto-bind the current tree and need no digests. Record
10440
+ self-review requirements with kind review and reviewContext matching your own
10441
+ host session; the lead may also record checks. Fresh-context review requires a
10442
+ session distinct from the task creator and every other evidence recorder. Record
10443
+ verification evidence last: later evidence or commits can reopen fixed findings
10444
+ for re-verification, so verify, resolve, then close with nothing in between.
10445
+ decision.record {binding with taskId/workspaceId from inspect plus presented and
10446
+ approvedContent} only through a native approval question asked receipt-shaped:
10447
+ header Workit decision: <purpose>, the same label repeated in the question
10448
+ text (some host UIs do not render headers), exactly two options approved and
10449
+ rejected; ask once, never re-ask to mint a receipt. task.close {outcome,
10450
+ summary, decisionIds}. A completed native subagent run stops its bound worker
10451
+ by itself; if a worker strands in cancelling with its run verifiably over,
10452
+ repeat worker.cancel {reason} to confirm the stop. Check and review evidence
10453
+ without a bound candidate goes stale; findings close only as fixed with passing
10454
+ verification, dismissed with supporting evidence, or deferred under an approved
10455
+ limitation. Use only the
10456
+ shared operations for task, policy, evidence, finding, decision, worker, writer,
10457
+ and state changes. Authority is bounded by the requested scope, current
10458
+ revision, caller/session provenance, and observed capabilities. Never claim host
10459
+ enforcement or evidence that the host cannot provide. Shell-executed writes are
10460
+ unattested agent-guided work even when a writer is held. Preserve unresolved
10461
+ requirements, gaps, and uncertain workers. Skill routing: slash aliases /wk-*
10462
+ always load on demand. Model-invoked: new instructions, interruptions, or
10463
+ forgotten items mid-task → load workit-steer before responding; about to open
10464
+ a PR or fresh from implementing → load workit-deslop; CI red → load
10465
+ workit-green-run; small-looking change before close or merge → load
10466
+ workit-blast-radius; ambiguous, consequential, or disputed proposal before
10467
+ recommending → load workit-challenge; spec or plan needs a flow diagram →
10468
+ load workit-diagram, a UI sketch → load workit-mockup. Load the skill; never
10469
+ act from memory of it.
10470
+ `.trim();
10471
+
10383
10472
  // packages/workit-core/src/core/task-context.ts
10384
10473
  function reconcileResume(view, observations = []) {
10385
10474
  if (observations.length > 0)
@@ -10389,7 +10478,7 @@ function reconcileResume(view, observations = []) {
10389
10478
  return candidate;
10390
10479
  const staleEvidenceIds = evaluateEvidence(view.task, candidate.data).filter((entry) => entry.status === "stale").map((entry) => entry.evidenceId);
10391
10480
  const blockers = [...view.task.progress.blockers];
10392
- if (view.task.workers.some((entry) => ["running", "cancelling", "unknown"].includes(entry.data.state)))
10481
+ if (view.task.workers.some((entry) => ["dispatching", "running", "cancelling", "unknown"].includes(entry.data.state)))
10393
10482
  blockers.push({
10394
10483
  reason: "worker state requires reconciliation",
10395
10484
  dependentAction: "resume",
@@ -10439,6 +10528,11 @@ function compactTaskContext(view) {
10439
10528
  digest: entry.data.digest,
10440
10529
  references: entry.data.binding.contentRefs.slice(0, 1).map(compactReference)
10441
10530
  }));
10531
+ const methods = view.task.policy ? selectMethods(view.task.policy, view.capabilities).map((method) => ({
10532
+ id: method.id,
10533
+ assurance: method.assurance,
10534
+ reason: compactText(method.reason, COMPACT_TEXT_BYTES) ?? ""
10535
+ })) : [];
10442
10536
  const gaps = Array.from(new Set([
10443
10537
  ...view.evidence.filter((entry) => entry.status === "stale").map((entry) => `stale evidence: ${entry.evidenceId}`),
10444
10538
  ...view.requirements.filter((entry) => entry.status !== "satisfied").map((entry) => entry.reason),
@@ -10448,15 +10542,18 @@ function compactTaskContext(view) {
10448
10542
  objective: compactText(view.task.intent.data.objective, COMPACT_TEXT_BYTES) ?? "",
10449
10543
  status: view.task.status,
10450
10544
  decisions,
10545
+ methods,
10451
10546
  gaps,
10452
10547
  nextAction: compactText(view.task.progress.nextAction, COMPACT_TEXT_BYTES)
10453
10548
  };
10454
10549
  let encoded = JSON.stringify(context);
10455
- while (compactBytes(encoded) > COMPACT_MAX_BYTES && (context.decisions.length || context.gaps.length)) {
10550
+ while (compactBytes(encoded) > COMPACT_MAX_BYTES && (context.decisions.length || context.methods.length || context.gaps.length)) {
10456
10551
  if (context.gaps.length)
10457
10552
  context.gaps.pop();
10458
- else
10553
+ else if (context.decisions.length)
10459
10554
  context.decisions.pop();
10555
+ else
10556
+ context.methods.pop();
10460
10557
  encoded = JSON.stringify(context);
10461
10558
  }
10462
10559
  if (compactBytes(encoded) > COMPACT_MAX_BYTES) {
@@ -10472,50 +10569,6 @@ var exportDigest = (bundle) => sha256({
10472
10569
  sourceWorkspaceId: bundle.sourceWorkspaceId,
10473
10570
  task: bundle.task
10474
10571
  });
10475
- // packages/workit-core/src/core/methods.ts
10476
- var invariantBootstrap = () => `
10477
- Workit keeps one accountable lead and one shared task state. Inspect current task
10478
- state before acting. An empty task.list means no session yet, not permission to
10479
- skip Workit; for user-requested product, debug, or behavior work with no active
10480
- or paused task, run task.start then policy.assess before other product mutations.
10481
- Omitted expectedRevision, expectedWorkspaceRevision, and writer workerId default
10482
- to the current records; explicit values are still concurrency-checked, so never
10483
- copy revisions between calls. Happy path: task.list, task.start {intent} with no
10484
- revisions, policy.assess {assessment: {facts, signals, consequences,
10485
- verification}} where facts are inferred or observed with file refs,
10486
- writer.acquire {taskId} before product writes, evidence.record {evidence} where
10487
- check and review kinds auto-bind the current tree and need no digests. Record
10488
- self-review requirements with kind review and reviewContext matching your own
10489
- host session; the lead may also record checks. Fresh-context review requires a
10490
- session distinct from the task creator and every other evidence recorder. Record
10491
- verification evidence last: later evidence or commits can reopen fixed findings
10492
- for re-verification, so verify, resolve, then close with nothing in between.
10493
- decision.record {binding with taskId/workspaceId from inspect plus presented and
10494
- approvedContent} only through a native approval question asked receipt-shaped:
10495
- header Workit decision: <purpose>, the same label repeated in the question
10496
- text (some host UIs do not render headers), exactly two options approved and
10497
- rejected; ask once, never re-ask to mint a receipt. task.close {outcome,
10498
- summary, decisionIds}. A completed native subagent run stops its bound worker
10499
- by itself; if a worker strands in cancelling with its run verifiably over,
10500
- repeat worker.cancel {reason} to confirm the stop. Check and review evidence
10501
- without a bound candidate goes stale; findings close only as fixed with passing
10502
- verification, dismissed with supporting evidence, or deferred under an approved
10503
- limitation. Use only the
10504
- shared operations for task, policy, evidence, finding, decision, worker, writer,
10505
- and state changes. Authority is bounded by the requested scope, current
10506
- revision, caller/session provenance, and observed capabilities. Never claim host
10507
- enforcement or evidence that the host cannot provide. Shell-executed writes are
10508
- unattested agent-guided work even when a writer is held. Preserve unresolved
10509
- requirements, gaps, and uncertain workers. Skill routing: slash aliases /wk-*
10510
- always load on demand. Model-invoked: new instructions, interruptions, or
10511
- forgotten items mid-task → load workit-steer before responding; about to open
10512
- a PR or fresh from implementing → load workit-deslop; CI red → load
10513
- workit-green-run; small-looking change before close or merge → load
10514
- workit-blast-radius; ambiguous, consequential, or disputed proposal before
10515
- recommending → load workit-challenge; spec or plan needs a flow diagram →
10516
- load workit-diagram, a UI sketch → load workit-mockup. Load the skill; never
10517
- act from memory of it.
10518
- `.trim();
10519
10572
  // packages/workit-core/src/core/external-action.ts
10520
10573
  var externalActionSchema = discriminatedUnion("operation", [
10521
10574
  object({
@@ -11104,10 +11157,10 @@ var applyWorkerLifecycle = (input) => {
11104
11157
  const notStarted = input.dispatch === true;
11105
11158
  if (notStarted && (input.state !== "stopped" || input.session !== null))
11106
11159
  return failure("invalid_input", "a never-dispatched worker stops with no session");
11107
- if (notStarted && (entry.data.state === "stopped" || entry.data.state === "unknown"))
11108
- return failure("invalid_transition", "worker is no longer awaiting dispatch");
11109
- if (notStarted && (entry.data.session !== null || entry.data.state === "running"))
11160
+ if (notStarted && entry.data.session !== null)
11110
11161
  return failure("invalid_transition", "worker already has an observed session");
11162
+ if (notStarted && !["dispatching", "cancelling"].includes(entry.data.state))
11163
+ return failure("invalid_transition", "worker launch was not claimed");
11111
11164
  if ((input.state === "running" || input.state === "cancelling" || input.state === "stopped" && !notStarted) && !input.session)
11112
11165
  return failure("invalid_input", "running worker observations require a session");
11113
11166
  if (entry.data.session && !sameValue(entry.data.session, input.session))
@@ -11494,7 +11547,7 @@ class WorkitCore {
11494
11547
  activeWorkerBlocker(task, workspace) {
11495
11548
  if (workspace.writer)
11496
11549
  return failure("recovery_required", "writer ownership must be released first");
11497
- if (task.workers.some((entry) => ["running", "cancelling", "unknown"].includes(entry.data.state)))
11550
+ if (task.workers.some((entry) => ["dispatching", "running", "cancelling", "unknown"].includes(entry.data.state)))
11498
11551
  return failure("recovery_required", "worker state requires reconciliation");
11499
11552
  return null;
11500
11553
  }
@@ -12258,7 +12311,12 @@ class WorkitCore {
12258
12311
  return failure("invalid_transition", "worker is not awaiting dispatch");
12259
12312
  return success(mutation.revision, null, {
12260
12313
  ...current,
12261
- workers: current.workers.map((item) => item.id === input.workerId ? { ...item, recordedAt: mutation.now, provenance: attested.data } : item)
12314
+ workers: current.workers.map((item) => item.id === input.workerId ? {
12315
+ ...item,
12316
+ recordedAt: mutation.now,
12317
+ provenance: attested.data,
12318
+ data: { ...item.data, state: "dispatching" }
12319
+ } : item)
12262
12320
  });
12263
12321
  }
12264
12322
  });
@@ -12727,7 +12785,7 @@ class WorkitCore {
12727
12785
  const base = reconcileResume(effectiveView);
12728
12786
  if (!base.ok)
12729
12787
  return base;
12730
- const needsReconciliation = view.task.workers.some((entry) => ["running", "cancelling", "unknown"].includes(observedStates.get(entry.id) ?? entry.data.state));
12788
+ const needsReconciliation = view.task.workers.some((entry) => ["dispatching", "running", "cancelling", "unknown"].includes(observedStates.get(entry.id) ?? entry.data.state));
12731
12789
  const blockers = [...base.data.blockers];
12732
12790
  if (needsReconciliation && !blockers.some((entry) => entry.reason === "worker state requires reconciliation"))
12733
12791
  blockers.push({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brainervirus/workit-cursor",
3
- "version": "1.0.8",
3
+ "version": "1.0.9",
4
4
  "private": false,
5
5
  "description": "Workit Cursor plugin — shared MCP transport, native hooks, and fourteen method skills",
6
6
  "keywords": [
@@ -44,8 +44,8 @@
44
44
  "build": "bun scripts/build.ts"
45
45
  },
46
46
  "dependencies": {
47
- "@brainervirus/workit-core": "^1.0.8",
48
- "@brainervirus/workit-mcp": "^1.0.8"
47
+ "@brainervirus/workit-core": "^1.0.9",
48
+ "@brainervirus/workit-mcp": "^1.0.9"
49
49
  },
50
50
  "engines": {
51
51
  "node": ">=24"
@@ -7,7 +7,9 @@ description: Use after creating a PR (auto-starts, drive default), when a PR nee
7
7
 
8
8
  Babysit starts automatically on PR creation unless declined (`babysit:false`).
9
9
  One babysitter per PR; never mutate PR topology (no rebase strategy changes,
10
- no force-push).
10
+ no force-push). When a PR URL is observed from a route Workit did not enforce
11
+ (for example a raw `gh pr create` the host allowed), load this skill and drive
12
+ that PR anyway; do not claim the Workit route was enforced.
11
13
 
12
14
  ## Before method work
13
15